Files
EPANET/src/input3.c

1863 lines
63 KiB
C
Executable File

/*
**********************************************************************
INPUT3.C -- Input data parser for EPANET
VERSION: 2.00
DATE: 5/30/00
9/7/00
10/25/00
3/1/01
6/24/02
8/15/07 (2.00.11)
2/14/08 (2.00.12)
AUTHOR: L. Rossman
US EPA - NRMRL
This module parses data from each line of input from file InFile.
All functions in this module are called from newline() in INPUT2.C.
**********************************************************************
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <math.h>
#include "hash.h"
#include "text.h"
#include "types.h"
#include "funcs.h"
#define EXTERN extern
#include "vars.h"
/* Defined in enumstxt.h in EPANET.C */
extern char *MixTxt[];
extern char *Fldname[];
/* Defined in INPUT2.C */
extern char *Tok[MAXTOKS];
extern STmplist *PrevPat;
extern STmplist *PrevCurve;
extern int Ntokens;
int juncdata()
/*
**--------------------------------------------------------------
** Input: none
** Output: returns error code
** Purpose: processes junction data
** Format:
** [JUNCTIONS]
** id elev. (demand) (demand pattern)
**--------------------------------------------------------------
*/
{
int n, p = 0;
double el,y = 0.0;
Pdemand demand;
STmplist *pat;
/* Add new junction to data base */
n = Ntokens;
if (Nnodes == MaxNodes) return(200);
Njuncs++;
Nnodes++;
if (!addnodeID(Njuncs,Tok[0])) return(215);
/* Check for valid data */
if (n < 2) return(201);
if (!getfloat(Tok[1],&el)) return(202);
if (n >= 3 && !getfloat(Tok[2],&y)) return(202);
if (n >= 4)
{
pat = findID(Tok[3],Patlist);
if (pat == NULL) return(205);
p = pat->i;
}
/* Save junction data */
Node[Njuncs].El = el;
Node[Njuncs].C0 = 0.0;
Node[Njuncs].S = NULL;
Node[Njuncs].Ke = 0.0;
Node[Njuncs].Rpt = 0;
/* Create a new demand record */
/*** Updated 6/24/02 ***/
if (n >= 3)
{
demand = (struct Sdemand *) malloc(sizeof(struct Sdemand));
if (demand == NULL) return(101);
demand->Base = y;
demand->Pat = p;
demand->next = Node[Njuncs].D;
Node[Njuncs].D = demand;
D[Njuncs] = y;
}
else D[Njuncs] = MISSING;
/*** end of update ***/
return(0);
} /* end of juncdata */
int tankdata()
/*
**--------------------------------------------------------------
** Input: none
** Output: returns error code
** Purpose: processes tank & reservoir data
** Format:
** [RESERVOIRS]
** id elev (pattern)
** [TANKS]
** id elev (pattern)
** id elev initlevel minlevel maxlevel diam (minvol vcurve)
**--------------------------------------------------------------
*/
{
int i, /* Node index */
n, /* # data items */
p = 0, /* Fixed grade time pattern index */
vcurve = 0; /* Volume curve index */
double el = 0.0, /* Elevation */
initlevel = 0.0, /* Initial level */
minlevel = 0.0, /* Minimum level */
maxlevel = 0.0, /* Maximum level */
minvol = 0.0, /* Minimum volume */
diam = 0.0, /* Diameter */
area; /* X-sect. area */
STmplist *t;
/* Add new tank to data base */
n = Ntokens;
if (Ntanks == MaxTanks
|| Nnodes == MaxNodes) return(200);
Ntanks++;
Nnodes++;
i = MaxJuncs + Ntanks; /* i = node index. */
if (!addnodeID(i,Tok[0])) return(215); /* Add ID to database. */
/* Check for valid data */
if (n < 2) return(201); /* Too few fields. */
if (!getfloat(Tok[1],&el)) return(202); /* Read elevation */
if (n <= 3) /* Tank is reservoir.*/
{
if (n == 3) /* Pattern supplied */
{
t = findID(Tok[2],Patlist);
if (t == NULL) return(205);
p = t->i;
}
}
else if (n < 6) return(201); /* Too few fields for tank.*/
else
{
/* Check for valid input data */
if (!getfloat(Tok[2],&initlevel)) return(202);
if (!getfloat(Tok[3],&minlevel)) return(202);
if (!getfloat(Tok[4],&maxlevel)) return(202);
if (!getfloat(Tok[5],&diam)) return(202);
if (diam < 0.0) return(202);
if (n >= 7
&& !getfloat(Tok[6],&minvol)) return(202);
/* If volume curve supplied check it exists */
if (n == 8)
{
t = findID(Tok[7],Curvelist);
if (t == NULL) return(202);
vcurve = t->i;
}
}
Node[i].Rpt = 0;
Node[i].El = el; /* Elevation. */
Node[i].C0 = 0.0; /* Init. quality. */
Node[i].S = NULL; /* WQ source data */
Node[i].Ke = 0.0; /* Emitter coeff. */
Tank[Ntanks].Node = i; /* Node index. */
Tank[Ntanks].H0 = initlevel; /* Init. level. */
Tank[Ntanks].Hmin = minlevel; /* Min. level. */
Tank[Ntanks].Hmax = maxlevel; /* Max level. */
Tank[Ntanks].A = diam; /* Diameter. */
Tank[Ntanks].Pat = p; /* Fixed grade pattern. */
Tank[Ntanks].Kb = MISSING; /* Reaction coeff. */
/*
*******************************************************************
NOTE: The min, max, & initial volumes set here are based on a
nominal tank diameter. They will be modified in INPUT1.C if
a volume curve is supplied for this tank.
*******************************************************************
*/
area = PI*SQR(diam)/4.0;
Tank[Ntanks].Vmin = area*minlevel;
if (minvol > 0.0) Tank[Ntanks].Vmin = minvol;
Tank[Ntanks].V0 = Tank[Ntanks].Vmin + area*(initlevel - minlevel);
Tank[Ntanks].Vmax = Tank[Ntanks].Vmin + area*(maxlevel - minlevel);
Tank[Ntanks].Vcurve = vcurve; /* Volume curve */
Tank[Ntanks].MixModel = MIX1; /* Completely mixed */
Tank[Ntanks].V1max = 1.0; /* Compart. size ratio */
return(0);
} /* end of tankdata */
int pipedata()
/*
**--------------------------------------------------------------
** Input: none
** Output: returns error code
** Purpose: processes pipe data
** Format:
** [PIPE]
** id node1 node2 length diam rcoeff (lcoeff) (status)
**--------------------------------------------------------------
*/
{
int j1, /* Start-node index */
j2, /* End-node index */
n; /* # data items */
char type = PIPE, /* Link type */
status = OPEN; /* Link status */
double length, /* Link length */
diam, /* Link diameter */
rcoeff, /* Roughness coeff. */
lcoeff = 0.0; /* Minor loss coeff. */
/* Add new pipe to data base */
n = Ntokens;
if (Nlinks == MaxLinks) return(200);
Npipes++;
Nlinks++;
if (!addlinkID(Nlinks,Tok[0])) return(215);
/* Check for valid data */
if (n < 6) return(201);
if ((j1 = findnode(Tok[1])) == 0 ||
(j2 = findnode(Tok[2])) == 0
) return(203);
/*** Updated 10/25/00 ***/
if (j1 == j2) return(222);
if (!getfloat(Tok[3],&length) ||
!getfloat(Tok[4],&diam) ||
!getfloat(Tok[5],&rcoeff)
) return(202);
if (length <= 0.0 ||
diam <= 0.0 ||
rcoeff <= 0.0
) return(202);
/* Case where either loss coeff. or status supplied */
if (n == 7)
{
if (match(Tok[6],w_CV)) type = CV;
else if (match(Tok[6],w_CLOSED)) status = CLOSED;
else if (match(Tok[6],w_OPEN)) status = OPEN;
else if (!getfloat(Tok[6],&lcoeff)) return(202);
}
/* Case where both loss coeff. and status supplied */
if (n == 8)
{
if (!getfloat(Tok[6],&lcoeff)) return(202);
if (match(Tok[7],w_CV)) type = CV;
else if (match(Tok[7],w_CLOSED)) status = CLOSED;
else if (match(Tok[7],w_OPEN)) status = OPEN;
else return(202);
}
if (lcoeff < 0.0) return(202);
/* Save pipe data */
Link[Nlinks].N1 = j1; /* Start-node index */
Link[Nlinks].N2 = j2; /* End-node index */
Link[Nlinks].Len = length; /* Length */
Link[Nlinks].Diam = diam; /* Diameter */
Link[Nlinks].Kc = rcoeff; /* Rough. coeff */
Link[Nlinks].Km = lcoeff; /* Loss coeff */
Link[Nlinks].Kb = MISSING; /* Bulk coeff */
Link[Nlinks].Kw = MISSING; /* Wall coeff */
Link[Nlinks].Type = type; /* Link type */
Link[Nlinks].Stat = status; /* Link status */
Link[Nlinks].Rpt = 0; /* Report flag */
return(0);
} /* end of pipedata */
int pumpdata()
/*
**--------------------------------------------------------------
** Input: none
** Output: returns error code
** Purpose: processes pump data
** Formats:
** [PUMP]
** (Version 1.x Format):
** id node1 node2 power
** id node1 node2 h1 q1
** id node1 node2 h0 h1 q1 h2 q2
** (Version 2 Format):
** id node1 node2 KEYWORD value {KEYWORD value ...}
** where KEYWORD = [POWER,HEAD,PATTERN,SPEED]
**--------------------------------------------------------------
*/
{
int j,
j1, /* Start-node index */
j2, /* End-node index */
m, n; /* # data items */
double y;
STmplist *t; /* Pattern record */
/* Add new pump to data base */
n = Ntokens;
if (Nlinks == MaxLinks ||
Npumps == MaxPumps
) return(200);
Nlinks++;
Npumps++;
if (!addlinkID(Nlinks,Tok[0])) return(215);
/* Check for valid data */
if (n < 4) return(201);
if ((j1 = findnode(Tok[1])) == 0 ||
(j2 = findnode(Tok[2])) == 0
) return(203);
/*** Updated 10/25/00 ***/
if (j1 == j2) return(222);
/* Save pump data */
Link[Nlinks].N1 = j1; /* Start-node index. */
Link[Nlinks].N2 = j2; /* End-node index. */
Link[Nlinks].Diam = Npumps; /* Pump index. */
Link[Nlinks].Len = 0.0; /* Link length. */
Link[Nlinks].Kc = 1.0; /* Speed factor. */
Link[Nlinks].Km = 0.0; /* Horsepower. */
Link[Nlinks].Kb = 0.0;
Link[Nlinks].Kw = 0.0;
Link[Nlinks].Type = PUMP; /* Link type. */
Link[Nlinks].Stat = OPEN; /* Link status. */
Link[Nlinks].Rpt = 0; /* Report flag. */
Pump[Npumps].Link = Nlinks; /* Link index. */
Pump[Npumps].Ptype = NOCURVE; /* Type of pump curve */
Pump[Npumps].Hcurve = 0; /* Pump curve index */
Pump[Npumps].Ecurve = 0; /* Effic. curve index */
Pump[Npumps].Upat = 0; /* Utilization pattern*/
Pump[Npumps].Ecost = 0.0; /* Unit energy cost */
Pump[Npumps].Epat = 0; /* Energy cost pattern*/
/* If 4-th token is a number then input follows Version 1.x format */
/* so retrieve pump curve parameters */
if (getfloat(Tok[3],&X[0]))
{
m = 1;
for (j=4; j<n; j++)
{
if (!getfloat(Tok[j],&X[m])) return(202);
m++;
}
return(getpumpcurve(m)); /* Get pump curve params */
}
/* Otherwise input follows Version 2 format */
/* so retrieve keyword/value pairs. */
m = 4;
while (m < n)
{
if (match(Tok[m-1],w_POWER)) /* Const. HP curve */
{
y = atof(Tok[m]);
if (y <= 0.0) return(202);
Pump[Npumps].Ptype = CONST_HP;
Link[Nlinks].Km = y;
}
else if (match(Tok[m-1],w_HEAD)) /* Custom pump curve */
{
t = findID(Tok[m],Curvelist);
if (t == NULL) return(206);
Pump[Npumps].Hcurve = t->i;
}
else if (match(Tok[m-1],w_PATTERN)) /* Speed/status pattern */
{
t = findID(Tok[m],Patlist);
if (t == NULL) return(205);
Pump[Npumps].Upat = t->i;
}
else if (match(Tok[m-1],w_SPEED)) /* Speed setting */
{
if (!getfloat(Tok[m],&y)) return(202);
if (y < 0.0) return(202);
Link[Nlinks].Kc = y;
}
else return(201);
m = m + 2; /* Skip to next keyword token */
}
return(0);
} /* end of pumpdata */
int valvedata()
/*
**--------------------------------------------------------------
** Input: none
** Output: returns error code
** Purpose: processes valve data
** Format:
** [VALVE]
** id node1 node2 diam type setting (lcoeff)
**--------------------------------------------------------------
*/
{
int j1, /* Start-node index */
j2, /* End-node index */
n; /* # data items */
char status = ACTIVE, /* Valve status */
type; /* Valve type */
double diam = 0.0, /* Valve diameter */
setting, /* Valve setting */
lcoeff = 0.0; /* Minor loss coeff. */
STmplist *t; /* Curve record */
/* Add new valve to data base */
n = Ntokens;
if (Nlinks == MaxLinks ||
Nvalves == MaxValves
) return(200);
Nvalves++;
Nlinks++;
if (!addlinkID(Nlinks,Tok[0])) return(215);
/* Check for valid data */
if (n < 6) return(201);
if ((j1 = findnode(Tok[1])) == 0 ||
(j2 = findnode(Tok[2])) == 0
) return(203);
/*** Updated 10/25/00 ***/
if (j1 == j2) return(222);
if (match(Tok[4],w_PRV)) type = PRV;
else if (match(Tok[4],w_PSV)) type = PSV;
else if (match(Tok[4],w_PBV)) type = PBV;
else if (match(Tok[4],w_FCV)) type = FCV;
else if (match(Tok[4],w_TCV)) type = TCV;
else if (match(Tok[4],w_GPV)) type = GPV;
else return(201); /* Illegal valve type.*/
if (!getfloat(Tok[3],&diam)) return(202);
if (diam <= 0.0) return(202); /* Illegal diameter.*/
if (type == GPV) /* Headloss curve for GPV */
{
t = findID(Tok[5],Curvelist);
if (t == NULL) return(206);
setting = t->i;
/*** Updated 9/7/00 ***/
status = OPEN;
}
else if (!getfloat(Tok[5],&setting)) return(202);
if (n >= 7 &&
!getfloat(Tok[6],&lcoeff)
) return(202);
/* Check that PRV, PSV, or FCV not connected to a tank & */
/* check for illegal connections between pairs of valves.*/
if ((j1 > Njuncs || j2 > Njuncs) &&
(type == PRV || type == PSV || type == FCV)
) return(219);
if (!valvecheck(type,j1,j2)) return(220);
/* Save valve data */
Link[Nlinks].N1 = j1; /* Start-node index. */
Link[Nlinks].N2 = j2; /* End-node index. */
Link[Nlinks].Diam = diam; /* Valve diameter. */
Link[Nlinks].Len = 0.0; /* Link length. */
Link[Nlinks].Kc = setting; /* Valve setting. */
Link[Nlinks].Km = lcoeff; /* Loss coeff */
Link[Nlinks].Kb = 0.0;
Link[Nlinks].Kw = 0.0;
Link[Nlinks].Type = type; /* Valve type. */
Link[Nlinks].Stat = status; /* Valve status. */
Link[Nlinks].Rpt = 0; /* Report flag. */
Valve[Nvalves].Link = Nlinks; /* Link index. */
return(0);
} /* end of valvedata */
int patterndata()
/*
**--------------------------------------------------------------
** Input: none
** Output: returns error code
** Purpose: processes time pattern data
** Format:
** [PATTERNS]
** id mult1 mult2 .....
**--------------------------------------------------------------
*/
{
int i,n;
double x;
SFloatlist *f;
STmplist *p;
n = Ntokens - 1;
if (n < 1) return(201); /* Too few values */
if ( /* Check for new pattern */
PrevPat != NULL &&
strcmp(Tok[0],PrevPat->ID) == 0
) p = PrevPat;
else p = findID(Tok[0],Patlist);
if (p == NULL) return(205);
for (i=1; i<=n; i++) /* Add multipliers to list */
{
if (!getfloat(Tok[i],&x)) return(202);
f = (SFloatlist *) malloc(sizeof(SFloatlist));
if (f == NULL) return(101);
f->value = x;
f->next = p->x;
p->x = f;
}
Pattern[p->i].Length += n; /* Save # multipliers for pattern */
PrevPat = p; /* Set previous pattern pointer */
return(0);
} /* end of patterndata */
int curvedata()
/*
**------------------------------------------------------
** Input: none
** Output: returns error code
** Purpose: processes curve data
** Format:
** [CURVES]
** CurveID x-value y-value
**------------------------------------------------------
*/
{
double x,y;
SFloatlist *fx, *fy;
STmplist *c;
/* Check for valid curve ID */
if (Ntokens < 3) return(201);
if (
PrevCurve != NULL &&
strcmp(Tok[0],PrevCurve->ID) == 0
) c = PrevCurve;
else c = findID(Tok[0],Curvelist);
if (c == NULL) return(205);
/* Check for valid data */
if (!getfloat(Tok[1],&x)) return(202);
if (!getfloat(Tok[2],&y)) return(202);
/* Add new data point to curve's linked list */
fx = (SFloatlist *) malloc(sizeof(SFloatlist));
fy = (SFloatlist *) malloc(sizeof(SFloatlist));
if (fx == NULL || fy == NULL) return(101);
fx->value = x;
fx->next = c->x;
c->x = fx;
fy->value = y;
fy->next = c->y;
c->y = fy;
Curve[c->i].Npts++;
/* Save the pointer to this curve */
PrevCurve = c;
return(0);
}
int demanddata()
/*
**--------------------------------------------------------------
** Input: none
** Output: returns error code
** Purpose: processes node demand data
** Format:
** [DEMANDS]
** MULTIPLY factor
** node base_demand (pattern)
**
** NOTE: Demands entered in this section replace those
** entered in the [JUNCTIONS] section
**--------------------------------------------------------------
*/
{
int j,n,p = 0;
double y;
Pdemand demand;
STmplist *pat;
/* Extract data from tokens */
n = Ntokens;
if (n < 2) return(201);
if (!getfloat(Tok[1],&y)) return(202);
/* If MULTIPLY command, save multiplier */
if (match(Tok[0],w_MULTIPLY))
{
if (y <= 0.0) return(202);
else Dmult = y;
return(0);
}
/* Otherwise find node (and pattern) being referenced */
if ((j = findnode(Tok[0])) == 0) return(208);
if (j > Njuncs) return(208);
if (n >= 3)
{
pat = findID(Tok[2],Patlist);
if (pat == NULL) return(205);
p = pat->i;
}
/* Replace any demand entered in [JUNCTIONS] section */
/* (Such demand was temporarily stored in D[]) */
/*** Updated 6/24/02 ***/
demand = Node[j].D;
if (demand && D[j] != MISSING)
{
demand->Base = y;
demand->Pat = p;
D[j] = MISSING;
}
/*** End of update ***/
/* Otherwise add a new demand to this junction */
else
{
demand = (struct Sdemand *) malloc(sizeof(struct Sdemand));
if (demand == NULL) return(101);
demand->Base = y;
demand->Pat = p;
demand->next = Node[j].D;
Node[j].D = demand;
}
return(0);
} /* end of demanddata */
int controldata()
/*
**--------------------------------------------------------------
** Input: none
** Output: returns error code
** Purpose: processes simple controls
** Formats:
** [CONTROLS]
** LINK linkID setting IF NODE nodeID {BELOW/ABOVE} level
** LINK linkID setting AT TIME value (units)
** LINK linkID setting AT CLOCKTIME value (units)
** (0) (1) (2) (3) (4) (5) (6) (7)
**--------------------------------------------------------------
*/
{
int i = 0, /* Node index */
k, /* Link index */
n; /* # data items */
char status = ACTIVE, /* Link status */
type; /* Link or control type */
double setting = MISSING, /* Link setting */
time = 0.0, /* Simulation time */
level = 0.0; /* Pressure or tank level */
/* Check for sufficient number of input tokens */
n = Ntokens;
if (n < 6) return(201);
/* Check that controlled link exists */
k = findlink(Tok[1]);
if (k == 0) return(204);
type = Link[k].Type;
if (type == CV) return(207); /* Cannot control check valve. */
/*** Updated 9/7/00 ***/
/* Parse control setting into a status level or numerical setting. */
if (match(Tok[2],w_OPEN))
{
status = OPEN;
if (type == PUMP) setting = 1.0;
if (type == GPV) setting = Link[k].Kc;
}
else if (match(Tok[2],w_CLOSED))
{
status = CLOSED;
if (type == PUMP) setting = 0.0;
if (type == GPV) setting = Link[k].Kc;
}
else if (type == GPV) return(206);
else if (!getfloat(Tok[2],&setting)) return(202);
/*** Updated 3/1/01 ***/
/* Set status for pump in case speed setting was supplied */
/* or for pipe if numerical setting was supplied */
if (type == PUMP || type == PIPE)
{
if (setting != MISSING)
{
if (setting < 0.0) return(202);
else if (setting == 0.0) status = CLOSED;
else status = OPEN;
}
}
/* Determine type of control */
if (match(Tok[4],w_TIME)) type = TIMER;
else if (match(Tok[4],w_CLOCKTIME)) type = TIMEOFDAY;
else
{
if (n < 8) return(201);
if ((i = findnode(Tok[5])) == 0) return(203);
if (match(Tok[6],w_BELOW)) type = LOWLEVEL;
else if (match(Tok[6],w_ABOVE)) type = HILEVEL;
else return(201);
}
/* Parse control level or time */
switch (type)
{
case TIMER:
case TIMEOFDAY:
if (n == 6) time = hour(Tok[5],"");
if (n == 7) time = hour(Tok[5],Tok[6]);
if (time < 0.0) return(201);
break;
case LOWLEVEL:
case HILEVEL:
if (!getfloat(Tok[7],&level)) return(202);
break;
}
/* Fill in fields of control data structure */
Ncontrols++;
if (Ncontrols > MaxControls) return(200);
Control[Ncontrols].Link = k;
Control[Ncontrols].Node = i;
Control[Ncontrols].Type = type;
Control[Ncontrols].Status = status;
Control[Ncontrols].Setting = setting;
Control[Ncontrols].Time = (long)(3600.0*time);
if (type == TIMEOFDAY)
Control[Ncontrols].Time %= SECperDAY;
Control[Ncontrols].Grade = level;
return(0);
} /* end of controldata */
int sourcedata()
/*
**--------------------------------------------------------------
** Input: none
** Output: returns error code
** Purpose: processes water quality source data
** Formats:
** [SOURCE]
** node sourcetype quality (pattern start stop)
**
** NOTE: units of mass-based source are mass/min
**--------------------------------------------------------------
*/
{
int i, /* Token with quality value */
j, /* Node index */
n, /* # data items */
p = 0; /* Time pattern */
char type = CONCEN; /* Source type */
double c0 = 0; /* Init. quality */
STmplist *pat;
Psource source;
n = Ntokens;
if (n < 2) return(201);
if ((j = findnode(Tok[0])) == 0) return(203);
/* NOTE: Under old format, SourceType not supplied so let */
/* i = index of token that contains quality value. */
i = 2;
if (match(Tok[1],w_CONCEN)) type = CONCEN;
else if (match(Tok[1],w_MASS)) type = MASS;
else if (match(Tok[1],w_SETPOINT)) type = SETPOINT;
else if (match(Tok[1],w_FLOWPACED)) type = FLOWPACED;
else i = 1;
if (!getfloat(Tok[i],&c0)) return(202); /* Illegal WQ value */
if (n > i+1 && strlen(Tok[i+1]) > 0 && strcmp(Tok[i+1], "*") != 0 ) //(2.00.11 - LR)
{
pat = findID(Tok[i+1],Patlist);
if (pat == NULL) return(205); /* Illegal pattern. */
p = pat->i;
}
source = (struct Ssource *) malloc(sizeof(struct Ssource));
if (source == NULL) return(101);
source->C0 = c0;
source->Pat = p;
source->Type = type;
Node[j].S = source;
return(0);
} /* end of sourcedata */
int emitterdata()
/*
**--------------------------------------------------------------
** Input: none
** Output: returns error code
** Purpose: processes junction emitter data
** Format:
** [EMITTER]
** node K
**--------------------------------------------------------------
*/
{
int j, /* Node index */
n; /* # data items */
double k; /* Flow coeff, */
n = Ntokens;
if (n < 2) return(201);
if ((j = findnode(Tok[0])) == 0) return(203);
if (j > Njuncs) return(209); /* Not a junction.*/
if (!getfloat(Tok[1],&k)) return(202);
if (k < 0.0) return(202);
Node[j].Ke = k;
return(0);
}
int qualdata()
/*
**--------------------------------------------------------------
** Input: none
** Output: returns error code
** Purpose: processes initial water quality data
** Formats:
** [QUALITY]
** node initqual
** node1 node2 initqual
**--------------------------------------------------------------
*/
{
int j,n;
long i,i0,i1;
double c0;
if (Nnodes == 0) return(208); /* No nodes defined yet */
n = Ntokens;
if (n < 2) return(0);
if (n == 2) /* Single node entered */
{
if ( (j = findnode(Tok[0])) == 0) return(0);
if (!getfloat(Tok[1],&c0)) return(209);
Node[j].C0 = c0;
}
else /* Node range entered */
{
if (!getfloat(Tok[2],&c0)) return(209);
/* If numerical range supplied, then use numerical comparison */
if ((i0 = atol(Tok[0])) > 0 && (i1 = atol(Tok[1])) > 0)
{
for (j=1; j<=Nnodes; j++)
{
i = atol(Node[j].ID);
if (i >= i0 && i <= i1) Node[j].C0 = c0;
}
}
else
{
for (j=1; j<=Nnodes; j++)
if ((strcmp(Tok[0],Node[j].ID) <= 0) &&
(strcmp(Tok[1],Node[j].ID) >= 0)
) Node[j].C0 = c0;
}
}
return(0);
} /* end of qualdata */
int reactdata()
/*
**--------------------------------------------------------------
** Input: none
** Output: returns error code
** Purpose: processes reaction coeff. data
** Formats:
** [REACTIONS]
** ORDER {BULK/WALL/TANK} value
** GLOBAL BULK coeff
** GLOBAL WALL coeff
** BULK link1 (link2) coeff
** WALL link1 (link2) coeff
** TANK node1 (node2) coeff
** LIMITING POTENTIAL value
** ROUGHNESS CORRELATION value
**--------------------------------------------------------------
*/
{
int item,j,n;
long i,i1,i2;
double y;
/* Skip line if insufficient data */
n = Ntokens;
if (n < 3) return(0);
/* Process input depending on keyword */
if (match(Tok[0],w_ORDER)) /* Reaction order */
{
if (!getfloat(Tok[n-1],&y)) return(213);
if (match(Tok[1],w_BULK)) BulkOrder = y;
else if (match(Tok[1],w_TANK)) TankOrder = y;
else if (match(Tok[1],w_WALL))
{
if (y == 0.0) WallOrder = 0.0;
else if (y == 1.0) WallOrder = 1.0;
else return(213);
}
else return(213);
return(0);
}
if (match(Tok[0],w_ROUGHNESS)) /* Roughness factor */
{
if (!getfloat(Tok[n-1],&y)) return(213);
Rfactor = y;
return(0);
}
if (match(Tok[0],w_LIMITING)) /* Limiting potential */
{
if (!getfloat(Tok[n-1],&y)) return(213);
/*if (y < 0.0) return(213);*/
Climit = y;
return(0);
}
if (match(Tok[0],w_GLOBAL)) /* Global rates */
{
if (!getfloat(Tok[n-1],&y)) return(213);
if (match(Tok[1],w_BULK)) Kbulk = y;
else if (match(Tok[1],w_WALL)) Kwall = y;
else return(201);
return(0);
}
if (match(Tok[0],w_BULK)) item = 1; /* Individual rates */
else if (match(Tok[0],w_WALL)) item = 2;
else if (match(Tok[0],w_TANK)) item = 3;
else return(201);
strcpy(Tok[0],Tok[1]); /* Save id in Tok[0] */
if (item == 3) /* Tank rates */
{
if (!getfloat(Tok[n-1],&y)) return(209); /* Rate coeff. */
if (n == 3)
{
if ( (j = findnode(Tok[1])) <= Njuncs) return(0);
Tank[j-Njuncs].Kb = y;
}
else
{
/* If numerical range supplied, then use numerical comparison */
if ((i1 = atol(Tok[1])) > 0 && (i2 = atol(Tok[2])) > 0)
{
for (j=Njuncs+1; j<=Nnodes; j++)
{
i = atol(Node[j].ID);
if (i >= i1 && i <= i2) Tank[j-Njuncs].Kb = y;
}
}
else for (j=Njuncs+1; j<=Nnodes; j++)
if ((strcmp(Tok[1],Node[j].ID) <= 0) &&
(strcmp(Tok[2],Node[j].ID) >= 0)
) Tank[j-Njuncs].Kb = y;
}
}
else /* Link rates */
{
if (!getfloat(Tok[n-1],&y)) return(211); /* Rate coeff. */
if (Nlinks == 0) return(0);
if (n == 3) /* Single link */
{
if ( (j = findlink(Tok[1])) == 0) return(0);
if (item == 1) Link[j].Kb = y;
else Link[j].Kw = y;
}
else /* Range of links */
{
/* If numerical range supplied, then use numerical comparison */
if ((i1 = atol(Tok[1])) > 0 && (i2 = atol(Tok[2])) > 0)
{
for (j=1; j<=Nlinks; j++)
{
i = atol(Link[j].ID);
if (i >= i1 && i <= i2)
{
if (item == 1) Link[j].Kb = y;
else Link[j].Kw = y;
}
}
}
else for (j=1; j<=Nlinks; j++)
if ((strcmp(Tok[1],Link[j].ID) <= 0) &&
(strcmp(Tok[2],Link[j].ID) >= 0) )
{
if (item == 1) Link[j].Kb = y;
else Link[j].Kw = y;
}
}
}
return(0);
} /* end of reactdata */
int mixingdata()
/*
**-------------------------------------------------------------
** Input: none
** Output: returns error code
** Purpose: processes tank mixing data
** Format:
** [MIXING]
** TankID MixModel FractVolume
**-------------------------------------------------------------
*/
{
int i,j,n;
double v;
if (Nnodes == 0) return(208); /* No nodes defined yet */
n = Ntokens;
if (n < 2) return(0);
if ( (j = findnode(Tok[0])) <= Njuncs) return(0);
if ( (i = findmatch(Tok[1],MixTxt)) < 0) return(201);
v = 1.0;
if ( (i == MIX2) &&
(n == 3) &&
(!getfloat(Tok[2],&v)) /* Get frac. vol. for 2COMP model */
) return(209);
if (v == 0.0) v = 1.0; /* v can't be zero */
n = j - Njuncs;
if (Tank[n].A == 0.0) return(0); /* Tank is a reservoir */
Tank[n].MixModel = (char)i;
Tank[n].V1max = v;
return(0);
}
int statusdata()
/*
**--------------------------------------------------------------
** Input: none
** Output: returns error code
** Purpose: processes link initial status data
** Formats:
** [STATUS]
** link value
** link1 (link2) value
**--------------------------------------------------------------
*/
{
int j,n;
long i,i0,i1;
double y = 0.0;
char status = ACTIVE;
if (Nlinks == 0) return(210);
n = Ntokens - 1;
if (n < 1) return(201);
/* Check for legal status setting */
if (match(Tok[n],w_OPEN)) status = OPEN;
else if (match(Tok[n],w_CLOSED)) status = CLOSED;
else if (!getfloat(Tok[n],&y)) return(211);
if (y < 0.0) return(211);
/* Single link ID supplied */
if (n == 1)
{
if ( (j = findlink(Tok[0])) == 0) return(0);
/* Cannot change status of a Check Valve */
if (Link[j].Type == CV) return(211);
/*** Updated 9/7/00 ***/
/* Cannot change setting for a GPV */
if (Link[j].Type == GPV
&& status == ACTIVE) return(211);
changestatus(j,status,y);
}
/* Range of ID's supplied */
else
{
/* Numerical range supplied */
if ((i0 = atol(Tok[0])) > 0 && (i1 = atol(Tok[1])) > 0)
{
for (j=1; j<=Nlinks; j++)
{
i = atol(Link[j].ID);
if (i >= i0 && i <= i1) changestatus(j,status,y);
}
}
else
for (j=1; j<=Nlinks; j++)
if ( (strcmp(Tok[0],Link[j].ID) <= 0) &&
(strcmp(Tok[1],Link[j].ID) >= 0)
) changestatus(j,status,y);
}
return(0);
} /* end of statusdata */
int energydata()
/*
**--------------------------------------------------------------
** Input: none
** Output: returns error code
** Purpose: processes pump energy data
** Formats:
** [ENERGY]
** GLOBAL {PRICE/PATTERN/EFFIC} value
** PUMP id {PRICE/PATTERN/EFFIC} value
** DEMAND CHARGE value
**--------------------------------------------------------------
*/
{
int j,k,n;
double y;
STmplist *t;
/* Check for sufficient data */
n = Ntokens;
if (n < 3) return(201);
/* Check first keyword */
if (match(Tok[0],w_DMNDCHARGE)) /* Demand charge */
{
if (!getfloat(Tok[2], &y)) return(213);
Dcost = y;
return(0);
}
if (match(Tok[0],w_GLOBAL)) /* Global parameter */
{
j = 0;
}
else if (match(Tok[0],w_PUMP)) /* Pump-specific parameter */
{
if (n < 4) return(201);
k = findlink(Tok[1]); /* Check that pump exists */
if (k == 0) return(216);
if (Link[k].Type != PUMP) return(216);
j = PUMPINDEX(k);
}
else return(201);
/* Find type of energy parameter */
if (match(Tok[n-2],w_PRICE)) /* Energy price */
{
if (!getfloat(Tok[n-1],&y))
{
if (j == 0) return(213);
else return(217);
}
if (j == 0) Ecost = y;
else Pump[j].Ecost = y;
return(0);
}
else if (match(Tok[n-2],w_PATTERN)) /* Price pattern */
{
t = findID(Tok[n-1],Patlist); /* Check if pattern exists */
if (t == NULL)
{
if (j == 0) return(213);
else return(217);
}
if (j == 0) Epat = t->i;
else Pump[j].Epat = t->i;
return(0);
}
else if (match(Tok[n-2],w_EFFIC)) /* Pump efficiency */
{
if (j == 0)
{
if (!getfloat(Tok[n-1], &y)) return(213);
if (y <= 0.0) return(213);
Epump = y;
}
else
{
t = findID(Tok[n-1],Curvelist); /* Check if curve exists */
if (t == NULL) return(217);
Pump[j].Ecurve = t->i;
}
return(0);
}
return(201);
}
int reportdata()
/*
**--------------------------------------------------------------
** Input: none
** Output: returns error code
** Purpose: processes report options data
** Formats:
** PAGE linesperpage
** STATUS {NONE/YES/FULL}
** SUMMARY {YES/NO}
** MESSAGES {YES/NO}
** ENERGY {NO/YES}
** NODES {NONE/ALL}
** NODES node1 node2 ...
** LINKS {NONE/ALL}
** LINKS link1 link2 ...
** FILE filename
** variable {YES/NO}
** variable {BELOW/ABOVE/PRECISION} value
**--------------------------------------------------------------
*/
{
int i,j,n;
double y;
n = Ntokens - 1;
if (n < 1) return(201);
/* Value for page size */
if (match(Tok[0],w_PAGE))
{
if (!getfloat(Tok[n],&y)) return(213);
if (y < 0.0 || y > 255.0) return(213);
PageSize = (int) y;
return(0);
}
/* Request that status reports be written */
if (match(Tok[0],w_STATUS))
{
if (match(Tok[n],w_NO)) Statflag = FALSE;
if (match(Tok[n],w_YES)) Statflag = TRUE;
if (match(Tok[n],w_FULL)) Statflag = FULL;
return(0);
}
/* Request summary report */
if (match(Tok[0],w_SUMMARY))
{
if (match(Tok[n],w_NO)) Summaryflag = FALSE;
if (match(Tok[n],w_YES)) Summaryflag = TRUE;
return(0);
}
/* Request error/warning message reporting */
if (match(Tok[0],w_MESSAGES))
{
if (match(Tok[n],w_NO)) Messageflag = FALSE;
if (match(Tok[n],w_YES)) Messageflag = TRUE;
return(0);
}
/* Request an energy usage report */
if (match(Tok[0],w_ENERGY))
{
if (match(Tok[n],w_NO)) Energyflag = FALSE;
if (match(Tok[n],w_YES)) Energyflag = TRUE;
return(0);
}
/* Particular reporting nodes specified */
if (match(Tok[0],w_NODE))
{
if (match(Tok[n],w_NONE)) Nodeflag = 0; /* No nodes */
else if (match(Tok[n],w_ALL)) Nodeflag = 1; /* All nodes */
else
{
if (Nnodes == 0) return(208);
for (i=1; i<=n; i++)
{
if ( (j = findnode(Tok[i])) == 0) return(208);
Node[j].Rpt = 1;
}
Nodeflag = 2;
}
return(0);
}
/* Particular reporting links specified */
if (match(Tok[0],w_LINK))
{
if (match(Tok[n],w_NONE)) Linkflag = 0;
else if (match(Tok[n],w_ALL)) Linkflag = 1;
else
{
if (Nlinks == 0) return(210);
for (i=1; i<=n; i++)
{
if ( (j = findlink(Tok[i])) == 0) return(210);
Link[j].Rpt = 1;
}
Linkflag = 2;
}
return(0);
}
/* Check if input is a reporting criterion. */
/*** Special case needed to distinguish "HEAD" from "HEADLOSS" ***/ //(2.00.11 - LR)
if (strcomp(Tok[0], w_HEADLOSS)) i = HEADLOSS; //(2.00.11 - LR)
else i = findmatch(Tok[0],Fldname); //(2.00.11 - LR)
if (i >= 0) //(2.00.11 - LR)
/*****************************************************************/ //(2.00.11 - LR)
{
if (i > FRICTION) return(201);
if (Ntokens == 1 || match(Tok[1],w_YES))
{
Field[i].Enabled = TRUE;
return(0);
}
if (match(Tok[1],w_NO))
{
Field[i].Enabled = FALSE;
return(0);
}
if (Ntokens < 3) return(201);
if (match(Tok[1],w_BELOW)) j = LOW; /* Get relation operator */
else if (match(Tok[1],w_ABOVE)) j = HI; /* or precision keyword */
else if (match(Tok[1],w_PRECISION)) j = PREC;
else return(201);
if (!getfloat(Tok[2],&y)) return(201);
if (j == PREC)
{
Field[i].Enabled = TRUE;
Field[i].Precision = ROUND(y);
}
else Field[i].RptLim[j] = y; /* Report limit value */
return(0);
}
/* Name of external report file */
if (match(Tok[0],w_FILE))
{
strncpy(Rpt2Fname,Tok[1],MAXFNAME);
return(0);
}
/* If get to here then return error condition */
return(201);
} /* end of reportdata */
int timedata()
/*
**--------------------------------------------------------------
** Input: none
** Output: returns error code
** Purpose: processes time options data
** Formats:
** STATISTIC {NONE/AVERAGE/MIN/MAX/RANGE}
** DURATION value (units)
** HYDRAULIC TIMESTEP value (units)
** QUALITY TIMESTEP value (units)
** MINIMUM TRAVELTIME value (units)
** RULE TIMESTEP value (units)
** PATTERN TIMESTEP value (units)
** PATTERN START value (units)
** REPORT TIMESTEP value (units)
** REPORT START value (units)
** START CLOCKTIME value (AM PM)
**-------------------------------------------------------------
*/
{
int n;
long t;
double y;
n = Ntokens - 1;
if (n < 1) return(201);
/* Check if setting time statistic flag */
if (match(Tok[0],w_STATISTIC))
{
if (match(Tok[n],w_NONE)) Tstatflag = SERIES;
else if (match(Tok[n],w_NO)) Tstatflag = SERIES;
else if (match(Tok[n],w_AVG)) Tstatflag = AVG;
else if (match(Tok[n],w_MIN)) Tstatflag = MIN;
else if (match(Tok[n],w_MAX)) Tstatflag = MAX;
else if (match(Tok[n],w_RANGE)) Tstatflag = RANGE;
else return(201);
return(0);
}
/* Convert text time value to numerical value in seconds */
/* Examples:
** 5 = 5 * 3600 sec
** 5 MINUTES = 5 * 60 sec
** 13:50 = 13*3600 + 50*60 sec
** 1:50 pm = (12+1)*3600 + 50*60 sec
*/
if (!getfloat(Tok[n],&y))
{
if ( (y = hour(Tok[n],"")) < 0.0)
{
if ( (y = hour(Tok[n-1],Tok[n])) < 0.0) return(213);
}
}
t = (long)(3600.0*y+0.5);
/* Process the value assigned to the matched parameter */
if (match(Tok[0],w_DURATION)) Dur = t; /* Simulation duration */
else if (match(Tok[0],w_HYDRAULIC)) Hstep = t; /* Hydraulic time step */
else if (match(Tok[0],w_QUALITY)) Qstep = t; /* Quality time step */
else if (match(Tok[0],w_RULE)) Rulestep = t; /* Rule time step */
else if (match(Tok[0],w_MINIMUM)) return(0); /* Not used anymore */
else if (match(Tok[0],w_PATTERN))
{
if (match(Tok[1],w_TIME)) Pstep = t; /* Pattern time step */
else if (match(Tok[1],w_START)) Pstart = t; /* Pattern start time */
else return(201);
}
else if (match(Tok[0],w_REPORT))
{
if (match(Tok[1],w_TIME)) Rstep = t; /* Reporting time step */
else if (match(Tok[1],w_START)) Rstart = t; /* Reporting start time */
else return(201);
} /* Simulation start time*/
else if (match(Tok[0],w_START)) Tstart = t % SECperDAY;
else return(201);
return(0);
} /* end of timedata */
int optiondata()
/*
**--------------------------------------------------------------
** Input: none
** Output: returns error code
** Purpose: processes [OPTIONS] data
**--------------------------------------------------------------
*/
{
int i,n;
n = Ntokens - 1;
i = optionchoice(n); /* Option is a named choice */
if (i >= 0) return(i);
return(optionvalue(n)); /* Option is a numerical value */
} /* end of optiondata */
int optionchoice(int n)
/*
**--------------------------------------------------------------
** Input: n = index of last input token saved in Tok[]
** Output: returns error code or 0 if option belongs to
** those listed below, or -1 otherwise
** Purpose: processes fixed choice [OPTIONS] data
** Formats:
** UNITS CFS/GPM/MGD/IMGD/AFD/LPS/LPM/MLD/CMH/CMD/SI
** PRESSURE PSI/KPA/M
** HEADLOSS H-W/D-W/C-M
** HYDRAULICS USE/SAVE filename
** QUALITY NONE/AGE/TRACE/CHEMICAL (TraceNode)
** MAP filename
** VERIFY filename
** UNBALANCED STOP/CONTINUE {Niter}
** PATTERN id
**--------------------------------------------------------------
*/
{
/* Check if 1st token matches a parameter name and */
/* process the input for the matched parameter */
if (n < 0) return(201);
if (match(Tok[0],w_UNITS))
{
if (n < 1) return(0);
else if (match(Tok[1],w_CFS)) Flowflag = CFS;
else if (match(Tok[1],w_GPM)) Flowflag = GPM;
else if (match(Tok[1],w_AFD)) Flowflag = AFD;
else if (match(Tok[1],w_MGD)) Flowflag = MGD;
else if (match(Tok[1],w_IMGD)) Flowflag = IMGD;
else if (match(Tok[1],w_LPS)) Flowflag = LPS;
else if (match(Tok[1],w_LPM)) Flowflag = LPM;
else if (match(Tok[1],w_CMH)) Flowflag = CMH;
else if (match(Tok[1],w_CMD)) Flowflag = CMD;
else if (match(Tok[1],w_MLD)) Flowflag = MLD;
else if (match(Tok[1],w_SI)) Flowflag = LPS;
else return(201);
}
else if (match(Tok[0],w_PRESSURE))
{
if (n < 1) return(0);
else if (match(Tok[1],w_PSI)) Pressflag = PSI;
else if (match(Tok[1],w_KPA)) Pressflag = KPA;
else if (match(Tok[1],w_METERS)) Pressflag = METERS;
else return(201);
}
else if (match(Tok[0],w_HEADLOSS))
{
if (n < 1) return(0);
else if (match(Tok[1],w_HW)) Formflag = HW;
else if (match(Tok[1],w_DW)) Formflag = DW;
else if (match(Tok[1],w_CM)) Formflag = CM;
else return(201);
}
else if (match(Tok[0],w_HYDRAULIC))
{
if (n < 2) return(0);
else if (match(Tok[1],w_USE)) Hydflag = USE;
else if (match(Tok[1],w_SAVE)) Hydflag = SAVE;
else return(201);
strncpy(HydFname,Tok[2],MAXFNAME);
}
else if (match(Tok[0],w_QUALITY))
{
if (n < 1) return(0);
else if (match(Tok[1],w_NONE)) Qualflag = NONE;
else if (match(Tok[1],w_CHEM)) Qualflag = CHEM;
else if (match(Tok[1],w_AGE)) Qualflag = AGE;
else if (match(Tok[1],w_TRACE)) Qualflag = TRACE;
else
{
Qualflag = CHEM;
strncpy(ChemName,Tok[1],MAXID);
if (n >= 2) strncpy(ChemUnits,Tok[2],MAXID);
}
if (Qualflag == TRACE) /* Source tracing option */
{
/* Copy Trace Node ID to Tok[0] for error reporting */
strcpy(Tok[0],"");
if (n < 2) return(212);
strcpy(Tok[0],Tok[2]);
TraceNode = findnode(Tok[2]);
if (TraceNode == 0) return(212);
strncpy(ChemName,u_PERCENT,MAXID);
strncpy(ChemUnits,Tok[2],MAXID);
}
if (Qualflag == AGE)
{
strncpy(ChemName,w_AGE,MAXID);
strncpy(ChemUnits,u_HOURS,MAXID);
}
}
else if (match(Tok[0],w_MAP))
{
if (n < 1) return(0);
strncpy(MapFname,Tok[1],MAXFNAME); /* Map file name */
}
else if (match(Tok[0],w_VERIFY))
{
/* Backward compatibility for verification file */
}
else if (match(Tok[0],w_UNBALANCED)) /* Unbalanced option */
{
if (n < 1) return(0);
if (match(Tok[1],w_STOP)) ExtraIter = -1;
else if (match(Tok[1],w_CONTINUE))
{
if (n >= 2) ExtraIter = atoi(Tok[2]);
else ExtraIter = 0;
}
else return(201);
}
else if (match(Tok[0],w_PATTERN)) /* Pattern option */
{
if (n < 1) return(0);
strncpy(DefPatID,Tok[1],MAXID);
}
else return(-1);
return(0);
} /* end of optionchoice */
int optionvalue(int n)
/*
**-------------------------------------------------------------
** Input: *line = line read from input file
** Output: returns error code
** Purpose: processes numerical value [OPTIONS] data
** Formats:
** DEMAND MULTIPLIER value
** EMITTER EXPONENT value
** VISCOSITY value
** DIFFUSIVITY value
** SPECIFIC GRAVITY value
** TRIALS value
** ACCURACY value
** TOLERANCE value
** SEGMENTS value (not used)
** ------ Undocumented Options -----
** HTOL value
** QTOL value
** RQTOL value
** CHECKFREQ value
** MAXCHECK value
** DAMPLIMIT value //(2.00.12 - LR)
**--------------------------------------------------------------
*/
{
int nvalue = 1; /* Index of token with numerical value */
double y;
/* Check for obsolete SEGMENTS keyword */
if (match(Tok[0],w_SEGMENTS)) return(0);
/* Check for missing value (which is permissible) */
if (match(Tok[0],w_SPECGRAV) || match(Tok[0],w_EMITTER)
|| match(Tok[0],w_DEMAND)) nvalue = 2;
if (n < nvalue) return(0);
/* Check for valid numerical input */
if (!getfloat(Tok[nvalue],&y)) return(213);
/* Check for WQ tolerance option (which can be 0) */
if (match(Tok[0],w_TOLERANCE))
{
if (y < 0.0) return(213);
Ctol = y; /* Quality tolerance*/
return(0);
}
/* Check for Diffusivity option */
if (match(Tok[0],w_DIFFUSIVITY))
{
if (y < 0.0) return(213);
Diffus = y;
return(0);
}
/* Check for Damping Limit option */ //(2.00.12 - LR)
if (match(Tok[0],w_DAMPLIMIT))
{
DampLimit = y;
return(0);
}
/* All other options must be > 0 */
if (y <= 0.0) return(213);
/* Assign value to specified option */
if (match(Tok[0],w_VISCOSITY)) Viscos = y; /* Viscosity */
else if (match(Tok[0],w_SPECGRAV)) SpGrav = y; /* Spec. gravity */
else if (match(Tok[0],w_TRIALS)) MaxIter = (int)y; /* Max. trials */
else if (match(Tok[0],w_ACCURACY)) /* Accuracy */
{
y = MAX(y,1.e-5);
y = MIN(y,1.e-1);
Hacc = y;
}
else if (match(Tok[0],w_HTOL)) Htol = y;
else if (match(Tok[0],w_QTOL)) Qtol = y;
else if (match(Tok[0],w_RQTOL))
{
if (y >= 1.0) return(213);
RQtol = y;
}
else if (match(Tok[0],w_CHECKFREQ)) CheckFreq = (int)y;
else if (match(Tok[0],w_MAXCHECK)) MaxCheck = (int)y;
else if (match(Tok[0],w_EMITTER)) Qexp = 1.0/y;
else if (match(Tok[0],w_DEMAND)) Dmult = y;
else return(201);
return(0);
} /* end of optionvalue */
int getpumpcurve(int n)
/*
**--------------------------------------------------------
** Input: n = number of parameters for pump curve
** Output: returns error code
** Purpose: processes pump curve data for Version 1.1-
** style input data
** Notes:
** 1. Called by pumpdata() in INPUT3.C
** 2. Current link index & pump index of pump being
** processed is found in global variables Nlinks
** and Npumps, respectively
** 3. Curve data read from input line is found in
** global variables X[0],...X[n-1]
**---------------------------------------------------------
*/
{
double a,b,c,h0,h1,h2,q1,q2;
if (n == 1) /* Const. HP curve */
{
if (X[0] <= 0.0) return(202);
Pump[Npumps].Ptype = CONST_HP;
Link[Nlinks].Km = X[0];
}
else
{
if (n == 2) /* Generic power curve */
{
q1 = X[1];
h1 = X[0];
h0 = 1.33334*h1;
q2 = 2.0*q1;
h2 = 0.0;
}
else if (n >= 5) /* 3-pt. power curve */
{
h0 = X[0];
h1 = X[1];
q1 = X[2];
h2 = X[3];
q2 = X[4];
}
else return(202);
Pump[Npumps].Ptype = POWER_FUNC;
if (!powercurve(h0,h1,h2,q1,q2,&a,&b,&c)) return(206);
Pump[Npumps].H0 = -a;
Pump[Npumps].R = -b;
Pump[Npumps].N = c;
Pump[Npumps].Q0 = q1;
Pump[Npumps].Qmax = pow((-a/b),(1.0/c));
Pump[Npumps].Hmax = h0;
}
return(0);
}
int powercurve(double h0, double h1, double h2, double q1,
double q2, double *a, double *b, double *c)
/*
**---------------------------------------------------------
** Input: h0 = shutoff head
** h1 = design head
** h2 = head at max. flow
** q1 = design flow
** q2 = max. flow
** Output: *a, *b, *c = pump curve coeffs. (H = a-bQ^c),
** Returns 1 if sucessful, 0 otherwise.
** Purpose: computes coeffs. for pump curve
**----------------------------------------------------------
*/
{
double h4,h5;
if (
h0 < TINY ||
h0 - h1 < TINY ||
h1 - h2 < TINY ||
q1 < TINY ||
q2 - q1 < TINY
) return(0);
*a = h0;
h4 = h0 - h1;
h5 = h0 - h2;
*c = log(h5/h4)/log(q2/q1);
if (*c <= 0.0 || *c > 20.0) return(0);
*b = -h4/pow(q1,*c);
/*** Updated 6/24/02 ***/
if (*b >= 0.0) return(0);
return(1);
}
int valvecheck(int type, int j1, int j2)
/*
**--------------------------------------------------------------
** Input: type = valve type
** j1 = index of upstream node
** j2 = index of downstream node
** Output: returns 1 for legal connection, 0 otherwise
** Purpose: checks for legal connections between PRVs & PSVs
**--------------------------------------------------------------
*/
{
int k, vk, vj1, vj2, vtype;
/* Examine each existing valve */
for (k=1; k<=Nvalves; k++)
{
vk = Valve[k].Link;
vj1 = Link[vk].N1;
vj2 = Link[vk].N2;
vtype = Link[vk].Type;
/* Cannot have two PRVs sharing downstream nodes or in series */
if (vtype == PRV && type == PRV)
{
if (vj2 == j2 ||
vj2 == j1 ||
vj1 == j2 ) return(0);
}
/* Cannot have two PSVs sharing upstream nodes or in series */
if (vtype == PSV && type == PSV)
{
if (vj1 == j1 ||
vj1 == j2 ||
vj2 == j1 ) return(0);
}
/* Cannot have PSV connected to downstream node of PRV */
if (vtype == PSV && type == PRV && vj1 == j2) return(0);
if (vtype == PRV && type == PSV && vj2 == j1) return(0);
/*** Updated 3/1/01 ***/
/* Cannot have PSV connected to downstream node of FCV */
/* nor have PRV connected to upstream node of FCV */
if (vtype == FCV && type == PSV && vj2 == j1) return(0);
if (vtype == FCV && type == PRV && vj1 == j2) return(0);
/*** Updated 4/14/05 ***/
if (vtype == PSV && type == FCV && vj1 == j2) return (0);
if (vtype == PRV && type == FCV && vj2 == j1) return (0);
}
return(1);
} /* End of valvecheck */
void changestatus(int j, char status, double y)
/*
**--------------------------------------------------------------
** Input: j = link index
** status = status setting (OPEN, CLOSED)
** y = numerical setting (pump speed, valve
** setting)
** Output: none
** Purpose: changes status or setting of a link
**
** NOTE: If status = ACTIVE, then a numerical setting (y) was
** supplied. If status = OPEN/CLOSED, then numerical
** setting is 0.
**--------------------------------------------------------------
*/
{
if (Link[j].Type == PIPE || Link[j].Type == GPV)
{
if (status != ACTIVE) Link[j].Stat = status;
}
else if (Link[j].Type == PUMP)
{
if (status == ACTIVE)
{
Link[j].Kc = y;
status = OPEN;
if (y == 0.0) status = CLOSED;
}
else if (status == OPEN) Link[j].Kc = 1.0;
Link[j].Stat = status;
}
else if (Link[j].Type >= PRV)
{
Link[j].Kc = y;
Link[j].Stat = status;
if (status != ACTIVE) Link[j].Kc = MISSING;
}
} /* end of changestatus */
/********************** END OF INPUT3.C ************************/