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: 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). 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 diff --git a/include/epanet2.h b/include/epanet2.h index 3951cd7..e619792 100644 --- a/include/epanet2.h +++ b/include/epanet2.h @@ -1170,9 +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 *)); + + 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/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 */ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index be6dc5a..38e5328 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -16,9 +16,18 @@ 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 -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); +}