Merge branch 'dev' of https://github.com/OpenWaterAnalytics/EPANET into Mariosmsk-fix_bug_getdemandname

This commit is contained in:
Michael Tryby
2019-04-08 15:22:16 -04:00
37 changed files with 970 additions and 924 deletions

View File

@@ -7,16 +7,20 @@
Authors: see AUTHORS
Copyright: see AUTHORS
License: see LICENSE
Last Updated: 04/02/2019
Last Updated: 04/03/2019
******************************************************************************
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef __APPLE__
#include <malloc.h>
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#else
#include <stdlib.h>
#endif
#include <stdio.h>
#include <string.h>
#include <float.h>
#include <math.h>
@@ -168,10 +172,7 @@ int DLLEXPORT EN_init(EN_Project p, const char *rptFile, const char *outFile,
initunits(p);
inittanks(p);
convertunits(p);
// Initialize the default demand pattern
p->parser.MaxPats = 0;
getpatterns(p);
p->Openflag = TRUE;
return errcode;
}
@@ -226,10 +227,6 @@ int DLLEXPORT EN_open(EN_Project p, const char *inpFile, const char *rptFile,
p->parser.InFile = NULL;
}
// Free temporary linked lists used for Patterns & Curves
freeTmplist(p->parser.Patlist);
freeTmplist(p->parser.Curvelist);
// If using previously saved hydraulics file then open it
if (p->outfile.Hydflag == USE) ERRCODE(openhydfile(p));
@@ -279,7 +276,7 @@ int DLLEXPORT EN_getcomment(EN_Project p, int object, int index, char *comment)
/*----------------------------------------------------------------
** Input: object = a type of object (see EN_ObjectType)
** index = the object's index
** Output: comment = the object's descriptive comment
** Output: comment = the object's descriptive comment
** Returns: error code
** Purpose: Retrieves an object's descriptive comment
**----------------------------------------------------------------
@@ -840,7 +837,7 @@ int DLLEXPORT EN_closeQ(EN_Project p)
if (!p->Openflag) return 102;
closequal(p);
p->quality.OpenQflag = FALSE;
closeoutfile(p);
closeoutfile(p);
return 0;
}
@@ -1104,8 +1101,7 @@ int DLLEXPORT EN_getoption(EN_Project p, int option, double *value)
v = qual->Ctol * Ucf[QUALITY];
break;
case EN_EMITEXPON:
if (hyd->Qexp > 0.0)
v = 1.0 / hyd->Qexp;
if (hyd->Qexp > 0.0) v = 1.0 / hyd->Qexp;
break;
case EN_DEMANDMULT:
v = hyd->Dmult;
@@ -1116,9 +1112,6 @@ int DLLEXPORT EN_getoption(EN_Project p, int option, double *value)
case EN_FLOWCHANGE:
v = hyd->FlowChangeLimit * Ucf[FLOW];
break;
case EN_DEFDEMANDPAT:
v = hyd->DefPat;
break;
case EN_HEADLOSSFORM:
v = hyd->Formflag;
break;
@@ -1134,6 +1127,39 @@ int DLLEXPORT EN_getoption(EN_Project p, int option, double *value)
case EN_DEMANDCHARGE:
v = hyd->Dcost;
break;
case EN_SP_GRAVITY:
v = hyd->SpGrav;
break;
case EN_SP_VISCOS:
v = hyd->Viscos / VISCOS;
break;
case EN_UNBALANCED:
v = hyd->ExtraIter;
break;
case EN_CHECKFREQ:
v = hyd->CheckFreq;
break;
case EN_MAXCHECK:
v = hyd->MaxCheck;
break;
case EN_DAMPLIMIT:
v = hyd->DampLimit;
break;
case EN_SP_DIFFUS:
v = qual->Diffus / DIFFUS;
break;
case EN_BULKORDER:
v = qual->BulkOrder;
break;
case EN_WALLORDER:
v = qual->WallOrder;
break;
case EN_TANKORDER:
v = qual->TankOrder;
break;
case EN_CONCENLIMIT:
v = qual->Climit * p->Ucf[QUALITY];
break;
default:
return 251;
@@ -1156,16 +1182,28 @@ int DLLEXPORT EN_setoption(EN_Project p, int option, double value)
Hydraul *hyd = &p->hydraul;
Quality *qual = &p->quality;
Snode *node;
Pdemand demand;
const int Njuncs = net->Njuncs;
int Njuncs = net->Njuncs;
double *Ucf = p->Ucf;
int i, j;
int tmpPat, pat, error;
char tmpId[MAXID + 1];
int i, j, pat;
double Ke, n, ucf;
if (!p->Openflag) return 102;
// The EN_UNBALANCED option can be < 0 indicating that the simulation
// should be halted if no convergence is reached in EN_TRIALS. Other
// values set the number of additional trials to use with no more
// link status changes to achieve convergence.
if (option == EN_UNBALANCED)
{
hyd->ExtraIter = (int)value;
if (hyd->ExtraIter < 0) hyd->ExtraIter = -1;
return 0;
}
// All other option values must be non-negative
if (value < 0.0) return 213;
// Process the speficied option
switch (option)
{
case EN_TRIALS:
@@ -1174,12 +1212,11 @@ int DLLEXPORT EN_setoption(EN_Project p, int option, double value)
break;
case EN_ACCURACY:
if (value < 1.e-5 || value > 1.e-1) return 213;
if (value < 1.e-8 || value > 1.e-1) return 213;
hyd->Hacc = value;
break;
case EN_TOLERANCE:
if (value < 0.0) return 213;
qual->Ctol = value / Ucf[QUALITY];
break;
@@ -1196,59 +1233,33 @@ int DLLEXPORT EN_setoption(EN_Project p, int option, double value)
break;
case EN_DEMANDMULT:
if (value <= 0.0) return 213;
hyd->Dmult = value;
break;
case EN_HEADERROR:
if (value < 0.0) return 213;
hyd->HeadErrorLimit = value / Ucf[HEAD];
break;
case EN_FLOWCHANGE:
if (value < 0.0) return 213;
hyd->FlowChangeLimit = value / Ucf[FLOW];
break;
case EN_DEFDEMANDPAT:
//check that the pattern exists or is set to zero to delete the default pattern
pat = ROUND(value);
if (pat < 0 || pat > net->Npats) return 205;
tmpPat = hyd->DefPat;
//get the new pattern ID
if (pat == 0)
{
strncpy(tmpId, p->parser.DefPatID, MAXID);
}
else
{
error = EN_getpatternid(p, pat, tmpId);
if (error != 0) return error;
}
// replace node patterns with default pattern
for (i = 1; i <= net->Nnodes; i++)
{
node = &net->Node[i];
for (demand = node->D; demand != NULL; demand = demand->next)
{
if (demand->Pat == tmpPat)
{
demand->Pat = pat;
demand->Name = xstrcpy(&demand->Name, "", MAXID);
}
}
}
strncpy(p->parser.DefPatID, tmpId, MAXID);
hyd->DefPat = pat;
case EN_HEADLOSSFORM:
// Can't change if hydraulic solver is open
if (p->hydraul.OpenHflag) return 262;
i = ROUND(value);
if (i < HW || i > CM) return 213;
hyd->Formflag = i;
if (hyd->Formflag == HW) hyd->Hexp = 1.852;
else hyd->Hexp = 2.0;
break;
case EN_GLOBALEFFIC:
if (value <= 0.0 || value > 100.0) return 213;
if (value <= 1.0 || value > 100.0) return 213;
hyd->Epump = value;
break;
case EN_GLOBALPRICE:
if (value < 0.0) return 213;
hyd->Ecost = value;
break;
@@ -1259,10 +1270,53 @@ int DLLEXPORT EN_setoption(EN_Project p, int option, double value)
break;
case EN_DEMANDCHARGE:
if (value < 0.0) return 213;
hyd->Dcost = value;
break;
case EN_SP_GRAVITY:
if (value <= 0.0) return 213;
Ucf[PRESSURE] *= (value / hyd->SpGrav);
hyd->SpGrav = value;
break;
case EN_SP_VISCOS:
if (value <= 0.0) return 213;
hyd->Viscos = value * VISCOS;
break;
case EN_CHECKFREQ:
hyd->CheckFreq = (int)value;
break;
case EN_MAXCHECK:
hyd->MaxCheck = (int)value;
break;
case EN_DAMPLIMIT:
hyd->DampLimit = value;
break;
case EN_SP_DIFFUS:
qual->Diffus = value * DIFFUS;
break;
case EN_BULKORDER:
qual->BulkOrder = value;
break;
case EN_WALLORDER:
if (value == 0.0 || value == 1.0) qual->WallOrder = value;
else return 213;
break;
case EN_TANKORDER:
qual->TankOrder = value;
break;
case EN_CONCENLIMIT:
qual->Climit = value / p->Ucf[QUALITY];
break;
default:
return 251;
}
@@ -1637,7 +1691,7 @@ int DLLEXPORT EN_setqualtype(EN_Project p, int qualType, char *chemName,
p->network.Node[i].C0 *= Ucf[QUALITY];
}
}
Ucf[QUALITY] = ccf;
Ucf[LINKQUAL] = ccf;
Ucf[REACTRATE] = ccf;
@@ -1700,7 +1754,7 @@ int DLLEXPORT EN_addnode(EN_Project p, char *id, int nodeType)
demand = (struct Sdemand *)malloc(sizeof(struct Sdemand));
demand->Base = 0.0;
demand->Pat = hyd->DefPat; // Use default pattern
demand->Pat = 0;
demand->Name = NULL;
demand->next = NULL;
node->D = demand;
@@ -2785,7 +2839,7 @@ int DLLEXPORT EN_setdemandname(EN_Project p, int nodeIndex, int demandIndex,
// Check that demandName is not too long
if (strlen(demandName) > MAXID) return 250;
// Locate demand category record and assign demandName to it
for (d = p->network.Node[nodeIndex].D;
n < demandIndex && d->next != NULL; d = d->next) n++;
@@ -3887,7 +3941,6 @@ int DLLEXPORT EN_addpattern(EN_Project p, char *id)
{
Network *net = &p->network;
Parser *parser = &p->parser;
Hydraul *hyd = &p->hydraul;
int i, n, err = 0;
Spattern *pat;
@@ -3922,9 +3975,6 @@ int DLLEXPORT EN_addpattern(EN_Project p, char *id)
// Update the number of patterns
net->Npats = n;
parser->MaxPats = n;
// Make new pattern be default demand pattern if name matches
if (strcmp(id, parser->DefPatID) == 0) hyd->DefPat = n;
return 0;
}
@@ -3953,14 +4003,6 @@ int DLLEXPORT EN_deletepattern(EN_Project p, int index)
// Adjust references by other objects to patterns
adjustpatterns(net, index);
// Modify default demand pattern
if (hyd->DefPat == index)
{
hyd->DefPat = 0;
strcpy(parser->DefPatID, "");
}
else if (hyd->DefPat > index) hyd->DefPat--;
// Modify global energy price pattern
if (hyd->Epat == index) hyd->Epat = 0;
else if (hyd->Epat > index) hyd->Epat--;
@@ -4186,6 +4228,7 @@ int DLLEXPORT EN_addcurve(EN_Project p, char *id)
curve = &net->Curve[n];
strcpy(curve->ID, id);
curve->Comment = NULL;
curve->Capacity = 1;
curve->Npts = 1;
curve->Type = GENERIC_CURVE;
curve->X = (double *)calloc(1, sizeof(double));
@@ -4257,20 +4300,11 @@ int DLLEXPORT EN_getcurveindex(EN_Project p, char *id, int *index)
**----------------------------------------------------------------
*/
{
int i;
*index = 0;
if (!p->Openflag) return 102;
for (i = 1; i <= p->network.Ncurves; i++)
{
if (strcmp(id, p->network.Curve[i].ID) == 0)
{
*index = i;
return 0;
}
}
*index = 0;
return 206;
*index = findcurve(&p->network, id);
if (*index == 0) return 206;
return 0;
}
int DLLEXPORT EN_getcurveid(EN_Project p, int index, char *id)
@@ -4359,8 +4393,8 @@ int DLLEXPORT EN_getcurvevalue(EN_Project p, int curveIndex, int pointIndex,
if (!p->Openflag) return 102;
if (curveIndex < 1 || curveIndex > p->network.Ncurves) return 206;
if (pointIndex < 1 || pointIndex > p->network.Curve[curveIndex].Npts) return 251;
*x = (double)p->network.Curve[curveIndex].X[pointIndex - 1];
*y = (double)p->network.Curve[curveIndex].Y[pointIndex - 1];
*x = p->network.Curve[curveIndex].X[pointIndex - 1];
*y = p->network.Curve[curveIndex].Y[pointIndex - 1];
return 0;
}
@@ -4374,23 +4408,48 @@ int DLLEXPORT EN_setcurvevalue(EN_Project p, int curveIndex, int pointIndex,
** Output: none
** Returns: error code
** Purpose: sets the value of a specific point on a data curve
** Note: if pointIndex exceeds the curve's length a new point is added.
**----------------------------------------------------------------
*/
{
Network *net = &p->network;
Scurve *curve;
double x1 = -1.e37, x2 = 1.e37;
int n = pointIndex - 1;
// Check for valid input
if (!p->Openflag) return 102;
if (curveIndex <= 0 || curveIndex > net->Ncurves) return 206;
curve = &net->Curve[curveIndex];
if (pointIndex <= 0 || pointIndex > curve->Npts) return 251;
curve->X[pointIndex - 1] = x;
curve->Y[pointIndex - 1] = y;
if (pointIndex <= 0) return 251;
// Check that new point maintains increasing x values
if (n - 1 >= 0) x1 = curve->X[n-1];
if (n + 1 < curve->Npts) x2 = curve->X[n+1];
if (x <= x1 || x >= x2) return 230;
// Expand curve if need be
if (pointIndex > curve->Npts) pointIndex = curve->Npts + 1;
if (pointIndex >= curve->Capacity)
{
if (resizecurve(curve, curve->Capacity + 10) > 0) return 101;
}
// Increase curve's number of points if need be
if (pointIndex > curve->Npts)
{
curve->Npts++;
n = curve->Npts - 1;
}
// Insert new point into curve
curve->X[n] = x;
curve->Y[n] = y;
return 0;
}
int DLLEXPORT EN_getcurve(EN_Project p, int index, char *id, int *nPoints,
double **xValues, double **yValues)
double *xValues, double *yValues)
/*----------------------------------------------------------------
** Input: index = data curve index
** Output: id = ID name of data curve
@@ -4415,8 +4474,8 @@ int DLLEXPORT EN_getcurve(EN_Project p, int index, char *id, int *nPoints,
*nPoints = curve->Npts;
for (i = 0; i < curve->Npts; i++)
{
*xValues[i] = curve->X[i];
*yValues[i] = curve->Y[i];
xValues[i] = curve->X[i];
yValues[i] = curve->Y[i];
}
return 0;
}
@@ -4445,15 +4504,12 @@ int DLLEXPORT EN_setcurve(EN_Project p, int index, double *xValues,
// Check that x values are increasing
for (j = 1; j < nPoints; j++) if (xValues[j-1] >= xValues[j]) return 230;
// Re-set number of points & reallocate memory for values
// Expand size of curve's data arrays if need be
curve = &net->Curve[index];
curve->Npts = nPoints;
curve->X = (double *)realloc(curve->X, nPoints * sizeof(double));
curve->Y = (double *)realloc(curve->Y, nPoints * sizeof(double));
if (curve->X == NULL) return 101;
if (curve->Y == NULL) return 101;
if (resizecurve(curve, nPoints) > 0) return 101;
// Load values into curve
curve->Npts = nPoints;
for (j = 0; j < nPoints; j++)
{
curve->X[j] = xValues[j];

View File

@@ -10,10 +10,12 @@
Last Updated: 03/17/2019
******************************************************************************
*/
#ifndef __APPLE__
#include <malloc.h>
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#else
#include <stdlib.h>
#include <stdlib.h>
#endif
#include <string.h>
@@ -645,7 +647,7 @@ int DLLEXPORT ENsetcurvevalue(int curveIndex, int pointIndex, EN_API_FLOAT_TYPE
}
int DLLEXPORT ENgetcurve(int index, char *id, int *nPoints,
EN_API_FLOAT_TYPE **xValues, EN_API_FLOAT_TYPE **yValues)
EN_API_FLOAT_TYPE *xValues, EN_API_FLOAT_TYPE *yValues)
{
int i;
Network *net = &_defaultProject->network;
@@ -657,8 +659,8 @@ int DLLEXPORT ENgetcurve(int index, char *id, int *nPoints,
*nPoints = curve->Npts;
for (i = 0; i < curve->Npts; i++)
{
*xValues[i] = (EN_API_FLOAT_TYPE)curve->X[i];
*yValues[i] = (EN_API_FLOAT_TYPE)curve->Y[i];
xValues[i] = (EN_API_FLOAT_TYPE)curve->X[i];
yValues[i] = (EN_API_FLOAT_TYPE)curve->Y[i];
}
return 0;
}

View File

@@ -11,8 +11,13 @@
******************************************************************************
*/
#include <stdlib.h>
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#else
#include <stdlib.h>
#endif
#include <string.h>
#include "epanet_py.h"
@@ -624,7 +629,7 @@ int EXPORT_PY_API curv_setvalue(Handle ph, int curveIndex, int pointIndex, doubl
return set_error(pr->error, EN_setcurvevalue(pr->project, curveIndex, pointIndex, x, y));
}
int EXPORT_PY_API curv_get(Handle ph, int curveIndex, char* id, int *nValues, double **xValues, double **yValues)
int EXPORT_PY_API curv_get(Handle ph, int curveIndex, char* id, int *nValues, double *xValues, double *yValues)
{
handle_t *pr = (handle_t *)ph;
return set_error(pr->error, EN_getcurve(pr->project, curveIndex, id, nValues, xValues, yValues));

View File

@@ -7,7 +7,7 @@
Authors: see AUTHORS
Copyright: see AUTHORS
License: see LICENSE
Last Updated: 03/17/2019
Last Updated: 04/03/2019
******************************************************************************
*/
#ifndef FUNCS_H
@@ -17,8 +17,6 @@
void initpointers(Project *);
int allocdata(Project *);
void freeTmplist(STmplist *);
void freeFloatlist(SFloatlist *);
void freedata(Project *);
int openfiles(Project *, const char *, const char *,const char *);
@@ -36,8 +34,12 @@ int findlink(Network *, char *);
int findtank(Network *, int);
int findvalve(Network *, int);
int findpump(Network *, int);
int findpattern(Network *, char *);
int findcurve(Network *, char *);
void adjustpatterns(Network *, int);
void adjustcurves(Network *, int);
int resizecurve(Scurve *, int);
int getcomment(Network *, int, int, char *);
int setcomment(Network *, int, int, const char *);
@@ -65,8 +67,6 @@ void convertunits(Project *);
int netsize(Project *);
int readdata(Project *);
int updatepumpparams(Project *, int);
int getpatterns(Project *);
int getcurves(Project *);
int findmatch(char *, char *[]);
int match(const char *, const char *);
int gettokens(char *, char **, int, char *);

View File

@@ -11,11 +11,13 @@
******************************************************************************
*/
#ifndef __APPLE__
#include <malloc.h>
#else
#include <stdlib.h>
#endif
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#else
#include <stdlib.h>
#endif
#include <string.h>
#include "hash.h"
@@ -84,7 +86,7 @@ int hashtable_update(HashTable *ht, char *key, int new_data)
{
unsigned int i = gethash(key);
DataEntry *entry;
if ( i >= HASHTABLEMAXSIZE ) return NOTFOUND;
entry = ht[i];
while (entry != NULL)
@@ -104,7 +106,7 @@ int hashtable_delete(HashTable *ht, char *key)
{
unsigned int i = gethash(key);
DataEntry *entry, *preventry;
if ( i >= HASHTABLEMAXSIZE ) return NOTFOUND;
preventry = NULL;
@@ -164,7 +166,7 @@ void hashtable_free(HashTable *ht)
{
DataEntry *entry, *nextentry;
int i;
for (i = 0; i < HASHTABLEMAXSIZE; i++)
{
entry = ht[i];

View File

@@ -11,13 +11,16 @@
******************************************************************************
*/
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#else
#include <stdlib.h>
#endif
#include <stdio.h>
#include <string.h>
#ifndef __APPLE__
#include <malloc.h>
#else
#include <stdlib.h>
#endif
#include <math.h>
#include "types.h"
@@ -85,12 +88,12 @@ void resistcoeff(Project *pr, int k)
double e, d, L;
Slink *link = &net->Link[k];
link->Qa = 0.0;
switch (link->Type) {
// ... Link is a pipe. Compute resistance based on headloss formula.
// Friction factor for D-W formula gets included during head loss
// Friction factor for D-W formula gets included during head loss
// calculation.
case CVPIPE:
case PIPE:
@@ -244,14 +247,14 @@ void linkcoeffs(Project *pr)
// Update linear system coeffs. associated with start node n1
// ... node n1 is junction
if (n1 <= net->Njuncs)
if (n1 <= net->Njuncs)
{
sm->Aii[sm->Row[n1]] += hyd->P[k]; // Diagonal coeff.
sm->F[sm->Row[n1]] += hyd->Y[k]; // RHS coeff.
}
// ... node n1 is a tank/reservoir
else sm->F[sm->Row[n2]] += (hyd->P[k] * hyd->NodeHead[n1]);
else sm->F[sm->Row[n2]] += (hyd->P[k] * hyd->NodeHead[n1]);
// Update linear system coeffs. associated with end node n2
// ... node n2 is junction
@@ -262,7 +265,7 @@ void linkcoeffs(Project *pr)
}
// ... node n2 is a tank/reservoir
else sm->F[sm->Row[n1]] += (hyd->P[k] * hyd->NodeHead[n2]);
else sm->F[sm->Row[n1]] += (hyd->P[k] * hyd->NodeHead[n2]);
}
}
@@ -321,13 +324,13 @@ void valvecoeffs(Project *pr)
// Coeffs. for fixed status valves have already been computed
if (hyd->LinkSetting[k] == MISSING) continue;
// Start & end nodes of valve's link
// Start & end nodes of valve's link
link = &net->Link[k];
n1 = link->N1;
n2 = link->N2;
// Call valve-specific function
switch (link->Type)
switch (link->Type)
{
case PRV:
prvcoeff(pr, k, n1, n2);
@@ -482,7 +485,7 @@ void demandcoeffs(Project *pr)
double dp, // pressure range over which demand can vary (ft)
n, // exponent in head loss v. demand function
hloss, // head loss in supplying demand (ft)
hgrad; // gradient of demand head loss (ft/cfs)
hgrad; // gradient of demand head loss (ft/cfs)
// Get demand function parameters
if (hyd->DemandModel == DDA) return;
@@ -659,12 +662,12 @@ void DWpipecoeff(Project *pr, int k)
Slink *link = &pr->network.Link[k];
double q = ABS(hyd->LinkFlow[k]);
double r = link->R; // Resistance coeff.
double ml = link->Km; // Minor loss coeff.
double r = link->R; // Resistance coeff.
double ml = link->Km; // Minor loss coeff.
double e = link->Kc / link->Diam; // Relative roughness
double s = hyd->Viscos * link->Diam; // Viscosity / diameter
double hloss, hgrad, f, dfdq, r1;
// Compute head loss and its derivative
// ... use Hagen-Poiseuille formula for laminar flow (Re <= 2000)
if (q <= A2 * s)
@@ -673,7 +676,7 @@ void DWpipecoeff(Project *pr, int k)
hloss = hyd->LinkFlow[k] * (r + ml * q);
hgrad = r + 2.0 * ml * q;
}
// ... otherwise use Darcy-Weisbach formula with friction factor
else
{
@@ -683,7 +686,7 @@ void DWpipecoeff(Project *pr, int k)
hloss = r1 * q * hyd->LinkFlow[k];
hgrad = (2.0 * r1 * q) + (dfdq * r * q * q);
}
// Compute P and Y coefficients
hyd->P[k] = 1.0 / hgrad;
hyd->Y[k] = hloss / hgrad;
@@ -753,7 +756,7 @@ void pumpcoeff(Project *pr, int k)
int p; // Pump index
double h0, // Shutoff head
q, // Abs. value of flow
q, // Abs. value of flow
r, // Flow resistance coeff.
n, // Flow exponent coeff.
setting, // Pump speed setting
@@ -899,7 +902,7 @@ void gpvcoeff(Project *pr, int k)
Hydraul *hyd = &pr->hydraul;
// Treat as a pipe if valve closed
if (hyd->LinkStatus[k] == CLOSED) valvecoeff(pr, k);
if (hyd->LinkStatus[k] == CLOSED) valvecoeff(pr, k);
// Otherwise utilize segment of head loss curve
// bracketing current flow (curve index is stored
@@ -939,7 +942,7 @@ void pbvcoeff(Project *pr, int k)
// If valve fixed OPEN or CLOSED then treat as a pipe
if (hyd->LinkSetting[k] == MISSING || hyd->LinkSetting[k] == 0.0)
{
valvecoeff(pr, k);
valvecoeff(pr, k);
}
// If valve is active
@@ -948,7 +951,7 @@ void pbvcoeff(Project *pr, int k)
// Treat as a pipe if minor loss > valve setting
if (link->Km * SQR(hyd->LinkFlow[k]) > hyd->LinkSetting[k])
{
valvecoeff(pr, k);
valvecoeff(pr, k);
}
// Otherwise force headloss across valve to be equal to setting
else
@@ -983,7 +986,7 @@ void tcvcoeff(Project *pr, int k)
}
// Then apply usual valve formula
valvecoeff(pr, k);
valvecoeff(pr, k);
// Restore original loss coeff.
link->Km = km;
@@ -1017,7 +1020,7 @@ void prvcoeff(Project *pr, int k, int n1, int n2)
{
// Set coeffs. to force head at downstream
// node equal to valve setting & force flow
// node equal to valve setting & force flow
// to equal to flow excess at downstream node.
hyd->P[k] = 0.0;
@@ -1069,7 +1072,7 @@ void psvcoeff(Project *pr, int k, int n1, int n2)
if (hyd->LinkStatus[k] == ACTIVE)
{
// Set coeffs. to force head at upstream
// node equal to valve setting & force flow
// node equal to valve setting & force flow
// equal to flow excess at upstream node.
hyd->P[k] = 0.0;
@@ -1138,7 +1141,7 @@ void fcvcoeff(Project *pr, int k, int n1, int n2)
else
{
valvecoeff(pr, k);
valvecoeff(pr, k);
sm->Aij[sm->Ndx[k]] -= hyd->P[k];
sm->Aii[i] += hyd->P[k];
sm->Aii[j] += hyd->P[k];
@@ -1162,7 +1165,7 @@ void valvecoeff(Project *pr, int k)
Slink *link = &pr->network.Link[k];
double flow, q, y, qa, hgrad;
flow = hyd->LinkFlow[k];
// Valve is closed. Use a very small matrix coeff.

View File

@@ -3,7 +3,7 @@
Project: OWA EPANET
Version: 2.2
Module: hydraul.c
Description: implements EPANET's hydraulic engine
Description: implements EPANET's hydraulic engine
Authors: see AUTHORS
Copyright: see AUTHORS
License: see LICENSE
@@ -11,13 +11,16 @@
******************************************************************************
*/
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#else
#include <stdlib.h>
#endif
#include <stdio.h>
#include <string.h>
#ifndef __APPLE__
#include <malloc.h>
#else
#include <stdlib.h>
#endif
#include <math.h>
#include "types.h"
@@ -48,9 +51,9 @@ void tanklevels(Project *, long);
int openhyd(Project *pr)
/*
*--------------------------------------------------------------
* Input: none
* Output: returns error code
* Purpose: opens hydraulics solver system
* Input: none
* Output: returns error code
* Purpose: opens hydraulics solver system
*--------------------------------------------------------------
*/
{
@@ -92,8 +95,8 @@ void inithyd(Project *pr, int initflag)
**--------------------------------------------------------------
** Input: initflag > 0 if link flows should be re-initialized
** = 0 if not
** Output: none
** Purpose: initializes hydraulics solver system
** Output: none
** Purpose: initializes hydraulics solver system
**--------------------------------------------------------------
*/
{
@@ -106,7 +109,7 @@ void inithyd(Project *pr, int initflag)
Stank *tank;
Slink *link;
Spump *pump;
// Initialize tanks
for (i = 1; i <= net->Ntanks; i++)
{
@@ -128,7 +131,7 @@ void inithyd(Project *pr, int initflag)
for (i = 1; i <= net->Nlinks; i++)
{
link = &net->Link[i];
// Initialize status and setting
hyd->LinkStatus[i] = link->Status;
hyd->LinkSetting[i] = link->Kc;
@@ -140,7 +143,7 @@ void inithyd(Project *pr, int initflag)
if (
(link->Type == PRV || link->Type == PSV
|| link->Type == FCV) && (link->Kc != MISSING)
) hyd->LinkStatus[i] = ACTIVE;
) hyd->LinkStatus[i] = ACTIVE;
// Initialize flows if necessary
if (hyd->LinkStatus[i] <= CLOSED)
@@ -170,7 +173,7 @@ void inithyd(Project *pr, int initflag)
// Re-position hydraulics file
if (pr->outfile.Saveflag)
{
{
fseek(out->HydFile,out->HydOffset,SEEK_SET);
}
@@ -185,10 +188,10 @@ void inithyd(Project *pr, int initflag)
int runhyd(Project *pr, long *t)
/*
**--------------------------------------------------------------
** Input: none
** Input: none
** Output: t = pointer to current time (in seconds)
** Returns: error code
** Purpose: solves network hydraulics in a single time period
** Returns: error code
** Purpose: solves network hydraulics in a single time period
**--------------------------------------------------------------
*/
{
@@ -199,7 +202,7 @@ int runhyd(Project *pr, long *t)
int iter; // Iteration count
int errcode; // Error code
double relerr; // Solution accuracy
// Find new demands & control actions
*t = time->Htime;
demands(pr);
@@ -212,7 +215,7 @@ int runhyd(Project *pr, long *t)
{
// Report new status & save results
if (rpt->Statflag) writehydstat(pr,iter,relerr);
// If system unbalanced and no extra trials
// allowed, then activate the Haltflag
if (relerr > hyd->Hacc && hyd->ExtraIter == -1)
@@ -229,11 +232,11 @@ int runhyd(Project *pr, long *t)
int nexthyd(Project *pr, long *tstep)
/*
**--------------------------------------------------------------
** Input: none
** Input: none
** Output: tstep = pointer to time step (in seconds)
** Returns: error code
** Returns: error code
** Purpose: finds length of next time step & updates tank
** levels and rule-based contol actions
** levels and rule-based contol actions
**--------------------------------------------------------------
*/
{
@@ -242,7 +245,7 @@ int nexthyd(Project *pr, long *tstep)
long hydstep; // Actual time step
int errcode = 0; // Error code
// Save current results to hydraulics file and
// force end of simulation if Haltflag is active
if (pr->outfile.Saveflag) errcode = savehyd(pr, &time->Htime);
@@ -277,14 +280,14 @@ int nexthyd(Project *pr, long *tstep)
*tstep = hydstep;
return errcode;
}
void closehyd(Project *pr)
/*
**--------------------------------------------------------------
** Input: none
** Output: returns error code
** Purpose: closes hydraulics solver system
** Input: none
** Output: returns error code
** Purpose: closes hydraulics solver system
**--------------------------------------------------------------
*/
{
@@ -296,9 +299,9 @@ void closehyd(Project *pr)
int allocmatrix(Project *pr)
/*
**--------------------------------------------------------------
** Input: none
** Output: returns error code
** Purpose: allocates memory used for solution matrix coeffs.
** Input: none
** Output: returns error code
** Purpose: allocates memory used for solution matrix coeffs.
**--------------------------------------------------------------
*/
{
@@ -306,7 +309,7 @@ int allocmatrix(Project *pr)
Hydraul *hyd = &pr->hydraul;
int errcode = 0;
hyd->P = (double *) calloc(net->Nlinks+1,sizeof(double));
hyd->Y = (double *) calloc(net->Nlinks+1,sizeof(double));
hyd->DemandFlow = (double *) calloc(net->Nnodes + 1, sizeof(double));
@@ -328,14 +331,14 @@ int allocmatrix(Project *pr)
void freematrix(Project *pr)
/*
**--------------------------------------------------------------
** Input: none
** Output: none
** Purpose: frees memory used for solution matrix coeffs.
** Input: none
** Output: none
** Purpose: frees memory used for solution matrix coeffs.
**--------------------------------------------------------------
*/
{
Hydraul *hyd = &pr->hydraul;
free(hyd->P);
free(hyd->Y);
free(hyd->DemandFlow);
@@ -351,7 +354,7 @@ void initlinkflow(Project *pr, int i, char s, double k)
** Input: i = link index
** s = link status
** k = link setting (i.e., pump speed)
** Output: none
** Output: none
** Purpose: sets initial flow in link to QZERO if link is closed,
** to design flow for a pump, or to flow at velocity of
** 1 fps for other links.
@@ -362,7 +365,7 @@ void initlinkflow(Project *pr, int i, char s, double k)
Network *n = &pr->network;
Slink *link = &n->Link[i];
if (s == CLOSED)
{
hyd->LinkFlow[i] = QZERO;
@@ -383,8 +386,8 @@ void setlinkflow(Project *pr, int k, double dh)
**--------------------------------------------------------------
** Input: k = link index
** dh = head loss across link
** Output: none
** Purpose: sets flow in link based on current headloss
** Output: none
** Purpose: sets flow in link based on current headloss
**--------------------------------------------------------------
*/
{
@@ -396,7 +399,7 @@ void setlinkflow(Project *pr, int k, double dh)
double x ,y;
Slink *link = &net->Link[k];
Scurve *curve;
switch (link->Type)
{
case CVPIPE:
@@ -408,7 +411,7 @@ void setlinkflow(Project *pr, int k, double dh)
y = sqrt(ABS(dh) / link->R / 1.32547);
hyd->LinkFlow[k] = x * y;
}
// For Hazen-Williams or Manning formulas use inverse of formula
else
{
@@ -416,16 +419,16 @@ void setlinkflow(Project *pr, int k, double dh)
y = 1.0 / hyd->Hexp;
hyd->LinkFlow[k] = pow(x, y);
}
// Change sign of flow to match sign of head loss
if (dh < 0.0) hyd->LinkFlow[k] = -hyd->LinkFlow[k];
break;
case PUMP:
// Convert headloss to pump head gain
dh = -dh;
p = findpump(net, k);
// For custom pump curve, interpolate from curve
if (net->Pump[p].Ptype == CUSTOM)
{
@@ -435,7 +438,7 @@ void setlinkflow(Project *pr, int k, double dh)
hyd->LinkFlow[k] = interp(curve->Npts, curve->Y, curve->X, dh) *
hyd->LinkSetting[k] / pr->Ucf[FLOW];
}
// Otherwise use inverse of power curve
else
{
@@ -459,7 +462,7 @@ void setlinkstatus(Project *pr, int index, char value, StatusType *s, double *k
** s = pointer to link status
** k = pointer to link setting
** Output: none
** Purpose: sets link status to OPEN or CLOSED
** Purpose: sets link status to OPEN or CLOSED
**----------------------------------------------------------------
*/
{
@@ -467,11 +470,11 @@ void setlinkstatus(Project *pr, int index, char value, StatusType *s, double *k
Slink *link = &net->Link[index];
LinkType t = link->Type;
// Status set to open
// Status set to open
if (value == 1)
{
// Adjust link setting for pumps & valves
// Adjust link setting for pumps & valves
if (t == PUMP) *k = 1.0;
if (t > PUMP && t != GPV) *k = MISSING;
@@ -479,7 +482,7 @@ void setlinkstatus(Project *pr, int index, char value, StatusType *s, double *k
*s = OPEN;
}
// Status set to closed
// Status set to closed
else if (value == 0)
{
// Adjust link setting for pumps & valves
@@ -509,7 +512,7 @@ void setlinksetting(Project *pr, int index, double value, StatusType *s,
Slink *link = &net->Link[index];
LinkType t = link->Type;
// For a pump, status is OPEN if speed > 0, CLOSED otherwise
if (t == PUMP)
{
@@ -531,15 +534,15 @@ void setlinksetting(Project *pr, int index, double value, StatusType *s,
if (*k == MISSING && *s <= CLOSED) *s = OPEN;
*k = value;
}
}
}
void demands(Project *pr)
/*
**--------------------------------------------------------------------
** Input: none
** Output: none
** Purpose: computes demands at nodes during current time period
** Input: none
** Output: none
** Purpose: computes demands at nodes during current time period
**--------------------------------------------------------------------
*/
{
@@ -610,9 +613,9 @@ void demands(Project *pr)
int controls(Project *pr)
/*
**---------------------------------------------------------------------
** Input: none
** Output: number of links whose setting changes
** Purpose: implements simple controls based on time or tank levels
** Input: none
** Output: number of links whose setting changes
** Purpose: implements simple controls based on time or tank levels
**---------------------------------------------------------------------
*/
{
@@ -626,7 +629,7 @@ int controls(Project *pr)
double k1, k2;
char s1, s2;
Slink *link;
Scontrol *control;
Scontrol *control;
// Examine each control statement
setsum = 0;
@@ -680,7 +683,7 @@ int controls(Project *pr)
if (pr->report.Statflag) writecontrolaction(pr,k,i);
setsum++;
}
}
}
}
return setsum;
}
@@ -689,9 +692,9 @@ int controls(Project *pr)
long timestep(Project *pr)
/*
**----------------------------------------------------------------
** Input: none
** Output: returns time step until next change in hydraulics
** Purpose: computes time step to advance hydraulic simulation
** Input: none
** Output: returns time step until next change in hydraulics
** Purpose: computes time step to advance hydraulic simulation
**----------------------------------------------------------------
*/
{
@@ -699,26 +702,26 @@ long timestep(Project *pr)
Times *time = &pr->times;
long n, t, tstep;
// Normal time step is hydraulic time step
tstep = time->Hstep;
// Revise time step based on time until next demand period
// (n = next pattern period, t = time till next period)
n = ((time->Htime + time->Pstart) / time->Pstep) + 1;
t = n * time->Pstep - time->Htime;
if (t > 0 && t < tstep) tstep = t;
// Revise time step based on time until next reporting period
t = time->Rtime - time->Htime;
if (t > 0 && t < tstep) tstep = t;
// Revise time step based on smallest time to fill or drain a tank
tanktimestep(pr, &tstep);
// Revise time step based on smallest time to activate a control
controltimestep(pr, &tstep);
// Evaluate rule-based controls (which will also update tank levels)
if (net->Nrules > 0) ruletimestep(pr, &tstep);
else tanklevels(pr, tstep);
@@ -729,10 +732,10 @@ long timestep(Project *pr)
int tanktimestep(Project *pr, long *tstep)
/*
**-----------------------------------------------------------------
** Input: *tstep = current time step
** Output: *tstep = modified current time step
** Input: *tstep = current time step
** Output: *tstep = modified current time step
** Purpose: revises time step based on shortest time to fill or
** drain a tank
** drain a tank
**-----------------------------------------------------------------
*/
{
@@ -777,10 +780,10 @@ int tanktimestep(Project *pr, long *tstep)
void controltimestep(Project *pr, long *tstep)
/*
**------------------------------------------------------------------
** Input: *tstep = current time step
** Output: *tstep = modified current time step
** Input: *tstep = current time step
** Output: *tstep = modified current time step
** Purpose: revises time step based on shortest time to activate
** a simple control
** a simple control
**------------------------------------------------------------------
*/
{
@@ -792,24 +795,24 @@ void controltimestep(Project *pr, long *tstep)
long t, t1, t2;
Slink *link;
Scontrol *control;
// Examine each control
for (i = 1; i <= net->Ncontrols; i++)
{
t = 0;
control = &net->Control[i];
// Control depends on a tank level
// Control depends on a tank level
if ( (n = control->Node) > 0)
{
// Skip node if not a tank or reservoir
if ((j = n - net->Njuncs) <= 0) continue;
// Find current head and flow into tank
h = hyd->NodeHead[n];
q = hyd->NodeDemand[n];
if (ABS(q) <= QZERO) continue;
// Find time to reach upper or lower control level
if ( (h < control->Grade && control->Type == HILEVEL && q > 0.0)
|| (h > control->Grade && control->Type == LOWLEVEL && q < 0.0) )
@@ -821,7 +824,7 @@ void controltimestep(Project *pr, long *tstep)
// Control is based on elapsed time
if (control->Type == TIMER)
{
{
if (control->Time > pr->times.Htime)
{
t = control->Time - pr->times.Htime;
@@ -853,16 +856,16 @@ void controltimestep(Project *pr, long *tstep)
void ruletimestep(Project *pr, long *tstep)
/*
**--------------------------------------------------------------
** Input: *tstep = current time step (sec)
** Output: *tstep = modified time step
** Input: *tstep = current time step (sec)
** Output: *tstep = modified time step
** Purpose: updates next time step by checking if any rules
** will fire before then; also updates tank levels.
** will fire before then; also updates tank levels.
**--------------------------------------------------------------
*/
{
Network *net = &pr->network;
Times *time = &pr->times;
long tnow, // Start of time interval for rule evaluation
tmax, // End of time interval for rule evaluation
dt, // Normal time increment for rule evaluation
@@ -880,7 +883,7 @@ void ruletimestep(Project *pr, long *tstep)
}
// Otherwise, time increment equals rule evaluation time step and
// first actual increment equals time until next even multiple of
// first actual increment equals time until next even multiple of
// Rulestep occurs.
else
{
@@ -888,7 +891,7 @@ void ruletimestep(Project *pr, long *tstep)
dt1 = time->Rulestep - (tnow % time->Rulestep);
}
// Make sure time increment is no larger than current time step
// Make sure time increment is no larger than current time step
dt = MIN(dt, *tstep);
dt1 = MIN(dt1, *tstep);
if (dt1 == 0) dt1 = dt;
@@ -918,14 +921,14 @@ void ruletimestep(Project *pr, long *tstep)
*tstep = time->Htime - tnow;
time->Htime = tnow;
}
void addenergy(Project *pr, long hstep)
/*
**-------------------------------------------------------------
** Input: hstep = time step (sec)
** Output: none
** Purpose: accumulates pump energy usage
** Input: hstep = time step (sec)
** Output: none
** Purpose: accumulates pump energy usage
**-------------------------------------------------------------
*/
{
@@ -1003,10 +1006,10 @@ void addenergy(Project *pr, long hstep)
void getenergy(Project *pr, int k, double *kw, double *eff)
/*
**----------------------------------------------------------------
** Input: k = link index
** Input: k = link index
** Output: *kw = kwatt energy used
** *eff = efficiency (pumps only)
** Purpose: computes flow energy associated with link k
** Purpose: computes flow energy associated with link k
**----------------------------------------------------------------
*/
{
@@ -1022,7 +1025,7 @@ void getenergy(Project *pr, int k, double *kw, double *eff)
double speed; // current speed setting
Scurve *curve;
Slink *link = &net->Link[k];
// No energy if link is closed
if (hyd->LinkStatus[k] <= CLOSED)
{
@@ -1065,10 +1068,10 @@ void getenergy(Project *pr, int k, double *kw, double *eff)
void tanklevels(Project *pr, long tstep)
/*
**----------------------------------------------------------------
** Input: tstep = current time step
** Output: none
** Purpose: computes new water levels in tanks after current
** time step
** Input: tstep = current time step
** Output: none
** Purpose: computes new water levels in tanks after current
** time step
**----------------------------------------------------------------
*/
{
@@ -1077,17 +1080,17 @@ void tanklevels(Project *pr, long tstep)
int i, n;
double dv;
for (i = 1; i <= net->Ntanks; i++)
{
Stank *tank = &net->Tank[i];
if (tank->A == 0.0) continue; // Skip reservoirs
// Update the tank's volume & water elevation
// Update the tank's volume & water elevation
n = tank->Node;
dv = hyd->NodeDemand[n] * tstep;
tank->V += dv;
// Check if tank full/empty within next second
if (tank->V + hyd->NodeDemand[n] >= tank->Vmax)
{
@@ -1105,10 +1108,10 @@ void tanklevels(Project *pr, long tstep)
double tankvolume(Project *pr, int i, double h)
/*
**--------------------------------------------------------------------
** Input: i = tank index
** h = water elevation in tank
** Output: returns water volume in tank
** Purpose: finds water volume in tank i corresponding to elev. h.
** Input: i = tank index
** h = water elevation in tank
** Output: returns water volume in tank
** Purpose: finds water volume in tank i corresponding to elev. h.
**--------------------------------------------------------------------
*/
{
@@ -1122,7 +1125,7 @@ double tankvolume(Project *pr, int i, double h)
// Use level*area if no volume curve
j = tank->Vcurve;
if (j == 0) return(tank->Vmin + (h - tank->Hmin) * tank->A);
// If curve exists, interpolate on h to find volume v
// remembering that volume curve is in original units.
else
@@ -1138,10 +1141,10 @@ double tankvolume(Project *pr, int i, double h)
double tankgrade(Project *pr, int i, double v)
/*
**-------------------------------------------------------------------
** Input: i = tank index
** v = volume in tank
** Output: returns water level in tank
** Purpose: finds water level in tank i corresponding to volume v.
** Input: i = tank index
** v = volume in tank
** Output: returns water level in tank
** Purpose: finds water level in tank i corresponding to volume v.
**-------------------------------------------------------------------
*/
{
@@ -1154,7 +1157,7 @@ double tankgrade(Project *pr, int i, double v)
// Use area if no volume curve
j = tank->Vcurve;
if (j == 0) return(tank->Hmin + (v - tank->Vmin) / tank->A);
// If curve exists, interpolate on volume (originally the Y-variable
// but used here as the X-variable) to find new level above bottom.
// Remember that volume curve is stored in original units.

View File

@@ -12,13 +12,16 @@
******************************************************************************
*/
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#else
#include <stdlib.h>
#endif
#include <stdio.h>
#include <string.h>
#ifndef __APPLE__
#include <malloc.h>
#else
#include <stdlib.h>
#endif
#include <math.h>
#include "types.h"
@@ -453,7 +456,7 @@ void newlinkflows(Project *pr, Hydbalance *hbal, double *qsum, double *dqsum)
hbal->maxflownode = -1;
}
// Update net flows to fixed grade nodes
// Update net flows to fixed grade nodes
if (hyd->LinkStatus[k] > CLOSED)
{
if (n1 > net->Njuncs) hyd->NodeDemand[n1] -= hyd->LinkFlow[k];
@@ -487,7 +490,7 @@ void newemitterflows(Project *pr, Hydbalance *hbal, double *qsum,
// Skip junction if it does not have an emitter
if (net->Node[i].Ke == 0.0) continue;
// Find emitter head loss and gradient
// Find emitter head loss and gradient
emitheadloss(pr, i, &hloss, &hgrad);
// Find emitter flow change

View File

@@ -10,8 +10,15 @@ License: see LICENSE
Last Updated: 11/27/2018
******************************************************************************
*/
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#else
#include <stdlib.h>
#endif
#include <stdio.h>
#include "types.h"
#include "funcs.h"
@@ -48,7 +55,7 @@ int valvestatus(Project *pr)
n1, n2; // Start & end nodes
double hset; // Valve head setting
StatusType status; // Valve status settings
Slink *link;
Slink *link;
// Examine each valve
for (i = 1; i <= net->Nvalves; i++)
@@ -59,7 +66,7 @@ int valvestatus(Project *pr)
// Ignore valve if its status is fixed to OPEN/CLOSED
if (hyd->LinkSetting[k] == MISSING) continue;
// Get start/end node indexes & save current status
n1 = link->N1;
n2 = link->N2;
@@ -449,7 +456,7 @@ void tankstatus(Project *pr, int k, int n1, int n2)
// Case 2: Downstream head > tank head
// (e.g., an open outflow check valve would close)
else if (cvstatus(pr, OPEN, h, q) == CLOSED)
else if (cvstatus(pr, OPEN, h, q) == CLOSED)
{
hyd->LinkStatus[k] = TEMPCLOSED;
}

View File

@@ -7,17 +7,20 @@ Description: saves network data to an EPANET formatted text file
Authors: see AUTHORS
Copyright: see AUTHORS
License: see LICENSE
Last Updated: 04/02/2019
Last Updated: 04/03/2019
******************************************************************************
*/
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#else
#include <stdlib.h>
#endif
#include <stdio.h>
#include <string.h>
#ifndef __APPLE__
#include <malloc.h>
#else
#include <stdlib.h>
#endif
#include <math.h>
#include "types.h"
@@ -38,7 +41,7 @@ extern char *TstatTxt[];
extern char *RptFlagTxt[];
extern char *SectTxt[];
void saveauxdata(Project *pr, FILE *f)
void saveauxdata(Project *pr, FILE *f)
/*
------------------------------------------------------------
Writes auxilary data from original input file to new file.
@@ -51,7 +54,7 @@ void saveauxdata(Project *pr, FILE *f)
char line[MAXLINE + 1];
char s[MAXLINE + 1];
FILE *InFile = pr->parser.InFile;
// Re-open the input file
if (InFile == NULL)
{
@@ -88,7 +91,7 @@ void saveauxdata(Project *pr, FILE *f)
}
}
}
// Write line of auxilary data to file
else
{
@@ -147,7 +150,7 @@ int saveinpfile(Project *pr, const char *fname)
// Open the new text file
if ((f = fopen(fname, "wt")) == NULL) return 302;
// Write [TITLE] section
// Write [TITLE] section
fprintf(f, s_TITLE);
for (i = 0; i < 3; i++)
{
@@ -205,7 +208,7 @@ int saveinpfile(Project *pr, const char *fname)
}
}
// Write [PIPES] section
// Write [PIPES] section
fprintf(f, "\n\n");
fprintf(f, s_PIPES);
for (i = 1; i <= net->Nlinks; i++)
@@ -244,7 +247,7 @@ int saveinpfile(Project *pr, const char *fname)
// Pump has constant power
if (pump->Ptype == CONST_HP) sprintf(s1, " POWER %.4f", link->Km);
// Pump has a head curve
// Pump has a head curve
else if ((j = pump->Hcurve) > 0)
{
sprintf(s1, " HEAD %s", net->Curve[j].ID);
@@ -539,7 +542,7 @@ int saveinpfile(Project *pr, const char *fname)
fprintf(f, "\n ORDER TANK %-.2f", qual->TankOrder);
fprintf(f, "\n GLOBAL BULK %-.6f", qual->Kbulk * SECperDAY);
fprintf(f, "\n GLOBAL WALL %-.6f", qual->Kwall * SECperDAY);
if (qual->Climit > 0.0)
{
fprintf(f, "\n LIMITING POTENTIAL %-.6f", qual->Climit * pr->Ucf[QUALITY]);
@@ -548,7 +551,7 @@ int saveinpfile(Project *pr, const char *fname)
{
fprintf(f, "\n ROUGHNESS CORRELATION %-.6f", qual->Rfactor);
}
// Pipe-specific parameters
for (i = 1; i <= net->Nlinks; i++)
{
@@ -633,10 +636,6 @@ int saveinpfile(Project *pr, const char *fname)
fprintf(f, "\n UNITS %s", FlowUnitsTxt[parser->Flowflag]);
fprintf(f, "\n PRESSURE %s", PressUnitsTxt[parser->Pressflag]);
fprintf(f, "\n HEADLOSS %s", FormTxt[hyd->Formflag]);
if (hyd->DefPat >= 1 && hyd->DefPat <= net->Npats)
{
fprintf(f, "\n PATTERN %s", net->Pattern[hyd->DefPat].ID);
}
switch (out->Hydflag)
{
case USE:

View File

@@ -3,26 +3,31 @@
Project: OWA EPANET
Version: 2.2
Module: input1.c
Description: retrieves network data from an EPANET input file
Description: retrieves network data from an EPANET input file
Authors: see AUTHORS
Copyright: see AUTHORS
License: see LICENSE
Last Updated: 03/17/2019
Last Updated: 04/03/2019
******************************************************************************
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef __APPLE__
#include <malloc.h>
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#else
#include <stdlib.h>
#endif
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "types.h"
#include "funcs.h"
#include "hash.h"
#include "text.h"
#include <math.h>
// Default values
#define MAXITER 200 // Default max. # hydraulic iterations
@@ -56,7 +61,7 @@ int getdata(Project *pr)
int errcode = 0;
// Assign default data values & reporting options
setdefaults(pr);
setdefaults(pr);
initreport(&pr->report);
// Read in network data
@@ -100,9 +105,10 @@ void setdefaults(Project *pr)
parser->Unitsflag = US; // US unit system
parser->Flowflag = GPM; // Flow units are gpm
parser->Pressflag = PSI; // Pressure units are psi
parser->DefPat = 0; // Default demand pattern index
out->Hydflag = SCRATCH; // No external hydraulics file
rpt->Tstatflag = SERIES; // Generate time series output
hyd->Formflag = HW; // Use Hazen-Williams formula
hyd->Htol = HTOL; // Default head tolerance
hyd->Qtol = QTOL; // Default flow tolerance
@@ -117,7 +123,6 @@ void setdefaults(Project *pr)
hyd->ExtraIter = -1; // Stop if network unbalanced
hyd->Viscos = MISSING; // Temporary viscosity
hyd->SpGrav = SPGRAV; // Default specific gravity
hyd->DefPat = 0; // Default demand pattern index
hyd->Epat = 0; // No energy price pattern
hyd->Ecost = 0.0; // Zero unit energy cost
hyd->Dcost = 0.0; // Zero energy demand charge
@@ -326,16 +331,13 @@ void adjustdata(Project *pr)
}
// Use default pattern if none assigned to a demand
for (i = 1; i <= net->Nnodes; i++)
parser->DefPat = findpattern(net, parser->DefPatID);
if (parser->DefPat > 0) for (i = 1; i <= net->Nnodes; i++)
{
node = &net->Node[i];
for (demand = node->D; demand != NULL; demand = demand->next)
{
if (demand->Pat == 0)
{
demand->Pat = hyd->DefPat;
xstrcpy(&demand->Name, "", MAXID);
}
if (demand->Pat == 0) demand->Pat = parser->DefPat;
}
}
@@ -353,7 +355,7 @@ int inittanks(Project *pr)
*/
{
Network *net = &pr->network;
int i, j, n = 0;
double a;
int errcode = 0, levelerr;
@@ -546,7 +548,7 @@ void convertunits(Project *pr)
Slink *link;
Spump *pump;
Scontrol *control;
// Convert nodal elevations & initial WQ
// (WQ source units are converted in QUALITY.C
for (i = 1; i <= net->Nnodes; i++)
@@ -644,7 +646,7 @@ void convertunits(Project *pr)
pump->H0 /= pr->Ucf[HEAD];
pump->R *= (pow(pr->Ucf[FLOW], pump->N) / pr->Ucf[HEAD]);
}
// Convert flow range & max. head units
pump->Q0 /= pr->Ucf[FLOW];
pump->Qmax /= pr->Ucf[FLOW];
@@ -653,7 +655,7 @@ void convertunits(Project *pr)
}
else
{
// For flow control valves, convert flow setting
// For flow control valves, convert flow setting
// while for other valves convert pressure setting
link->Diam /= pr->Ucf[DIAM];
link->Km = 0.02517 * link->Km / SQR(link->Diam) / SQR(link->Diam);

View File

@@ -7,16 +7,20 @@ Description: reads and interprets network data from an EPANET input file
Authors: see AUTHORS
Copyright: see AUTHORS
License: see LICENSE
Last Updated: 04/02/2019
Last Updated: 04/03/2019
******************************************************************************
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef __APPLE__
#include <malloc.h>
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#else
#include <stdlib.h>
#endif
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "types.h"
@@ -31,7 +35,6 @@ extern char *SectTxt[]; // Input section keywords (see ENUMSTXT.H)
// Exported functions
int addnodeID(Network *n, int, char *);
int addlinkID(Network *n, int, char *);
STmplist *getlistitem(char *, STmplist *);
// Imported functions
extern int powercurve(double, double, double, double, double, double *,
@@ -39,8 +42,8 @@ extern int powercurve(double, double, double, double, double, double *,
// Local functions
static int newline(Project *, int, char *);
static int addpattern(Parser *, char *);
static int addcurve(Parser *, char *);
static int addpattern(Network *, char *);
static int addcurve(Network *, char *);
static int unlinked(Project *);
static int getpumpparams(Project *);
static void inperrmsg(Project *, int, int, char *);
@@ -56,11 +59,12 @@ int netsize(Project *pr)
*/
{
Parser *parser = &pr->parser;
char line[MAXLINE + 1]; // Line from input data file
char *tok; // First token of line
int sect, newsect; // Input data sections
int errcode = 0; // Error code
Spattern *pattern;
// Initialize object counts
parser->MaxJuncs = 0;
@@ -73,13 +77,20 @@ int netsize(Project *pr)
parser->MaxCurves = 0;
sect = -1;
// Add a default demand pattern
parser->MaxPats = -1;
addpattern(parser,"");
if (parser->InFile == NULL) return 0;
// Add a "dummy" time pattern with index of 0 and a single multiplier
// of 1.0 to be used by all demands not assigned a pattern
pr->network.Npats = -1;
errcode = addpattern(&pr->network, "");
if (errcode) return errcode;
pattern = &pr->network.Pattern[0];
pattern->Length = 1;
pattern[0].F = (double *)calloc(1, sizeof(double));
pattern[0].F[0] = 1.0;
parser->MaxPats = pr->network.Npats;
// Make a pass through input file counting number of each object
if (parser->InFile == NULL) return 0;
while (fgets(line, MAXLINE, parser->InFile) != NULL)
{
// Skip blank lines & those beginning with a comment
@@ -111,8 +122,14 @@ int netsize(Project *pr)
case _VALVES: parser->MaxValves++; break;
case _CONTROLS: parser->MaxControls++; break;
case _RULES: addrule(parser,tok); break;
case _PATTERNS: errcode = addpattern(parser, tok); break;
case _CURVES: errcode = addcurve(parser, tok); break;
case _PATTERNS:
errcode = addpattern(&pr->network, tok);
parser->MaxPats = pr->network.Npats;
break;
case _CURVES:
errcode = addcurve(&pr->network, tok);
parser->MaxCurves = pr->network.Ncurves;
break;
}
if (errcode) break;
}
@@ -162,12 +179,15 @@ int readdata(Project *pr)
net->Nvalves = 0;
net->Ncontrols = 0;
net->Nrules = 0;
net->Ncurves = parser->MaxCurves;
net->Npats = parser->MaxPats;
// Patterns & Curves were created previously in netsize()
parser->MaxPats = net->Npats;
parser->MaxCurves = net->Ncurves;
parser->PrevPat = NULL;
parser->PrevCurve = NULL;
// Initialize full line comment, input data section and error count
parser->LineComment[0] = '\0';
sect = -1;
errsum = 0;
@@ -246,16 +266,14 @@ int readdata(Project *pr)
// Stop if reach end of file or max. error count
if (errsum == MAXERRS) break;
}
// Check for errors
if (errsum > 0) errcode = 200;
// Check for unlinked nodes
if (!errcode) errcode = unlinked(pr);
// Get pattern & curve data from temporary lists
if (!errcode) errcode = getpatterns(pr);
if (!errcode) errcode = getcurves(pr);
// Determine pump curve parameters
if (!errcode) errcode = getpumpparams(pr);
// Free input buffer
@@ -397,7 +415,7 @@ int updatepumpparams(Project *pr, int pumpindex)
curve->Type = PUMP_CURVE;
npts = curve->Npts;
// Generic power function curve
// Generic power function curve
if (npts == 1)
{
pump->Ptype = POWER_FUNC;
@@ -407,7 +425,7 @@ int updatepumpparams(Project *pr, int pumpindex)
q2 = 2.0 * q1;
h2 = 0.0;
}
// 3 point curve with shutoff head
else if (npts == 3 && curve->X[0] == 0.0)
{
@@ -418,7 +436,7 @@ int updatepumpparams(Project *pr, int pumpindex)
q2 = curve->X[2];
h2 = curve->Y[2];
}
// Custom pump curve
else
{
@@ -431,7 +449,7 @@ int updatepumpparams(Project *pr, int pumpindex)
pump->Q0 = (curve->X[0] + pump->Qmax) / 2.0;
pump->Hmax = curve->Y[0];
}
// Compute shape factors & limits of power function curves
if (pump->Ptype == POWER_FUNC)
{
@@ -461,7 +479,7 @@ int addnodeID(Network *net, int n, char *id)
**--------------------------------------------------------------
*/
{
if (findnode(net,id)) return 0;
if (findnode(net,id)) return 0;
strncpy(net->Node[n].ID, id, MAXID);
hashtable_insert(net->NodeHashTable, net->Node[n].ID, n);
return 1;
@@ -483,7 +501,7 @@ int addlinkID(Network *net, int n, char *id)
return 1;
}
int addpattern(Parser *parser, char *id)
int addpattern(Network *network, char *id)
/*
**-------------------------------------------------------------
** Input: id = pattern ID label
@@ -492,34 +510,33 @@ int addpattern(Parser *parser, char *id)
**--------------------------------------------------------------
*/
{
STmplist *patlist;
int n = network->Npats;
Spattern *pattern;
// Check if ID is same as last one processed
if (parser->Patlist != NULL && strcmp(id, parser->Patlist->ID) == 0) return 0;
// Check that pattern was not already created
if (getlistitem(id, parser->Patlist) == NULL)
// Check if pattern was already created
if (n > 0)
{
// Update pattern count & create new list element
(parser->MaxPats)++;
patlist = (STmplist *)malloc(sizeof(STmplist));
if (patlist == NULL) return 101;
// Initialize list element properties
else
{
patlist->i = parser->MaxPats;
strncpy(patlist->ID, id, MAXID);
patlist->x = NULL;
patlist->y = NULL;
patlist->next = parser->Patlist;
parser->Patlist = patlist;
}
if (strcmp(id, network->Pattern[n].ID) == 0) return 0;
if (findpattern(network, id) > 0) return 0;
}
if (strlen(id) > MAXID) return 250;
// Update pattern count & add a new pattern to the database
n = n + 2;
network->Pattern = (Spattern *)realloc(network->Pattern, n * sizeof(Spattern));
if (network->Pattern == NULL) return 101;
(network->Npats)++;
// Initialize the pattern
pattern = &network->Pattern[network->Npats];
strncpy(pattern->ID, id, MAXID);
pattern->Comment = NULL;
pattern->Length = 0;
pattern->F = NULL;
return 0;
}
int addcurve(Parser *parser, char *id)
int addcurve(Network *network, char *id)
/*
**-------------------------------------------------------------
** Input: id = curve ID label
@@ -528,51 +545,34 @@ int addcurve(Parser *parser, char *id)
**--------------------------------------------------------------
*/
{
STmplist *curvelist;
int n = network->Ncurves;
Scurve *curve;
// Check if ID is same as last one processed
if (parser->Curvelist != NULL && strcmp(id, parser->Curvelist->ID) == 0) return 0;
// Check that curve was not already created
if (getlistitem(id, parser->Curvelist) == NULL)
// Check if was already created
if (n > 0)
{
// Update curve count & create new list element
(parser->MaxCurves)++;
curvelist = (STmplist *)malloc(sizeof(STmplist));
if (curvelist == NULL) return 101;
// Initialize list element properties
else
{
curvelist->i = parser->MaxCurves;
strncpy(curvelist->ID, id, MAXID);
curvelist->x = NULL;
curvelist->y = NULL;
curvelist->next = parser->Curvelist;
parser->Curvelist = curvelist;
}
if (strcmp(id, network->Curve[n].ID) == 0) return 0;
if (findcurve(network, id) > 0) return 0;
}
if (strlen(id) > MAXID) return 250;
n = n + 2;
network->Curve = (Scurve *)realloc(network->Curve, n * sizeof(Scurve));
if (network->Curve == NULL) return 101;
(network->Ncurves)++;
// Initialize the curve
curve = &network->Curve[network->Ncurves];
strncpy(curve->ID, id, MAXID);
curve->Type = GENERIC_CURVE;
curve->Comment = NULL;
curve->Capacity = 0;
curve->Npts = 0;
curve->X = NULL;
curve->Y = NULL;
return 0;
}
STmplist *getlistitem(char *id, STmplist *list)
/*
**-------------------------------------------------------------
** Input: id = ID label
** list = pointer to head of a temporary list
** Output: returns list item with requested ID label
** Purpose: searches for item in temporary list
**-------------------------------------------------------------
*/
{
STmplist *item;
for (item = list; item != NULL; item = item->next)
{
if (strcmp(item->ID, id) == 0) return item;
}
return NULL;
}
int unlinked(Project *pr)
/*
**--------------------------------------------------------------
@@ -587,7 +587,7 @@ int unlinked(Project *pr)
Network *net = &pr->network;
int *marked;
int i, err, errcode;
errcode = 0;
err = 0;
@@ -596,19 +596,19 @@ int unlinked(Project *pr)
ERRCODE(MEMCHECK(marked));
if (errcode) return errcode;
memset(marked, 0, (net->Nnodes + 1) * sizeof(int));
// Mark end nodes of each link
for (i = 1; i <= net->Nlinks; i++)
{
marked[net->Link[i].N1]++;
marked[net->Link[i].N2]++;
}
// Check each junction
for (i = 1; i <= net->Njuncs; i++)
{
// If not marked then error
if (marked[i] == 0)
if (marked[i] == 0)
{
err++;
sprintf(pr->Msg, "Error 233: %s %s", geterrmsg(233, pr->Msg), net->Node[i].ID);
@@ -621,144 +621,6 @@ int unlinked(Project *pr)
return errcode;
}
int getpatterns(Project *pr)
/*
**-----------------------------------------------------------
** Input: none
** Output: returns error code
** Purpose: retrieves pattern data from temporary linked list
**-------------------------------------------------------------
*/
{
Network *net = &pr->network;
Hydraul *hyd = &pr->hydraul;
Parser *parser = &pr->parser;
int i, j;
SFloatlist *f;
STmplist *tmppattern;
Spattern *pattern;
// Start at head of the list of patterns
tmppattern = parser->Patlist;
// Traverse list of temporary patterns
while (tmppattern != NULL)
{
// Get index of temporary pattern in network's Pattern array
i = tmppattern->i;
// Check if this is the default pattern
if (strcmp(tmppattern->ID, parser->DefPatID) == 0) hyd->DefPat = i;
// Copy temporary patttern to network's pattern
if (i >= 0 && i <= parser->MaxPats)
{
pattern = &net->Pattern[i];
strcpy(pattern->ID, tmppattern->ID);
/* Give pattern a length of at least 1 */
if (pattern->Length == 0) pattern->Length = 1;
// Allocate array of pattern factors
pattern->F = (double *)calloc(pattern->Length, sizeof(double));
if (pattern->F == NULL) return 101;
// Start at head of temporary pattern multiplier list
// (which holds multipliers in reverse order)
f = tmppattern->x;
j = pattern->Length - 1;
// Use at least one multiplier equal to 1.0
if (f == NULL) pattern->F[0] = 1.0;
// Traverse temporary multiplier list, copying Pattern array */
else while (f != NULL && j >= 0)
{
pattern->F[j] = f->value;
f = f->next;
j--;
}
}
tmppattern = tmppattern->next;
}
return 0;
}
int getcurves(Project *pr)
/*
**-----------------------------------------------------------
** Input: none
** Output: returns error code
** Purpose: retrieves curve data from temporary linked list
**-----------------------------------------------------------
*/
{
Network *net = &pr->network;
Parser *parser = &pr->parser;
int i, j;
double x;
char errmsg[MAXMSG+1];
SFloatlist *fx, *fy;
STmplist *tmpcurve;
Scurve *curve;
// Traverse list of temporary curves
tmpcurve = parser->Curvelist;
while (tmpcurve != NULL)
{
// Get index of temporary curve in network's Curve array
i = tmpcurve->i;
// Copy temporary curve to network's curve
if (i >= 1 && i <= parser->MaxCurves)
{
curve = &net->Curve[i];
strcpy(curve->ID, tmpcurve->ID);
// Check that network curve has data points
if (curve->Npts <= 0)
{
sprintf(pr->Msg, "Error 230: %s %s", geterrmsg(230, errmsg), curve->ID);
writeline(pr, pr->Msg);
return 200;
}
// Allocate memory for network's curve data
curve->X = (double *)calloc(curve->Npts, sizeof(double));
curve->Y = (double *)calloc(curve->Npts, sizeof(double));
if (curve->X == NULL || curve->Y == NULL) return 101;
// Traverse list of x,y data
x = BIG;
fx = tmpcurve->x;
fy = tmpcurve->y;
j = curve->Npts - 1;
while (fx != NULL && fy != NULL && j >= 0)
{
// Check that x data is in ascending order
if (fx->value >= x)
{
sprintf(pr->Msg, "Error 230: %s %s", geterrmsg(230, errmsg), curve->ID);
writeline(pr, pr->Msg);
return 200;
}
x = fx->value;
// Copy x,y data to network's curve
curve->X[j] = fx->value;
fx = fx->next;
curve->Y[j] = fy->value;
fy = fy->next;
j--;
}
}
tmpcurve = tmpcurve->next;
}
return 0;
}
int findmatch(char *line, char *keyword[])
/*
**--------------------------------------------------------------
@@ -824,17 +686,17 @@ int gettokens(char *s, char** Tok, int maxToks, char *comment)
**--------------------------------------------------------------
*/
{
int m, n;
size_t len;
int n;
size_t len, m;
char *c, *c2;
// clear comment
comment[0] = '\0';
// Begin with no tokens
for (n=0; n<maxToks; n++) Tok[n] = NULL;
n = 0;
// Truncate s at start of comment
c = strchr(s,';');
if (c)
@@ -855,7 +717,7 @@ int gettokens(char *s, char** Tok, int maxToks, char *comment)
*c = '\0';
}
len = (int)strlen(s);
// Scan s for tokens until nothing left
while (len > 0 && n < MAXTOKS)
{
@@ -874,7 +736,7 @@ int gettokens(char *s, char** Tok, int maxToks, char *comment)
{
s++; // Start token after quote
m = (int)strcspn(s,"\"\n\r"); // Find end quote (or EOL)
}
}
s[m] = '\0'; // Null-terminate the token
Tok[n] = s; // Save pointer to token
n++; // Update token count
@@ -882,7 +744,7 @@ int gettokens(char *s, char** Tok, int maxToks, char *comment)
}
}
return n;
}
}
double hour(char *time, char *units)
/*
@@ -920,7 +782,7 @@ double hour(char *time, char *units)
if (match(units, w_DAYS)) return (y[0] * 24.0);
}
// Convert hh:mm:ss format to decimal hours
// Convert hh:mm:ss format to decimal hours
if (n > 1) y[0] = y[0] + y[1] / 60.0 + y[2] / 3600.0;
// If am/pm attached then adjust hour accordingly
@@ -939,7 +801,7 @@ double hour(char *time, char *units)
else return (y[0] + 12.0);
}
return -1.0;
}
}
int getfloat(char *s, double *y)
/*
@@ -985,14 +847,14 @@ void inperrmsg(Project *pr, int err, int sect, char *line)
*/
{
Parser *parser = &pr->parser;
char errStr[MAXMSG + 1] = "";
char tok[MAXMSG + 1];
// Get token associated with input error
if (parser->ErrTok >= 0) strcpy(tok, parser->Tok[parser->ErrTok]);
else strcpy(tok, "");
// write error message to report file
sprintf(pr->Msg, "Error %d: %s %s in %s section:",
err, geterrmsg(err, errStr), tok, SectTxt[sect]);

View File

@@ -7,16 +7,20 @@ Description: parses network data from a line of an EPANET input file
Authors: see AUTHORS
Copyright: see AUTHORS
License: see LICENSE
Last Updated: 03/17/2019
Last Updated: 04/03/2019
******************************************************************************
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef __APPLE__
#include <malloc.h>
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#else
#include <stdlib.h>
#endif
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "types.h"
@@ -36,7 +40,6 @@ int powercurve(double, double, double, double, double, double *, double *,
// Imported Functions
extern int addnodeID(Network *, int, char *);
extern int addlinkID(Network *, int, char *);
extern STmplist *getlistitem(char *, STmplist *);
// Local functions
static int optionchoice(Project *, int);
@@ -83,7 +86,6 @@ int juncdata(Project *pr)
double el, // elevation
y = 0.0; // base demand
Pdemand demand; // demand record
STmplist *patlist; // list of demands
Snode *node;
// Add new junction to data base
@@ -100,9 +102,8 @@ int juncdata(Project *pr)
if (n >= 3 && !getfloat(parser->Tok[2], &y)) return setError(parser, 2, 202);
if (n >= 4)
{
patlist = getlistitem(parser->Tok[3], parser->Patlist);
if (patlist == NULL) return setError(parser, 3, 205);
p = patlist->i;
p = findpattern(net, parser->Tok[3]);
if (p == 0) return setError(parser, 3, 205);
}
// Save junction data
@@ -158,7 +159,6 @@ int tankdata(Project *pr)
minvol = 0.0, // Minimum volume
diam = 0.0, // Diameter
area; // X-sect. area
STmplist *tmplist;
Snode *node;
Stank *tank;
@@ -182,9 +182,8 @@ int tankdata(Project *pr)
// Head pattern supplied
if (n == 3)
{
tmplist = getlistitem(parser->Tok[2], parser->Patlist);
if (tmplist == NULL) return setError(parser, 2, 205);
pattern = tmplist->i;
pattern = findpattern(net, parser->Tok[2]);
if (pattern == 0) return setError(parser, 2, 205);
}
}
else if (n < 6) return 201;
@@ -201,9 +200,8 @@ int tankdata(Project *pr)
// If volume curve supplied check it exists
if (n == 8)
{
tmplist = getlistitem(parser->Tok[7], parser->Curvelist);
if (tmplist == NULL) return setError(parser, 7, 206);
curve = tmplist->i;
curve = findcurve(net, parser->Tok[7]);
if (curve == 0) return setError(parser, 7, 206);
net->Curve[curve].Type = VOLUME_CURVE;
}
if (initlevel < 0.0) return setError(parser, 2, 209);
@@ -353,12 +351,12 @@ int pumpdata(Project *pr)
Network *net = &pr->network;
Parser *parser = &pr->parser;
int j,
int j, m, // Token array indexes
j1, // Start-node index
j2, // End-node index
m, n; // # data items
n, // # data items
c, p; // Curve & Pattern indexes
double y;
STmplist *tmplist; // Temporary list
Slink *link;
Spump *pump;
@@ -428,15 +426,15 @@ int pumpdata(Project *pr)
}
else if (match(parser->Tok[m - 1], w_HEAD)) // Custom pump curve
{
tmplist = getlistitem(parser->Tok[m], parser->Curvelist);
if (tmplist == NULL) return setError(parser, m, 206);
pump->Hcurve = tmplist->i;
c = findcurve(net, parser->Tok[m]);
if (c == 0) return setError(parser, m, 206);
pump->Hcurve = c;
}
else if (match(parser->Tok[m - 1], w_PATTERN)) // Speed/status pattern
{
tmplist = getlistitem(parser->Tok[m], parser->Patlist);
if (tmplist == NULL) return setError(parser, m, 205);
pump->Upat = tmplist->i;
p = findpattern(net, parser->Tok[m]);
if (p == 0) return setError(parser, m, 205);
pump->Upat = p;
}
else if (match(parser->Tok[m - 1], w_SPEED)) // Speed setting
{
@@ -465,7 +463,8 @@ int valvedata(Project *pr)
Network *net = &pr->network;
Parser *parser = &pr->parser;
int j1, // Start-node index
int c, // Curve index
j1, // Start-node index
j2, // End-node index
n; // # data items
char status = ACTIVE, // Valve status
@@ -473,7 +472,6 @@ int valvedata(Project *pr)
double diam = 0.0, // Valve diameter
setting, // Valve setting
lcoeff = 0.0; // Minor loss coeff.
STmplist *tmplist; // Temporary list
Slink *link;
// Add new valve to data base
@@ -504,10 +502,10 @@ int valvedata(Project *pr)
// Find headloss curve for GPV
if (type == GPV)
{
tmplist = getlistitem(parser->Tok[5], parser->Curvelist);
if (tmplist == NULL) return setError(parser, 5, 206);
setting = tmplist->i;
net->Curve[tmplist->i].Type = HLOSS_CURVE;
c = findcurve(net, parser->Tok[5]);
if (c == 0) return setError(parser, 5, 206);
setting = c;
net->Curve[c].Type = HLOSS_CURVE;
status = OPEN;
}
else if (!getfloat(parser->Tok[5], &setting)) return setError(parser, 5, 202);
@@ -554,43 +552,47 @@ int patterndata(Project *pr)
Network *net = &pr->network;
Parser *parser = &pr->parser;
int i, n;
int i, j, n, n1;
double x;
SFloatlist *f;
STmplist *p;
Spattern *pattern;
// "n" is the number of pattern factors contained in the line
n = parser->Ntokens - 1;
if (n < 1) return 201;
// Check for a new pattern
if (parser->PrevPat != NULL &&
strcmp(parser->Tok[0], parser->PrevPat->ID) == 0) p = parser->PrevPat;
// Check if previous input line was for the same pattern
if (parser->PrevPat && strcmp(parser->Tok[0], parser->PrevPat->ID) == 0)
{
pattern = parser->PrevPat;
}
// Otherwise retrieve pattern from the network's Pattern array
else
{
p = getlistitem(parser->Tok[0], parser->Patlist);
if (p == NULL) return setError(parser, 0, 205);
pattern = &(net->Pattern[p->i]);
pattern->Comment = xstrcpy(&pattern->Comment, parser->Comment, MAXMSG);
i = findpattern(net, parser->Tok[0]);
if (i == 0) return setError(parser, 0, 205);
pattern = &(net->Pattern[i]);
if (pattern->Comment == NULL && parser->Comment[0])
{
pattern->Comment = xstrcpy(&pattern->Comment, parser->Comment, MAXMSG);
}
}
// Expand size of the pattern's factors array
n1 = pattern->Length;
pattern->Length += n;
pattern->F = realloc(pattern->F, pattern->Length * sizeof(double));
// Add parsed multipliers to the pattern
for (i = 1; i <= n; i++)
for (j = 1; j <= n; j++)
{
if (!getfloat(parser->Tok[i], &x)) return setError(parser, i, 202);
f = (SFloatlist *)malloc(sizeof(SFloatlist));
if (f == NULL) return 101;
f->value = x;
f->next = p->x;
p->x = f;
if (!getfloat(parser->Tok[j], &x)) return setError(parser, j, 202);
pattern->F[n1 + j - 1] = x;
}
// Save # multipliers for pattern
net->Pattern[p->i].Length += n;
// Set previous pattern pointer
parser->PrevPat = p;
return (0);
// Save a reference to this pattern for processing additional pattern data
parser->PrevPat = pattern;
return 0;
}
int curvedata(Project *pr)
@@ -608,46 +610,46 @@ int curvedata(Project *pr)
Network *net = &pr->network;
Parser *parser = &pr->parser;
int i;
double x, y;
SFloatlist *fx, *fy;
STmplist *c;
Scurve *curve;
// Check for valid curve ID
if (parser->Ntokens < 3) return 201;
if (parser->PrevCurve != NULL &&
strcmp(parser->Tok[0], parser->PrevCurve->ID) == 0) c = parser->PrevCurve;
else
{
c = getlistitem(parser->Tok[0], parser->Curvelist);
if (c == NULL) return setError(parser, 0, 206);
curve = &(net->Curve[c->i]);
curve->Comment = xstrcpy(&curve->Comment, parser->Comment, MAXMSG);
}
// Check for valid data
if (parser->Ntokens < 3) return 201;
if (!getfloat(parser->Tok[1], &x)) return setError(parser, 1, 202);
if (!getfloat(parser->Tok[2], &y)) return setError(parser, 2, 202);
// Add new data point to curve
fx = (SFloatlist *)malloc(sizeof(SFloatlist));
if (fx == NULL) return 101;
fy = (SFloatlist *)malloc(sizeof(SFloatlist));
if (fy == NULL)
// Check if previous input line was for the same curve
if (parser->PrevCurve && strcmp(parser->Tok[0], parser->PrevCurve->ID) == 0)
{
free(fx);
return 101;
curve = parser->PrevCurve;
}
fx->value = x;
fx->next = c->x;
c->x = fx;
fy->value = y;
fy->next = c->y;
c->y = fy;
net->Curve[c->i].Npts++;
// Save the pointer to this curve
parser->PrevCurve = c;
// Otherwise retrieve curve from the network's Curve array
else
{
i = findcurve(net, parser->Tok[0]);
if (i == 0) return setError(parser, 0, 206);
curve = &(net->Curve[i]);
if (curve->Comment == NULL && parser->Comment[0])
{
curve->Comment = xstrcpy(&curve->Comment, parser->Comment, MAXMSG);
}
}
// Expand size of data arrays if need be
if (curve->Capacity == curve->Npts)
{
if (resizecurve(curve, curve->Capacity + 10) > 0) return 101;
}
// Add new data point to curve
curve->X[curve->Npts] = x;
curve->Y[curve->Npts] = y;
curve->Npts++;
// Save a reference to this curve for processing additional curve data
parser->PrevCurve = curve;
return 0;
}
@@ -709,7 +711,6 @@ int demanddata(Project *pr)
double y;
Pdemand demand;
Pdemand cur_demand;
STmplist *patlist;
// Extract data from tokens
n = parser->Ntokens;
@@ -729,9 +730,8 @@ int demanddata(Project *pr)
if (j > net->Njuncs) return 0;
if (n >= 3)
{
patlist = getlistitem(parser->Tok[2], parser->Patlist);
if (patlist == NULL) return setError(parser, 2, 205);
p = patlist->i;
p = findpattern(net, parser->Tok[2]);
if (p == 0) return setError(parser, 2, 205);
}
// Replace any demand entered in [JUNCTIONS] section
@@ -742,7 +742,10 @@ int demanddata(Project *pr)
// with what is specified in this section
demand->Base = y;
demand->Pat = p;
demand->Name = xstrcpy(&demand->Name, parser->Comment, MAXID);
if (parser->Comment[0])
{
demand->Name = xstrcpy(&demand->Name, parser->Comment, MAXID);
}
hyd->NodeDemand[j] = MISSING; // marker - next iteration will append a new category.
}
@@ -755,7 +758,11 @@ int demanddata(Project *pr)
if (demand == NULL) return 101;
demand->Base = y;
demand->Pat = p;
demand->Name = xstrcpy(&demand->Name, parser->Comment, MAXID);
demand->Name = NULL;
if (parser->Comment[0])
{
demand->Name = xstrcpy(&demand->Name, parser->Comment, MAXID);
}
demand->next = NULL;
cur_demand->next = demand;
}
@@ -896,7 +903,6 @@ int sourcedata(Project *pr)
p = 0; // Time pattern index
char type = CONCEN; // Source type
double c0 = 0; // Initial quality
STmplist *patlist;
Psource source;
// Check for enough tokens & that source node exists
@@ -925,9 +931,8 @@ int sourcedata(Project *pr)
if (n > i + 1 && strlen(parser->Tok[i + 1]) > 0 &&
strcmp(parser->Tok[i + 1], "*") != 0)
{
patlist = getlistitem(parser->Tok[i + 1], parser->Patlist);
if (patlist == NULL) return setError(parser, i+1, 205);
p = patlist->i;
p = findpattern(net, parser->Tok[i + 1]);
if (p == 0) return setError(parser, i + 1, 205);
}
// Destroy any existing source assigned to node
@@ -1331,10 +1336,9 @@ int energydata(Project *pr)
Hydraul *hyd = &pr->hydraul;
Parser *parser = &pr->parser;
int j, k, n;
int j, k, n, p, c;
double y;
STmplist *listitem;
Slink *Link = net->Link;
Spump *Pump = net->Pump;
@@ -1381,10 +1385,10 @@ int energydata(Project *pr)
// Price PATTERN being set
else if (match(parser->Tok[n - 2], w_PATTERN))
{
listitem = getlistitem(parser->Tok[n - 1], parser->Patlist);
if (listitem == NULL) return setError(parser, n - 1, 205);
if (j == 0) hyd->Epat = listitem->i;
else Pump[j].Epat = listitem->i;
p = findpattern(net, parser->Tok[n - 1]);
if (p == 0) return setError(parser, n - 1, 205);
if (j == 0) hyd->Epat = p;
else Pump[j].Epat = p;
return 0;
}
@@ -1399,10 +1403,10 @@ int energydata(Project *pr)
}
else
{
listitem = getlistitem(parser->Tok[n - 1], parser->Curvelist);
if (listitem == NULL) return setError(parser, n - 1, 206);
Pump[j].Ecurve = listitem->i;
net->Curve[listitem->i].Type = EFFIC_CURVE;
c = findcurve(net, parser->Tok[n - 1]);
if (c == 0) return setError(parser, n - 1, 206);
Pump[j].Ecurve = c;
net->Curve[c].Type = EFFIC_CURVE;
}
return 0;
}

View File

@@ -14,10 +14,14 @@
******************************************************************************
*/
#include <stdlib.h>
#ifndef __APPLE__
#include <malloc.h>
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#else
#include <stdlib.h>
#endif
#include "mempool.h"
/*

View File

@@ -11,13 +11,16 @@ Last Updated: 11/27/2018
******************************************************************************
*/
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#else
#include <stdlib.h>
#endif
#include <stdio.h>
#include <string.h>
#ifndef __APPLE__
#include <malloc.h>
#else
#include <stdlib.h>
#endif
#include <math.h>
#include "types.h"
@@ -32,7 +35,7 @@ static int savetimestat(Project *, REAL4 *, HdrType);
static int savenetreacts(Project *, double, double, double, double);
static int saveepilog(Project *);
// Functions to write/read x[1] to x[n] to/from binary file
// Functions to write/read x[1] to x[n] to/from binary file
size_t f_save(REAL4 *x, int n, FILE *file)
{
return fwrite(x + 1, sizeof(REAL4), n, file);
@@ -79,7 +82,7 @@ int savenetdata(Project *pr)
{
// Write integer variables to outFile
ibuf[0] = MAGICNUMBER;
ibuf[1] = 20012; // keep version at 2.00.12 so that GUI will run
ibuf[1] = 20012; // keep version at 2.00.12 so that GUI will run
ibuf[2] = net->Nnodes;
ibuf[3] = net->Ntanks;
ibuf[4] = net->Nlinks;
@@ -141,7 +144,7 @@ int savenetdata(Project *pr)
x[i] = (REAL4)(net->Node[i].El * pr->Ucf[ELEV]);
}
f_save(x, net->Nnodes, outFile);
// Save link lengths & diameters to outFile
for (i = 1; i <= net->Nlinks; i++)
{
@@ -185,7 +188,7 @@ int savehyd(Project *pr, long *htime)
int errcode = 0;
REAL4 *x;
FILE *HydFile = out->HydFile;
x = (REAL4 *)calloc(MAX(net->Nnodes, net->Nlinks) + 1, sizeof(REAL4));
if (x == NULL) return 101;
@@ -212,13 +215,13 @@ int savehyd(Project *pr, long *htime)
fwrite(x + 1, sizeof(REAL4), net->Nlinks, HydFile);
//f_save(x, net->Nlinks, HydFile);
// Save link status
// Save link status
for (i = 1; i <= net->Nlinks; i++) x[i] = (REAL4)hyd->LinkStatus[i];
fwrite(x + 1, sizeof(REAL4), net->Nlinks, HydFile);
//f_save(x, net->Nlinks, HydFile);
// Save link settings & check for successful write-to-disk
// (We assume that if any of the previous fwrites failed,
// Save link settings & check for successful write-to-disk
// (We assume that if any of the previous fwrites failed,
// then this one will also fail.)
for (i = 1; i <= net->Nlinks; i++) x[i] = (REAL4)hyd->LinkSetting[i];
if (fwrite(x + 1, sizeof(REAL4), net->Nlinks, HydFile) <
@@ -354,7 +357,7 @@ int readhyd(Project *pr, long *hydtime)
int result = 1;
REAL4 *x;
FILE *HydFile = out->HydFile;
x = (REAL4 *)calloc(MAX(net->Nnodes, net->Nlinks) + 1, sizeof(REAL4));
if (x == NULL) return 0;
@@ -473,7 +476,7 @@ int nodeoutput(Project *pr, int j, REAL4 *x, double ucf)
}
}
// Write x[1] to x[net->Nnodes] to output file
// Write x[1] to x[net->Nnodes] to output file
if (f_save(x, net->Nnodes, outFile) < (unsigned)net->Nnodes) return 308;
return 0;
}
@@ -497,7 +500,7 @@ int linkoutput(Project *pr, int j, REAL4 *x, double ucf)
int i;
double a, h, q, f, setting;
FILE *outFile = out->TmpOutFile;
// Load computed results (in proper units) into buffer x
switch (j)
{
@@ -631,7 +634,7 @@ int savefinaloutput(Project *pr)
int errcode = 0;
REAL4 *x;
FILE *outFile = out->OutFile;
// Save time series statistic if computed
if (rpt->Tstatflag != SERIES && out->TmpOutFile != NULL)
{
@@ -680,7 +683,7 @@ int savetimestat(Project *pr, REAL4 *x, HdrType objtype)
long startbyte, skipbytes;
float *stat1, *stat2, xx;
FILE *outFile = out->OutFile;
// Compute number of bytes in temp output file to skip over (skipbytes)
// when moving from one time period to the next for a particular variable
if (objtype == NODEHDR)
@@ -722,11 +725,11 @@ int savetimestat(Project *pr, REAL4 *x, HdrType objtype)
stat2[i] = MISSING;
}
// Position temp output file at start of output
// Position temp output file at start of output
fseek(out->TmpOutFile, startbyte + (j - n1) * n * sizeof(REAL4),
SEEK_SET);
// Process each time period
// Process each time period
for (p = 1; p <= rpt->Nperiods; p++)
{
// Get output results for time period & update stats
@@ -751,7 +754,7 @@ int savetimestat(Project *pr, REAL4 *x, HdrType objtype)
}
}
// Advance file to next period
// Advance file to next period
if (p < rpt->Nperiods) fseek(out->TmpOutFile, skipbytes, SEEK_CUR);
}
@@ -821,7 +824,7 @@ int savenetreacts(Project *pr, double wbulk, double wwall, double wtank, double
double t;
REAL4 w[4];
FILE *outFile = out->OutFile;
if (time->Dur > 0) t = (double)time->Dur / 3600.;
else t = 1.;
w[0] = (REAL4)(wbulk / t);
@@ -846,7 +849,7 @@ int saveepilog(Project *pr)
int errcode = 0;
INT4 i;
FILE *outFile = out->OutFile;
i = rpt->Nperiods;
if (fwrite(&i, sizeof(INT4), 1, outFile) < 1) errcode = 308;
i = pr->Warnflag;

View File

@@ -7,11 +7,17 @@
Authors: see AUTHORS
Copyright: see AUTHORS
License: see LICENSE
Last Updated: 03/17/2019
Last Updated: 04/03/2019
******************************************************************************
*/
#include <stdlib.h>
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#else
#include <stdlib.h>
#endif
#include <stdio.h>
#include <string.h>
@@ -268,9 +274,6 @@ void initpointers(Project *pr)
pr->network.NodeHashTable = NULL;
pr->network.LinkHashTable = NULL;
pr->parser.Patlist = NULL;
pr->parser.Curvelist = NULL;
pr->hydraul.smatrix.Aii = NULL;
pr->hydraul.smatrix.Aij = NULL;
pr->hydraul.smatrix.F = NULL;
@@ -311,10 +314,10 @@ int allocdata(Project *pr)
if (!errcode)
{
n = pr->parser.MaxNodes + 1;
pr->network.Node = (Snode *)calloc(n, sizeof(Snode));
pr->network.Node = (Snode *)calloc(n, sizeof(Snode));
pr->hydraul.NodeDemand = (double *)calloc(n, sizeof(double));
pr->hydraul.NodeHead = (double *)calloc(n, sizeof(double));
pr->quality.NodeQual = (double *)calloc(n, sizeof(double));
pr->quality.NodeQual = (double *)calloc(n, sizeof(double));
ERRCODE(MEMCHECK(pr->network.Node));
ERRCODE(MEMCHECK(pr->hydraul.NodeDemand));
ERRCODE(MEMCHECK(pr->hydraul.NodeHead));
@@ -325,8 +328,8 @@ int allocdata(Project *pr)
if (!errcode)
{
n = pr->parser.MaxLinks + 1;
pr->network.Link = (Slink *)calloc(n, sizeof(Slink));
pr->hydraul.LinkFlow = (double *)calloc(n, sizeof(double));
pr->network.Link = (Slink *)calloc(n, sizeof(Slink));
pr->hydraul.LinkFlow = (double *)calloc(n, sizeof(double));
pr->hydraul.LinkSetting = (double *)calloc(n, sizeof(double));
pr->hydraul.LinkStatus = (StatusType *)calloc(n, sizeof(StatusType));
ERRCODE(MEMCHECK(pr->network.Link));
@@ -335,8 +338,8 @@ int allocdata(Project *pr)
ERRCODE(MEMCHECK(pr->hydraul.LinkStatus));
}
// Allocate memory for tanks, sources, pumps, valves,
// controls, demands, time patterns, & operating curves
// Allocate memory for tanks, sources, pumps, valves, and controls
// (memory for Patterns and Curves arrays expanded as each is added)
if (!errcode)
{
pr->network.Tank =
@@ -347,35 +350,15 @@ int allocdata(Project *pr)
(Svalve *)calloc(pr->parser.MaxValves + 1, sizeof(Svalve));
pr->network.Control =
(Scontrol *)calloc(pr->parser.MaxControls + 1, sizeof(Scontrol));
pr->network.Pattern =
(Spattern *)calloc(pr->parser.MaxPats + 1, sizeof(Spattern));
pr->network.Curve =
(Scurve *)calloc(pr->parser.MaxCurves + 1, sizeof(Scurve));
ERRCODE(MEMCHECK(pr->network.Tank));
ERRCODE(MEMCHECK(pr->network.Pump));
ERRCODE(MEMCHECK(pr->network.Valve));
ERRCODE(MEMCHECK(pr->network.Control));
ERRCODE(MEMCHECK(pr->network.Pattern));
ERRCODE(MEMCHECK(pr->network.Curve));
}
// Initialize pointers used in patterns, curves, and demand category lists
// Initialize pointers used in nodes and links
if (!errcode)
{
for (n = 0; n <= pr->parser.MaxPats; n++)
{
pr->network.Pattern[n].Length = 0;
pr->network.Pattern[n].F = NULL;
pr->network.Pattern[n].Comment = NULL;
}
for (n = 0; n <= pr->parser.MaxCurves; n++)
{
pr->network.Curve[n].Npts = 0;
pr->network.Curve[n].Type = GENERIC_CURVE;
pr->network.Curve[n].X = NULL;
pr->network.Curve[n].Y = NULL;
pr->network.Curve[n].Comment = NULL;
}
for (n = 0; n <= pr->parser.MaxNodes; n++)
{
pr->network.Node[n].D = NULL; // node demand
@@ -393,43 +376,6 @@ int allocdata(Project *pr)
return errcode;
}
void freeTmplist(STmplist *t)
/*----------------------------------------------------------------
** Input: t = pointer to start of a temporary list
** Output: none
** Purpose: frees memory used for temporary storage
** of pattern & curve data
**----------------------------------------------------------------
*/
{
STmplist *tnext;
while (t != NULL)
{
tnext = t->next;
freeFloatlist(t->x);
freeFloatlist(t->y);
free(t);
t = tnext;
}
}
void freeFloatlist(SFloatlist *f)
/*----------------------------------------------------------------
** Input: f = pointer to start of list of floats
** Output: none
** Purpose: frees memory used for storing list of floats
**----------------------------------------------------------------
*/
{
SFloatlist *fnext;
while (f != NULL)
{
fnext = f->next;
free(f);
f = fnext;
}
}
void freedata(Project *pr)
/*----------------------------------------------------------------
** Input: none
@@ -440,7 +386,6 @@ void freedata(Project *pr)
{
int j;
Pdemand demand, nextdemand;
Psource source;
// Free memory for computed results
free(pr->hydraul.NodeDemand);
@@ -468,8 +413,7 @@ void freedata(Project *pr)
demand = nextdemand;
}
// Free memory used for WQ source data
source = pr->network.Node[j].S;
free(source);
free(pr->network.Node[j].S);
free(pr->network.Node[j].Comment);
}
free(pr->network.Node);
@@ -505,7 +449,8 @@ void freedata(Project *pr)
// Free memory for curves
if (pr->network.Curve != NULL)
{
for (j = 0; j <= pr->parser.MaxCurves; j++)
// There is no Curve[0]
for (j = 1; j <= pr->parser.MaxCurves; j++)
{
free(pr->network.Curve[j].X);
free(pr->network.Curve[j].Y);
@@ -803,6 +748,40 @@ int findvalve(Network *network, int index)
return NOTFOUND;
}
int findpattern(Network *network, char *id)
/*----------------------------------------------------------------
** Input: id = time pattern ID
** Output: none
** Returns: time pattern index, or 0 if pattern not found
** Purpose: finds index of time pattern given its ID
**----------------------------------------------------------------
*/
{
int i;
for (i = 1; i <= network->Npats; i++)
{
if (strcmp(id, network->Pattern[i].ID) == 0) return i;
}
return 0;
}
int findcurve(Network *network, char *id)
/*----------------------------------------------------------------
** Input: id = data curve ID
** Output: none
** Returns: data curve index, or 0 if curve not found
** Purpose: finds index of data curve given its ID
**----------------------------------------------------------------
*/
{
int i;
for (i = 1; i <= network->Ncurves; i++)
{
if (strcmp(id, network->Curve[i].ID) == 0) return i;
}
return 0;
}
void adjustpattern(int *pat, int index)
/*----------------------------------------------------------------
** Local function that modifies a reference to a deleted time pattern
@@ -898,6 +877,35 @@ void adjustcurves(Network *network, int index)
}
}
int resizecurve(Scurve *curve, int size)
/*----------------------------------------------------------------
** Input: curve = a data curve object
** size = desired number of curve data points
** Output: error code
** Purpose: resizes a data curve to a desired size
**----------------------------------------------------------------
*/
{
double *x;
double *y;
if (curve->Capacity < size)
{
x = (double *)realloc(curve->X, size * sizeof(double));
if (x == NULL) return 101;
y = (double *)realloc(curve->Y, size * sizeof(double));
if (y == NULL)
{
free(x);
return 101;
}
curve->X = x;
curve->Y = y;
curve->Capacity = size;
}
return 0;
}
int getcomment(Network *network, int object, int index, char *comment)
//----------------------------------------------------------------
// Input: object = a type of network object

View File

@@ -11,13 +11,16 @@ Last Updated: 11/27/2018
******************************************************************************
*/
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#else
#include <stdlib.h>
#endif
#include <stdio.h>
#include <string.h>
#ifndef __APPLE__
#include <malloc.h>
#else
#include <stdlib.h>
#endif
#include <math.h>
#include "mempool.h"
@@ -60,7 +63,7 @@ int openqual(Project *pr)
int errcode = 0;
int n;
// Return if no quality analysis requested
if (qual->Qualflag == NONE) return errcode;

View File

@@ -11,6 +11,13 @@ Last Updated: 11/27/2018
******************************************************************************
*/
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#else
#include <stdlib.h>
#endif
#include <stdio.h>
#include <math.h>
#include "types.h"

View File

@@ -11,13 +11,17 @@ Last Updated: 11/27/2018
******************************************************************************
*/
#include <stdio.h>
#ifndef __APPLE__
#include <malloc.h>
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#else
#include <stdlib.h>
#include <stdlib.h>
#endif
#include <stdio.h>
#include <math.h>
#include "mempool.h"
#include "types.h"

View File

@@ -11,13 +11,15 @@
******************************************************************************
*/
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#else
#include <stdlib.h>
#endif
#include <stdio.h>
#include <string.h>
#ifndef __APPLE__
#include <malloc.h>
#else
#include <stdlib.h>
#endif
#ifdef _WIN32
#define snprintf _snprintf
@@ -83,7 +85,7 @@ int copyreport(Project* pr, char *filename)
FILE *tfile;
int c;
Report *rpt = &pr->report;
// Check that project's report file exists
if (rpt->RptFile == NULL) return 0;
@@ -101,7 +103,7 @@ int copyreport(Project* pr, char *filename)
while ((c = fgetc(rpt->RptFile)) != EOF) fputc(c, tfile);
fclose(rpt->RptFile);
}
// Close destination file
fclose(tfile);

View File

@@ -11,13 +11,15 @@
******************************************************************************
*/
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#else
#include <stdlib.h>
#endif
#include <stdio.h>
#include <string.h>
#ifndef __APPLE__
#include <malloc.h>
#else
#include <stdlib.h>
#endif
#include "types.h"
#include "funcs.h"

View File

@@ -18,13 +18,16 @@
linsolve() -- called from netsolve() in HYDRAUL.C
*/
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#else
#include <stdlib.h>
#endif
#include <stdio.h>
#include <string.h>
#ifndef __APPLE__
#include <malloc.h>
#else
#include <stdlib.h>
#endif
#include <math.h>
#include <limits.h>

View File

@@ -7,7 +7,7 @@
Authors: see AUTHORS
Copyright: see AUTHORS
License: see LICENSE
Last Updated: 03/17/2019
Last Updated: 04/03/2019
******************************************************************************
*/
@@ -317,23 +317,6 @@ struct IDstring // Holds component ID label
char ID[MAXID+1];
};
struct Floatlist // Element of List of Numbers
{
double value; // element's numerical value
struct Floatlist *next; // next element on the list
};
typedef struct Floatlist SFloatlist;
struct Tmplist // Item of Temporary List of Objects
{
int i; // object's index
char ID[MAXID+1]; // object's ID name
SFloatlist *x; // list of data values
SFloatlist *y; // list of data values
struct Tmplist *next; // next object on list
};
typedef struct Tmplist STmplist; // Pointer to temporary list of objects
typedef struct // Time Pattern Object
{
char ID[MAXID+1]; // pattern ID
@@ -348,6 +331,7 @@ typedef struct // Curve Object
char *Comment; // curve comment
CurveType Type; // curve type
int Npts; // number of points
int Capacity; // size of X & Y arrays
double *X; // x-values
double *Y; // y-values
} Scurve;
@@ -573,14 +557,11 @@ typedef struct {
ErrTok, // Index of error-producing token
Unitsflag, // Unit system flag
Flowflag, // Flow units flag
Pressflag; // Pressure units flag
Pressflag, // Pressure units flag
DefPat; // Default demand pattern
STmplist
*Patlist, // Temporary time pattern list
*PrevPat, // Previous pattern list element
*Curvelist, // Temporary list of curves
*PrevCurve; // Previous curve list element
Spattern *PrevPat; // Previous pattern processed
Scurve *PrevCurve; // Previous curve processed
double *X; // Temporary array for curve data
} Parser;
@@ -738,7 +719,6 @@ typedef struct {
*Xflow; // Inflow - outflow at each node
int
DefPat, // Default demand pattern
Epat, // Energy cost time pattern
DemandModel, // Fixed or pressure dependent
Formflag, // Head loss formula flag