From 70f51d9567d93612036b2aad817a98be72a7af1f Mon Sep 17 00:00:00 2001 From: Marios Kyriakou Date: Tue, 28 Aug 2018 00:19:56 +0300 Subject: [PATCH 01/35] add ENsetdemandpattern --- include/epanet2.bas | 1 + include/epanet2.h | 10 ++++++++++ include/epanet2.vb | 4 +++- src/epanet.c | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 1 deletion(-) diff --git a/include/epanet2.bas b/include/epanet2.bas index 0ded96c..88f2135 100644 --- a/include/epanet2.bas +++ b/include/epanet2.bas @@ -254,6 +254,7 @@ Public Const EN_G_CURVE = 4 ' General\default curve Declare Function ENsetqualtype Lib "epanet2.dll" (ByVal QualCode As Long, ByVal ChemName As String, ByVal ChemUnits As String, ByVal TraceNode As String) As Long Declare Function ENgetqualinfo Lib "epanet2.dll" (QualCode As Long, ByVal ChemName As String, ByVal ChemUnits As String, TraceNode As Long) As Long Declare Function ENsetbasedemand Lib "epanet2.dll" (ByVal nodeIndex As Long, ByVal DemandIndex As Long, ByVal BaseDemand As Single) As Long + Declare Function ENsetdemandpattern Lib "epanet2.dll" (ByVal Index As Long, ByVal DemandIndex As Long, ByVal PatIndex 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 diff --git a/include/epanet2.h b/include/epanet2.h index e6d91c6..0aeb7b4 100644 --- a/include/epanet2.h +++ b/include/epanet2.h @@ -932,6 +932,15 @@ extern "C" { @see ENgetbasedemand */ int DLLEXPORT ENsetbasedemand(int nodeIndex, int demandIdx, EN_API_FLOAT_TYPE baseDemand); + + /** + @brief Sets the index of the demand pattern assigned to a node for a category index. + @param nodeIndex The index of a node (first node is index 1). + @param demandIndex The index of a category (first category is index 1). + @param pattIndex The index of the pattern for this node and category. + @return Error code + */ + int DLLEXPORT ENsetdemandpattern(int nodeIndex, int demandIdx, int patIndex); /** @brief Retrieves index of curve with specific ID. @@ -1265,6 +1274,7 @@ extern "C" { int DLLEXPORT EN_getqualinfo(EN_ProjectHandle ph, int *qualcode, char *chemname, char *chemunits, int *tracenode); int DLLEXPORT EN_setbasedemand(EN_ProjectHandle ph, int nodeIndex, int demandIdx, EN_API_FLOAT_TYPE baseDemand); + int DLLEXPORT EN_setdemandpattern(EN_ProjectHandle ph, int nodeIndex, int demandIdx, int patIndex); int DLLEXPORT EN_getcurveindex(EN_ProjectHandle ph, char *id, int *index); int DLLEXPORT EN_getcurveid(EN_ProjectHandle ph, int index, char *id); int DLLEXPORT EN_getcurvelen(EN_ProjectHandle ph, int index, int *len); diff --git a/include/epanet2.vb b/include/epanet2.vb index fcb71af..069db45 100644 --- a/include/epanet2.vb +++ b/include/epanet2.vb @@ -197,8 +197,10 @@ Public Const EN_CUSTOM = 2 ' user-defined custom curve Declare Function ENsetcoord Lib "epanet2.dll" (ByVal Index As Int32, ByVal X As Single, ByVal Y As Single) As Int32 Declare Function ENgetnumdemands Lib "epanet2.dll" (ByVal Index As Int32, ByRef numDemands As Int32) As Int32 'ES - Declare Function ENgetbasedemand Lib "epanet2.dll" (ByVal Index As Int32, ByVal DemandIndex As Int32, ByRef Value As Single) As Int32 'ES + Declare Function ENgetbasedemand Lib "epanet2.dll" (ByVal Index As Int32, ByVal DemandIndex As Int32, ByRef BaseDemand As Single) As Int32 'ES + Declare Function ENsetbasedemand Lib "epanet2.dll" (ByVal Index As Int32, ByVal DemandIndex As Int32, ByVal BaseDemand As Single) As Int32 'ES Declare Function ENgetdemandpattern Lib "epanet2.dll" (ByVal Index As Int32, ByVal DemandIndex As Int32, ByRef PatIndex As Int32) As Int32 'ES + Declare Function ENsetdemandpattern Lib "epanet2.dll" (ByVal Index As Int32, ByVal DemandIndex As Int32, ByVal PatIndex As Int32) As Int32 'ES Declare Function ENgetlinkindex Lib "epanet2.dll" (ByVal ID As String, ByRef Index As Int32) As Int32 Declare Function ENgetlinkid Lib "epanet2.dll" (ByVal Index As Int32, ByVal ID As StringBuilder) As Int32 diff --git a/src/epanet.c b/src/epanet.c index 6463c08..6f1254c 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -473,6 +473,10 @@ int DLLEXPORT ENsetbasedemand(int nodeIndex, int demandIdx, return EN_setbasedemand(_defaultModel, nodeIndex, demandIdx, baseDemand); } +int DLLEXPORT ENsetdemandpattern(int nodeIndex, int demandIdx, int patIndex) { + return EN_setdemandpattern(_defaultModel, nodeIndex, demandIdx, patIndex); +} + int DLLEXPORT ENgetdemandpattern(int nodeIndex, int demandIdx, int *pattIdx) { return EN_getdemandpattern(_defaultModel, nodeIndex, demandIdx, pattIdx); } @@ -4516,6 +4520,36 @@ int DLLEXPORT EN_setbasedemand(EN_ProjectHandle ph, int nodeIndex, int demandIdx return set_error(pr->error_handle, 0); } +int DLLEXPORT EN_setdemandpattern(EN_ProjectHandle ph, int nodeIndex, int demandIdx, int patIndex) { + + EN_Project *pr = (EN_Project*)ph; + + EN_Network *net = &pr->network; + Snode *Node = net->Node; + + const int Nnodes = net->Nnodes; + const int Njuncs = net->Njuncs; + const int Npats = net->Npats; + + Pdemand d; + int n = 1; + /* Check for valid arguments */ + if (!pr->Openflag) + return set_error(pr->error_handle, 102); + if (nodeIndex <= 0 || nodeIndex > Nnodes) + return set_error(pr->error_handle, 203); + if (patIndex < 1 || patIndex > Npats) + return(205); + if (nodeIndex <= Njuncs) { + for (d = Node[nodeIndex].D; n < demandIdx && d != NULL; d = d->next) + n++; + if (n != demandIdx) + return set_error(pr->error_handle, 253); + d->Pat = patIndex; + } + return set_error(pr->error_handle, 0); +} + int DLLEXPORT EN_getdemandpattern(EN_ProjectHandle ph, int nodeIndex, int demandIdx, int *pattIdx) { EN_Project *p = (EN_Project*)ph; From 8ca56d7c9d35b8a8f8ba617f4c030d8f243b6731 Mon Sep 17 00:00:00 2001 From: Marios Kyriakou Date: Tue, 28 Aug 2018 00:25:31 +0300 Subject: [PATCH 02/35] remove space --- src/epanet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/epanet.c b/src/epanet.c index 6f1254c..18c6540 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -473,7 +473,7 @@ int DLLEXPORT ENsetbasedemand(int nodeIndex, int demandIdx, return EN_setbasedemand(_defaultModel, nodeIndex, demandIdx, baseDemand); } -int DLLEXPORT ENsetdemandpattern(int nodeIndex, int demandIdx, int patIndex) { +int DLLEXPORT ENsetdemandpattern(int nodeIndex, int demandIdx, int patIndex) { return EN_setdemandpattern(_defaultModel, nodeIndex, demandIdx, patIndex); } From 476604bf6f14f406aca10890f09738da11006917 Mon Sep 17 00:00:00 2001 From: Marios Kyriakou Date: Tue, 28 Aug 2018 12:07:25 +0300 Subject: [PATCH 03/35] add ENsetdemandpattern function in epanet2.def --- win_build/WinSDK/epanet2.def | 1 + 1 file changed, 1 insertion(+) diff --git a/win_build/WinSDK/epanet2.def b/win_build/WinSDK/epanet2.def index 46c82c2..a497c50 100644 --- a/win_build/WinSDK/epanet2.def +++ b/win_build/WinSDK/epanet2.def @@ -65,6 +65,7 @@ EXPORTS ENsetcoord = _ENsetcoord@12 ENgetqualinfo = _ENgetqualinfo@16 ENsetbasedemand = _ENsetbasedemand@12 + ENsetdemandpattern = _ENsetdemandpattern@12 ENgetaveragepatternvalue = _ENgetaveragepatternvalue@8 ENgetheadcurveindex = _ENgetheadcurveindex@8 ENgetpumptype = _ENgetpumptype@8 From bdfe7ec28928994b9758a5b8c52965c08338da60 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 28 Aug 2018 11:23:30 -0400 Subject: [PATCH 04/35] Fixing build for python wrapper --- CMakeLists.txt | 3 +-- include/epanet2.h | 6 +++--- run/CMakeLists.txt | 1 - win_build/WinSDK/Makefile.bat | 8 ++++---- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 466e964..d0fbce6 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,12 +75,11 @@ source_group("Library" FILES ${EPANET_LIB_ALL}) # the shared library -add_library(epanet SHARED ${EPANET_SOURCES}) #${EPANET_API_HEADER}) +add_library(epanet SHARED ${EPANET_SOURCES}) target_include_directories(epanet PUBLIC ${PROJECT_SOURCE_DIR}/include) # create export lib so we can link against dll using Visual Studio -add_definitions(-D WITH_GENX) include(GenerateExportHeader) GENERATE_EXPORT_HEADER(epanet BASE_NAME epanet diff --git a/include/epanet2.h b/include/epanet2.h index e6d91c6..3acbc75 100644 --- a/include/epanet2.h +++ b/include/epanet2.h @@ -30,9 +30,7 @@ #define EN_API_FLOAT_TYPE float #endif -#ifdef WITH_GENX - #include "epanet_export.h" -#else +#ifdef NO_GENX // --- define WINDOWS #undef WINDOWS #ifdef _WIN32 @@ -62,6 +60,8 @@ #define DLLEXPORT #endif #endif +#else + #include "epanet_export.h" #endif diff --git a/run/CMakeLists.txt b/run/CMakeLists.txt index 53e792b..4822e95 100644 --- a/run/CMakeLists.txt +++ b/run/CMakeLists.txt @@ -19,7 +19,6 @@ source_group("CLI" FILES ${EPANET_CLI_SOURCES}) # Creates the EPANET command line executable -add_definitions(-D WITH_GENX) add_executable(runepanet ${EPANET_CLI_SOURCES}) if(NOT WIN32) target_link_libraries(runepanet LINK_PUBLIC epanet m) diff --git a/win_build/WinSDK/Makefile.bat b/win_build/WinSDK/Makefile.bat index 91ffc95..e5188c2 100644 --- a/win_build/WinSDK/Makefile.bat +++ b/win_build/WinSDK/Makefile.bat @@ -21,9 +21,9 @@ Find /i "x86" < checkOS.tmp > StringCheck.tmp If %ERRORLEVEL% == 1 ( CALL "%SDK_PATH%bin\"SetEnv.cmd /x64 /release rem : create EPANET2.DLL - cl -o epanet2.dll epanet.c util\errormanager.c hash.c hydraul.c hydcoeffs.c hydstatus.c hydsolver.c inpfile.c input1.c input2.c input3.c mempool.c output.c quality.c report.c rules.c smatrix.c genmmd.c /I ..\include /I ..\run /link /DLL + cl -o epanet2.dll /D NO_GENX epanet.c util\errormanager.c hash.c hydraul.c hydcoeffs.c hydstatus.c hydsolver.c inpfile.c input1.c input2.c input3.c mempool.c output.c quality.c report.c rules.c smatrix.c genmmd.c /I ..\include /I ..\run /link /DLL rem : create EPANET2.EXE - cl -o epanet2.exe epanet.c util\errormanager.c ..\run\main.c hash.c hydraul.c hydcoeffs.c hydstatus.c hydsolver.c inpfile.c input1.c input2.c input3.c mempool.c output.c quality.c report.c rules.c smatrix.c genmmd.c /I ..\include /I ..\run /I ..\src /link + cl -o epanet2.exe /D NO_GENX epanet.c util\errormanager.c ..\run\main.c hash.c hydraul.c hydcoeffs.c hydstatus.c hydsolver.c inpfile.c input1.c input2.c input3.c mempool.c output.c quality.c report.c rules.c smatrix.c genmmd.c /I ..\include /I ..\run /I ..\src /link md "%Build_PATH%"\64bit move /y "%SRC_PATH%"\*.dll "%Build_PATH%"\64bit move /y "%SRC_PATH%"\*.exe "%Build_PATH%"\64bit @@ -35,9 +35,9 @@ rem : 32 bit with DEF CALL "%SDK_PATH%bin\"SetEnv.cmd /x86 /release echo "32 bit with epanet2.def mapping" rem : create EPANET2.DLL -cl -o epanet2.dll epanet.c util\errormanager.c hash.c hydraul.c hydcoeffs.c hydstatus.c hydsolver.c inpfile.c input1.c input2.c input3.c mempool.c output.c quality.c report.c rules.c smatrix.c genmmd.c /I ..\include /I ..\run /link /DLL /def:..\win_build\WinSDK\epanet2.def /MAP +cl -o epanet2.dll /D NO_GENX epanet.c util\errormanager.c hash.c hydraul.c hydcoeffs.c hydstatus.c hydsolver.c inpfile.c input1.c input2.c input3.c mempool.c output.c quality.c report.c rules.c smatrix.c genmmd.c /I ..\include /I ..\run /link /DLL /def:..\win_build\WinSDK\epanet2.def /MAP rem : create EPANET2.EXE -cl -o epanet2.exe epanet.c util\errormanager.c ..\run\main.c hash.c hydraul.c hydcoeffs.c hydstatus.c hydsolver.c inpfile.c input1.c input2.c input3.c mempool.c output.c quality.c report.c rules.c smatrix.c genmmd.c /I ..\include /I ..\run /I ..\src /link +cl -o epanet2.exe /D NO_GENX epanet.c util\errormanager.c ..\run\main.c hash.c hydraul.c hydcoeffs.c hydstatus.c hydsolver.c inpfile.c input1.c input2.c input3.c mempool.c output.c quality.c report.c rules.c smatrix.c genmmd.c /I ..\include /I ..\run /I ..\src /link md "%Build_PATH%"\32bit move /y "%SRC_PATH%"\*.dll "%Build_PATH%"\32bit move /y "%SRC_PATH%"\*.exe "%Build_PATH%"\32bit From 0188b8e976b2025d068f04091e1cb66c7c9f9014 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 28 Aug 2018 12:18:27 -0400 Subject: [PATCH 05/35] Fixing compiler warning on Travis build --- src/epanet.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/epanet.c b/src/epanet.c index 6463c08..de468cf 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -132,7 +132,7 @@ execute function x and set the error code equal to its return value. // This single global variable is used only when the library is called // in "legacy mode" with the 2.1-style API. -EN_Project *_defaultModel; +void *_defaultModel; // Local functions @@ -167,9 +167,11 @@ int DLLEXPORT ENepanet(const char *f1, const char *f2, const char *f3, void (*pv ERRCODE(EN_createproject(&_defaultModel)); ERRCODE(EN_open(_defaultModel, f1, f2, f3)); - _defaultModel->viewprog = pviewprog; - if (_defaultModel->out_files.Hydflag != USE) { + EN_Project *p = (EN_Project*)(_defaultModel); + p->viewprog = pviewprog; + + if (p->out_files.Hydflag != USE) { ERRCODE(EN_solveH(_defaultModel)); } From bb047c972f1b72bb7620580dd36d58bcd98c4a55 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 28 Aug 2018 13:58:47 -0400 Subject: [PATCH 06/35] Fixing build error on Visual Studio 2010 --- src/epanet.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/epanet.c b/src/epanet.c index de468cf..95d99c9 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -164,11 +164,12 @@ void errorLookup(int errcode, char *errmsg, int len); int DLLEXPORT ENepanet(const char *f1, const char *f2, const char *f3, void (*pviewprog)(char *)) { int errcode = 0; + EN_Project *p = NULL; ERRCODE(EN_createproject(&_defaultModel)); ERRCODE(EN_open(_defaultModel, f1, f2, f3)); - EN_Project *p = (EN_Project*)(_defaultModel); + p = (EN_Project*)(_defaultModel); p->viewprog = pviewprog; if (p->out_files.Hydflag != USE) { From edf4a09ebeb2fa9b6ed0417de229151acd9caf41 Mon Sep 17 00:00:00 2001 From: Elad Salomons Date: Wed, 29 Aug 2018 15:14:49 +0300 Subject: [PATCH 07/35] Fix EN_addpattern Closes #231. Also adds unit test for the function. --- src/epanet.c | 4 ++-- tests/test_toolkit.cpp | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/epanet.c b/src/epanet.c index 95d99c9..8cb5449 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -3103,7 +3103,7 @@ int DLLEXPORT EN_addpattern(EN_ProjectHandle ph, char *id) { if (!p->Openflag) return set_error(p->error_handle, 102); - if (ENgetpatternindex(id, &i) == 0) + if (EN_getpatternindex(ph, id, &i) == 0) return set_error(p->error_handle, 215); /* Check that id name is not too long */ @@ -3156,7 +3156,7 @@ int DLLEXPORT EN_addpattern(EN_ProjectHandle ph, char *id) { for (i = 0; i <= Npats; i++) free(Pattern[i].F); free(Pattern); - Pattern = tmpPat; + net->Pattern = tmpPat; net->Npats = n; par->MaxPats = n; return set_error(p->error_handle, 0); diff --git a/tests/test_toolkit.cpp b/tests/test_toolkit.cpp index 6ca6322..3c7aa5b 100644 --- a/tests/test_toolkit.cpp +++ b/tests/test_toolkit.cpp @@ -204,4 +204,26 @@ BOOST_FIXTURE_TEST_CASE(test_progressive_stepping, Fixture) } +BOOST_FIXTURE_TEST_CASE(test_addpattern, Fixture) +{ + int pat_index, n_patterns_1, n_patterns_2; + + // get the number of current patterns + error = EN_getcount(ph, EN_PATCOUNT, &n_patterns_1); + BOOST_REQUIRE(error == 0); + + // add a new pattern + error = EN_addpattern(ph, 'new_pattern'); + BOOST_REQUIRE(error == 0); + + // get the new patterns count, shoul dbe the old one + 1 + error = EN_getcount(ph, EN_PATCOUNT, &n_patterns_2); + BOOST_REQUIRE(error == 0); + BOOST_REQUIRE(n_patterns_1 + 1 == n_patterns_2); + + // gwt the new patterns index, should be as the number of patterns + error = EN_getpatternindex(ph, 'new_pattern', &pat_index); + BOOST_REQUIRE(pat_index == n_patterns_2); +} + BOOST_AUTO_TEST_SUITE_END() From 5161ad9972ea629938df1db9caff4aac34f112ac Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Wed, 29 Aug 2018 10:17:36 -0400 Subject: [PATCH 08/35] Fix Appveyor badge Close #246 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0c1c01b..4020cb0 100755 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ EPANET {#epanet-readme} ====== ## Build Status -[![Build status](https://ci.appveyor.com/api/projects/status/19wpg4g2cmj3oihl?svg=true)](https://ci.appveyor.com/project/OpenWaterAnalytics/epanet) +[![Build status](https://ci.appveyor.com/api/projects/status/19wpg4g2cmj3oihl?svg=true)](https://ci.appveyor.com/project/OpenWaterAnalytics/epanet/branch/dev) [![Build Status](https://travis-ci.org/OpenWaterAnalytics/EPANET.svg?branch=master)](https://travis-ci.org/OpenWaterAnalytics/EPANET) ## For EPANET-related questions and discussion From f3d680dc54d494e107d848b645d7d7bc5c52dfd1 Mon Sep 17 00:00:00 2001 From: Elad Salomons Date: Wed, 29 Aug 2018 18:12:25 +0300 Subject: [PATCH 09/35] Fix test_addpattern test Thanks @mariosmsk Co-Authored-By: Marios S. Kyriakou --- tests/test_toolkit.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_toolkit.cpp b/tests/test_toolkit.cpp index 3c7aa5b..433614e 100644 --- a/tests/test_toolkit.cpp +++ b/tests/test_toolkit.cpp @@ -207,13 +207,14 @@ BOOST_FIXTURE_TEST_CASE(test_progressive_stepping, Fixture) BOOST_FIXTURE_TEST_CASE(test_addpattern, Fixture) { int pat_index, n_patterns_1, n_patterns_2; + char newpat[] = "new_pattern"; // get the number of current patterns error = EN_getcount(ph, EN_PATCOUNT, &n_patterns_1); BOOST_REQUIRE(error == 0); // add a new pattern - error = EN_addpattern(ph, 'new_pattern'); + error = EN_addpattern(ph, newpat); BOOST_REQUIRE(error == 0); // get the new patterns count, shoul dbe the old one + 1 @@ -222,7 +223,7 @@ BOOST_FIXTURE_TEST_CASE(test_addpattern, Fixture) BOOST_REQUIRE(n_patterns_1 + 1 == n_patterns_2); // gwt the new patterns index, should be as the number of patterns - error = EN_getpatternindex(ph, 'new_pattern', &pat_index); + error = EN_getpatternindex(ph, newpat, &pat_index); BOOST_REQUIRE(pat_index == n_patterns_2); } From bcd6877935c33a5e8750084100defd452b86b939 Mon Sep 17 00:00:00 2001 From: Elad Salomons Date: Wed, 29 Aug 2018 22:26:32 +0300 Subject: [PATCH 10/35] Add legacy ENinit API Closes #232 --- src/epanet.c | 14 +++++++++++--- win_build/WinSDK/epanet2.def | 3 ++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/epanet.c b/src/epanet.c index 95d99c9..9943d16 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -185,6 +185,14 @@ int DLLEXPORT ENepanet(const char *f1, const char *f2, const char *f3, void (*pv return (errcode); } +int DLLEXPORT ENinit(char *f2, char *f3, int UnitsType, + int HeadlossFormula) { + int errcode = 0; + ERRCODE(EN_createproject(&_defaultModel)); + ERRCODE(EN_init(_defaultModel, f2, f3, UnitsType, HeadlossFormula)); + return (errcode); +} + int DLLEXPORT ENopen(char *f1, char *f2, char *f3) { int errcode = 0; ERRCODE(EN_createproject(&_defaultModel)); @@ -602,7 +610,7 @@ int DLLEXPORT EN_deleteproject(EN_ProjectHandle *ph) } -int DLLEXPORT EN_init(EN_ProjectHandle *ph, char *f2, char *f3, +int DLLEXPORT EN_init(EN_ProjectHandle ph, char *f2, char *f3, EN_FlowUnits UnitsType, EN_FormType HeadlossFormula) /*---------------------------------------------------------------- ** Input: @@ -623,7 +631,7 @@ int DLLEXPORT EN_init(EN_ProjectHandle *ph, char *f2, char *f3, _fpreset(); #endif - EN_Project *pr = (EN_Project*)*ph; + EN_Project *pr = (EN_Project*)ph; /* Set system flags */ pr->Openflag = TRUE; @@ -3643,7 +3651,7 @@ int DLLEXPORT EN_setheadcurveindex(EN_ProjectHandle ph, int index, int curveinde double *Ucf = p->Ucf; int pIdx; Spump *pump; - + if (!p->Openflag) return set_error(p->error_handle, 102); if (index < 1 || index > Nlinks || EN_PUMP != Link[index].Type) { diff --git a/win_build/WinSDK/epanet2.def b/win_build/WinSDK/epanet2.def index 46c82c2..0dcdfc3 100644 --- a/win_build/WinSDK/epanet2.def +++ b/win_build/WinSDK/epanet2.def @@ -67,6 +67,7 @@ EXPORTS ENsetbasedemand = _ENsetbasedemand@12 ENgetaveragepatternvalue = _ENgetaveragepatternvalue@8 ENgetheadcurveindex = _ENgetheadcurveindex@8 + ENsetheadcurveindex = _ENsetheadcurveindex@8 ENgetpumptype = _ENgetpumptype@8 ENgetcurveindex = _ENgetcurveindex@8 ENgetcurveid = _ENgetcurveid@8 @@ -96,4 +97,4 @@ EXPORTS ENgetdemandmodel = _ENgetdemandmodel@16 ENsetdemandmodel = _ENsetdemandmodel@16 ENgetcurvetype = _ENgetcurvetype@8 - + ENinit = _ENinit@16 \ No newline at end of file From dbdafd6352d2e5f2fda7fabe17a2944ffa6df1e0 Mon Sep 17 00:00:00 2001 From: Elad Salomons Date: Wed, 29 Aug 2018 22:31:28 +0300 Subject: [PATCH 11/35] Set status for new links in EN_addlink Status is OPEN for pumps\pipes\CV and ACTIVE for valves. Closes #173 --- src/epanet.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/epanet.c b/src/epanet.c index 9943d16..dbcf3f8 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -4806,6 +4806,7 @@ int DLLEXPORT EN_addlink(EN_ProjectHandle ph, char *id, EN_LinkType linkType, ch link->Type = linkType; link->N1 = N1; link->N2 = N2; + link->Stat = OPEN; if (linkType == EN_PUMP) { link->Kc = 1.0; // Speed factor @@ -4821,23 +4822,14 @@ int DLLEXPORT EN_addlink(EN_ProjectHandle ph, char *id, EN_LinkType linkType, ch link->Kc = 0.0; // Valve setting. link->Km = 0.0; // Loss coeff link->Len = 0.0; + link->Stat = ACTIVE; } - // link->Len = 0.0; - // link->Kc = 0.01; - // link->Km = 0; link->Kb = 0; link->Kw = 0; link->R = 0; link->Rc = 0; link->Rpt = 0; - if (linkType == EN_CVPIPE) { - link->Stat = OPEN; - } - else { - link->Stat = CLOSED; - } - ENHashTableInsert(net->LinkHashTable, link->ID, n); return set_error(p->error_handle, 0); } From c0b91fa9e32ec989faca8c2fe0cd65da451f6e80 Mon Sep 17 00:00:00 2001 From: Marios Kyriakou Date: Thu, 30 Aug 2018 12:32:00 +0300 Subject: [PATCH 12/35] Fix crash with wrong parameters ENgetbasedemand, ENsetbasedemand, ENgetdemandpattern, ENsetdemandpattern --- src/epanet.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/epanet.c b/src/epanet.c index 18c6540..5a90a4a 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -4468,7 +4468,7 @@ int DLLEXPORT EN_getnumdemands(EN_ProjectHandle ph, int nodeIndex, int *numDeman int DLLEXPORT EN_getbasedemand(EN_ProjectHandle ph, int nodeIndex, int demandIdx, EN_API_FLOAT_TYPE *baseDemand) { Pdemand d; - int n = 1; + int n = 1, numDemands; EN_Project *p = (EN_Project*)ph; @@ -4478,10 +4478,10 @@ int DLLEXPORT EN_getbasedemand(EN_ProjectHandle ph, int nodeIndex, int demandIdx if (nodeIndex <= 0 || nodeIndex > p->network.Nnodes) return set_error(p->error_handle, 203); if (nodeIndex <= p->network.Njuncs) { - for (d = p->network.Node[nodeIndex].D; n < demandIdx && d != NULL; d = d->next) { - n++; - } - if (n != demandIdx) { + for (d = p->network.Node[nodeIndex].D; n < demandIdx && d != NULL; d = d->next) + n++; + EN_getnumdemands(ph, nodeIndex, &numDemands); + if (n < demandIdx || demandIdx <= 0 || n > numDemands) { return set_error(p->error_handle, 253); } *baseDemand = (EN_API_FLOAT_TYPE)(d->Base * p->Ucf[FLOW]); @@ -4504,7 +4504,8 @@ int DLLEXPORT EN_setbasedemand(EN_ProjectHandle ph, int nodeIndex, int demandIdx double *Ucf = pr->Ucf; Pdemand d; - int n = 1; + int n = 1, numDemands; + /* Check for valid arguments */ if (!pr->Openflag) return set_error(pr->error_handle, 102); @@ -4513,8 +4514,10 @@ int DLLEXPORT EN_setbasedemand(EN_ProjectHandle ph, int nodeIndex, int demandIdx if (nodeIndex <= Njuncs) { for (d = Node[nodeIndex].D; n < demandIdx && d != NULL; d = d->next) n++; - if (n != demandIdx) + EN_getnumdemands(ph, nodeIndex, &numDemands); + if (n < demandIdx || demandIdx <= 0 || n > numDemands) { return set_error(pr->error_handle, 253); + } d->Base = baseDemand / Ucf[FLOW]; } return set_error(pr->error_handle, 0); @@ -4532,7 +4535,8 @@ int DLLEXPORT EN_setdemandpattern(EN_ProjectHandle ph, int nodeIndex, int deman const int Npats = net->Npats; Pdemand d; - int n = 1; + int n = 1, numDemands; + /* Check for valid arguments */ if (!pr->Openflag) return set_error(pr->error_handle, 102); @@ -4543,8 +4547,10 @@ int DLLEXPORT EN_setdemandpattern(EN_ProjectHandle ph, int nodeIndex, int deman if (nodeIndex <= Njuncs) { for (d = Node[nodeIndex].D; n < demandIdx && d != NULL; d = d->next) n++; - if (n != demandIdx) + EN_getnumdemands(ph, nodeIndex, &numDemands); + if (n < demandIdx || demandIdx <= 0 || n > numDemands) { return set_error(pr->error_handle, 253); + } d->Pat = patIndex; } return set_error(pr->error_handle, 0); @@ -4559,7 +4565,8 @@ int DLLEXPORT EN_getdemandpattern(EN_ProjectHandle ph, int nodeIndex, int demand const int Nnodes = net->Nnodes; Pdemand d; - int n = 1; + int n = 1, numDemands; + /* Check for valid arguments */ if (!p->Openflag) return set_error(p->error_handle, 102); @@ -4567,7 +4574,8 @@ int DLLEXPORT EN_getdemandpattern(EN_ProjectHandle ph, int nodeIndex, int demand return set_error(p->error_handle, 203); for (d = Node[nodeIndex].D; n < demandIdx && d != NULL; d = d->next) n++; - if (n != demandIdx) + EN_getnumdemands(ph, nodeIndex, &numDemands); + if (n < demandIdx || demandIdx <= 0 || n > numDemands) return set_error(p->error_handle, 253); *pattIdx = d->Pat; return set_error(p->error_handle, 0); From 803f86959d38619324b1f672cfd5d49ace66c826 Mon Sep 17 00:00:00 2001 From: Marios Kyriakou Date: Thu, 30 Aug 2018 12:45:21 +0300 Subject: [PATCH 13/35] Revert "Fix crash with wrong parameters" This reverts commit c0b91fa9e32ec989faca8c2fe0cd65da451f6e80. --- src/epanet.c | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/src/epanet.c b/src/epanet.c index 5a90a4a..18c6540 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -4468,7 +4468,7 @@ int DLLEXPORT EN_getnumdemands(EN_ProjectHandle ph, int nodeIndex, int *numDeman int DLLEXPORT EN_getbasedemand(EN_ProjectHandle ph, int nodeIndex, int demandIdx, EN_API_FLOAT_TYPE *baseDemand) { Pdemand d; - int n = 1, numDemands; + int n = 1; EN_Project *p = (EN_Project*)ph; @@ -4478,10 +4478,10 @@ int DLLEXPORT EN_getbasedemand(EN_ProjectHandle ph, int nodeIndex, int demandIdx if (nodeIndex <= 0 || nodeIndex > p->network.Nnodes) return set_error(p->error_handle, 203); if (nodeIndex <= p->network.Njuncs) { - for (d = p->network.Node[nodeIndex].D; n < demandIdx && d != NULL; d = d->next) - n++; - EN_getnumdemands(ph, nodeIndex, &numDemands); - if (n < demandIdx || demandIdx <= 0 || n > numDemands) { + for (d = p->network.Node[nodeIndex].D; n < demandIdx && d != NULL; d = d->next) { + n++; + } + if (n != demandIdx) { return set_error(p->error_handle, 253); } *baseDemand = (EN_API_FLOAT_TYPE)(d->Base * p->Ucf[FLOW]); @@ -4504,8 +4504,7 @@ int DLLEXPORT EN_setbasedemand(EN_ProjectHandle ph, int nodeIndex, int demandIdx double *Ucf = pr->Ucf; Pdemand d; - int n = 1, numDemands; - + int n = 1; /* Check for valid arguments */ if (!pr->Openflag) return set_error(pr->error_handle, 102); @@ -4514,10 +4513,8 @@ int DLLEXPORT EN_setbasedemand(EN_ProjectHandle ph, int nodeIndex, int demandIdx if (nodeIndex <= Njuncs) { for (d = Node[nodeIndex].D; n < demandIdx && d != NULL; d = d->next) n++; - EN_getnumdemands(ph, nodeIndex, &numDemands); - if (n < demandIdx || demandIdx <= 0 || n > numDemands) { + if (n != demandIdx) return set_error(pr->error_handle, 253); - } d->Base = baseDemand / Ucf[FLOW]; } return set_error(pr->error_handle, 0); @@ -4535,8 +4532,7 @@ int DLLEXPORT EN_setdemandpattern(EN_ProjectHandle ph, int nodeIndex, int deman const int Npats = net->Npats; Pdemand d; - int n = 1, numDemands; - + int n = 1; /* Check for valid arguments */ if (!pr->Openflag) return set_error(pr->error_handle, 102); @@ -4547,10 +4543,8 @@ int DLLEXPORT EN_setdemandpattern(EN_ProjectHandle ph, int nodeIndex, int deman if (nodeIndex <= Njuncs) { for (d = Node[nodeIndex].D; n < demandIdx && d != NULL; d = d->next) n++; - EN_getnumdemands(ph, nodeIndex, &numDemands); - if (n < demandIdx || demandIdx <= 0 || n > numDemands) { + if (n != demandIdx) return set_error(pr->error_handle, 253); - } d->Pat = patIndex; } return set_error(pr->error_handle, 0); @@ -4565,8 +4559,7 @@ int DLLEXPORT EN_getdemandpattern(EN_ProjectHandle ph, int nodeIndex, int demand const int Nnodes = net->Nnodes; Pdemand d; - int n = 1, numDemands; - + int n = 1; /* Check for valid arguments */ if (!p->Openflag) return set_error(p->error_handle, 102); @@ -4574,8 +4567,7 @@ int DLLEXPORT EN_getdemandpattern(EN_ProjectHandle ph, int nodeIndex, int demand return set_error(p->error_handle, 203); for (d = Node[nodeIndex].D; n < demandIdx && d != NULL; d = d->next) n++; - EN_getnumdemands(ph, nodeIndex, &numDemands); - if (n < demandIdx || demandIdx <= 0 || n > numDemands) + if (n != demandIdx) return set_error(p->error_handle, 253); *pattIdx = d->Pat; return set_error(p->error_handle, 0); From d41f362ab523e2ff85bae55ee825c48714353c2b Mon Sep 17 00:00:00 2001 From: Marios Kyriakou Date: Thu, 30 Aug 2018 12:52:23 +0300 Subject: [PATCH 14/35] Fix crash with wrong parameters ENgetbasedemand, ENsetbasedemand, ENgetdemandpattern, ENsetdemandpattern Co-Authored-By: Elad Salomons --- src/epanet.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/epanet.c b/src/epanet.c index 18c6540..63d1524 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -4478,7 +4478,7 @@ int DLLEXPORT EN_getbasedemand(EN_ProjectHandle ph, int nodeIndex, int demandIdx if (nodeIndex <= 0 || nodeIndex > p->network.Nnodes) return set_error(p->error_handle, 203); if (nodeIndex <= p->network.Njuncs) { - for (d = p->network.Node[nodeIndex].D; n < demandIdx && d != NULL; d = d->next) { + for (d = p->network.Node[nodeIndex].D; n < demandIdx && d->next != NULL; d = d->next) { n++; } if (n != demandIdx) { @@ -4511,7 +4511,7 @@ int DLLEXPORT EN_setbasedemand(EN_ProjectHandle ph, int nodeIndex, int demandIdx if (nodeIndex <= 0 || nodeIndex > Nnodes) return set_error(pr->error_handle, 203); if (nodeIndex <= Njuncs) { - for (d = Node[nodeIndex].D; n < demandIdx && d != NULL; d = d->next) + for (d = Node[nodeIndex].D; n < demandIdx && d->next != NULL; d = d->next) n++; if (n != demandIdx) return set_error(pr->error_handle, 253); @@ -4541,7 +4541,7 @@ int DLLEXPORT EN_setdemandpattern(EN_ProjectHandle ph, int nodeIndex, int deman if (patIndex < 1 || patIndex > Npats) return(205); if (nodeIndex <= Njuncs) { - for (d = Node[nodeIndex].D; n < demandIdx && d != NULL; d = d->next) + for (d = Node[nodeIndex].D; n < demandIdx && d->next != NULL; d = d->next) n++; if (n != demandIdx) return set_error(pr->error_handle, 253); @@ -4565,7 +4565,7 @@ int DLLEXPORT EN_getdemandpattern(EN_ProjectHandle ph, int nodeIndex, int demand return set_error(p->error_handle, 102); if (nodeIndex <= 0 || nodeIndex > Nnodes) return set_error(p->error_handle, 203); - for (d = Node[nodeIndex].D; n < demandIdx && d != NULL; d = d->next) + for (d = Node[nodeIndex].D; n < demandIdx && d->next != NULL; d = d->next) n++; if (n != demandIdx) return set_error(p->error_handle, 253); From 8991d6baf9c82817cb108f719d40649350d401a6 Mon Sep 17 00:00:00 2001 From: Marios Kyriakou Date: Thu, 30 Aug 2018 17:21:02 +0300 Subject: [PATCH 15/35] add test for the function EN_setdemandpattern --- tests/test_toolkit.cpp | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/test_toolkit.cpp b/tests/test_toolkit.cpp index 6ca6322..a0e0bdb 100644 --- a/tests/test_toolkit.cpp +++ b/tests/test_toolkit.cpp @@ -204,4 +204,38 @@ BOOST_FIXTURE_TEST_CASE(test_progressive_stepping, Fixture) } +BOOST_FIXTURE_TEST_CASE(test_setdemandpattern, Fixture) +{ + int i, j, pat_index, pat_index_2, numDemands, nnodes; + char newpat[] = "new_pattern"; + + // get the number of nodes + error = EN_getcount(ph, EN_NODECOUNT, &nnodes); + BOOST_REQUIRE(error == 0); + + // add a new pattern + error = EN_addpattern(ph, newpat); + BOOST_REQUIRE(error == 0); + + // get the new patterns index, should be as the number of patterns + error = EN_getpatternindex(ph, newpat, &pat_index); + BOOST_REQUIRE(error == 0); + + for (i = 1; i <= nnodes; i++) { + // get the number of demand categories + error = EN_getnumdemands(ph, i, &numDemands); + BOOST_REQUIRE(error == 0); + + for (j = 1; j <= numDemands; j++) { + // set demand patterns + error = EN_setdemandpattern(ph, i, j, pat_index); + BOOST_REQUIRE(error == 0); + // get demand patterns should be the same with set + error = EN_getdemandpattern(ph, i, j, &pat_index_2); + BOOST_REQUIRE(error == 0); + BOOST_REQUIRE(pat_index == pat_index_2); + } + } +} + BOOST_AUTO_TEST_SUITE_END() From 74d68a884c278bd19f488e24a3349e1c98c1db5d Mon Sep 17 00:00:00 2001 From: Elad Salomons Date: Thu, 30 Aug 2018 18:05:39 +0300 Subject: [PATCH 16/35] Fix typo --- tests/test_toolkit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_toolkit.cpp b/tests/test_toolkit.cpp index 7b87674..f514a26 100644 --- a/tests/test_toolkit.cpp +++ b/tests/test_toolkit.cpp @@ -236,7 +236,7 @@ BOOST_FIXTURE_TEST_CASE(test_setdemandpattern, Fixture) BOOST_REQUIRE(pat_index == pat_index_2); } } - +} BOOST_FIXTURE_TEST_CASE(test_addpattern, Fixture) { int pat_index, n_patterns_1, n_patterns_2; From 21f40f0daf6e89cc3c152960ad405628be273ba8 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Thu, 30 Aug 2018 15:30:34 -0400 Subject: [PATCH 17/35] Making memorypool.c reentrant and adding test --- include/epanet2.h | 5 +- src/epanet.c | 23 +++++ src/mempool.c | 8 +- tests/CMakeLists.txt | 26 +++++- tests/data/example_0.inp | 178 +++++++++++++++++++++++++++++++++++++++ tests/data/example_1.inp | 178 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 412 insertions(+), 6 deletions(-) create mode 100644 tests/data/example_0.inp create mode 100644 tests/data/example_1.inp diff --git a/include/epanet2.h b/include/epanet2.h index 3acbc75..1333acd 100644 --- a/include/epanet2.h +++ b/include/epanet2.h @@ -1174,8 +1174,9 @@ extern "C" { void DLLEXPORT EN_clearError(EN_ProjectHandle ph); int DLLEXPORT EN_checkError(EN_ProjectHandle ph, char** msg_buffer); - //int DLLEXPORT EN_epanet(EN_ProjectHandle ph, const char *f1, const char *f2, - // const char *f3, void(*pviewprog)(char *)); + int DLLEXPORT EN_runproject(EN_ProjectHandle ph, const char *f1, const char *f2, + const char *f3, void(*pviewprog)(char *)); + int DLLEXPORT EN_init(EN_ProjectHandle *ph, char *rptFile, char *binOutFile, EN_FlowUnits UnitsType, EN_FormType HeadlossFormula); diff --git a/src/epanet.c b/src/epanet.c index 13529a7..a7fd843 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -185,6 +185,29 @@ int DLLEXPORT ENepanet(const char *f1, const char *f2, const char *f3, void (*pv return (errcode); } +int DLLEXPORT EN_runproject(EN_ProjectHandle ph, const char *f1, const char *f2, + const char *f3, void (*pviewprog)(char *)) +{ + int errcode = 0; + EN_Project *p = NULL; + + ERRCODE(EN_open(ph, f1, f2, f3)); + + p = (EN_Project*)(ph); + p->viewprog = pviewprog; + + if (p->out_files.Hydflag != USE) { + ERRCODE(EN_solveH(ph)); + } + + ERRCODE(EN_solveQ(ph)); + ERRCODE(EN_report(ph)); + + EN_close(ph); + + return errcode; +} + int DLLEXPORT ENinit(char *f2, char *f3, int UnitsType, int HeadlossFormula) { int errcode = 0; diff --git a/src/mempool.c b/src/mempool.c index ef7e645..17ba55a 100755 --- a/src/mempool.c +++ b/src/mempool.c @@ -21,6 +21,12 @@ #endif #include "mempool.h" +#ifdef _MSC_VER +#define THREAD_LOCAL __declspec(thread) +#else +#define THREAD_LOCAL __thread +#endif + /* ** ALLOC_BLOCK_SIZE - adjust this size to suit your installation - it ** should be reasonably large otherwise you will be mallocing a lot. @@ -54,7 +60,7 @@ typedef struct alloc_root_s ** root - Pointer to the current pool. */ -static alloc_root_t *root; +THREAD_LOCAL alloc_root_t *root; /* diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index be6dc5a..8b93c76 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -17,15 +17,35 @@ enable_testing() set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) -#Prep ourselves for compiling boost -find_package(Boost REQUIRED) +if(UNIX) + set(CMAKE_CXX_FLAGS "-std=c++11") +endif(UNIX) + + +#Prep ourselves to link with boost +if(MSVC) + set(Boost_DEBUG OFF) + set(Boost_DETAILED_FAILURE_MSG OFF) + set(Boost_THREADAPI win32) + set(Boost_USE_STATIC_LIBS ON) +endif(MSVC) +set(Boost_THREAD_FOUND OFF) +find_package(Boost COMPONENTS thread) include_directories (${Boost_INCLUDE_DIRS}) -#I like to keep test files in a separate source directory called test +#Test files are in separate source directory called tests file(GLOB TEST_SRCS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} test_*.cpp) +# If thread library is not found skip the reentrancy test +MESSAGE( STATUS "Thread found: " ${Boost_THREAD_FOUND}) +if(NOT ${Boost_THREAD_FOUND}) + list(REMOVE_ITEM TEST_SRCS test_reent.cpp) + MESSAGE("${TEST_SRCS}") +endif() + + #Run through each source foreach(testSrc ${TEST_SRCS}) #Extract the filename without an extension (NAME_WE) diff --git a/tests/data/example_0.inp b/tests/data/example_0.inp new file mode 100644 index 0000000..4df5bbf --- /dev/null +++ b/tests/data/example_0.inp @@ -0,0 +1,178 @@ +[TITLE] + EPANET Example Network 1 +A simple example of modeling chlorine decay. Both bulk and +wall reactions are included. + +[JUNCTIONS] +;ID Elev Demand Pattern + 10 710 0 ; + 11 710 150 ; + 12 700 150 ; + 13 695 100 ; + 21 700 150 ; + 22 695 200 ; + 23 690 150 ; + 31 700 100 ; + 32 710 100 ; + +[RESERVOIRS] +;ID Head Pattern + 9 800 ; + +[TANKS] +;ID Elevation InitLevel MinLevel MaxLevel Diameter MinVol VolCurve + 2 850 120 100 150 50.5 0 ; + +[PIPES] +;ID Node1 Node2 Length Diameter Roughness MinorLoss Status + 10 10 11 10530 18 100 0 Open ; + 11 11 12 5280 14 100 0 Open ; + 12 12 13 5280 10 100 0 Open ; + 21 21 22 5280 10 100 0 Open ; + 22 22 23 5280 12 100 0 Open ; + 31 31 32 5280 6 100 0 Open ; + 110 2 12 200 18 100 0 Open ; + 111 11 21 5280 10 100 0 Open ; + 112 12 22 5280 12 100 0 Open ; + 113 13 23 5280 8 100 0 Open ; + 121 21 31 5280 8 100 0 Open ; + 122 22 32 5280 6 100 0 Open ; + +[PUMPS] +;ID Node1 Node2 Parameters + 9 9 10 HEAD 1 ; + +[VALVES] +;ID Node1 Node2 Diameter Type Setting MinorLoss + +[TAGS] + +[DEMANDS] +;Junction Demand Pattern Category + +[STATUS] +;ID Status/Setting + +[PATTERNS] +;ID Multipliers +;Demand Pattern + 1 1.0 1.2 1.4 1.6 1.4 1.2 + 1 1.0 0.8 0.6 0.4 0.6 0.8 + +[CURVES] +;ID X-Value Y-Value +;PUMP: Pump Curve for Pump 9 + 1 1500 250 + +[CONTROLS] + LINK 9 OPEN IF NODE 2 BELOW 110 + LINK 9 CLOSED IF NODE 2 ABOVE 140 + + +[RULES] + +[ENERGY] + Global Efficiency 75 + Global Price 0.0 + Demand Charge 0.0 + +[EMITTERS] +;Junction Coefficient + +[QUALITY] +;Node InitQual + 10 0.5 + 11 0.5 + 12 0.5 + 13 0.5 + 21 0.5 + 22 0.5 + 23 0.5 + 31 0.5 + 32 0.5 + 9 1.0 + 2 1.0 + +[SOURCES] +;Node Type Quality Pattern + +[REACTIONS] +;Type Pipe/Tank Coefficient + + +[REACTIONS] + Order Bulk 1 + Order Tank 1 + Order Wall 1 + Global Bulk -.5 + Global Wall -1 + Limiting Potential 0.0 + Roughness Correlation 0.0 + +[MIXING] +;Tank Model + +[TIMES] + Duration 24:00 + Hydraulic Timestep 1:00 + Quality Timestep 0:05 + Pattern Timestep 2:00 + Pattern Start 0:00 + Report Timestep 1:00 + Report Start 0:00 + Start ClockTime 12 am + Statistic None + +[REPORT] + Status Yes + Summary No + Page 0 + +[OPTIONS] + Units GPM + Headloss H-W + Specific Gravity 1.0 + Viscosity 1.0 + Trials 40 + Accuracy 0.001 + CHECKFREQ 2 + MAXCHECK 10 + DAMPLIMIT 0 + Unbalanced Continue 10 + Pattern 1 + Demand Multiplier 1.0 + Emitter Exponent 0.5 + Quality Chlorine mg/L + Diffusivity 1.0 + Tolerance 0.01 + +[COORDINATES] +;Node X-Coord Y-Coord + 10 20.00 70.00 + 11 30.00 70.00 + 12 50.00 70.00 + 13 70.00 70.00 + 21 30.00 40.00 + 22 50.00 40.00 + 23 70.00 40.00 + 31 30.00 10.00 + 32 50.00 10.00 + 9 10.00 70.00 + 2 50.00 90.00 + +[VERTICES] +;Link X-Coord Y-Coord + +[LABELS] +;X-Coord Y-Coord Label & Anchor Node + 6.99 73.63 "Source" + 13.48 68.13 "Pump" + 43.85 91.21 "Tank" + +[BACKDROP] + DIMENSIONS 7.00 6.00 73.00 94.00 + UNITS None + FILE + OFFSET 0.00 0.00 + +[END] diff --git a/tests/data/example_1.inp b/tests/data/example_1.inp new file mode 100644 index 0000000..4df5bbf --- /dev/null +++ b/tests/data/example_1.inp @@ -0,0 +1,178 @@ +[TITLE] + EPANET Example Network 1 +A simple example of modeling chlorine decay. Both bulk and +wall reactions are included. + +[JUNCTIONS] +;ID Elev Demand Pattern + 10 710 0 ; + 11 710 150 ; + 12 700 150 ; + 13 695 100 ; + 21 700 150 ; + 22 695 200 ; + 23 690 150 ; + 31 700 100 ; + 32 710 100 ; + +[RESERVOIRS] +;ID Head Pattern + 9 800 ; + +[TANKS] +;ID Elevation InitLevel MinLevel MaxLevel Diameter MinVol VolCurve + 2 850 120 100 150 50.5 0 ; + +[PIPES] +;ID Node1 Node2 Length Diameter Roughness MinorLoss Status + 10 10 11 10530 18 100 0 Open ; + 11 11 12 5280 14 100 0 Open ; + 12 12 13 5280 10 100 0 Open ; + 21 21 22 5280 10 100 0 Open ; + 22 22 23 5280 12 100 0 Open ; + 31 31 32 5280 6 100 0 Open ; + 110 2 12 200 18 100 0 Open ; + 111 11 21 5280 10 100 0 Open ; + 112 12 22 5280 12 100 0 Open ; + 113 13 23 5280 8 100 0 Open ; + 121 21 31 5280 8 100 0 Open ; + 122 22 32 5280 6 100 0 Open ; + +[PUMPS] +;ID Node1 Node2 Parameters + 9 9 10 HEAD 1 ; + +[VALVES] +;ID Node1 Node2 Diameter Type Setting MinorLoss + +[TAGS] + +[DEMANDS] +;Junction Demand Pattern Category + +[STATUS] +;ID Status/Setting + +[PATTERNS] +;ID Multipliers +;Demand Pattern + 1 1.0 1.2 1.4 1.6 1.4 1.2 + 1 1.0 0.8 0.6 0.4 0.6 0.8 + +[CURVES] +;ID X-Value Y-Value +;PUMP: Pump Curve for Pump 9 + 1 1500 250 + +[CONTROLS] + LINK 9 OPEN IF NODE 2 BELOW 110 + LINK 9 CLOSED IF NODE 2 ABOVE 140 + + +[RULES] + +[ENERGY] + Global Efficiency 75 + Global Price 0.0 + Demand Charge 0.0 + +[EMITTERS] +;Junction Coefficient + +[QUALITY] +;Node InitQual + 10 0.5 + 11 0.5 + 12 0.5 + 13 0.5 + 21 0.5 + 22 0.5 + 23 0.5 + 31 0.5 + 32 0.5 + 9 1.0 + 2 1.0 + +[SOURCES] +;Node Type Quality Pattern + +[REACTIONS] +;Type Pipe/Tank Coefficient + + +[REACTIONS] + Order Bulk 1 + Order Tank 1 + Order Wall 1 + Global Bulk -.5 + Global Wall -1 + Limiting Potential 0.0 + Roughness Correlation 0.0 + +[MIXING] +;Tank Model + +[TIMES] + Duration 24:00 + Hydraulic Timestep 1:00 + Quality Timestep 0:05 + Pattern Timestep 2:00 + Pattern Start 0:00 + Report Timestep 1:00 + Report Start 0:00 + Start ClockTime 12 am + Statistic None + +[REPORT] + Status Yes + Summary No + Page 0 + +[OPTIONS] + Units GPM + Headloss H-W + Specific Gravity 1.0 + Viscosity 1.0 + Trials 40 + Accuracy 0.001 + CHECKFREQ 2 + MAXCHECK 10 + DAMPLIMIT 0 + Unbalanced Continue 10 + Pattern 1 + Demand Multiplier 1.0 + Emitter Exponent 0.5 + Quality Chlorine mg/L + Diffusivity 1.0 + Tolerance 0.01 + +[COORDINATES] +;Node X-Coord Y-Coord + 10 20.00 70.00 + 11 30.00 70.00 + 12 50.00 70.00 + 13 70.00 70.00 + 21 30.00 40.00 + 22 50.00 40.00 + 23 70.00 40.00 + 31 30.00 10.00 + 32 50.00 10.00 + 9 10.00 70.00 + 2 50.00 90.00 + +[VERTICES] +;Link X-Coord Y-Coord + +[LABELS] +;X-Coord Y-Coord Label & Anchor Node + 6.99 73.63 "Source" + 13.48 68.13 "Pump" + 43.85 91.21 "Tank" + +[BACKDROP] + DIMENSIONS 7.00 6.00 73.00 94.00 + UNITS None + FILE + OFFSET 0.00 0.00 + +[END] From c4b6756926c421f87c58e9020388dc39c7137c09 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Thu, 30 Aug 2018 15:39:06 -0400 Subject: [PATCH 18/35] Fixing compile error on Travis --- include/epanet2.h | 4 ++-- src/epanet.c | 45 ++++++++++++++++++++++----------------------- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/include/epanet2.h b/include/epanet2.h index 1333acd..9d2fcb5 100644 --- a/include/epanet2.h +++ b/include/epanet2.h @@ -1176,8 +1176,8 @@ extern "C" { int DLLEXPORT EN_runproject(EN_ProjectHandle ph, const char *f1, const char *f2, const char *f3, void(*pviewprog)(char *)); - - int DLLEXPORT EN_init(EN_ProjectHandle *ph, char *rptFile, char *binOutFile, + + int DLLEXPORT EN_init(EN_ProjectHandle ph, char *rptFile, char *binOutFile, EN_FlowUnits UnitsType, EN_FormType HeadlossFormula); int DLLEXPORT EN_open(EN_ProjectHandle ph, const char *inpFile, diff --git a/src/epanet.c b/src/epanet.c index a7fd843..58b8477 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -185,29 +185,6 @@ int DLLEXPORT ENepanet(const char *f1, const char *f2, const char *f3, void (*pv return (errcode); } -int DLLEXPORT EN_runproject(EN_ProjectHandle ph, const char *f1, const char *f2, - const char *f3, void (*pviewprog)(char *)) -{ - int errcode = 0; - EN_Project *p = NULL; - - ERRCODE(EN_open(ph, f1, f2, f3)); - - p = (EN_Project*)(ph); - p->viewprog = pviewprog; - - if (p->out_files.Hydflag != USE) { - ERRCODE(EN_solveH(ph)); - } - - ERRCODE(EN_solveQ(ph)); - ERRCODE(EN_report(ph)); - - EN_close(ph); - - return errcode; -} - int DLLEXPORT ENinit(char *f2, char *f3, int UnitsType, int HeadlossFormula) { int errcode = 0; @@ -632,6 +609,28 @@ int DLLEXPORT EN_deleteproject(EN_ProjectHandle *ph) return 0; } +int DLLEXPORT EN_runproject(EN_ProjectHandle ph, const char *f1, const char *f2, + const char *f3, void (*pviewprog)(char *)) +{ + int errcode = 0; + EN_Project *p = NULL; + + ERRCODE(EN_open(ph, f1, f2, f3)); + + p = (EN_Project*)(ph); + p->viewprog = pviewprog; + + if (p->out_files.Hydflag != USE) { + ERRCODE(EN_solveH(ph)); + } + + ERRCODE(EN_solveQ(ph)); + ERRCODE(EN_report(ph)); + + EN_close(ph); + + return errcode; +} int DLLEXPORT EN_init(EN_ProjectHandle ph, char *f2, char *f3, EN_FlowUnits UnitsType, EN_FormType HeadlossFormula) From 3433b9d5ebf0ead4c6e40d01509639833175d302 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Thu, 30 Aug 2018 15:47:44 -0400 Subject: [PATCH 19/35] Add boost threads lib to Travis config --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 3cf3c7f..4dcd2fa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ env: before_install: - sudo apt-get -qq update - sudo apt-get install -y libboost-test-dev + - sudo apt-get install -y libboost-thread-dev - sudo apt-get install -y swig #install: From 6527819d0092992bc31366c33ae6ab9549813483 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Thu, 30 Aug 2018 15:53:01 -0400 Subject: [PATCH 20/35] Forgot to add test --- tests/test_reent.cpp | 56 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 tests/test_reent.cpp diff --git a/tests/test_reent.cpp b/tests/test_reent.cpp new file mode 100644 index 0000000..fbcbbc9 --- /dev/null +++ b/tests/test_reent.cpp @@ -0,0 +1,56 @@ + +#include +#include +#include + +#include + +#include "epanet2.h" + +#define NUM_THREADS 2 + +using namespace std; + +void epanet_thread(long i) +{ + int errorcode = 0; + EN_ProjectHandle ph; + + string prefix = "example_"; + string suffix = ".inp"; + string input = prefix + to_string(static_cast(i)) + suffix; + + suffix = ".rpt"; + string report = prefix + to_string(static_cast(i)) + suffix; + + suffix = ".out"; + string output = prefix + to_string(static_cast(i)) + suffix; + + printf("Thread #%ld starting EPANET ...\n", i); + + EN_createproject(&ph); + errorcode = EN_runproject(ph, input.c_str(), report.c_str(), output.c_str(), NULL); + EN_deleteproject(&ph); + + printf("Thread #%ld EPANET done. Status = %d\n", i, errorcode); +} + +int main(int argc, char *argv[]) +{ + long i; + boost::thread *threads[NUM_THREADS]; + + for (i = 0; i < NUM_THREADS; i++) { + threads[i] = new boost::thread(epanet_thread, i); + printf("Main: creating thread %ld.\n", i); + } + + for (i = 0; i < NUM_THREADS; i++) { + threads[i]->join(); + printf("Main: joining thread %ld.\n", i); + delete threads[i]; + } + + printf("Main: program completed. Exiting.\n"); + return(0); +} From 5a007bc1f6672a1df77daa45f11374ffc9d2dbe5 Mon Sep 17 00:00:00 2001 From: michaeltryby Date: Thu, 30 Aug 2018 19:12:27 -0400 Subject: [PATCH 21/35] Adding header --- tests/test_reent.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/test_reent.cpp b/tests/test_reent.cpp index fbcbbc9..1117284 100644 --- a/tests/test_reent.cpp +++ b/tests/test_reent.cpp @@ -1,3 +1,12 @@ +/* + * test_reent.cpp + * + * Created: 8/30/2018 + * Author: Michael E. Tryby + * US EPA - ORD/NRMRL + * + * Unit testing for EPANET Output API. +*/ #include #include From dcf556ef0d412bf0dc017382c49a1d6ff867dcc0 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Fri, 31 Aug 2018 08:24:23 -0400 Subject: [PATCH 22/35] Cleaning up unit test build and test header --- tests/CMakeLists.txt | 2 -- tests/test_reent.cpp | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8b93c76..add4e31 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -26,7 +26,6 @@ endif(UNIX) if(MSVC) set(Boost_DEBUG OFF) set(Boost_DETAILED_FAILURE_MSG OFF) - set(Boost_THREADAPI win32) set(Boost_USE_STATIC_LIBS ON) endif(MSVC) set(Boost_THREAD_FOUND OFF) @@ -42,7 +41,6 @@ file(GLOB TEST_SRCS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} test_*.cpp) MESSAGE( STATUS "Thread found: " ${Boost_THREAD_FOUND}) if(NOT ${Boost_THREAD_FOUND}) list(REMOVE_ITEM TEST_SRCS test_reent.cpp) - MESSAGE("${TEST_SRCS}") endif() diff --git a/tests/test_reent.cpp b/tests/test_reent.cpp index 1117284..4ac1d3c 100644 --- a/tests/test_reent.cpp +++ b/tests/test_reent.cpp @@ -5,7 +5,7 @@ * Author: Michael E. Tryby * US EPA - ORD/NRMRL * - * Unit testing for EPANET Output API. + * Multi-threading / reentrancy test for EPANET Toolkit API. */ #include From b6250e27ebed95f7cfccd23491bd2e04c70d980c Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Fri, 31 Aug 2018 08:41:42 -0400 Subject: [PATCH 23/35] Reverting change to Boost_THREADAPI --- tests/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index add4e31..50f8bf4 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -26,6 +26,7 @@ endif(UNIX) if(MSVC) set(Boost_DEBUG OFF) set(Boost_DETAILED_FAILURE_MSG OFF) + set(Boost_THREADAPI win32) set(Boost_USE_STATIC_LIBS ON) endif(MSVC) set(Boost_THREAD_FOUND OFF) From 84eb3066816b5587c1fedbe6f411acac5f6a740f Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Fri, 31 Aug 2018 10:54:37 -0400 Subject: [PATCH 24/35] Shutting of regression testing. --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4dcd2fa..7dfa9f9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,7 @@ script: - cd tests - ctest # run regression tests - - cd $EPANET_HOME - - pip install -r tools/requirements.txt - - tools/before-test.sh $TEST_HOME $EPANET_HOME/$BUILD_HOME/bin $TRAVIS_COMMIT - - tools/run-nrtest.sh $TEST_HOME $TRAVIS_COMMIT + #- cd $EPANET_HOME + #- pip install -r tools/requirements.txt + #- tools/before-test.sh $TEST_HOME $EPANET_HOME/$BUILD_HOME/bin $TRAVIS_COMMIT + #- tools/run-nrtest.sh $TEST_HOME $TRAVIS_COMMIT From d33167161aa3fea2d85793efe930a3cf2ad7cf4e Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Fri, 31 Aug 2018 11:14:16 -0400 Subject: [PATCH 25/35] Revert "Make memorypool threadsafe " --- .travis.yml | 1 - include/epanet2.h | 7 +- src/epanet.c | 22 ----- src/mempool.c | 8 +- tests/CMakeLists.txt | 26 +----- tests/data/example_0.inp | 178 --------------------------------------- tests/data/example_1.inp | 178 --------------------------------------- tests/test_reent.cpp | 65 -------------- 8 files changed, 7 insertions(+), 478 deletions(-) delete mode 100644 tests/data/example_0.inp delete mode 100644 tests/data/example_1.inp delete mode 100644 tests/test_reent.cpp diff --git a/.travis.yml b/.travis.yml index 4dcd2fa..3cf3c7f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,6 @@ env: before_install: - sudo apt-get -qq update - sudo apt-get install -y libboost-test-dev - - sudo apt-get install -y libboost-thread-dev - sudo apt-get install -y swig #install: diff --git a/include/epanet2.h b/include/epanet2.h index 837fb05..6ac7733 100644 --- a/include/epanet2.h +++ b/include/epanet2.h @@ -1183,10 +1183,9 @@ extern "C" { void DLLEXPORT EN_clearError(EN_ProjectHandle ph); int DLLEXPORT EN_checkError(EN_ProjectHandle ph, char** msg_buffer); - int DLLEXPORT EN_runproject(EN_ProjectHandle ph, const char *f1, const char *f2, - const char *f3, void(*pviewprog)(char *)); - - int DLLEXPORT EN_init(EN_ProjectHandle ph, char *rptFile, char *binOutFile, + //int DLLEXPORT EN_epanet(EN_ProjectHandle ph, const char *f1, const char *f2, + // const char *f3, void(*pviewprog)(char *)); + int DLLEXPORT EN_init(EN_ProjectHandle *ph, char *rptFile, char *binOutFile, EN_FlowUnits UnitsType, EN_FormType HeadlossFormula); int DLLEXPORT EN_open(EN_ProjectHandle ph, const char *inpFile, diff --git a/src/epanet.c b/src/epanet.c index 2ed29c9..ca3495a 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -613,28 +613,6 @@ int DLLEXPORT EN_deleteproject(EN_ProjectHandle *ph) return 0; } -int DLLEXPORT EN_runproject(EN_ProjectHandle ph, const char *f1, const char *f2, - const char *f3, void (*pviewprog)(char *)) -{ - int errcode = 0; - EN_Project *p = NULL; - - ERRCODE(EN_open(ph, f1, f2, f3)); - - p = (EN_Project*)(ph); - p->viewprog = pviewprog; - - if (p->out_files.Hydflag != USE) { - ERRCODE(EN_solveH(ph)); - } - - ERRCODE(EN_solveQ(ph)); - ERRCODE(EN_report(ph)); - - EN_close(ph); - - return errcode; -} int DLLEXPORT EN_init(EN_ProjectHandle ph, char *f2, char *f3, EN_FlowUnits UnitsType, EN_FormType HeadlossFormula) diff --git a/src/mempool.c b/src/mempool.c index 17ba55a..ef7e645 100755 --- a/src/mempool.c +++ b/src/mempool.c @@ -21,12 +21,6 @@ #endif #include "mempool.h" -#ifdef _MSC_VER -#define THREAD_LOCAL __declspec(thread) -#else -#define THREAD_LOCAL __thread -#endif - /* ** ALLOC_BLOCK_SIZE - adjust this size to suit your installation - it ** should be reasonably large otherwise you will be mallocing a lot. @@ -60,7 +54,7 @@ typedef struct alloc_root_s ** root - Pointer to the current pool. */ -THREAD_LOCAL alloc_root_t *root; +static alloc_root_t *root; /* diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8b93c76..be6dc5a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -17,35 +17,15 @@ enable_testing() set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) -if(UNIX) - set(CMAKE_CXX_FLAGS "-std=c++11") -endif(UNIX) - - -#Prep ourselves to link with boost -if(MSVC) - set(Boost_DEBUG OFF) - set(Boost_DETAILED_FAILURE_MSG OFF) - set(Boost_THREADAPI win32) - set(Boost_USE_STATIC_LIBS ON) -endif(MSVC) -set(Boost_THREAD_FOUND OFF) -find_package(Boost COMPONENTS thread) +#Prep ourselves for compiling boost +find_package(Boost REQUIRED) include_directories (${Boost_INCLUDE_DIRS}) -#Test files are in separate source directory called tests +#I like to keep test files in a separate source directory called test file(GLOB TEST_SRCS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} test_*.cpp) -# If thread library is not found skip the reentrancy test -MESSAGE( STATUS "Thread found: " ${Boost_THREAD_FOUND}) -if(NOT ${Boost_THREAD_FOUND}) - list(REMOVE_ITEM TEST_SRCS test_reent.cpp) - MESSAGE("${TEST_SRCS}") -endif() - - #Run through each source foreach(testSrc ${TEST_SRCS}) #Extract the filename without an extension (NAME_WE) diff --git a/tests/data/example_0.inp b/tests/data/example_0.inp deleted file mode 100644 index 4df5bbf..0000000 --- a/tests/data/example_0.inp +++ /dev/null @@ -1,178 +0,0 @@ -[TITLE] - EPANET Example Network 1 -A simple example of modeling chlorine decay. Both bulk and -wall reactions are included. - -[JUNCTIONS] -;ID Elev Demand Pattern - 10 710 0 ; - 11 710 150 ; - 12 700 150 ; - 13 695 100 ; - 21 700 150 ; - 22 695 200 ; - 23 690 150 ; - 31 700 100 ; - 32 710 100 ; - -[RESERVOIRS] -;ID Head Pattern - 9 800 ; - -[TANKS] -;ID Elevation InitLevel MinLevel MaxLevel Diameter MinVol VolCurve - 2 850 120 100 150 50.5 0 ; - -[PIPES] -;ID Node1 Node2 Length Diameter Roughness MinorLoss Status - 10 10 11 10530 18 100 0 Open ; - 11 11 12 5280 14 100 0 Open ; - 12 12 13 5280 10 100 0 Open ; - 21 21 22 5280 10 100 0 Open ; - 22 22 23 5280 12 100 0 Open ; - 31 31 32 5280 6 100 0 Open ; - 110 2 12 200 18 100 0 Open ; - 111 11 21 5280 10 100 0 Open ; - 112 12 22 5280 12 100 0 Open ; - 113 13 23 5280 8 100 0 Open ; - 121 21 31 5280 8 100 0 Open ; - 122 22 32 5280 6 100 0 Open ; - -[PUMPS] -;ID Node1 Node2 Parameters - 9 9 10 HEAD 1 ; - -[VALVES] -;ID Node1 Node2 Diameter Type Setting MinorLoss - -[TAGS] - -[DEMANDS] -;Junction Demand Pattern Category - -[STATUS] -;ID Status/Setting - -[PATTERNS] -;ID Multipliers -;Demand Pattern - 1 1.0 1.2 1.4 1.6 1.4 1.2 - 1 1.0 0.8 0.6 0.4 0.6 0.8 - -[CURVES] -;ID X-Value Y-Value -;PUMP: Pump Curve for Pump 9 - 1 1500 250 - -[CONTROLS] - LINK 9 OPEN IF NODE 2 BELOW 110 - LINK 9 CLOSED IF NODE 2 ABOVE 140 - - -[RULES] - -[ENERGY] - Global Efficiency 75 - Global Price 0.0 - Demand Charge 0.0 - -[EMITTERS] -;Junction Coefficient - -[QUALITY] -;Node InitQual - 10 0.5 - 11 0.5 - 12 0.5 - 13 0.5 - 21 0.5 - 22 0.5 - 23 0.5 - 31 0.5 - 32 0.5 - 9 1.0 - 2 1.0 - -[SOURCES] -;Node Type Quality Pattern - -[REACTIONS] -;Type Pipe/Tank Coefficient - - -[REACTIONS] - Order Bulk 1 - Order Tank 1 - Order Wall 1 - Global Bulk -.5 - Global Wall -1 - Limiting Potential 0.0 - Roughness Correlation 0.0 - -[MIXING] -;Tank Model - -[TIMES] - Duration 24:00 - Hydraulic Timestep 1:00 - Quality Timestep 0:05 - Pattern Timestep 2:00 - Pattern Start 0:00 - Report Timestep 1:00 - Report Start 0:00 - Start ClockTime 12 am - Statistic None - -[REPORT] - Status Yes - Summary No - Page 0 - -[OPTIONS] - Units GPM - Headloss H-W - Specific Gravity 1.0 - Viscosity 1.0 - Trials 40 - Accuracy 0.001 - CHECKFREQ 2 - MAXCHECK 10 - DAMPLIMIT 0 - Unbalanced Continue 10 - Pattern 1 - Demand Multiplier 1.0 - Emitter Exponent 0.5 - Quality Chlorine mg/L - Diffusivity 1.0 - Tolerance 0.01 - -[COORDINATES] -;Node X-Coord Y-Coord - 10 20.00 70.00 - 11 30.00 70.00 - 12 50.00 70.00 - 13 70.00 70.00 - 21 30.00 40.00 - 22 50.00 40.00 - 23 70.00 40.00 - 31 30.00 10.00 - 32 50.00 10.00 - 9 10.00 70.00 - 2 50.00 90.00 - -[VERTICES] -;Link X-Coord Y-Coord - -[LABELS] -;X-Coord Y-Coord Label & Anchor Node - 6.99 73.63 "Source" - 13.48 68.13 "Pump" - 43.85 91.21 "Tank" - -[BACKDROP] - DIMENSIONS 7.00 6.00 73.00 94.00 - UNITS None - FILE - OFFSET 0.00 0.00 - -[END] diff --git a/tests/data/example_1.inp b/tests/data/example_1.inp deleted file mode 100644 index 4df5bbf..0000000 --- a/tests/data/example_1.inp +++ /dev/null @@ -1,178 +0,0 @@ -[TITLE] - EPANET Example Network 1 -A simple example of modeling chlorine decay. Both bulk and -wall reactions are included. - -[JUNCTIONS] -;ID Elev Demand Pattern - 10 710 0 ; - 11 710 150 ; - 12 700 150 ; - 13 695 100 ; - 21 700 150 ; - 22 695 200 ; - 23 690 150 ; - 31 700 100 ; - 32 710 100 ; - -[RESERVOIRS] -;ID Head Pattern - 9 800 ; - -[TANKS] -;ID Elevation InitLevel MinLevel MaxLevel Diameter MinVol VolCurve - 2 850 120 100 150 50.5 0 ; - -[PIPES] -;ID Node1 Node2 Length Diameter Roughness MinorLoss Status - 10 10 11 10530 18 100 0 Open ; - 11 11 12 5280 14 100 0 Open ; - 12 12 13 5280 10 100 0 Open ; - 21 21 22 5280 10 100 0 Open ; - 22 22 23 5280 12 100 0 Open ; - 31 31 32 5280 6 100 0 Open ; - 110 2 12 200 18 100 0 Open ; - 111 11 21 5280 10 100 0 Open ; - 112 12 22 5280 12 100 0 Open ; - 113 13 23 5280 8 100 0 Open ; - 121 21 31 5280 8 100 0 Open ; - 122 22 32 5280 6 100 0 Open ; - -[PUMPS] -;ID Node1 Node2 Parameters - 9 9 10 HEAD 1 ; - -[VALVES] -;ID Node1 Node2 Diameter Type Setting MinorLoss - -[TAGS] - -[DEMANDS] -;Junction Demand Pattern Category - -[STATUS] -;ID Status/Setting - -[PATTERNS] -;ID Multipliers -;Demand Pattern - 1 1.0 1.2 1.4 1.6 1.4 1.2 - 1 1.0 0.8 0.6 0.4 0.6 0.8 - -[CURVES] -;ID X-Value Y-Value -;PUMP: Pump Curve for Pump 9 - 1 1500 250 - -[CONTROLS] - LINK 9 OPEN IF NODE 2 BELOW 110 - LINK 9 CLOSED IF NODE 2 ABOVE 140 - - -[RULES] - -[ENERGY] - Global Efficiency 75 - Global Price 0.0 - Demand Charge 0.0 - -[EMITTERS] -;Junction Coefficient - -[QUALITY] -;Node InitQual - 10 0.5 - 11 0.5 - 12 0.5 - 13 0.5 - 21 0.5 - 22 0.5 - 23 0.5 - 31 0.5 - 32 0.5 - 9 1.0 - 2 1.0 - -[SOURCES] -;Node Type Quality Pattern - -[REACTIONS] -;Type Pipe/Tank Coefficient - - -[REACTIONS] - Order Bulk 1 - Order Tank 1 - Order Wall 1 - Global Bulk -.5 - Global Wall -1 - Limiting Potential 0.0 - Roughness Correlation 0.0 - -[MIXING] -;Tank Model - -[TIMES] - Duration 24:00 - Hydraulic Timestep 1:00 - Quality Timestep 0:05 - Pattern Timestep 2:00 - Pattern Start 0:00 - Report Timestep 1:00 - Report Start 0:00 - Start ClockTime 12 am - Statistic None - -[REPORT] - Status Yes - Summary No - Page 0 - -[OPTIONS] - Units GPM - Headloss H-W - Specific Gravity 1.0 - Viscosity 1.0 - Trials 40 - Accuracy 0.001 - CHECKFREQ 2 - MAXCHECK 10 - DAMPLIMIT 0 - Unbalanced Continue 10 - Pattern 1 - Demand Multiplier 1.0 - Emitter Exponent 0.5 - Quality Chlorine mg/L - Diffusivity 1.0 - Tolerance 0.01 - -[COORDINATES] -;Node X-Coord Y-Coord - 10 20.00 70.00 - 11 30.00 70.00 - 12 50.00 70.00 - 13 70.00 70.00 - 21 30.00 40.00 - 22 50.00 40.00 - 23 70.00 40.00 - 31 30.00 10.00 - 32 50.00 10.00 - 9 10.00 70.00 - 2 50.00 90.00 - -[VERTICES] -;Link X-Coord Y-Coord - -[LABELS] -;X-Coord Y-Coord Label & Anchor Node - 6.99 73.63 "Source" - 13.48 68.13 "Pump" - 43.85 91.21 "Tank" - -[BACKDROP] - DIMENSIONS 7.00 6.00 73.00 94.00 - UNITS None - FILE - OFFSET 0.00 0.00 - -[END] diff --git a/tests/test_reent.cpp b/tests/test_reent.cpp deleted file mode 100644 index 1117284..0000000 --- a/tests/test_reent.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * test_reent.cpp - * - * Created: 8/30/2018 - * Author: Michael E. Tryby - * US EPA - ORD/NRMRL - * - * Unit testing for EPANET Output API. -*/ - -#include -#include -#include - -#include - -#include "epanet2.h" - -#define NUM_THREADS 2 - -using namespace std; - -void epanet_thread(long i) -{ - int errorcode = 0; - EN_ProjectHandle ph; - - string prefix = "example_"; - string suffix = ".inp"; - string input = prefix + to_string(static_cast(i)) + suffix; - - suffix = ".rpt"; - string report = prefix + to_string(static_cast(i)) + suffix; - - suffix = ".out"; - string output = prefix + to_string(static_cast(i)) + suffix; - - printf("Thread #%ld starting EPANET ...\n", i); - - EN_createproject(&ph); - errorcode = EN_runproject(ph, input.c_str(), report.c_str(), output.c_str(), NULL); - EN_deleteproject(&ph); - - printf("Thread #%ld EPANET done. Status = %d\n", i, errorcode); -} - -int main(int argc, char *argv[]) -{ - long i; - boost::thread *threads[NUM_THREADS]; - - for (i = 0; i < NUM_THREADS; i++) { - threads[i] = new boost::thread(epanet_thread, i); - printf("Main: creating thread %ld.\n", i); - } - - for (i = 0; i < NUM_THREADS; i++) { - threads[i]->join(); - printf("Main: joining thread %ld.\n", i); - delete threads[i]; - } - - printf("Main: program completed. Exiting.\n"); - return(0); -} From b2aa8de927c03b42386970634b27a568d49096c1 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Fri, 31 Aug 2018 13:15:00 -0400 Subject: [PATCH 26/35] Fixing build error on Travis --- include/epanet2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/epanet2.h b/include/epanet2.h index 6ac7733..f7ca1a9 100644 --- a/include/epanet2.h +++ b/include/epanet2.h @@ -1185,7 +1185,7 @@ extern "C" { //int DLLEXPORT EN_epanet(EN_ProjectHandle ph, const char *f1, const char *f2, // const char *f3, void(*pviewprog)(char *)); - int DLLEXPORT EN_init(EN_ProjectHandle *ph, char *rptFile, char *binOutFile, + int DLLEXPORT EN_init(EN_ProjectHandle ph, char *rptFile, char *binOutFile, EN_FlowUnits UnitsType, EN_FormType HeadlossFormula); int DLLEXPORT EN_open(EN_ProjectHandle ph, const char *inpFile, From f7d54810ea9402ccb266a3541535dd9c8a6341e9 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Fri, 31 Aug 2018 13:36:03 -0400 Subject: [PATCH 27/35] Update README.md Fixing Travis badge. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4020cb0..2c84538 100755 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ EPANET {#epanet-readme} ## Build Status [![Build status](https://ci.appveyor.com/api/projects/status/19wpg4g2cmj3oihl?svg=true)](https://ci.appveyor.com/project/OpenWaterAnalytics/epanet/branch/dev) -[![Build Status](https://travis-ci.org/OpenWaterAnalytics/EPANET.svg?branch=master)](https://travis-ci.org/OpenWaterAnalytics/EPANET) +[![Build Status](https://travis-ci.org/OpenWaterAnalytics/EPANET.svg?branch=dev)](https://travis-ci.org/OpenWaterAnalytics/EPANET) ## 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). From 6e73b6a4f5582ef4b13a40cdf6786cf1702d2cc3 Mon Sep 17 00:00:00 2001 From: Lew Rossman Date: Mon, 3 Sep 2018 10:29:41 -0400 Subject: [PATCH 28/35] Made mempool.c threadsafe (#234) --- src/mempool.c | 240 ++++++++++++++++++-------------------------------- src/mempool.h | 36 ++------ src/quality.c | 17 ++-- src/types.h | 5 +- 4 files changed, 100 insertions(+), 198 deletions(-) diff --git a/src/mempool.c b/src/mempool.c index ef7e645..f77d8ec 100755 --- a/src/mempool.c +++ b/src/mempool.c @@ -1,17 +1,9 @@ /* mempool.c ** -** A simple fast memory allocation package. +** A simple fast pooled memory allocation package. ** -** By Steve Hill in Graphics Gems III, David Kirk (ed.), -** Academic Press, Boston, MA, 1992 -** -** Modified by Lew Rossman, 8/13/94. -** -** AllocInit() - create an alloc pool, returns the old pool handle -** Alloc() - allocate memory -** AllocReset() - reset the current pool -** AllocSetPool() - set the current pool -** AllocFree() - free the memory used by the current pool. +** Based on code by Steve Hill in Graphics Gems III, +** David Kirk (ed.), Academic Press, Boston, MA, 1992 ** */ @@ -28,95 +20,80 @@ #define ALLOC_BLOCK_SIZE 64000 /*(62*1024)*/ -/* -** alloc_hdr_t - Header for each block of memory. -*/ - -typedef struct alloc_hdr_s +struct MemBlock { - struct alloc_hdr_s *next; /* Next Block */ - char *block, /* Start of block */ - *free, /* Next free in block */ - *end; /* block + block size */ -} alloc_hdr_t; + struct MemBlock *next; // Next block + char *block, // Start of block + *free, // Next free position in block + *end; // block + block size +}; -/* -** alloc_root_t - Header for the whole pool. -*/ - -typedef struct alloc_root_s +struct Mempool { - alloc_hdr_t *first, /* First header in pool */ - *current; /* Current header */ -} alloc_root_t; + struct MemBlock *first; + struct MemBlock *current; +}; -/* -** root - Pointer to the current pool. -*/ - -static alloc_root_t *root; - - -/* -** AllocHdr() -** -** Private routine to allocate a header and memory block. -*/ - -static alloc_hdr_t *AllocHdr(void); - -static alloc_hdr_t * AllocHdr() +static struct MemBlock* createMemBlock() { - alloc_hdr_t *hdr; - char *block; - - block = (char *) malloc(ALLOC_BLOCK_SIZE); - hdr = (alloc_hdr_t *) malloc(sizeof(alloc_hdr_t)); - - if (hdr == NULL || block == NULL) return(NULL); - hdr->block = block; - hdr->free = block; - hdr->next = NULL; - hdr->end = block + ALLOC_BLOCK_SIZE; - - return(hdr); + struct MemBlock* memBlock = malloc(sizeof(struct MemBlock)); + if (memBlock) + { + memBlock->block = malloc(ALLOC_BLOCK_SIZE * sizeof(char)); + if (memBlock->block == NULL) + { + free(memBlock); + return NULL; + } + memBlock->free = memBlock->block; + memBlock->next = NULL; + memBlock->end = memBlock->block + ALLOC_BLOCK_SIZE; + } + return memBlock; } -/* -** AllocInit() -** -** Create a new memory pool with one block. -** Returns pointer to the new pool. -*/ - -DLLEXPORT alloc_handle_t * AllocInit() +static void deleteMemBlock(struct MemBlock* memBlock) { - alloc_handle_t *newpool; - root = (alloc_root_t *) malloc(sizeof(alloc_root_t)); - if (root == NULL) { - return(NULL); - } - if ( (root->first = AllocHdr()) == NULL) { - return(NULL); - } - root->current = root->first; - newpool = (alloc_handle_t *) root; - return(newpool); + free(memBlock->block); + free(memBlock); } -/* -** Alloc() -** -** Use as a direct replacement for malloc(). Allocates -** memory from the current pool. -*/ - -DLLEXPORT char *Alloc(long size) +struct Mempool * mempool_create() { - alloc_hdr_t *hdr = root->current; - char *ptr; + struct Mempool *mempool; + mempool = (struct Mempool *)malloc(sizeof(struct Mempool)); + if (mempool == NULL) return NULL; + mempool->first = createMemBlock(); + mempool->current = mempool->first; + if (mempool->first == NULL) return NULL; + return mempool; +} + +void mempool_delete(struct Mempool *mempool) +{ + if (mempool == NULL) return; + while (mempool->first) + { + mempool->current = mempool->first->next; + deleteMemBlock(mempool->first); + mempool->first = mempool->current; + } + free(mempool); + mempool = NULL; +} + +void mempool_reset(struct Mempool *mempool) +{ + mempool->current = mempool->first; + mempool->current->free = mempool->current->block; +} + + +char * mempool_alloc(struct Mempool *mempool, size_t size) +{ + char* ptr; /* ** Align to 4 byte boundary - should be ok for most machines. @@ -124,86 +101,37 @@ DLLEXPORT char *Alloc(long size) */ size = (size + 3) & 0xfffffffc; - ptr = hdr->free; - hdr->free += size; + if (!mempool->current) return NULL; + ptr = mempool->current->free; + mempool->current->free += size; - /* Check if the current block is exhausted. */ + // Check if the current block is exhausted - if (hdr->free >= hdr->end) + if (mempool->current->free >= mempool->current->end) { - /* Is the next block already allocated? */ + // Is the next block already allocated? - if (hdr->next != NULL) + if (mempool->current->next) { - /* re-use block */ - hdr->next->free = hdr->next->block; - root->current = hdr->next; + // re-use block + mempool->current->next->free = mempool->current->next->block; + mempool->current = mempool->current->next; } else { - /* extend the pool with a new block */ - if ( (hdr->next = AllocHdr()) == NULL) return(NULL); - root->current = hdr->next; + // extend the pool with a new block + mempool->current->next = createMemBlock(); + if (!mempool->current->next) return NULL; + mempool->current = mempool->current->next; } - /* set ptr to the first location in the next block */ - ptr = root->current->free; - root->current->free += size; + // set ptr to the first location in the next block + + ptr = mempool->current->free; + mempool->current->free += size; } - /* Return pointer to allocated memory. */ + // Return pointer to allocated memory - return(ptr); -} - - -/* -** AllocSetPool() -** -** Change the current pool. Return the old pool. -*/ - -DLLEXPORT alloc_handle_t * AllocSetPool(alloc_handle_t *newpool) -{ - alloc_handle_t *old = (alloc_handle_t *) root; - root = (alloc_root_t *) newpool; - return(old); -} - - -/* -** AllocReset() -** -** Reset the current pool for re-use. No memory is freed, -** so this is very fast. -*/ - -DLLEXPORT void AllocReset() -{ - root->current = root->first; - root->current->free = root->current->block; -} - - -/* -** AllocFreePool() -** -** Free the memory used by the current pool. -** Don't use where AllocReset() could be used. -*/ - -DLLEXPORT void AllocFreePool() -{ - alloc_hdr_t *tmp, - *hdr = root->first; - - while (hdr != NULL) - { - tmp = hdr->next; - free((char *) hdr->block); - free((char *) hdr); - hdr = tmp; - } - free((char *) root); - root = NULL; + return ptr; } diff --git a/src/mempool.h b/src/mempool.h index 4fe3c0f..002272f 100755 --- a/src/mempool.h +++ b/src/mempool.h @@ -3,41 +3,17 @@ ** ** Header for mempool.c ** -** The type alloc_handle_t provides an opaque reference to the -** alloc pool - only the alloc routines know its structure. +** A simple pooled memory allocator */ #ifndef MEMPOOL_H #define MEMPOOL_H -#ifndef DLLEXPORT - #ifdef DLL - #ifdef __cplusplus - #define DLLEXPORT extern "C" __declspec(dllexport) - #else - #define DLLEXPORT __declspec(dllexport) __stdcall - #endif - #elif defined(CYGWIN) - #define DLLEXPORT __stdcall - #else - #ifdef __cplusplus - #define DLLEXPORT - #else - #define DLLEXPORT - #endif - #endif -#endif +struct Mempool; - -typedef struct -{ - long dummy; -} alloc_handle_t; - -alloc_handle_t *AllocInit(void); -char *Alloc(long); -alloc_handle_t *AllocSetPool(alloc_handle_t *); -void AllocReset(void); -void AllocFreePool(void); +struct Mempool * mempool_create(); +void mempool_delete(struct Mempool *mempool); +void mempool_reset(struct Mempool *mempool); +char * mempool_alloc(struct Mempool *mempool, size_t size); #endif \ No newline at end of file diff --git a/src/quality.c b/src/quality.c index a7286db..1a70beb 100644 --- a/src/quality.c +++ b/src/quality.c @@ -29,9 +29,9 @@ AUTHOR: L. Rossman closequal() -- called from ENcloseQ() in EPANET.C Calls are made to: - AllocInit() - Alloc() - AllocFree() + mempool_create() + mempool_alloc() + mempool_delete() in MEMPOOL.C to utilize a memory pool to prevent excessive malloc'ing when constantly creating and destroying pipe sub-segments during the water quality transport calculations. @@ -89,7 +89,7 @@ int openqual(EN_Project *pr) /* Allocate memory pool for WQ segments */ qu->OutOfMemory = FALSE; - qu->SegPool = AllocInit(); + qu->SegPool = mempool_create(); if (qu->SegPool == NULL) { errcode = 101; } @@ -193,8 +193,7 @@ void initqual(EN_Project *pr) /* Reset memory pool */ qu->FreeSeg = NULL; - AllocSetPool(qu->SegPool); - AllocReset(); + mempool_reset(qu->SegPool); } /* Initialize avg. reaction rates */ @@ -438,8 +437,7 @@ int closequal(EN_Project *pr) /* Free memory pool */ if (qu->SegPool) { - AllocSetPool(qu->SegPool); - AllocFreePool(); + mempool_delete(qu->SegPool); } free(qu->FirstSeg); @@ -573,7 +571,6 @@ void transport(EN_Project *pr, long tstep) /* Repeat until elapsed time equals hydraulic time step */ - AllocSetPool(qu->SegPool); qtime = 0; while (!qu->OutOfMemory && qtime < tstep) { /* Qstep is quality time step */ dt = MIN(qu->Qstep, tstep - qtime); /* Current time step */ @@ -793,7 +790,7 @@ void addseg(EN_Project *pr, int k, double v, double c) seg = qu->FreeSeg; qu->FreeSeg = seg->prev; } else { - seg = (struct Sseg *)Alloc(sizeof(struct Sseg)); + seg = (struct Sseg *) mempool_alloc(qu->SegPool, sizeof(struct Sseg)); if (seg == NULL) { qu->OutOfMemory = TRUE; return; diff --git a/src/types.h b/src/types.h index d887c96..0a2d26c 100755 --- a/src/types.h +++ b/src/types.h @@ -22,7 +22,6 @@ AUTHOR: L. Rossman #include "epanet2.h" #include "hash.h" -#include "mempool.h" #include "util/errormanager.h" @@ -538,6 +537,8 @@ typedef struct s_ActItem /* Action list item */ } ActItem; +// Forward declaration of the Mempool structure defined in mempool.h +struct Mempool; typedef struct { char @@ -578,7 +579,7 @@ typedef struct { Qtime; /// Current quality time (sec) char OutOfMemory; /* Out of memory indicator */ - alloc_handle_t *SegPool; // Memory pool for water quality segments + struct Mempool *SegPool; // Memory pool for water quality segments Pseg FreeSeg; /* Pointer to unused segment */ Pseg *FirstSeg, /* First (downstream) segment in each pipe */ From fdca2bef42ab641a54663de03d55dca3ebad78f1 Mon Sep 17 00:00:00 2001 From: Lew Rossman Date: Mon, 3 Sep 2018 10:34:03 -0400 Subject: [PATCH 29/35] Edits made to 2.2 Release Notes --- ReleaseNotes2_2.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/ReleaseNotes2_2.md b/ReleaseNotes2_2.md index d09fbf8..65f1574 100644 --- a/ReleaseNotes2_2.md +++ b/ReleaseNotes2_2.md @@ -1,6 +1,4 @@  - - Release Notes for EPANET 2.2 (Draft) ============================ @@ -49,15 +47,18 @@ These new parameters augment the current `EN_ACCURACY` option which always remai ## Improved Linear Solver Routine EPANET's hydraulic solver requires solving a system of linear equations over a series of iterations until a set of convergence criteria are met. The coefficient matrix of this linear system is square and symmetric. It has a row for each network node and a non-zero off-diagonal coefficient for each link. The numerical effort needed to solve the linear system can be reduced if the nodes are re-ordered so that the non-zero coefficients cluster more tightly around the diagonal. -EPANET's original node re-ordering scheme has been replaced by the more powerful **Multiple Minimum Degree (MMD)** algorithm. On a series of eight networks ranging in size from 7,700 to 100,000 nodes **MMD** reduced the solution time for a single period (steady state) hydraulic analysis by an average of more than 50%. +EPANET's original node re-ordering scheme has been replaced by the more powerful **Multiple Minimum Degree (MMD)** algorithm. On a series of eight networks ranging in size from 7,700 to 100,000 nodes **MMD** reduced the solution time for a single period (steady state) hydraulic analysis by an average of 58%. ## Pressure Dependent Demands EPANET has always employed a Demand Driven Analysis (**DDA**) when modeling network hydraulics. Under this approach nodal demands at a given point in time are fixed values that must be delivered no matter what nodal heads and link flows are produced by a hydraulic solution. This can result in situations where required demands are satisfied at nodes that have negative pressures - a physical impossibility. To address this issue EPANET has been extended to use a Pressure Driven Analysis (**PDA**) if so desired. Under **PDA**, the demand *D* delivered at a node depends on the node's available pressure *P* according to: -$$D =D_f\left(\frac{P-P_{min}}{P_{req}-P_{min}}\right)^{P_{exp}} for P_{0}<=P<=P_{req}$$where *Df* is the full demand required, *Pmin* is the pressure below which demand is zero, *Preq* is the pressure required to deliver the full required demand and *Pexp* is an exponent. When *P < Pmin* demand is 0 and when *P > Preq* demand equals *Df*. -To implement pressure dependent analysis four new parameters have been added to the [OPTIONS] section of the EPANET input file: +*D = Df [ (P - Pmin) / (Preq - Pmin) ]Pexp* + +where *Df* is the full demand required, *Pmin* is the pressure below which demand is zero, *Preq* is the pressure required to deliver the full required demand and *Pexp* is an exponent. When *P < Pmin* demand is 0 and when *P > Preq* demand equals *Df*. + +To implement pressure driven analysis four new parameters have been added to the [OPTIONS] section of the EPANET input file: | Parameter | Description | Default | @@ -81,7 +82,8 @@ for the thread-safe API. Some additional points regarding the new **PDA** option - If no DEMAND MODEL and its parameters are specified then the analysis defaults to being demand driven (**DDA**). - This implementation of **PDA** assumes that the same parameters apply to all nodes in the network. Extending the framework to allow different parameters for specific nodes is straightforward to do but is left as a future feature to implement. - - *P0* is allowed to equal to *Preq*. This condition can be used to find a solution that results in the smallest amount of demand reductions needed to insure that no node delivers positive demand at a pressure below *Pmin*. + - *Pmin* is allowed to equal to *Preq*. This condition can be used to find a solution that results in the smallest amount of demand reductions needed to insure that no node delivers positive demand at a pressure below *Pmin*. + ## Code Changes From b7e9988b152fdc117cb530859da9b3918cce71ca Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 4 Sep 2018 09:38:44 -0400 Subject: [PATCH 30/35] Adding unit test for reentrancy --- include/epanet2.h | 2 + src/epanet.c | 21 ++ tests/CMakeLists.txt | 8 +- tests/data/example_0.inp | 481 +++++++++++++++++++++++++++++++++++++++ tests/data/example_1.inp | 178 +++++++++++++++ tests/test_reent.cpp | 65 ++++++ 6 files changed, 754 insertions(+), 1 deletion(-) create mode 100644 tests/data/example_0.inp create mode 100644 tests/data/example_1.inp create mode 100644 tests/test_reent.cpp diff --git a/include/epanet2.h b/include/epanet2.h index f7ca1a9..f5a613f 100644 --- a/include/epanet2.h +++ b/include/epanet2.h @@ -1179,6 +1179,8 @@ extern "C" { ***************************************************/ int DLLEXPORT EN_createproject(EN_ProjectHandle *ph); int DLLEXPORT EN_deleteproject(EN_ProjectHandle *ph); + int DLLEXPORT EN_runproject(EN_ProjectHandle ph, const char *f1, const char *f2, + const char *f3, void (*pviewprog)(char *)); void DLLEXPORT EN_clearError(EN_ProjectHandle ph); int DLLEXPORT EN_checkError(EN_ProjectHandle ph, char** msg_buffer); diff --git a/src/epanet.c b/src/epanet.c index ca3495a..12dba99 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -613,6 +613,27 @@ int DLLEXPORT EN_deleteproject(EN_ProjectHandle *ph) return 0; } +int DLLEXPORT EN_runproject(EN_ProjectHandle ph, const char *f1, const char *f2, + const char *f3, void (*pviewprog)(char *)) +{ + int errcode = 0; + EN_Project *p = NULL; + + ERRCODE(EN_open(ph, f1, f2, f3)); + p = (EN_Project*)(ph); + p->viewprog = pviewprog; + + if (p->out_files.Hydflag != USE) { + ERRCODE(EN_solveH(ph)); + } + + ERRCODE(EN_solveQ(ph)); + ERRCODE(EN_report(ph)); + + EN_close(ph); + + return errcode; +} int DLLEXPORT EN_init(EN_ProjectHandle ph, char *f2, char *f3, EN_FlowUnits UnitsType, EN_FormType HeadlossFormula) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index be6dc5a..3fca5ab 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -18,7 +18,13 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) #Prep ourselves for compiling boost -find_package(Boost REQUIRED) +if(MSVC) + set(Boost_DEBUG OFF) + set(Boost_DETAILED_FAILURE_MSG OFF) + set(Boost_USE_STATIC_LIBS ON) +endif(MSVC) +set(Boost_THREAD_FOUND OFF) +find_package(Boost COMPONENTS thread) include_directories (${Boost_INCLUDE_DIRS}) diff --git a/tests/data/example_0.inp b/tests/data/example_0.inp new file mode 100644 index 0000000..3be1e96 --- /dev/null +++ b/tests/data/example_0.inp @@ -0,0 +1,481 @@ +[TITLE] +EPANET Example Network 3 +Example showing how the percent of Lake water in a dual-source +system changes over time. + +[JUNCTIONS] +;ID Elev Demand Pattern + 10 147 0 ; + 15 32 1 3 ; + 20 129 0 ; + 35 12.5 1 4 ; + 40 131.9 0 ; + 50 116.5 0 ; + 60 0 0 ; + 601 0 0 ; + 61 0 0 ; + 101 42 189.95 ; + 103 43 133.2 ; + 105 28.5 135.37 ; + 107 22 54.64 ; + 109 20.3 231.4 ; + 111 10 141.94 ; + 113 2 20.01 ; + 115 14 52.1 ; + 117 13.6 117.71 ; + 119 2 176.13 ; + 120 0 0 ; + 121 -2 41.63 ; + 123 11 1 2 ; + 125 11 45.6 ; + 127 56 17.66 ; + 129 51 0 ; + 131 6 42.75 ; + 139 31 5.89 ; + 141 4 9.85 ; + 143 -4.5 6.2 ; + 145 1 27.63 ; + 147 18.5 8.55 ; + 149 16 27.07 ; + 151 33.5 144.48 ; + 153 66.2 44.17 ; + 157 13.1 51.79 ; + 159 6 41.32 ; + 161 4 15.8 ; + 163 5 9.42 ; + 164 5 0 ; + 166 -2 2.6 ; + 167 -5 14.56 ; + 169 -5 0 ; + 171 -4 39.34 ; + 173 -4 0 ; + 177 8 58.17 ; + 179 8 0 ; + 181 8 0 ; + 183 11 0 ; + 184 16 0 ; + 185 16 25.65 ; + 187 12.5 0 ; + 189 4 107.92 ; + 191 25 81.9 ; + 193 18 71.31 ; + 195 15.5 0 ; + 197 23 17.04 ; + 199 -2 119.32 ; + 201 0.1 44.61 ; + 203 2 1 5 ; + 204 21 0 ; + 205 21 65.36 ; + 206 1 0 ; + 207 9 69.39 ; + 208 16 0 ; + 209 -2 0.87 ; + 211 7 8.67 ; + 213 7 13.94 ; + 215 7 92.19 ; + 217 6 24.22 ; + 219 4 41.32 ; + 225 8 22.8 ; + 229 10.5 64.18 ; + 231 5 16.48 ; + 237 14 15.61 ; + 239 13 44.61 ; + 241 13 0 ; + 243 14 4.34 ; + 247 18 70.38 ; + 249 18 0 ; + 251 30 24.16 ; + 253 36 54.52 ; + 255 27 40.39 ; + 257 17 0 ; + 259 25 0 ; + 261 0 0 ; + 263 0 0 ; + 265 0 0 ; + 267 21 0 ; + 269 0 0 ; + 271 6 0 ; + 273 8 0 ; + 275 10 0 ; + +[RESERVOIRS] +;ID Head Pattern + River 220.0 ; + Lake 167.0 ; + +[TANKS] +;ID Elevation InitLevel MinLevel MaxLevel Diameter MinVol VolCurve + 1 131.9 13.1 .1 32.1 85 0 ; + 2 116.5 23.5 6.5 40.3 50 0 ; + 3 129.0 29.0 4.0 35.5 164 0 ; + +[PIPES] +;ID Node1 Node2 Length Diameter Roughness MinorLoss Status + 20 3 20 99 99 199 0 Open ; + 40 1 40 99 99 199 0 Open ; + 50 2 50 99 99 199 0 Open ; + 60 River 60 1231 24 140 0 Open ; + 101 10 101 14200 18 110 0 Open ; + 103 101 103 1350 16 130 0 Open ; + 105 101 105 2540 12 130 0 Open ; + 107 105 107 1470 12 130 0 Open ; + 109 103 109 3940 16 130 0 Open ; + 111 109 111 2000 12 130 0 Open ; + 112 115 111 1160 12 130 0 Open ; + 113 111 113 1680 12 130 0 Open ; + 114 115 113 2000 8 130 0 Open ; + 115 107 115 1950 8 130 0 Open ; + 116 113 193 1660 12 130 0 Open ; + 117 263 105 2725 12 130 0 Open ; + 119 115 117 2180 12 130 0 Open ; + 120 119 120 730 12 130 0 Open ; + 121 120 117 1870 12 130 0 Open ; + 122 121 120 2050 8 130 0 Open ; + 123 121 119 2000 30 141 0 Open ; + 125 123 121 1500 30 141 0 Open ; + 129 121 125 930 24 130 0 Open ; + 131 125 127 3240 24 130 0 Open ; + 133 20 127 785 20 130 0 Open ; + 135 127 129 900 24 130 0 Open ; + 137 129 131 6480 16 130 0 Open ; + 145 129 139 2750 8 130 0 Open ; + 147 139 141 2050 8 130 0 Open ; + 149 143 141 1400 8 130 0 Open ; + 151 15 143 1650 8 130 0 Open ; + 153 145 141 3510 12 130 0 Open ; + 155 147 145 2200 12 130 0 Open ; + 159 147 149 880 12 130 0 Open ; + 161 149 151 1020 8 130 0 Open ; + 163 151 153 1170 12 130 0 Open ; + 169 125 153 4560 8 130 0 Open ; + 171 119 151 3460 12 130 0 Open ; + 173 119 157 2080 30 141 0 Open ; + 175 157 159 2910 30 141 0 Open ; + 177 159 161 2000 30 141 0 Open ; + 179 161 163 430 30 141 0 Open ; + 180 163 164 150 14 130 0 Open ; + 181 164 166 490 14 130 0 Open ; + 183 265 169 590 30 141 0 Open ; + 185 167 169 60 8 130 0 Open ; + 186 187 204 99.9 8 130 0 Open ; + 187 169 171 1270 30 141 0 Open ; + 189 171 173 50 30 141 0 Open ; + 191 271 171 760 24 130 0 Open ; + 193 35 181 30 24 130 0 Open ; + 195 181 177 30 12 130 0 Open ; + 197 177 179 30 12 130 0 Open ; + 199 179 183 210 12 130 0 Open ; + 201 40 179 1190 12 130 0 Open ; + 202 185 184 99.9 8 130 0 Open ; + 203 183 185 510 8 130 0 Open ; + 204 184 205 4530. 12 130 0 Open ; + 205 204 185 1325. 12 130 0 Open ; + 207 189 183 1350 12 130 0 Open ; + 209 189 187 500 8 130 0 Open ; + 211 169 269 646 12 130 0 Open ; + 213 191 187 2560 12 130 0 Open ; + 215 267 189 1230 12 130 0 Open ; + 217 191 193 520 12 130 0 Open ; + 219 193 195 360 12 130 0 Open ; + 221 161 195 2300 8 130 0 Open ; + 223 197 191 1150 12 130 0 Open ; + 225 111 197 2790 12 130 0 Open ; + 229 173 199 4000 24 141 0 Open ; + 231 199 201 630 24 141 0 Open ; + 233 201 203 120 24 130 0 Open ; + 235 199 273 725 12 130 0 Open ; + 237 205 207 1200 12 130 0 Open ; + 238 207 206 450 12 130 0 Open ; + 239 275 207 1430 12 130 0 Open ; + 240 206 208 510 12 130 0 Open ; + 241 208 209 885 12 130 0 Open ; + 243 209 211 1210 16 130 0 Open ; + 245 211 213 990 16 130 0 Open ; + 247 213 215 4285 16 130 0 Open ; + 249 215 217 1660 16 130 0 Open ; + 251 217 219 2050 14 130 0 Open ; + 257 217 225 1560 12 130 0 Open ; + 261 213 229 2200 8 130 0 Open ; + 263 229 231 1960 12 130 0 Open ; + 269 211 237 2080 12 130 0 Open ; + 271 237 229 790 8 130 0 Open ; + 273 237 239 510 12 130 0 Open ; + 275 239 241 35 12 130 0 Open ; + 277 241 243 2200 12 130 0 Open ; + 281 241 247 445 10 130 0 Open ; + 283 239 249 430 12 130 0 Open ; + 285 247 249 10 12 130 0 Open ; + 287 247 255 1390 10 130 0 Open ; + 289 50 255 925 10 130 0 Open ; + 291 255 253 1100 10 130 0 Open ; + 293 255 251 1100 8 130 0 Open ; + 295 249 251 1450 12 130 0 Open ; + 297 120 257 645 8 130 0 Open ; + 299 257 259 350 8 130 0 Open ; + 301 259 263 1400 8 130 0 Open ; + 303 257 261 1400 8 130 0 Open ; + 305 117 261 645 12 130 0 Open ; + 307 261 263 350 12 130 0 Open ; + 309 265 267 1580 8 130 0 Open ; + 311 193 267 1170 12 130 0 Open ; + 313 269 189 646 12 130 0 Open ; + 315 181 271 260 24 130 0 Open ; + 317 273 275 2230 8 130 0 Open ; + 319 273 205 645 12 130 0 Open ; + 321 163 265 1200 30 141 0 Open ; + 323 201 275 300 12 130 0 Open ; + 325 269 271 1290 8 130 0 Open ; + 329 61 123 45500 30 140 0 Open ; + 330 60 601 1 30 140 0 Closed ; + 333 601 61 1 30 140 0 Open ; + +[PUMPS] +;ID Node1 Node2 Parameters + 10 Lake 10 HEAD 1 ; + 335 60 61 HEAD 2 ; + +[VALVES] +;ID Node1 Node2 Diameter Type Setting MinorLoss + +[TAGS] + +[DEMANDS] +;Junction Demand Pattern Category + +[STATUS] +;ID Status/Setting + 10 Closed + +[PATTERNS] +;ID Multipliers +;General Default Demand Pattern + 1 1.34 1.94 1.46 1.44 .76 .92 + 1 .85 1.07 .96 1.1 1.08 1.19 + 1 1.16 1.08 .96 .83 .79 .74 + 1 .64 .64 .85 .96 1.24 1.67 +;Demand Pattern for Node 123 + 2 0 0 0 0 0 1219 + 2 0 0 0 1866 1836 1818 + 2 1818 1822 1822 1817 1824 1816 + 2 1833 1817 1830 1814 1840 1859 +;Demand Pattern for Node 15 + 3 620 620 620 620 620 360 + 3 360 0 0 0 0 360 + 3 360 360 360 360 0 0 + 3 0 0 0 0 360 360 +;Demand Pattern for Node 35 + 4 1637 1706 1719 1719 1791 1819 + 4 1777 1842 1815 1825 1856 1801 + 4 1819 1733 1664 1620 1613 1620 + 4 1616 1647 1627 1627 1671 1668 +;Demand Pattern for Node 203 + 5 4439 4531 4511 4582 4531 4582 + 5 4572 4613 4643 4643 4592 4613 + 5 4531 4521 4449 4439 4449 4460 + 5 4439 4419 4368 4399 4470 4480 + +[CURVES] +;ID X-Value Y-Value +;PUMP: Pump Curve for Pump 10 (Lake Source) + 1 0 104. + 1 2000. 92. + 1 4000. 63. +;PUMP: Pump Curve for Pump 335 (River Source) + 2 0 200. + 2 8000. 138. + 2 14000. 86. + +[CONTROLS] +;Lake source operates only part of the day +Link 10 OPEN AT TIME 1 +Link 10 CLOSED AT TIME 15 + +;Pump 335 controlled by level in Tank 1 +;When pump is closed, bypass pipe is opened +Link 335 OPEN IF Node 1 BELOW 17.1 +Link 335 CLOSED IF Node 1 ABOVE 19.1 +Link 330 CLOSED IF Node 1 BELOW 17.1 +Link 330 OPEN IF Node 1 ABOVE 19.1 + + +[RULES] + +[ENERGY] + Global Efficiency 75 + Global Price 0.0 + Demand Charge 0.0 + +[EMITTERS] +;Junction Coefficient + +[QUALITY] +;Node InitQual + +[SOURCES] +;Node Type Quality Pattern + +[REACTIONS] +;Type Pipe/Tank Coefficient + + +[REACTIONS] + Order Bulk 1 + Order Tank 1 + Order Wall 1 + Global Bulk 0.0 + Global Wall 0.0 + Limiting Potential 0.0 + Roughness Correlation 0.0 + +[MIXING] +;Tank Model + +[TIMES] + Duration 24:00 + Hydraulic Timestep 1:00 + Quality Timestep 0:05 + Pattern Timestep 1:00 + Pattern Start 0:00 + Report Timestep 1:00 + Report Start 0:00 + Start ClockTime 12 am + Statistic None + +[REPORT] + Status Yes + Summary No + Page 0 + +[OPTIONS] + Units GPM + Headloss H-W + Specific Gravity 1.0 + Viscosity 1.0 + Trials 40 + Accuracy 0.001 + CHECKFREQ 2 + MAXCHECK 10 + DAMPLIMIT 0 + Unbalanced Continue 10 + Pattern 1 + Demand Multiplier 1.0 + Emitter Exponent 0.5 + Quality Trace Lake + Diffusivity 1.0 + Tolerance 0.01 + +[COORDINATES] +;Node X-Coord Y-Coord + 10 9.00 27.85 + 15 38.68 23.76 + 20 29.44 26.91 + 35 25.46 10.52 + 40 27.02 9.81 + 50 33.01 3.01 + 60 23.90 29.94 + 601 23.00 29.49 + 61 23.71 29.03 + 101 13.81 22.94 + 103 12.96 21.31 + 105 16.97 21.28 + 107 18.45 20.46 + 109 17.64 18.92 + 111 20.21 17.53 + 113 22.04 16.61 + 115 20.98 19.18 + 117 21.69 21.28 + 119 23.70 22.76 + 120 22.08 23.10 + 121 23.54 25.50 + 123 23.37 27.31 + 125 24.59 25.64 + 127 29.29 26.40 + 129 30.32 26.39 + 131 37.89 29.55 + 139 33.28 24.54 + 141 35.68 23.08 + 143 37.47 21.97 + 145 33.02 19.29 + 147 30.24 20.38 + 149 29.62 20.74 + 151 28.29 21.39 + 153 28.13 22.63 + 157 24.85 20.16 + 159 23.12 17.50 + 161 25.10 15.28 + 163 25.39 14.98 + 164 25.98 15.14 + 166 26.48 15.13 + 167 25.88 12.98 + 169 25.68 12.74 + 171 26.65 11.80 + 173 26.87 11.59 + 177 25.92 10.59 + 179 25.71 10.40 + 181 25.72 10.74 + 183 25.45 10.18 + 184 25.15 9.52 + 185 25.01 9.67 + 187 23.64 11.04 + 189 24.15 11.37 + 191 22.10 14.07 + 193 22.88 14.35 + 195 23.18 14.72 + 197 20.97 15.18 + 199 29.42 8.44 + 201 30.89 8.57 + 203 31.14 8.89 + 204 23.80 10.90 + 205 29.20 6.46 + 206 31.66 6.64 + 207 31.00 6.61 + 208 32.54 6.81 + 209 33.76 6.59 + 211 34.20 5.54 + 213 35.26 6.16 + 215 39.95 8.73 + 217 42.11 8.67 + 219 44.86 9.32 + 225 43.53 7.38 + 229 36.16 3.49 + 231 38.38 2.54 + 237 35.37 3.08 + 239 35.76 2.31 + 241 35.87 2.11 + 243 37.04 0.00 + 247 35.02 2.05 + 249 35.02 1.81 + 251 34.15 1.10 + 253 32.17 1.88 + 255 33.51 2.45 + 257 21.17 23.32 + 259 20.80 23.40 + 261 20.79 21.45 + 263 20.32 21.57 + 265 25.39 13.60 + 267 23.38 12.95 + 269 25.03 12.14 + 271 25.97 11.00 + 273 29.16 7.38 + 275 31.07 8.29 + River 24.15 31.06 + Lake 8.00 27.53 + 1 27.46 9.84 + 2 32.99 3.45 + 3 29.41 27.27 + +[VERTICES] +;Link X-Coord Y-Coord + +[LABELS] +;X-Coord Y-Coord Label & Anchor Node + 8.00 29.42 "LAKE" + 25.00 31.10 "RIVER" + +[BACKDROP] + DIMENSIONS 6.16 -1.55 46.70 32.61 + UNITS None + FILE + OFFSET 0.00 0.00 + +[END] diff --git a/tests/data/example_1.inp b/tests/data/example_1.inp new file mode 100644 index 0000000..4df5bbf --- /dev/null +++ b/tests/data/example_1.inp @@ -0,0 +1,178 @@ +[TITLE] + EPANET Example Network 1 +A simple example of modeling chlorine decay. Both bulk and +wall reactions are included. + +[JUNCTIONS] +;ID Elev Demand Pattern + 10 710 0 ; + 11 710 150 ; + 12 700 150 ; + 13 695 100 ; + 21 700 150 ; + 22 695 200 ; + 23 690 150 ; + 31 700 100 ; + 32 710 100 ; + +[RESERVOIRS] +;ID Head Pattern + 9 800 ; + +[TANKS] +;ID Elevation InitLevel MinLevel MaxLevel Diameter MinVol VolCurve + 2 850 120 100 150 50.5 0 ; + +[PIPES] +;ID Node1 Node2 Length Diameter Roughness MinorLoss Status + 10 10 11 10530 18 100 0 Open ; + 11 11 12 5280 14 100 0 Open ; + 12 12 13 5280 10 100 0 Open ; + 21 21 22 5280 10 100 0 Open ; + 22 22 23 5280 12 100 0 Open ; + 31 31 32 5280 6 100 0 Open ; + 110 2 12 200 18 100 0 Open ; + 111 11 21 5280 10 100 0 Open ; + 112 12 22 5280 12 100 0 Open ; + 113 13 23 5280 8 100 0 Open ; + 121 21 31 5280 8 100 0 Open ; + 122 22 32 5280 6 100 0 Open ; + +[PUMPS] +;ID Node1 Node2 Parameters + 9 9 10 HEAD 1 ; + +[VALVES] +;ID Node1 Node2 Diameter Type Setting MinorLoss + +[TAGS] + +[DEMANDS] +;Junction Demand Pattern Category + +[STATUS] +;ID Status/Setting + +[PATTERNS] +;ID Multipliers +;Demand Pattern + 1 1.0 1.2 1.4 1.6 1.4 1.2 + 1 1.0 0.8 0.6 0.4 0.6 0.8 + +[CURVES] +;ID X-Value Y-Value +;PUMP: Pump Curve for Pump 9 + 1 1500 250 + +[CONTROLS] + LINK 9 OPEN IF NODE 2 BELOW 110 + LINK 9 CLOSED IF NODE 2 ABOVE 140 + + +[RULES] + +[ENERGY] + Global Efficiency 75 + Global Price 0.0 + Demand Charge 0.0 + +[EMITTERS] +;Junction Coefficient + +[QUALITY] +;Node InitQual + 10 0.5 + 11 0.5 + 12 0.5 + 13 0.5 + 21 0.5 + 22 0.5 + 23 0.5 + 31 0.5 + 32 0.5 + 9 1.0 + 2 1.0 + +[SOURCES] +;Node Type Quality Pattern + +[REACTIONS] +;Type Pipe/Tank Coefficient + + +[REACTIONS] + Order Bulk 1 + Order Tank 1 + Order Wall 1 + Global Bulk -.5 + Global Wall -1 + Limiting Potential 0.0 + Roughness Correlation 0.0 + +[MIXING] +;Tank Model + +[TIMES] + Duration 24:00 + Hydraulic Timestep 1:00 + Quality Timestep 0:05 + Pattern Timestep 2:00 + Pattern Start 0:00 + Report Timestep 1:00 + Report Start 0:00 + Start ClockTime 12 am + Statistic None + +[REPORT] + Status Yes + Summary No + Page 0 + +[OPTIONS] + Units GPM + Headloss H-W + Specific Gravity 1.0 + Viscosity 1.0 + Trials 40 + Accuracy 0.001 + CHECKFREQ 2 + MAXCHECK 10 + DAMPLIMIT 0 + Unbalanced Continue 10 + Pattern 1 + Demand Multiplier 1.0 + Emitter Exponent 0.5 + Quality Chlorine mg/L + Diffusivity 1.0 + Tolerance 0.01 + +[COORDINATES] +;Node X-Coord Y-Coord + 10 20.00 70.00 + 11 30.00 70.00 + 12 50.00 70.00 + 13 70.00 70.00 + 21 30.00 40.00 + 22 50.00 40.00 + 23 70.00 40.00 + 31 30.00 10.00 + 32 50.00 10.00 + 9 10.00 70.00 + 2 50.00 90.00 + +[VERTICES] +;Link X-Coord Y-Coord + +[LABELS] +;X-Coord Y-Coord Label & Anchor Node + 6.99 73.63 "Source" + 13.48 68.13 "Pump" + 43.85 91.21 "Tank" + +[BACKDROP] + DIMENSIONS 7.00 6.00 73.00 94.00 + UNITS None + FILE + OFFSET 0.00 0.00 + +[END] diff --git a/tests/test_reent.cpp b/tests/test_reent.cpp new file mode 100644 index 0000000..4ac1d3c --- /dev/null +++ b/tests/test_reent.cpp @@ -0,0 +1,65 @@ +/* + * test_reent.cpp + * + * Created: 8/30/2018 + * Author: Michael E. Tryby + * US EPA - ORD/NRMRL + * + * Multi-threading / reentrancy test for EPANET Toolkit API. +*/ + +#include +#include +#include + +#include + +#include "epanet2.h" + +#define NUM_THREADS 2 + +using namespace std; + +void epanet_thread(long i) +{ + int errorcode = 0; + EN_ProjectHandle ph; + + string prefix = "example_"; + string suffix = ".inp"; + string input = prefix + to_string(static_cast(i)) + suffix; + + suffix = ".rpt"; + string report = prefix + to_string(static_cast(i)) + suffix; + + suffix = ".out"; + string output = prefix + to_string(static_cast(i)) + suffix; + + printf("Thread #%ld starting EPANET ...\n", i); + + EN_createproject(&ph); + errorcode = EN_runproject(ph, input.c_str(), report.c_str(), output.c_str(), NULL); + EN_deleteproject(&ph); + + printf("Thread #%ld EPANET done. Status = %d\n", i, errorcode); +} + +int main(int argc, char *argv[]) +{ + long i; + boost::thread *threads[NUM_THREADS]; + + for (i = 0; i < NUM_THREADS; i++) { + threads[i] = new boost::thread(epanet_thread, i); + printf("Main: creating thread %ld.\n", i); + } + + for (i = 0; i < NUM_THREADS; i++) { + threads[i]->join(); + printf("Main: joining thread %ld.\n", i); + delete threads[i]; + } + + printf("Main: program completed. Exiting.\n"); + return(0); +} From 7188642e39641d7c535a3e19971864b7abee913e Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 4 Sep 2018 09:50:08 -0400 Subject: [PATCH 31/35] Installing boost thread library --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 3049e05..7dfa9f9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ env: before_install: - sudo apt-get -qq update - sudo apt-get install -y libboost-test-dev + - sudo apt-get install -y libboost-thread-dev - sudo apt-get install -y swig #install: From a056bbf2c812ce5ce95703e081b6cddd39206ee2 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 4 Sep 2018 10:05:27 -0400 Subject: [PATCH 32/35] Fixing build error on Travis --- tests/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3fca5ab..38e5328 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -16,6 +16,9 @@ enable_testing() # Sets for output directory for executables and libraries. set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +if(UNIX) + set(CMAKE_CXX_FLAGS "-std=c++11") +endif(UNIX) #Prep ourselves for compiling boost if(MSVC) From b9a1934879ecb280a79a406da0ce654fc8628db6 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 4 Sep 2018 11:53:53 -0400 Subject: [PATCH 33/35] Making epanet exports opt in --- CMakeLists.txt | 1 + include/epanet2.h | 20 +++++++------------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d0fbce6..88ae5f6 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,6 +80,7 @@ target_include_directories(epanet PUBLIC ${PROJECT_SOURCE_DIR}/include) # create export lib so we can link against dll using Visual Studio +add_definitions(-DWITH_GENX) include(GenerateExportHeader) GENERATE_EXPORT_HEADER(epanet BASE_NAME epanet diff --git a/include/epanet2.h b/include/epanet2.h index f7ca1a9..3951cd7 100644 --- a/include/epanet2.h +++ b/include/epanet2.h @@ -30,7 +30,9 @@ #define EN_API_FLOAT_TYPE float #endif -#ifdef NO_GENX +#ifdef WITH_GENX + #include "epanet_export.h" +#else // --- define WINDOWS #undef WINDOWS #ifdef _WIN32 @@ -60,8 +62,6 @@ #define DLLEXPORT #endif #endif -#else - #include "epanet_export.h" #endif @@ -932,15 +932,6 @@ extern "C" { @see ENgetbasedemand */ int DLLEXPORT ENsetbasedemand(int nodeIndex, int demandIdx, EN_API_FLOAT_TYPE baseDemand); - - /** - @brief Sets the index of the demand pattern assigned to a node for a category index. - @param nodeIndex The index of a node (first node is index 1). - @param demandIndex The index of a category (first category is index 1). - @param pattIndex The index of the pattern for this node and category. - @return Error code - */ - int DLLEXPORT ENsetdemandpattern(int nodeIndex, int demandIdx, int patIndex); /** @brief Retrieves index of curve with specific ID. @@ -1179,6 +1170,9 @@ extern "C" { ***************************************************/ int DLLEXPORT EN_createproject(EN_ProjectHandle *ph); int DLLEXPORT EN_deleteproject(EN_ProjectHandle *ph); + + int DLLEXPORT EN_runproject(EN_ProjectHandle ph, const char *inpFile, + const char *rptFile, const char *binOutFile, void (*callback) (char *)); void DLLEXPORT EN_clearError(EN_ProjectHandle ph); int DLLEXPORT EN_checkError(EN_ProjectHandle ph, char** msg_buffer); @@ -1274,7 +1268,7 @@ extern "C" { int DLLEXPORT EN_getqualinfo(EN_ProjectHandle ph, int *qualcode, char *chemname, char *chemunits, int *tracenode); int DLLEXPORT EN_setbasedemand(EN_ProjectHandle ph, int nodeIndex, int demandIdx, EN_API_FLOAT_TYPE baseDemand); - int DLLEXPORT EN_setdemandpattern(EN_ProjectHandle ph, int nodeIndex, int demandIdx, int patIndex); + int DLLEXPORT EN_setdemandpattern(EN_ProjectHandle ph, int nodeIndex, int demandIdx, int patIndex); int DLLEXPORT EN_getcurveindex(EN_ProjectHandle ph, char *id, int *index); int DLLEXPORT EN_getcurveid(EN_ProjectHandle ph, int index, char *id); int DLLEXPORT EN_getcurvelen(EN_ProjectHandle ph, int index, int *len); From 78999ea795e3341c5f8f2f08cf2fe3a3ab683729 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 4 Sep 2018 13:13:56 -0400 Subject: [PATCH 34/35] Getting runepanet to link on 32bit --- run/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/run/CMakeLists.txt b/run/CMakeLists.txt index 4822e95..18b28aa 100644 --- a/run/CMakeLists.txt +++ b/run/CMakeLists.txt @@ -17,6 +17,7 @@ include_directories(include) source_group("CLI" FILES ${EPANET_CLI_SOURCES}) +add_definitions(-DWITH_GENX) # Creates the EPANET command line executable add_executable(runepanet ${EPANET_CLI_SOURCES}) From 30a694d62e25a91441c4df7906a8d2c70c78602b Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 4 Sep 2018 14:42:24 -0400 Subject: [PATCH 35/35] Removing NO_GENX from win_build Makefile.bat --- win_build/WinSDK/Makefile.bat | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/win_build/WinSDK/Makefile.bat b/win_build/WinSDK/Makefile.bat index e5188c2..91ffc95 100644 --- a/win_build/WinSDK/Makefile.bat +++ b/win_build/WinSDK/Makefile.bat @@ -21,9 +21,9 @@ Find /i "x86" < checkOS.tmp > StringCheck.tmp If %ERRORLEVEL% == 1 ( CALL "%SDK_PATH%bin\"SetEnv.cmd /x64 /release rem : create EPANET2.DLL - cl -o epanet2.dll /D NO_GENX epanet.c util\errormanager.c hash.c hydraul.c hydcoeffs.c hydstatus.c hydsolver.c inpfile.c input1.c input2.c input3.c mempool.c output.c quality.c report.c rules.c smatrix.c genmmd.c /I ..\include /I ..\run /link /DLL + cl -o epanet2.dll epanet.c util\errormanager.c hash.c hydraul.c hydcoeffs.c hydstatus.c hydsolver.c inpfile.c input1.c input2.c input3.c mempool.c output.c quality.c report.c rules.c smatrix.c genmmd.c /I ..\include /I ..\run /link /DLL rem : create EPANET2.EXE - cl -o epanet2.exe /D NO_GENX epanet.c util\errormanager.c ..\run\main.c hash.c hydraul.c hydcoeffs.c hydstatus.c hydsolver.c inpfile.c input1.c input2.c input3.c mempool.c output.c quality.c report.c rules.c smatrix.c genmmd.c /I ..\include /I ..\run /I ..\src /link + cl -o epanet2.exe epanet.c util\errormanager.c ..\run\main.c hash.c hydraul.c hydcoeffs.c hydstatus.c hydsolver.c inpfile.c input1.c input2.c input3.c mempool.c output.c quality.c report.c rules.c smatrix.c genmmd.c /I ..\include /I ..\run /I ..\src /link md "%Build_PATH%"\64bit move /y "%SRC_PATH%"\*.dll "%Build_PATH%"\64bit move /y "%SRC_PATH%"\*.exe "%Build_PATH%"\64bit @@ -35,9 +35,9 @@ rem : 32 bit with DEF CALL "%SDK_PATH%bin\"SetEnv.cmd /x86 /release echo "32 bit with epanet2.def mapping" rem : create EPANET2.DLL -cl -o epanet2.dll /D NO_GENX epanet.c util\errormanager.c hash.c hydraul.c hydcoeffs.c hydstatus.c hydsolver.c inpfile.c input1.c input2.c input3.c mempool.c output.c quality.c report.c rules.c smatrix.c genmmd.c /I ..\include /I ..\run /link /DLL /def:..\win_build\WinSDK\epanet2.def /MAP +cl -o epanet2.dll epanet.c util\errormanager.c hash.c hydraul.c hydcoeffs.c hydstatus.c hydsolver.c inpfile.c input1.c input2.c input3.c mempool.c output.c quality.c report.c rules.c smatrix.c genmmd.c /I ..\include /I ..\run /link /DLL /def:..\win_build\WinSDK\epanet2.def /MAP rem : create EPANET2.EXE -cl -o epanet2.exe /D NO_GENX epanet.c util\errormanager.c ..\run\main.c hash.c hydraul.c hydcoeffs.c hydstatus.c hydsolver.c inpfile.c input1.c input2.c input3.c mempool.c output.c quality.c report.c rules.c smatrix.c genmmd.c /I ..\include /I ..\run /I ..\src /link +cl -o epanet2.exe epanet.c util\errormanager.c ..\run\main.c hash.c hydraul.c hydcoeffs.c hydstatus.c hydsolver.c inpfile.c input1.c input2.c input3.c mempool.c output.c quality.c report.c rules.c smatrix.c genmmd.c /I ..\include /I ..\run /I ..\src /link md "%Build_PATH%"\32bit move /y "%SRC_PATH%"\*.dll "%Build_PATH%"\32bit move /y "%SRC_PATH%"\*.exe "%Build_PATH%"\32bit