From 21f40f0daf6e89cc3c152960ad405628be273ba8 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Thu, 30 Aug 2018 15:30:34 -0400 Subject: [PATCH 1/5] 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 2/5] 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 3/5] 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 4/5] 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 5/5] 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