Merge branch 'dev' into issue-172

This commit is contained in:
Michael Tryby
2018-09-04 15:00:21 -04:00
committed by GitHub
19 changed files with 1000 additions and 239 deletions

View File

@@ -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
@@ -164,12 +164,15 @@ 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));
_defaultModel->viewprog = pviewprog;
if (_defaultModel->out_files.Hydflag != USE) {
p = (EN_Project*)(_defaultModel);
p->viewprog = pviewprog;
if (p->out_files.Hydflag != USE) {
ERRCODE(EN_solveH(_defaultModel));
}
@@ -182,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));
@@ -473,6 +484,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);
}
@@ -598,8 +613,29 @@ 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;
int DLLEXPORT EN_init(EN_ProjectHandle *ph, char *f2, char *f3,
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)
/*----------------------------------------------------------------
** Input:
@@ -620,7 +656,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;
@@ -3100,7 +3136,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 */
@@ -3153,7 +3189,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);
@@ -3640,7 +3676,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) {
@@ -4474,7 +4510,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) {
@@ -4507,7 +4543,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);
@@ -4516,6 +4552,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->next != 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;
@@ -4531,7 +4597,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);
@@ -4846,6 +4912,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
@@ -4861,23 +4928,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);
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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 */