epanet-plus 0.2.1__cp311-cp311-macosx_11_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- docs/conf.py +67 -0
- epanet-msx-src/dispersion.h +27 -0
- epanet-msx-src/hash.c +107 -0
- epanet-msx-src/hash.h +28 -0
- epanet-msx-src/include/epanetmsx.h +104 -0
- epanet-msx-src/include/epanetmsx_export.h +42 -0
- epanet-msx-src/mathexpr.c +937 -0
- epanet-msx-src/mathexpr.h +39 -0
- epanet-msx-src/mempool.c +204 -0
- epanet-msx-src/mempool.h +24 -0
- epanet-msx-src/msxchem.c +1285 -0
- epanet-msx-src/msxcompiler.c +368 -0
- epanet-msx-src/msxdict.h +42 -0
- epanet-msx-src/msxdispersion.c +586 -0
- epanet-msx-src/msxerr.c +116 -0
- epanet-msx-src/msxfile.c +260 -0
- epanet-msx-src/msxfuncs.c +175 -0
- epanet-msx-src/msxfuncs.h +35 -0
- epanet-msx-src/msxinp.c +1504 -0
- epanet-msx-src/msxout.c +398 -0
- epanet-msx-src/msxproj.c +791 -0
- epanet-msx-src/msxqual.c +2011 -0
- epanet-msx-src/msxrpt.c +400 -0
- epanet-msx-src/msxtank.c +422 -0
- epanet-msx-src/msxtoolkit.c +1164 -0
- epanet-msx-src/msxtypes.h +551 -0
- epanet-msx-src/msxutils.c +524 -0
- epanet-msx-src/msxutils.h +56 -0
- epanet-msx-src/newton.c +158 -0
- epanet-msx-src/newton.h +34 -0
- epanet-msx-src/rk5.c +287 -0
- epanet-msx-src/rk5.h +39 -0
- epanet-msx-src/ros2.c +293 -0
- epanet-msx-src/ros2.h +35 -0
- epanet-msx-src/smatrix.c +816 -0
- epanet-msx-src/smatrix.h +29 -0
- epanet-src/AUTHORS +60 -0
- epanet-src/LICENSE +21 -0
- epanet-src/enumstxt.h +151 -0
- epanet-src/epanet.c +5937 -0
- epanet-src/epanet2.c +961 -0
- epanet-src/epanet2.def +131 -0
- epanet-src/errors.dat +79 -0
- epanet-src/flowbalance.c +186 -0
- epanet-src/funcs.h +219 -0
- epanet-src/genmmd.c +1000 -0
- epanet-src/hash.c +177 -0
- epanet-src/hash.h +28 -0
- epanet-src/hydcoeffs.c +1303 -0
- epanet-src/hydraul.c +1164 -0
- epanet-src/hydsolver.c +781 -0
- epanet-src/hydstatus.c +442 -0
- epanet-src/include/epanet2.h +466 -0
- epanet-src/include/epanet2_2.h +1962 -0
- epanet-src/include/epanet2_enums.h +518 -0
- epanet-src/inpfile.c +884 -0
- epanet-src/input1.c +672 -0
- epanet-src/input2.c +970 -0
- epanet-src/input3.c +2265 -0
- epanet-src/leakage.c +527 -0
- epanet-src/mempool.c +146 -0
- epanet-src/mempool.h +24 -0
- epanet-src/output.c +853 -0
- epanet-src/project.c +1691 -0
- epanet-src/quality.c +695 -0
- epanet-src/qualreact.c +800 -0
- epanet-src/qualroute.c +696 -0
- epanet-src/report.c +1559 -0
- epanet-src/rules.c +1500 -0
- epanet-src/smatrix.c +871 -0
- epanet-src/text.h +508 -0
- epanet-src/types.h +928 -0
- epanet-src/util/cstr_helper.c +59 -0
- epanet-src/util/cstr_helper.h +38 -0
- epanet-src/util/errormanager.c +92 -0
- epanet-src/util/errormanager.h +39 -0
- epanet-src/util/filemanager.c +212 -0
- epanet-src/util/filemanager.h +81 -0
- epanet-src/validate.c +408 -0
- epanet.cpython-311-darwin.so +0 -0
- epanet_plus/VERSION +1 -0
- epanet_plus/__init__.py +8 -0
- epanet_plus/epanet_plus.c +118 -0
- epanet_plus/epanet_toolkit.py +2833 -0
- epanet_plus/epanet_wrapper.py +2434 -0
- epanet_plus/include/epanet_plus.h +9 -0
- epanet_plus-0.2.1.dist-info/METADATA +157 -0
- epanet_plus-0.2.1.dist-info/RECORD +106 -0
- epanet_plus-0.2.1.dist-info/WHEEL +6 -0
- epanet_plus-0.2.1.dist-info/licenses/LICENSE +21 -0
- epanet_plus-0.2.1.dist-info/top_level.txt +11 -0
- examples/basic_usage.py +35 -0
- examples/epanet_msx.py +35 -0
- python-extension/ext.c +344 -0
- python-extension/pyepanet.c +2771 -0
- python-extension/pyepanet.h +144 -0
- python-extension/pyepanet2.c +2453 -0
- python-extension/pyepanet2.h +142 -0
- python-extension/pyepanet_plus.c +43 -0
- python-extension/pyepanet_plus.h +4 -0
- python-extension/pyepanetmsx.c +524 -0
- python-extension/pyepanetmsx.h +35 -0
- tests/test_epanet.py +18 -0
- tests/test_epanetmsx.py +38 -0
- tests/test_epyt.py +115 -0
- tests/test_load_inp_from_buffer.py +59 -0
epanet-src/input3.c
ADDED
|
@@ -0,0 +1,2265 @@
|
|
|
1
|
+
/*
|
|
2
|
+
******************************************************************************
|
|
3
|
+
Project: OWA EPANET
|
|
4
|
+
Version: 2.3
|
|
5
|
+
Module: input3.c
|
|
6
|
+
Description: parses network data from a line of an EPANET input file
|
|
7
|
+
Authors: see AUTHORS
|
|
8
|
+
Copyright: see AUTHORS
|
|
9
|
+
License: see LICENSE
|
|
10
|
+
Last Updated: 04/19/2025
|
|
11
|
+
******************************************************************************
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
#include <stdlib.h>
|
|
15
|
+
#include <stdio.h>
|
|
16
|
+
#include <string.h>
|
|
17
|
+
#include <math.h>
|
|
18
|
+
|
|
19
|
+
#include "types.h"
|
|
20
|
+
#include "funcs.h"
|
|
21
|
+
#include "hash.h"
|
|
22
|
+
#include "text.h"
|
|
23
|
+
|
|
24
|
+
// Defined in ENUMSTXT.H
|
|
25
|
+
extern char *MixTxt[];
|
|
26
|
+
extern char *Fldname[];
|
|
27
|
+
extern char *DemandModelTxt[];
|
|
28
|
+
extern char *BackflowTxt[];
|
|
29
|
+
extern char *CurveTypeTxt[];
|
|
30
|
+
|
|
31
|
+
// Imported Functions
|
|
32
|
+
extern int addnodeID(Network *, int, char *);
|
|
33
|
+
extern int addlinkID(Network *, int, char *);
|
|
34
|
+
extern int getunitsoption(Project *, char *);
|
|
35
|
+
extern int getheadlossoption(Project *, char *);
|
|
36
|
+
|
|
37
|
+
// Local functions
|
|
38
|
+
static double gettokvalue(Project *, double, int, int *, int *);
|
|
39
|
+
static int getlinknodes(Project *, int *, int *);
|
|
40
|
+
static int optionchoice(Project *, int);
|
|
41
|
+
static int optionvalue(Project *, int);
|
|
42
|
+
static int getpumpcurve(Project *, int);
|
|
43
|
+
static void changestatus(Network *, int, StatusType, double);
|
|
44
|
+
static int setError(Parser *, int, int);
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
int setError(Parser *parser, int tokindex, int errcode)
|
|
48
|
+
/*
|
|
49
|
+
**--------------------------------------------------------------
|
|
50
|
+
** Input: tokindex = index of input line token
|
|
51
|
+
** errcode = an error code
|
|
52
|
+
** Output: returns error code
|
|
53
|
+
** Purpose: records index of token from line of input associated
|
|
54
|
+
** with an error
|
|
55
|
+
**--------------------------------------------------------------
|
|
56
|
+
*/
|
|
57
|
+
{
|
|
58
|
+
parser->ErrTok = tokindex;
|
|
59
|
+
return errcode;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
int juncdata(Project *pr)
|
|
63
|
+
/*
|
|
64
|
+
**--------------------------------------------------------------
|
|
65
|
+
** Input: none
|
|
66
|
+
** Output: returns error code
|
|
67
|
+
** Purpose: processes junction data
|
|
68
|
+
** Format:
|
|
69
|
+
** [JUNCTIONS]
|
|
70
|
+
** id elev. (demand) (demand pattern)
|
|
71
|
+
**--------------------------------------------------------------
|
|
72
|
+
*/
|
|
73
|
+
{
|
|
74
|
+
Network *net = &pr->network;
|
|
75
|
+
Parser *parser = &pr->parser;
|
|
76
|
+
Hydraul *hyd = &pr->hydraul;
|
|
77
|
+
|
|
78
|
+
int p = 0; // time pattern index
|
|
79
|
+
int n; // number of tokens
|
|
80
|
+
int njuncs; // number of network junction nodes
|
|
81
|
+
double el = 0.0, // elevation
|
|
82
|
+
d = 0.0, // base demand
|
|
83
|
+
x;
|
|
84
|
+
Snode *node;
|
|
85
|
+
int errcode = 0;
|
|
86
|
+
int errtok = -1;
|
|
87
|
+
|
|
88
|
+
// Add new junction to data base
|
|
89
|
+
if (net->Nnodes == parser->MaxNodes) return 200;
|
|
90
|
+
errcode = addnodeID(net, net->Njuncs + 1, parser->Tok[0]);
|
|
91
|
+
if (errcode > 0) return setError(parser, 0, errcode);
|
|
92
|
+
net->Njuncs++;
|
|
93
|
+
net->Nnodes++;
|
|
94
|
+
|
|
95
|
+
// Check for valid data
|
|
96
|
+
n = parser->Ntokens;
|
|
97
|
+
if (n > 1)
|
|
98
|
+
{
|
|
99
|
+
if (!getfloat(parser->Tok[1], &x))
|
|
100
|
+
{
|
|
101
|
+
errcode = 202;
|
|
102
|
+
errtok = 1;
|
|
103
|
+
}
|
|
104
|
+
else el = x;
|
|
105
|
+
}
|
|
106
|
+
if (!errcode && n > 2)
|
|
107
|
+
{
|
|
108
|
+
if (!getfloat(parser->Tok[2], &x))
|
|
109
|
+
{
|
|
110
|
+
errcode = 202;
|
|
111
|
+
errtok = 2;
|
|
112
|
+
}
|
|
113
|
+
else d = x;
|
|
114
|
+
}
|
|
115
|
+
if (!errcode && n > 3)
|
|
116
|
+
{
|
|
117
|
+
p = findpattern(net, parser->Tok[3]);
|
|
118
|
+
if (p < 0)
|
|
119
|
+
{
|
|
120
|
+
errcode = 205;
|
|
121
|
+
errtok = 3;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Save junction data
|
|
126
|
+
njuncs = net->Njuncs;
|
|
127
|
+
node = &net->Node[njuncs];
|
|
128
|
+
node->X = MISSING;
|
|
129
|
+
node->Y = MISSING;
|
|
130
|
+
node->El = el;
|
|
131
|
+
node->C0 = 0.0;
|
|
132
|
+
node->S = NULL;
|
|
133
|
+
node->Ke = 0.0;
|
|
134
|
+
node->Rpt = 0;
|
|
135
|
+
node->ResultIndex = 0;
|
|
136
|
+
node->Type = JUNCTION;
|
|
137
|
+
node->Comment = xstrcpy(&node->Comment, parser->Comment, MAXMSG);
|
|
138
|
+
|
|
139
|
+
// Create a demand for the junction and use NodeDemand as an indicator
|
|
140
|
+
// to be used when processing demands from the [DEMANDS] section
|
|
141
|
+
if (!adddemand(node, d, p, NULL)) return 101;
|
|
142
|
+
hyd->NodeDemand[njuncs] = d;
|
|
143
|
+
|
|
144
|
+
// Return error code
|
|
145
|
+
if (errcode > 0) return setError(parser, errtok, errcode);
|
|
146
|
+
return 0;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
int tankdata(Project *pr)
|
|
150
|
+
/*
|
|
151
|
+
**--------------------------------------------------------------
|
|
152
|
+
** Input: none
|
|
153
|
+
** Output: returns error code
|
|
154
|
+
** Purpose: processes tank & reservoir data
|
|
155
|
+
** Format:
|
|
156
|
+
** [RESERVOIRS]
|
|
157
|
+
** id elev (pattern)
|
|
158
|
+
** [TANKS]
|
|
159
|
+
** id elev initlevel minlevel maxlevel diam (minvol vcurve)
|
|
160
|
+
**--------------------------------------------------------------
|
|
161
|
+
*/
|
|
162
|
+
{
|
|
163
|
+
Network *net = &pr->network;
|
|
164
|
+
Parser *parser = &pr->parser;
|
|
165
|
+
|
|
166
|
+
int i, // Node index
|
|
167
|
+
n, // # data items
|
|
168
|
+
pattern = 0, // Time pattern index
|
|
169
|
+
curve = 0, // Curve index
|
|
170
|
+
overflow = FALSE;// Overflow indicator
|
|
171
|
+
|
|
172
|
+
double el = 0.0, // Elevation
|
|
173
|
+
initlevel = 0.0, // Initial level
|
|
174
|
+
minlevel = 0.0, // Minimum level
|
|
175
|
+
maxlevel = 0.0, // Maximum level
|
|
176
|
+
minvol = 0.0, // Minimum volume
|
|
177
|
+
diam = 0.0, // Diameter
|
|
178
|
+
area; // X-sect. area
|
|
179
|
+
Snode *node;
|
|
180
|
+
Stank *tank;
|
|
181
|
+
|
|
182
|
+
int errcode = 0;
|
|
183
|
+
int errtok = -1;
|
|
184
|
+
double x;
|
|
185
|
+
|
|
186
|
+
// Add new tank to data base
|
|
187
|
+
if (net->Ntanks == parser->MaxTanks ||
|
|
188
|
+
net->Nnodes == parser->MaxNodes) return 200;
|
|
189
|
+
i = parser->MaxJuncs + net->Ntanks + 1;
|
|
190
|
+
errcode = addnodeID(net, i, parser->Tok[0]);
|
|
191
|
+
if (errcode) return setError(parser, 0, errcode);
|
|
192
|
+
net->Ntanks++;
|
|
193
|
+
net->Nnodes++;
|
|
194
|
+
|
|
195
|
+
// Check for valid data
|
|
196
|
+
n = parser->Ntokens;
|
|
197
|
+
if (n < 2) errcode = 201;
|
|
198
|
+
if (!errcode && !getfloat(parser->Tok[1], &x))
|
|
199
|
+
{
|
|
200
|
+
errcode = 202;
|
|
201
|
+
errtok = 1;
|
|
202
|
+
}
|
|
203
|
+
else el = x;
|
|
204
|
+
|
|
205
|
+
// Node is a reservoir
|
|
206
|
+
if (n <= 3)
|
|
207
|
+
{
|
|
208
|
+
// Head pattern supplied
|
|
209
|
+
if (n == 3 && !errcode)
|
|
210
|
+
{
|
|
211
|
+
pattern = findpattern(net, parser->Tok[2]);
|
|
212
|
+
if (pattern < 0)
|
|
213
|
+
{
|
|
214
|
+
errcode = 205;
|
|
215
|
+
errtok = 2;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Node is a storage tank
|
|
221
|
+
else if (!errcode)
|
|
222
|
+
{
|
|
223
|
+
if (n < 6) errcode = 201;
|
|
224
|
+
else
|
|
225
|
+
{
|
|
226
|
+
// Read required data
|
|
227
|
+
initlevel = gettokvalue(pr, initlevel, 2, &errcode, &errtok);
|
|
228
|
+
minlevel = gettokvalue(pr, minlevel, 3, &errcode, &errtok);
|
|
229
|
+
maxlevel = gettokvalue(pr, maxlevel, 4, &errcode, &errtok);
|
|
230
|
+
diam = gettokvalue(pr, diam, 5, &errcode, &errtok);
|
|
231
|
+
if (n >= 7) minvol = gettokvalue(pr, minvol, 6, &errcode, &errtok);
|
|
232
|
+
|
|
233
|
+
// If volume curve supplied check it exists
|
|
234
|
+
if (!errcode && n >= 8)
|
|
235
|
+
{
|
|
236
|
+
if (strlen(parser->Tok[7]) > 0 && *(parser->Tok[7]) != '*')
|
|
237
|
+
{
|
|
238
|
+
curve = findcurve(net, parser->Tok[7]);
|
|
239
|
+
if (curve == 0)
|
|
240
|
+
{
|
|
241
|
+
errcode = 206;
|
|
242
|
+
errtok = 7;
|
|
243
|
+
}
|
|
244
|
+
else net->Curve[curve].Type = VOLUME_CURVE;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Read overflow indicator if present
|
|
249
|
+
if (!errcode && n >= 9)
|
|
250
|
+
{
|
|
251
|
+
if (match(parser->Tok[8], w_YES)) overflow = TRUE;
|
|
252
|
+
else if (match(parser->Tok[8], w_NO)) overflow = FALSE;
|
|
253
|
+
else
|
|
254
|
+
{
|
|
255
|
+
errcode = 213;
|
|
256
|
+
errtok = 8;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
node = &net->Node[i];
|
|
262
|
+
tank = &net->Tank[net->Ntanks];
|
|
263
|
+
|
|
264
|
+
node->X = MISSING;
|
|
265
|
+
node->Y = MISSING;
|
|
266
|
+
node->Rpt = 0;
|
|
267
|
+
node->ResultIndex = 0;
|
|
268
|
+
node->El = el;
|
|
269
|
+
node->C0 = 0.0;
|
|
270
|
+
node->S = NULL;
|
|
271
|
+
node->Ke = 0.0;
|
|
272
|
+
node->Type = (diam == 0) ? RESERVOIR : TANK;
|
|
273
|
+
node->Comment = xstrcpy(&node->Comment, parser->Comment, MAXMSG);
|
|
274
|
+
tank->Node = i;
|
|
275
|
+
tank->H0 = initlevel;
|
|
276
|
+
tank->Hmin = minlevel;
|
|
277
|
+
tank->Hmax = maxlevel;
|
|
278
|
+
tank->A = diam;
|
|
279
|
+
tank->Pat = pattern;
|
|
280
|
+
tank->Kb = MISSING;
|
|
281
|
+
tank->CanOverflow = overflow;
|
|
282
|
+
|
|
283
|
+
//*******************************************************************
|
|
284
|
+
// NOTE: The min, max, & initial volumes set here are based on a
|
|
285
|
+
// nominal tank diameter. They will be modified in INPUT1.C if
|
|
286
|
+
// a volume curve is supplied for this tank.
|
|
287
|
+
//*******************************************************************
|
|
288
|
+
area = PI * SQR(diam) / 4.0;
|
|
289
|
+
tank->Vmin = area * minlevel;
|
|
290
|
+
if (minvol > 0.0) tank->Vmin = minvol;
|
|
291
|
+
tank->V0 = tank->Vmin + area * (initlevel - minlevel);
|
|
292
|
+
tank->Vmax = tank->Vmin + area * (maxlevel - minlevel);
|
|
293
|
+
|
|
294
|
+
tank->Vcurve = curve;
|
|
295
|
+
tank->MixModel = MIX1; // Completely mixed
|
|
296
|
+
tank->V1frac = 1.0; // Mixing compartment size fraction
|
|
297
|
+
|
|
298
|
+
// Return error code
|
|
299
|
+
if (errcode > 0) return setError(parser, errtok, errcode);
|
|
300
|
+
return 0;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
double gettokvalue(Project *pr, double x, int itok, int *errcode, int *errtok)
|
|
304
|
+
/*
|
|
305
|
+
**--------------------------------------------------------------
|
|
306
|
+
** Input: x = default numerical value
|
|
307
|
+
** itok = index into an array of string tokens
|
|
308
|
+
** Output: errcode = an error code or 0 if successful
|
|
309
|
+
** errtok = itok if an error occurs
|
|
310
|
+
** returns a numerical data value
|
|
311
|
+
** Purpose: converts a string token into a numerical value.
|
|
312
|
+
**--------------------------------------------------------------
|
|
313
|
+
*/
|
|
314
|
+
{
|
|
315
|
+
Parser *parser = &pr->parser;
|
|
316
|
+
double result;
|
|
317
|
+
|
|
318
|
+
if (*errcode) return x;
|
|
319
|
+
if (!getfloat(parser->Tok[itok], &result)) *errcode = 202;
|
|
320
|
+
else if (result < 0.0) *errcode = 209;
|
|
321
|
+
if (*errcode > 0)
|
|
322
|
+
{
|
|
323
|
+
result = x;
|
|
324
|
+
*errtok = itok;
|
|
325
|
+
}
|
|
326
|
+
return result;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
int pipedata(Project *pr)
|
|
330
|
+
/*
|
|
331
|
+
**--------------------------------------------------------------
|
|
332
|
+
** Input: none
|
|
333
|
+
** Output: returns error code
|
|
334
|
+
** Purpose: processes pipe data
|
|
335
|
+
** Format:
|
|
336
|
+
** [PIPE]
|
|
337
|
+
** id node1 node2 length diam rcoeff (lcoeff) (status)
|
|
338
|
+
**--------------------------------------------------------------
|
|
339
|
+
*/
|
|
340
|
+
{
|
|
341
|
+
Network *net = &pr->network;
|
|
342
|
+
Parser *parser = &pr->parser;
|
|
343
|
+
|
|
344
|
+
int j1, // Start-node index
|
|
345
|
+
j2, // End-node index
|
|
346
|
+
n; // # data items
|
|
347
|
+
double x;
|
|
348
|
+
Slink *link;
|
|
349
|
+
int errcode = 0;
|
|
350
|
+
|
|
351
|
+
// Check that end nodes exist
|
|
352
|
+
if (net->Nlinks == parser->MaxLinks) return 200;
|
|
353
|
+
n = parser->Ntokens;
|
|
354
|
+
if (n < 3) return setError(parser, -1, errcode);
|
|
355
|
+
if ((j1 = findnode(net, parser->Tok[1])) == 0) return setError(parser, 1, 203);
|
|
356
|
+
if ((j2 = findnode(net, parser->Tok[2])) == 0) return setError(parser, 2, 203);
|
|
357
|
+
if (j1 == j2) return setError(parser, 0, 222);
|
|
358
|
+
|
|
359
|
+
// Add new pipe to data base
|
|
360
|
+
errcode = addlinkID(net, net->Nlinks+1, parser->Tok[0]);
|
|
361
|
+
if (errcode) return setError(parser, 0, errcode);
|
|
362
|
+
net->Npipes++;
|
|
363
|
+
net->Nlinks++;
|
|
364
|
+
|
|
365
|
+
// Assign default data to pipe
|
|
366
|
+
link = &net->Link[net->Nlinks];
|
|
367
|
+
link->N1 = j1;
|
|
368
|
+
link->N2 = j2;
|
|
369
|
+
|
|
370
|
+
if (parser->Unitsflag == SI)
|
|
371
|
+
{
|
|
372
|
+
link->Len = 100.0;
|
|
373
|
+
link->Diam = 254.0;
|
|
374
|
+
}
|
|
375
|
+
else
|
|
376
|
+
{
|
|
377
|
+
link->Len = 330.0;
|
|
378
|
+
link->Diam = 10.0;
|
|
379
|
+
}
|
|
380
|
+
switch (pr->hydraul.Formflag)
|
|
381
|
+
{
|
|
382
|
+
case HW: link->Kc = 130; break;
|
|
383
|
+
case DW: link->Kc = 0.0005; break;
|
|
384
|
+
case CM: link->Kc = 0.01; break;
|
|
385
|
+
default: link->Kc = 1.0;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
link->Km = 0.0;
|
|
389
|
+
link->Kb = MISSING;
|
|
390
|
+
link->Kw = MISSING;
|
|
391
|
+
link->LeakArea = 0.0;
|
|
392
|
+
link->LeakExpan = 0.0;
|
|
393
|
+
link->Type = PIPE;
|
|
394
|
+
link->InitStatus = OPEN;
|
|
395
|
+
link->InitSetting = link->Kc;
|
|
396
|
+
link->Rpt = 0;
|
|
397
|
+
link->ResultIndex = 0;
|
|
398
|
+
link->Comment = xstrcpy(&link->Comment, parser->Comment, MAXMSG);
|
|
399
|
+
|
|
400
|
+
// Parse data values from input tokens
|
|
401
|
+
if (n > 3)
|
|
402
|
+
{
|
|
403
|
+
if (!getfloat(parser->Tok[3], &x) || x <= 0.0)
|
|
404
|
+
return setError(parser, 3, 202);
|
|
405
|
+
link->Len = x;
|
|
406
|
+
}
|
|
407
|
+
if (n > 4)
|
|
408
|
+
{
|
|
409
|
+
if (!getfloat(parser->Tok[4], &x) || x <= 0.0)
|
|
410
|
+
return setError(parser, 4, 202);
|
|
411
|
+
link->Diam = x;
|
|
412
|
+
}
|
|
413
|
+
if (n > 5)
|
|
414
|
+
{
|
|
415
|
+
if (!getfloat(parser->Tok[5], &x) || x <= 0.0)
|
|
416
|
+
return setError(parser, 5, 202);
|
|
417
|
+
link->Kc = x;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Either a loss coeff. or a status is supplied
|
|
421
|
+
if (n > 6)
|
|
422
|
+
{
|
|
423
|
+
if (match(parser->Tok[6], w_CV)) link->Type = CVPIPE;
|
|
424
|
+
else if (match(parser->Tok[6], w_CLOSED)) link->InitStatus = CLOSED;
|
|
425
|
+
else if (match(parser->Tok[6], w_OPEN)) link->InitStatus = OPEN;
|
|
426
|
+
else
|
|
427
|
+
{
|
|
428
|
+
if (!getfloat(parser->Tok[6], &x) || x < 0.0)
|
|
429
|
+
return setError(parser, 6, 202);
|
|
430
|
+
link->Km = x;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// Both a loss coeff. and a status is supplied
|
|
435
|
+
if (n > 7)
|
|
436
|
+
{
|
|
437
|
+
if (!getfloat(parser->Tok[6], &x) || x < 0.0)
|
|
438
|
+
return setError(parser, 6, 202);
|
|
439
|
+
link->Km = x;
|
|
440
|
+
if (match(parser->Tok[7], w_CV)) link->Type = CVPIPE;
|
|
441
|
+
else if (match(parser->Tok[7], w_CLOSED)) link->InitStatus = CLOSED;
|
|
442
|
+
else if (match(parser->Tok[7], w_OPEN)) link->InitStatus = OPEN;
|
|
443
|
+
else return setError(parser, 7, 213);
|
|
444
|
+
}
|
|
445
|
+
return 0;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
int pumpdata(Project *pr)
|
|
449
|
+
/*
|
|
450
|
+
**--------------------------------------------------------------
|
|
451
|
+
** Input: none
|
|
452
|
+
** Output: returns error code
|
|
453
|
+
** Purpose: processes pump data
|
|
454
|
+
** Formats:
|
|
455
|
+
** [PUMP]
|
|
456
|
+
** id node1 node2 KEYWORD value {KEYWORD value ...}
|
|
457
|
+
** where KEYWORD = [POWER,HEAD,PATTERN,SPEED]
|
|
458
|
+
**--------------------------------------------------------------
|
|
459
|
+
*/
|
|
460
|
+
{
|
|
461
|
+
Network *net = &pr->network;
|
|
462
|
+
Parser *parser = &pr->parser;
|
|
463
|
+
|
|
464
|
+
int m, // Token array indexes
|
|
465
|
+
j1, // Start-node index
|
|
466
|
+
j2, // End-node index
|
|
467
|
+
n, // # data items
|
|
468
|
+
c, p; // Curve & Pattern indexes
|
|
469
|
+
double y;
|
|
470
|
+
Slink *link;
|
|
471
|
+
Spump *pump;
|
|
472
|
+
int errcode = 0;
|
|
473
|
+
|
|
474
|
+
// Check that end nodes exist
|
|
475
|
+
if (net->Nlinks == parser->MaxLinks ||
|
|
476
|
+
net->Npumps == parser->MaxPumps) return 200;
|
|
477
|
+
n = parser->Ntokens;
|
|
478
|
+
if (n < 3) return setError(parser, -1, errcode);
|
|
479
|
+
if ((j1 = findnode(net, parser->Tok[1])) == 0) return setError(parser, 1, 203);
|
|
480
|
+
if ((j2 = findnode(net, parser->Tok[2])) == 0) return setError(parser, 2, 203);
|
|
481
|
+
if (j1 == j2) return setError(parser, 0, 222);
|
|
482
|
+
|
|
483
|
+
// Add new pump to data base
|
|
484
|
+
errcode = addlinkID(net, net->Nlinks+1, parser->Tok[0]);
|
|
485
|
+
if (errcode) return setError(parser, 0, errcode);
|
|
486
|
+
net->Nlinks++;
|
|
487
|
+
net->Npumps++;
|
|
488
|
+
|
|
489
|
+
// Assign default data to pump
|
|
490
|
+
link = &net->Link[net->Nlinks];
|
|
491
|
+
pump = &net->Pump[net->Npumps];
|
|
492
|
+
|
|
493
|
+
link->N1 = j1;
|
|
494
|
+
link->N2 = j2;
|
|
495
|
+
link->Diam = 0;
|
|
496
|
+
link->Len = 0.0;
|
|
497
|
+
link->Kc = 1.0;
|
|
498
|
+
link->Km = 0.0;
|
|
499
|
+
link->Kb = 0.0;
|
|
500
|
+
link->Kw = 0.0;
|
|
501
|
+
link->LeakArea = 0.0;
|
|
502
|
+
link->LeakExpan = 0.0;
|
|
503
|
+
link->Type = PUMP;
|
|
504
|
+
link->InitStatus = OPEN;
|
|
505
|
+
link->InitSetting = 1.0;
|
|
506
|
+
link->Rpt = 0;
|
|
507
|
+
link->ResultIndex = 0;
|
|
508
|
+
link->Comment = xstrcpy(&link->Comment, parser->Comment, MAXMSG);
|
|
509
|
+
pump->Link = net->Nlinks;
|
|
510
|
+
pump->Ptype = NOCURVE; // NOCURVE is a placeholder
|
|
511
|
+
pump->Hcurve = 0;
|
|
512
|
+
pump->Ecurve = 0;
|
|
513
|
+
pump->Upat = 0;
|
|
514
|
+
pump->Ecost = 0.0;
|
|
515
|
+
pump->Epat = 0;
|
|
516
|
+
if (n < 4) return 0;
|
|
517
|
+
|
|
518
|
+
// Retrieve keyword/value pairs
|
|
519
|
+
m = 4;
|
|
520
|
+
while (m < n)
|
|
521
|
+
{
|
|
522
|
+
if (match(parser->Tok[m - 1], w_POWER)) // Const. HP curve
|
|
523
|
+
{
|
|
524
|
+
if (!getfloat(parser->Tok[m], &y) || y <= 0.0)
|
|
525
|
+
return setError(parser, m, 202);
|
|
526
|
+
pump->Ptype = CONST_HP;
|
|
527
|
+
link->Km = y;
|
|
528
|
+
}
|
|
529
|
+
else if (match(parser->Tok[m - 1], w_HEAD)) // Custom pump curve
|
|
530
|
+
{
|
|
531
|
+
c = findcurve(net, parser->Tok[m]);
|
|
532
|
+
if (c == 0) return setError(parser, m, 206);
|
|
533
|
+
pump->Ptype = CUSTOM;
|
|
534
|
+
pump->Hcurve = c;
|
|
535
|
+
}
|
|
536
|
+
else if (match(parser->Tok[m - 1], w_PATTERN)) // Speed/status pattern
|
|
537
|
+
{
|
|
538
|
+
p = findpattern(net, parser->Tok[m]);
|
|
539
|
+
if (p < 0) return setError(parser, m, 205);
|
|
540
|
+
pump->Upat = p;
|
|
541
|
+
}
|
|
542
|
+
else if (match(parser->Tok[m - 1], w_SPEED)) // Speed setting
|
|
543
|
+
{
|
|
544
|
+
if (!getfloat(parser->Tok[m], &y) || y < 0.0)
|
|
545
|
+
return setError(parser, m, 202);
|
|
546
|
+
link->Kc = y;
|
|
547
|
+
}
|
|
548
|
+
else return setError(parser, m-1, 201);;
|
|
549
|
+
m = m + 2; // Move to next keyword token
|
|
550
|
+
}
|
|
551
|
+
link->InitSetting = link->Kc;
|
|
552
|
+
return 0;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
int valvedata(Project *pr)
|
|
556
|
+
/*
|
|
557
|
+
**--------------------------------------------------------------
|
|
558
|
+
** Input: none
|
|
559
|
+
** Output: returns error code
|
|
560
|
+
** Purpose: processes valve data
|
|
561
|
+
** Format:
|
|
562
|
+
** [VALVE]
|
|
563
|
+
** id node1 node2 diam type setting (lcoeff lcurve)
|
|
564
|
+
**--------------------------------------------------------------
|
|
565
|
+
*/
|
|
566
|
+
{
|
|
567
|
+
Network *net = &pr->network;
|
|
568
|
+
Parser *parser = &pr->parser;
|
|
569
|
+
|
|
570
|
+
int c, // Curve index
|
|
571
|
+
j1, // Start-node index
|
|
572
|
+
j2, // End-node index
|
|
573
|
+
n; // # data items
|
|
574
|
+
char status = ACTIVE, // Valve status
|
|
575
|
+
type; // Valve type
|
|
576
|
+
double x;
|
|
577
|
+
Slink *link;
|
|
578
|
+
int errcode = 0,
|
|
579
|
+
losscurve = 0; // Loss coeff. curve
|
|
580
|
+
|
|
581
|
+
// Check that end nodes exist
|
|
582
|
+
if (net->Nlinks == parser->MaxLinks ||
|
|
583
|
+
net->Nvalves == parser->MaxValves) return 200;
|
|
584
|
+
n = parser->Ntokens;
|
|
585
|
+
if (n < 5) return setError(parser, -1, errcode);
|
|
586
|
+
if ((j1 = findnode(net, parser->Tok[1])) == 0) return setError(parser, 1, 203);
|
|
587
|
+
if ((j2 = findnode(net, parser->Tok[2])) == 0) return setError(parser, 2, 203);
|
|
588
|
+
if (j1 == j2) return setError(parser, 0, 222);
|
|
589
|
+
|
|
590
|
+
// Parse valve type
|
|
591
|
+
if (match(parser->Tok[4], w_PRV)) type = PRV;
|
|
592
|
+
else if (match(parser->Tok[4], w_PSV)) type = PSV;
|
|
593
|
+
else if (match(parser->Tok[4], w_PBV)) type = PBV;
|
|
594
|
+
else if (match(parser->Tok[4], w_FCV)) type = FCV;
|
|
595
|
+
else if (match(parser->Tok[4], w_TCV)) type = TCV;
|
|
596
|
+
else if (match(parser->Tok[4], w_GPV)) type = GPV;
|
|
597
|
+
else if (match(parser->Tok[4], w_PCV)) type = PCV;
|
|
598
|
+
else return setError(parser, 4, 213);
|
|
599
|
+
|
|
600
|
+
// Check for illegal connections
|
|
601
|
+
if (valvecheck(pr, net->Nlinks, type, j1, j2))
|
|
602
|
+
{
|
|
603
|
+
if (j1 > net->Njuncs) return setError(parser, 1, 219);
|
|
604
|
+
else if (j2 > net->Njuncs) return setError(parser, 2, 219);
|
|
605
|
+
else return setError(parser, -1, 220);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// Add new valve to data base
|
|
609
|
+
errcode = addlinkID(net, net->Nlinks+1, parser->Tok[0]);
|
|
610
|
+
if (errcode) return setError(parser, 0, errcode);
|
|
611
|
+
net->Nvalves++;
|
|
612
|
+
net->Nlinks++;
|
|
613
|
+
|
|
614
|
+
// Assign default data to valve
|
|
615
|
+
link = &net->Link[net->Nlinks];
|
|
616
|
+
link->N1 = j1;
|
|
617
|
+
link->N2 = j2;
|
|
618
|
+
if (parser->Unitsflag == SI) link->Diam = 254.0;
|
|
619
|
+
else link->Diam = 10.0;
|
|
620
|
+
link->Len = 0.0;
|
|
621
|
+
link->Kc = 0.0;
|
|
622
|
+
link->Km = 0.0;
|
|
623
|
+
link->Kb = 0.0;
|
|
624
|
+
link->Kw = 0.0;
|
|
625
|
+
link->LeakArea = 0.0;
|
|
626
|
+
link->LeakExpan = 0.0;
|
|
627
|
+
link->Type = type;
|
|
628
|
+
link->InitStatus = ACTIVE;
|
|
629
|
+
link->InitSetting = 0.0;
|
|
630
|
+
link->Rpt = 0;
|
|
631
|
+
link->ResultIndex = 0;
|
|
632
|
+
link->Comment = xstrcpy(&link->Comment, parser->Comment, MAXMSG);
|
|
633
|
+
net->Valve[net->Nvalves].Link = net->Nlinks;
|
|
634
|
+
net->Valve[net->Nvalves].Curve = 0;
|
|
635
|
+
|
|
636
|
+
// Parse data values
|
|
637
|
+
if (!getfloat(parser->Tok[3], &x) || x <= 0.0)
|
|
638
|
+
return setError(parser, 3, 202);
|
|
639
|
+
link->Diam = x;
|
|
640
|
+
if (n > 5)
|
|
641
|
+
{
|
|
642
|
+
// Find headloss curve for GPV
|
|
643
|
+
if (type == GPV)
|
|
644
|
+
{
|
|
645
|
+
c = findcurve(net, parser->Tok[5]);
|
|
646
|
+
if (c == 0) return setError(parser, 5, 206);
|
|
647
|
+
link->Kc = c;
|
|
648
|
+
net->Curve[c].Type = HLOSS_CURVE;
|
|
649
|
+
link->InitStatus = OPEN;
|
|
650
|
+
}
|
|
651
|
+
else
|
|
652
|
+
{
|
|
653
|
+
if (!getfloat(parser->Tok[5], &x)) return setError(parser, 5, 202);
|
|
654
|
+
link->Kc = x;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
if (n > 6)
|
|
658
|
+
{
|
|
659
|
+
if (!getfloat(parser->Tok[6], &x) || x < 0.0)
|
|
660
|
+
return setError(parser, 6, 202);
|
|
661
|
+
link->Km = x;
|
|
662
|
+
}
|
|
663
|
+
if (n > 7 && type == PCV)
|
|
664
|
+
{
|
|
665
|
+
// Find loss coeff. curve for PCV
|
|
666
|
+
c = findcurve(net, parser->Tok[7]);
|
|
667
|
+
if (c == 0) return setError(parser, 7, 206);
|
|
668
|
+
net->Valve[net->Nvalves].Curve = c;
|
|
669
|
+
net->Curve[c].Type = VALVE_CURVE;
|
|
670
|
+
if (link->Kc > 100.0) link->Kc = 100.0;
|
|
671
|
+
}
|
|
672
|
+
link->InitSetting = link->Kc;
|
|
673
|
+
return 0;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
int patterndata(Project *pr)
|
|
677
|
+
/*
|
|
678
|
+
**--------------------------------------------------------------
|
|
679
|
+
** Input: none
|
|
680
|
+
** Output: returns error code
|
|
681
|
+
** Purpose: processes time pattern data
|
|
682
|
+
** Format:
|
|
683
|
+
** [PATTERNS]
|
|
684
|
+
** id mult1 mult2 .....
|
|
685
|
+
**--------------------------------------------------------------
|
|
686
|
+
*/
|
|
687
|
+
{
|
|
688
|
+
Network *net = &pr->network;
|
|
689
|
+
Parser *parser = &pr->parser;
|
|
690
|
+
|
|
691
|
+
int i, j, n, n1;
|
|
692
|
+
double x;
|
|
693
|
+
Spattern *pattern;
|
|
694
|
+
|
|
695
|
+
// "n" is the number of pattern factors contained in the line
|
|
696
|
+
n = parser->Ntokens - 1;
|
|
697
|
+
if (n < 1) return 201;
|
|
698
|
+
|
|
699
|
+
// Check if previous input line was for the same pattern
|
|
700
|
+
if (parser->PrevPat && strcmp(parser->Tok[0], parser->PrevPat->ID) == 0)
|
|
701
|
+
{
|
|
702
|
+
pattern = parser->PrevPat;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
// Otherwise retrieve pattern from the network's Pattern array
|
|
706
|
+
else
|
|
707
|
+
{
|
|
708
|
+
i = findpattern(net, parser->Tok[0]);
|
|
709
|
+
if (i <= 0) return setError(parser, 0, 205);
|
|
710
|
+
pattern = &(net->Pattern[i]);
|
|
711
|
+
if (pattern->Comment == NULL && parser->Comment[0])
|
|
712
|
+
{
|
|
713
|
+
pattern->Comment = xstrcpy(&pattern->Comment, parser->Comment, MAXMSG);
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
// Expand size of the pattern's factors array
|
|
718
|
+
n1 = pattern->Length;
|
|
719
|
+
pattern->Length += n;
|
|
720
|
+
pattern->F = realloc(pattern->F, pattern->Length * sizeof(double));
|
|
721
|
+
|
|
722
|
+
// Add parsed multipliers to the pattern
|
|
723
|
+
for (j = 1; j <= n; j++) pattern->F[n1 + j - 1] = 1.0;
|
|
724
|
+
for (j = 1; j <= n; j++)
|
|
725
|
+
{
|
|
726
|
+
if (!getfloat(parser->Tok[j], &x)) return setError(parser, j, 202);
|
|
727
|
+
pattern->F[n1 + j - 1] = x;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
// Save a reference to this pattern for processing additional pattern data
|
|
731
|
+
parser->PrevPat = pattern;
|
|
732
|
+
return 0;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
int curvedata(Project *pr)
|
|
736
|
+
/*
|
|
737
|
+
**------------------------------------------------------
|
|
738
|
+
** Input: none
|
|
739
|
+
** Output: returns error code
|
|
740
|
+
** Purpose: processes curve data
|
|
741
|
+
** Format:
|
|
742
|
+
** [CURVES]
|
|
743
|
+
** CurveID x-value y-value
|
|
744
|
+
**------------------------------------------------------
|
|
745
|
+
*/
|
|
746
|
+
{
|
|
747
|
+
Network *net = &pr->network;
|
|
748
|
+
Parser *parser = &pr->parser;
|
|
749
|
+
|
|
750
|
+
int i, ctype;
|
|
751
|
+
double x, y;
|
|
752
|
+
Scurve *curve;
|
|
753
|
+
|
|
754
|
+
// Check for valid data
|
|
755
|
+
if (parser->Ntokens < 3) return 201;
|
|
756
|
+
if (!getfloat(parser->Tok[1], &x)) return setError(parser, 1, 202);
|
|
757
|
+
if (!getfloat(parser->Tok[2], &y)) return setError(parser, 2, 202);
|
|
758
|
+
ctype = -1;
|
|
759
|
+
if (parser->Ntokens > 3)
|
|
760
|
+
{
|
|
761
|
+
ctype = findmatch(parser->Tok[3], CurveTypeTxt);
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
// Check if previous input line was for the same curve
|
|
765
|
+
if (parser->PrevCurve && strcmp(parser->Tok[0], parser->PrevCurve->ID) == 0)
|
|
766
|
+
{
|
|
767
|
+
curve = parser->PrevCurve;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
// Otherwise retrieve curve from the network's Curve array
|
|
771
|
+
else
|
|
772
|
+
{
|
|
773
|
+
i = findcurve(net, parser->Tok[0]);
|
|
774
|
+
if (i == 0) return setError(parser, 0, 206);
|
|
775
|
+
curve = &(net->Curve[i]);
|
|
776
|
+
if (curve->Comment == NULL && parser->Comment[0])
|
|
777
|
+
{
|
|
778
|
+
curve->Comment = xstrcpy(&curve->Comment, parser->Comment, MAXMSG);
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
// Expand size of data arrays if need be
|
|
783
|
+
if (curve->Capacity == curve->Npts)
|
|
784
|
+
{
|
|
785
|
+
if (resizecurve(curve, curve->Capacity + 10) > 0) return 101;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
// Add new data point to curve
|
|
789
|
+
curve->X[curve->Npts] = x;
|
|
790
|
+
curve->Y[curve->Npts] = y;
|
|
791
|
+
curve->Npts++;
|
|
792
|
+
if (ctype >= 0) curve->Type = (CurveType)ctype;
|
|
793
|
+
|
|
794
|
+
// Save a reference to this curve for processing additional curve data
|
|
795
|
+
parser->PrevCurve = curve;
|
|
796
|
+
return 0;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
int coordata(Project *pr)
|
|
800
|
+
/*
|
|
801
|
+
**--------------------------------------------------------------
|
|
802
|
+
** Input: none
|
|
803
|
+
** Output: returns 0
|
|
804
|
+
** Purpose: processes node coordinate data
|
|
805
|
+
** Format:
|
|
806
|
+
** [COORD]
|
|
807
|
+
** id x y
|
|
808
|
+
**
|
|
809
|
+
** Note: since node coords. are not used in any computations,
|
|
810
|
+
** invalid data are simply ignored.
|
|
811
|
+
**--------------------------------------------------------------
|
|
812
|
+
*/
|
|
813
|
+
{
|
|
814
|
+
Network *net = &pr->network;
|
|
815
|
+
Parser *parser = &pr->parser;
|
|
816
|
+
|
|
817
|
+
int j;
|
|
818
|
+
double x, y;
|
|
819
|
+
Snode *node;
|
|
820
|
+
|
|
821
|
+
// Check for valid node ID
|
|
822
|
+
if (parser->Ntokens < 3) return 0;
|
|
823
|
+
if ((j = findnode(net, parser->Tok[0])) == 0) return 0;
|
|
824
|
+
|
|
825
|
+
// Check for valid data
|
|
826
|
+
if (!getfloat(parser->Tok[1], &x)) return 0;
|
|
827
|
+
if (!getfloat(parser->Tok[2], &y)) return 0;
|
|
828
|
+
|
|
829
|
+
// Save coord data
|
|
830
|
+
node = &net->Node[j];
|
|
831
|
+
node->X = x;
|
|
832
|
+
node->Y = y;
|
|
833
|
+
return 0;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
int vertexdata(Project *pr)
|
|
837
|
+
/*
|
|
838
|
+
**--------------------------------------------------------------
|
|
839
|
+
** Input: none
|
|
840
|
+
** Output: returns 0
|
|
841
|
+
** Purpose: processes link vertex data
|
|
842
|
+
** Format:
|
|
843
|
+
** [VERTICES]
|
|
844
|
+
** id x y
|
|
845
|
+
**
|
|
846
|
+
** Note: since vertex coords. are not used in any computations,
|
|
847
|
+
** invalid data are simply ignored.
|
|
848
|
+
**--------------------------------------------------------------
|
|
849
|
+
*/
|
|
850
|
+
{
|
|
851
|
+
Network *net = &pr->network;
|
|
852
|
+
Parser *parser = &pr->parser;
|
|
853
|
+
|
|
854
|
+
int j;
|
|
855
|
+
double x, y;
|
|
856
|
+
|
|
857
|
+
// Check for valid link ID
|
|
858
|
+
if (parser->Ntokens < 3) return 0;
|
|
859
|
+
if ((j = findlink(net, parser->Tok[0])) == 0) return 0;
|
|
860
|
+
|
|
861
|
+
// Check for valid coordinate data
|
|
862
|
+
if (!getfloat(parser->Tok[1], &x)) return 0;
|
|
863
|
+
if (!getfloat(parser->Tok[2], &y)) return 0;
|
|
864
|
+
|
|
865
|
+
// Add to link's list of vertex points
|
|
866
|
+
return addlinkvertex(&net->Link[j], x, y);
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
|
|
870
|
+
int demanddata(Project *pr)
|
|
871
|
+
/*
|
|
872
|
+
**--------------------------------------------------------------
|
|
873
|
+
** Input: none
|
|
874
|
+
** Output: returns error code
|
|
875
|
+
** Purpose: processes node demand data
|
|
876
|
+
** Format:
|
|
877
|
+
** [DEMANDS]
|
|
878
|
+
** node base_demand (pattern)
|
|
879
|
+
**
|
|
880
|
+
** NOTE: Demands entered in this section replace those
|
|
881
|
+
** entered in the [JUNCTIONS] section
|
|
882
|
+
**--------------------------------------------------------------
|
|
883
|
+
*/
|
|
884
|
+
{
|
|
885
|
+
Network *net = &pr->network;
|
|
886
|
+
Hydraul *hyd = &pr->hydraul;
|
|
887
|
+
Parser *parser = &pr->parser;
|
|
888
|
+
|
|
889
|
+
int j, n, p = 0;
|
|
890
|
+
double y;
|
|
891
|
+
|
|
892
|
+
Pdemand demand;
|
|
893
|
+
|
|
894
|
+
// Extract data from tokens
|
|
895
|
+
n = parser->Ntokens;
|
|
896
|
+
if (n < 2) return 201;
|
|
897
|
+
if (!getfloat(parser->Tok[1], &y)) return setError(parser, 1, 202);
|
|
898
|
+
|
|
899
|
+
// Find node (and pattern) being referenced
|
|
900
|
+
if ((j = findnode(net, parser->Tok[0])) == 0) return setError(parser, 0, 203);
|
|
901
|
+
if (j > net->Njuncs) return 0;
|
|
902
|
+
if (n >= 3)
|
|
903
|
+
{
|
|
904
|
+
p = findpattern(net, parser->Tok[2]);
|
|
905
|
+
if (p < 0) return setError(parser, 2, 205);
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
// Replace any demand entered in [JUNCTIONS] section
|
|
909
|
+
demand = net->Node[j].D;
|
|
910
|
+
if (demand && hyd->NodeDemand[j] != MISSING)
|
|
911
|
+
{
|
|
912
|
+
// First category encountered will overwrite demand category
|
|
913
|
+
// created when junction was read from [JUNCTIONS] section
|
|
914
|
+
demand->Base = y;
|
|
915
|
+
demand->Pat = p;
|
|
916
|
+
if (parser->Comment[0])
|
|
917
|
+
{
|
|
918
|
+
demand->Name = xstrcpy(&demand->Name, parser->Comment, MAXID);
|
|
919
|
+
}
|
|
920
|
+
hyd->NodeDemand[j] = MISSING; // marker - next iteration will append a new category.
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
// Otherwise add new demand to junction
|
|
924
|
+
else if (!adddemand(&net->Node[j], y, p, parser->Comment) > 0) return 101;
|
|
925
|
+
return 0;
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
int controldata(Project *pr)
|
|
929
|
+
/*
|
|
930
|
+
**--------------------------------------------------------------
|
|
931
|
+
** Input: none
|
|
932
|
+
** Output: returns error code
|
|
933
|
+
** Purpose: processes simple controls
|
|
934
|
+
** Formats:
|
|
935
|
+
** [CONTROLS]
|
|
936
|
+
** LINK linkID setting IF NODE nodeID {BELOW/ABOVE} level (DISABLED)
|
|
937
|
+
** LINK linkID setting AT TIME value (units) (DISABLED)
|
|
938
|
+
** LINK linkID setting AT CLOCKTIME value (units) (DISABLED)
|
|
939
|
+
** (0) (1) (2) (3) (4) (5) (6) (7) (8)
|
|
940
|
+
**--------------------------------------------------------------
|
|
941
|
+
*/
|
|
942
|
+
{
|
|
943
|
+
Network *net = &pr->network;
|
|
944
|
+
Parser *parser = &pr->parser;
|
|
945
|
+
|
|
946
|
+
int i = 0, // Node index
|
|
947
|
+
k, // Link index
|
|
948
|
+
n, // # data items
|
|
949
|
+
isEnabled = TRUE; // Control enabled
|
|
950
|
+
double setting = MISSING, // Link setting
|
|
951
|
+
time = 0.0, // Simulation time
|
|
952
|
+
level = 0.0; // Pressure or tank level
|
|
953
|
+
StatusType status = ACTIVE; // Link status
|
|
954
|
+
ControlType ctltype; // Control type
|
|
955
|
+
LinkType linktype; // Link type
|
|
956
|
+
Scontrol *control;
|
|
957
|
+
|
|
958
|
+
// Check for sufficient number of input tokens
|
|
959
|
+
n = parser->Ntokens;
|
|
960
|
+
if (n < 6) return 201;
|
|
961
|
+
|
|
962
|
+
// Check if last token is "DISABLED"
|
|
963
|
+
if (match(parser->Tok[n-1], w_DISABLED))
|
|
964
|
+
{
|
|
965
|
+
isEnabled = FALSE;
|
|
966
|
+
n = n - 1;
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
// Check that controlled link exists
|
|
970
|
+
k = findlink(net, parser->Tok[1]);
|
|
971
|
+
if (k == 0) return setError(parser, 1, 204);
|
|
972
|
+
|
|
973
|
+
// Cannot control a check valve
|
|
974
|
+
linktype = net->Link[k].Type;
|
|
975
|
+
if (linktype == CVPIPE) return setError(parser, 1, 207);
|
|
976
|
+
|
|
977
|
+
// Parse control setting into a status level or numerical setting
|
|
978
|
+
if (match(parser->Tok[2], w_OPEN))
|
|
979
|
+
{
|
|
980
|
+
status = OPEN;
|
|
981
|
+
if (linktype == PUMP) setting = 1.0;
|
|
982
|
+
if (linktype == GPV) setting = net->Link[k].Kc;
|
|
983
|
+
}
|
|
984
|
+
else if (match(parser->Tok[2], w_CLOSED))
|
|
985
|
+
{
|
|
986
|
+
status = CLOSED;
|
|
987
|
+
if (linktype == PUMP) setting = 0.0;
|
|
988
|
+
if (linktype == GPV) setting = net->Link[k].Kc;
|
|
989
|
+
}
|
|
990
|
+
else if (linktype == GPV) return setError(parser, 1, 207);
|
|
991
|
+
else if (!getfloat(parser->Tok[2], &setting)) return setError(parser, 2, 202);
|
|
992
|
+
|
|
993
|
+
// Set status for pump in case speed setting was supplied
|
|
994
|
+
// or for pipe if numerical setting was supplied
|
|
995
|
+
if (linktype == PUMP || linktype == PIPE)
|
|
996
|
+
{
|
|
997
|
+
if (setting != MISSING)
|
|
998
|
+
{
|
|
999
|
+
if (setting < 0.0) return setError(parser, 2, 211);
|
|
1000
|
+
else if (setting == 0.0) status = CLOSED;
|
|
1001
|
+
else status = OPEN;
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
// Determine type of control
|
|
1006
|
+
if (match(parser->Tok[4], w_TIME)) ctltype = TIMER;
|
|
1007
|
+
else if (match(parser->Tok[4], w_CLOCKTIME)) ctltype = TIMEOFDAY;
|
|
1008
|
+
else
|
|
1009
|
+
{
|
|
1010
|
+
if (n < 8) return 201;
|
|
1011
|
+
if ((i = findnode(net, parser->Tok[5])) == 0) return setError(parser, 5, 203);
|
|
1012
|
+
if (match(parser->Tok[6], w_BELOW)) ctltype = LOWLEVEL;
|
|
1013
|
+
else if (match(parser->Tok[6], w_ABOVE)) ctltype = HILEVEL;
|
|
1014
|
+
else return setError(parser, 6, 213);
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
// Parse control level or time
|
|
1018
|
+
switch (ctltype)
|
|
1019
|
+
{
|
|
1020
|
+
case TIMER:
|
|
1021
|
+
case TIMEOFDAY:
|
|
1022
|
+
if (n == 6) time = hour(parser->Tok[5], "");
|
|
1023
|
+
if (n >= 7) time = hour(parser->Tok[5], parser->Tok[6]);
|
|
1024
|
+
if (time < 0.0) return setError(parser, 5, 213);
|
|
1025
|
+
break;
|
|
1026
|
+
case LOWLEVEL:
|
|
1027
|
+
case HILEVEL:
|
|
1028
|
+
if (!getfloat(parser->Tok[7], &level)) return setError(parser, 7, 202);
|
|
1029
|
+
break;
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
// Fill in fields of control data structure
|
|
1033
|
+
net->Ncontrols++;
|
|
1034
|
+
if (net->Ncontrols > parser->MaxControls) return 200;
|
|
1035
|
+
control = &net->Control[net->Ncontrols];
|
|
1036
|
+
control->Link = k;
|
|
1037
|
+
control->Node = i;
|
|
1038
|
+
control->Type = ctltype;
|
|
1039
|
+
control->Status = status;
|
|
1040
|
+
control->Setting = setting;
|
|
1041
|
+
control->Time = (long)(3600.0 * time);
|
|
1042
|
+
if (ctltype == TIMEOFDAY) control->Time %= SECperDAY;
|
|
1043
|
+
control->Grade = level;
|
|
1044
|
+
control->isEnabled = isEnabled;
|
|
1045
|
+
return 0;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
int sourcedata(Project *pr)
|
|
1049
|
+
/*
|
|
1050
|
+
**--------------------------------------------------------------
|
|
1051
|
+
** Input: none
|
|
1052
|
+
** Output: returns error code
|
|
1053
|
+
** Purpose: processes water quality source data
|
|
1054
|
+
** Formats:
|
|
1055
|
+
** [SOURCE]
|
|
1056
|
+
** node sourcetype quality (pattern)
|
|
1057
|
+
**
|
|
1058
|
+
** NOTE: units of mass-based source are mass/min
|
|
1059
|
+
**--------------------------------------------------------------
|
|
1060
|
+
*/
|
|
1061
|
+
{
|
|
1062
|
+
Network *net = &pr->network;
|
|
1063
|
+
Parser *parser = &pr->parser;
|
|
1064
|
+
|
|
1065
|
+
int i, // Token with quality value
|
|
1066
|
+
j, // Node index
|
|
1067
|
+
n, // # data items
|
|
1068
|
+
p = 0; // Time pattern index
|
|
1069
|
+
char type = CONCEN; // Source type
|
|
1070
|
+
double c0 = 0; // Initial quality
|
|
1071
|
+
Psource source;
|
|
1072
|
+
|
|
1073
|
+
// Check for enough tokens & that source node exists
|
|
1074
|
+
n = parser->Ntokens;
|
|
1075
|
+
if (n < 2) return 201;
|
|
1076
|
+
if ((j = findnode(net, parser->Tok[0])) == 0) return setError(parser, 0, 203);
|
|
1077
|
+
|
|
1078
|
+
// Parse source type
|
|
1079
|
+
// NOTE: Under old 1.1 format, SourceType not supplied so
|
|
1080
|
+
// let i = index of token that contains quality value
|
|
1081
|
+
i = 2;
|
|
1082
|
+
if (match(parser->Tok[1], w_CONCEN)) type = CONCEN;
|
|
1083
|
+
else if (match(parser->Tok[1], w_MASS)) type = MASS;
|
|
1084
|
+
else if (match(parser->Tok[1], w_SETPOINT)) type = SETPOINT;
|
|
1085
|
+
else if (match(parser->Tok[1], w_FLOWPACED)) type = FLOWPACED;
|
|
1086
|
+
else i = 1;
|
|
1087
|
+
|
|
1088
|
+
// Parse source quality
|
|
1089
|
+
if (!getfloat(parser->Tok[i], &c0))
|
|
1090
|
+
{
|
|
1091
|
+
if (i == 1) return setError(parser, i, 213);
|
|
1092
|
+
else return setError(parser, i, 202);
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
// Parse optional source time pattern
|
|
1096
|
+
if (n > i + 1 && strlen(parser->Tok[i + 1]) > 0 &&
|
|
1097
|
+
strcmp(parser->Tok[i + 1], "*") != 0)
|
|
1098
|
+
{
|
|
1099
|
+
p = findpattern(net, parser->Tok[i + 1]);
|
|
1100
|
+
if (p < 0) return setError(parser, i + 1, 205);
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
// Destroy any existing source assigned to node
|
|
1104
|
+
if (net->Node[j].S != NULL) free(net->Node[j].S);
|
|
1105
|
+
|
|
1106
|
+
// Create a new source & assign it to the node
|
|
1107
|
+
source = (struct Ssource *)malloc(sizeof(struct Ssource));
|
|
1108
|
+
if (source == NULL) return 101;
|
|
1109
|
+
source->C0 = c0;
|
|
1110
|
+
source->Pat = p;
|
|
1111
|
+
source->Type = type;
|
|
1112
|
+
net->Node[j].S = source;
|
|
1113
|
+
return 0;
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
int emitterdata(Project *pr)
|
|
1117
|
+
/*
|
|
1118
|
+
**--------------------------------------------------------------
|
|
1119
|
+
** Input: none
|
|
1120
|
+
** Output: returns error code
|
|
1121
|
+
** Purpose: processes junction emitter data
|
|
1122
|
+
** Format:
|
|
1123
|
+
** [EMITTER]
|
|
1124
|
+
** node Ke
|
|
1125
|
+
**--------------------------------------------------------------
|
|
1126
|
+
*/
|
|
1127
|
+
{
|
|
1128
|
+
Network *net = &pr->network;
|
|
1129
|
+
Parser *parser = &pr->parser;
|
|
1130
|
+
|
|
1131
|
+
int j, // Node index
|
|
1132
|
+
n; // # data items
|
|
1133
|
+
double k; // Flow coeff.
|
|
1134
|
+
|
|
1135
|
+
// Check that node exists & is a junction
|
|
1136
|
+
n = parser->Ntokens;
|
|
1137
|
+
if (n < 2) return 201;
|
|
1138
|
+
if ((j = findnode(net, parser->Tok[0])) == 0) return setError(parser, 0, 203);
|
|
1139
|
+
if (j > net->Njuncs) return 0;
|
|
1140
|
+
|
|
1141
|
+
// Parse emitter flow coeff.
|
|
1142
|
+
if (!getfloat(parser->Tok[1], &k)) return setError(parser, 1, 202);
|
|
1143
|
+
if (k < 0.0) return setError(parser, 1, 209);
|
|
1144
|
+
net->Node[j].Ke = k;
|
|
1145
|
+
return 0;
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
int leakagedata(Project *pr)
|
|
1149
|
+
/*
|
|
1150
|
+
**--------------------------------------------------------------
|
|
1151
|
+
** Input: none
|
|
1152
|
+
** Output: returns error code
|
|
1153
|
+
** Purpose: processes link leakage data
|
|
1154
|
+
** Format:
|
|
1155
|
+
** [LEAKAGE]
|
|
1156
|
+
** link C1 C2
|
|
1157
|
+
**--------------------------------------------------------------
|
|
1158
|
+
*/
|
|
1159
|
+
{
|
|
1160
|
+
Network *net = &pr->network;
|
|
1161
|
+
Parser *parser = &pr->parser;
|
|
1162
|
+
|
|
1163
|
+
int j, // Link index
|
|
1164
|
+
n; // # data items
|
|
1165
|
+
double c1, c2; // Flow coeff.
|
|
1166
|
+
|
|
1167
|
+
// Check that link exists & is a pipe
|
|
1168
|
+
n = parser->Ntokens;
|
|
1169
|
+
if (n < 3) return 201;
|
|
1170
|
+
if ((j = findlink(net, parser->Tok[0])) == 0) return setError(parser, 0, 203);
|
|
1171
|
+
if (net->Link[j].Type > PIPE) return 0;
|
|
1172
|
+
|
|
1173
|
+
// Parse leakage coeffs.
|
|
1174
|
+
if (!getfloat(parser->Tok[1], &c1)) return setError(parser, 1, 202);
|
|
1175
|
+
if (c1 < 0.0) return setError(parser, 1, 209);
|
|
1176
|
+
if (!getfloat(parser->Tok[2], &c2)) return setError(parser, 2, 202);
|
|
1177
|
+
if (c2 < 0.0) return setError(parser, 1, 209);
|
|
1178
|
+
net->Link[j].LeakArea = c1;
|
|
1179
|
+
net->Link[j].LeakExpan = c2;
|
|
1180
|
+
return 0;
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
int qualdata(Project *pr)
|
|
1184
|
+
/*
|
|
1185
|
+
**--------------------------------------------------------------
|
|
1186
|
+
** Input: none
|
|
1187
|
+
** Output: returns error code
|
|
1188
|
+
** Purpose: processes initial water quality data
|
|
1189
|
+
** Formats:
|
|
1190
|
+
** [QUALITY]
|
|
1191
|
+
** node initqual
|
|
1192
|
+
** node1 node2 initqual
|
|
1193
|
+
**--------------------------------------------------------------
|
|
1194
|
+
*/
|
|
1195
|
+
{
|
|
1196
|
+
Network *net = &pr->network;
|
|
1197
|
+
Parser *parser = &pr->parser;
|
|
1198
|
+
|
|
1199
|
+
int j, n;
|
|
1200
|
+
long i, i1, i2;
|
|
1201
|
+
double c0;
|
|
1202
|
+
Snode *Node = net->Node;
|
|
1203
|
+
|
|
1204
|
+
if (net->Nnodes == 0) return setError(parser, 0, 203); // No nodes defined yet
|
|
1205
|
+
n = parser->Ntokens;
|
|
1206
|
+
if (n < 2) return 0;
|
|
1207
|
+
|
|
1208
|
+
// Single node name supplied
|
|
1209
|
+
if (n == 2)
|
|
1210
|
+
{
|
|
1211
|
+
if ((j = findnode(net,parser->Tok[0])) == 0) return setError(parser, 0, 203);
|
|
1212
|
+
if (!getfloat(parser->Tok[1], &c0)) return setError(parser, 1, 202);
|
|
1213
|
+
if (c0 < 0.0) return setError(parser, 1, 209);
|
|
1214
|
+
Node[j].C0 = c0;
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
// Range of node names supplied
|
|
1218
|
+
else
|
|
1219
|
+
{
|
|
1220
|
+
// Parse quality value
|
|
1221
|
+
if (!getfloat(parser->Tok[2], &c0)) return setError(parser, 2, 202);
|
|
1222
|
+
if (c0 < 0.0) return setError(parser, 2, 209);
|
|
1223
|
+
|
|
1224
|
+
// If numerical node names supplied, then use numerical comparison
|
|
1225
|
+
// to find which nodes are assigned the quality value
|
|
1226
|
+
if ((i1 = atol(parser->Tok[0])) > 0 &&
|
|
1227
|
+
(i2 = atol(parser->Tok[1])) > 0)
|
|
1228
|
+
{
|
|
1229
|
+
for (j = 1; j <= net->Nnodes; j++)
|
|
1230
|
+
{
|
|
1231
|
+
i = atol(Node[j].ID);
|
|
1232
|
+
if (i >= i1 && i <= i2) Node[j].C0 = c0;
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
// Otherwise use lexicographic comparison
|
|
1237
|
+
else
|
|
1238
|
+
{
|
|
1239
|
+
for (j = 1; j <= net->Nnodes; j++)
|
|
1240
|
+
{
|
|
1241
|
+
if ((strcmp(parser->Tok[0], Node[j].ID) <= 0) &&
|
|
1242
|
+
(strcmp(parser->Tok[1], Node[j].ID) >= 0)
|
|
1243
|
+
) Node[j].C0 = c0;
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
return 0;
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
int reactdata(Project *pr)
|
|
1251
|
+
/*
|
|
1252
|
+
**--------------------------------------------------------------
|
|
1253
|
+
** Input: none
|
|
1254
|
+
** Output: returns error code
|
|
1255
|
+
** Purpose: processes reaction coeff. data
|
|
1256
|
+
** Formats:
|
|
1257
|
+
** [REACTIONS]
|
|
1258
|
+
** ORDER {BULK/WALL/TANK} value
|
|
1259
|
+
** GLOBAL BULK coeff
|
|
1260
|
+
** GLOBAL WALL coeff
|
|
1261
|
+
** BULK link1 (link2) coeff
|
|
1262
|
+
** WALL link1 (link2) coeff
|
|
1263
|
+
** TANK node1 (node2) coeff
|
|
1264
|
+
** LIMITING POTENTIAL value
|
|
1265
|
+
** ROUGHNESS CORRELATION value
|
|
1266
|
+
**--------------------------------------------------------------
|
|
1267
|
+
*/
|
|
1268
|
+
{
|
|
1269
|
+
Network *net = &pr->network;
|
|
1270
|
+
Quality *qual = &pr->quality;
|
|
1271
|
+
Parser *parser = &pr->parser;
|
|
1272
|
+
|
|
1273
|
+
int item, j, n;
|
|
1274
|
+
long i, i1, i2;
|
|
1275
|
+
double y;
|
|
1276
|
+
|
|
1277
|
+
// Skip line if insufficient data
|
|
1278
|
+
n = parser->Ntokens;
|
|
1279
|
+
if (n < 3) return 0;
|
|
1280
|
+
|
|
1281
|
+
// Keyword is ORDER
|
|
1282
|
+
if (match(parser->Tok[0], w_ORDER))
|
|
1283
|
+
{
|
|
1284
|
+
if (!getfloat(parser->Tok[n - 1], &y)) return setError(parser, n-1, 202);
|
|
1285
|
+
if (match(parser->Tok[1], w_BULK)) qual->BulkOrder = y;
|
|
1286
|
+
else if (match(parser->Tok[1], w_TANK)) qual->TankOrder = y;
|
|
1287
|
+
else if (match(parser->Tok[1], w_WALL))
|
|
1288
|
+
{
|
|
1289
|
+
if (y == 0.0) qual->WallOrder = 0.0;
|
|
1290
|
+
else if (y == 1.0) qual->WallOrder = 1.0;
|
|
1291
|
+
else return setError(parser, n-1, 213);
|
|
1292
|
+
}
|
|
1293
|
+
else return setError(parser, 1, 213);
|
|
1294
|
+
return 0;
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
// Keyword is ROUGHNESS
|
|
1298
|
+
if (match(parser->Tok[0], w_ROUGHNESS))
|
|
1299
|
+
{
|
|
1300
|
+
if (!getfloat(parser->Tok[n - 1], &y)) return setError(parser, n-1, 202);
|
|
1301
|
+
qual->Rfactor = y;
|
|
1302
|
+
return 0;
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
// Keyword is LIMITING
|
|
1306
|
+
if (match(parser->Tok[0], w_LIMITING))
|
|
1307
|
+
{
|
|
1308
|
+
if (!getfloat(parser->Tok[n - 1], &y)) return setError(parser, n-1, 202);
|
|
1309
|
+
qual->Climit = y;
|
|
1310
|
+
return 0;
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
// Keyword is GLOBAL
|
|
1314
|
+
if (match(parser->Tok[0], w_GLOBAL))
|
|
1315
|
+
{
|
|
1316
|
+
if (!getfloat(parser->Tok[n - 1], &y)) return setError(parser, n-1, 202);
|
|
1317
|
+
if (match(parser->Tok[1], w_BULK)) qual->Kbulk = y;
|
|
1318
|
+
else if (match(parser->Tok[1], w_WALL)) qual->Kwall = y;
|
|
1319
|
+
else return setError(parser, 1, 213);
|
|
1320
|
+
return 0;
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
// Keyword is BULK, WALL or TANK
|
|
1324
|
+
if (match(parser->Tok[0], w_BULK)) item = 1;
|
|
1325
|
+
else if (match(parser->Tok[0], w_WALL)) item = 2;
|
|
1326
|
+
else if (match(parser->Tok[0], w_TANK)) item = 3;
|
|
1327
|
+
else return setError(parser, 0, 213);
|
|
1328
|
+
|
|
1329
|
+
// Case where tank rate coeffs. are being set
|
|
1330
|
+
if (item == 3)
|
|
1331
|
+
{
|
|
1332
|
+
// Get the rate coeff. value
|
|
1333
|
+
if (!getfloat(parser->Tok[n - 1], &y)) return setError(parser, n-1, 202);
|
|
1334
|
+
|
|
1335
|
+
// Case where just a single tank is specified
|
|
1336
|
+
if (n == 3)
|
|
1337
|
+
{
|
|
1338
|
+
if ((j = findnode(net,parser->Tok[1])) <= net->Njuncs) return 0;
|
|
1339
|
+
net->Tank[j - net->Njuncs].Kb = y;
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
// Case where a numerical range of tank IDs is specified
|
|
1343
|
+
else if ((i1 = atol(parser->Tok[1])) > 0 &&
|
|
1344
|
+
(i2 = atol(parser->Tok[2])) > 0)
|
|
1345
|
+
{
|
|
1346
|
+
for (j = net->Njuncs + 1; j <= net->Nnodes; j++)
|
|
1347
|
+
{
|
|
1348
|
+
i = atol(net->Node[j].ID);
|
|
1349
|
+
if (i >= i1 && i <= i2) net->Tank[j - net->Njuncs].Kb = y;
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
// Case where a general range of tank IDs is specified
|
|
1354
|
+
else for (j = net->Njuncs + 1; j <= net->Nnodes; j++)
|
|
1355
|
+
{
|
|
1356
|
+
if ((strcmp(parser->Tok[1], net->Node[j].ID) <= 0) &&
|
|
1357
|
+
(strcmp(parser->Tok[2], net->Node[j].ID) >= 0)
|
|
1358
|
+
) net->Tank[j - net->Njuncs].Kb = y;
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
// Case where pipe rate coeffs. are being set
|
|
1363
|
+
else
|
|
1364
|
+
{
|
|
1365
|
+
// Get the rate coeff. value
|
|
1366
|
+
if (!getfloat(parser->Tok[n - 1], &y)) return setError(parser, n-1, 202);
|
|
1367
|
+
if (net->Nlinks == 0) return 0;
|
|
1368
|
+
|
|
1369
|
+
// Case where just a single link is specified
|
|
1370
|
+
if (n == 3)
|
|
1371
|
+
{
|
|
1372
|
+
if ((j = findlink(net, parser->Tok[1])) == 0) return 0;
|
|
1373
|
+
if (item == 1) net->Link[j].Kb = y;
|
|
1374
|
+
else net->Link[j].Kw = y;
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
// Case where a numerical range of link IDs is specified
|
|
1378
|
+
else if ((i1 = atol(parser->Tok[1])) > 0 &&
|
|
1379
|
+
(i2 = atol(parser->Tok[2])) > 0)
|
|
1380
|
+
{
|
|
1381
|
+
for (j = 1; j <= net->Nlinks; j++)
|
|
1382
|
+
{
|
|
1383
|
+
i = atol(net->Link[j].ID);
|
|
1384
|
+
if (i >= i1 && i <= i2)
|
|
1385
|
+
{
|
|
1386
|
+
if (item == 1) net->Link[j].Kb = y;
|
|
1387
|
+
else net->Link[j].Kw = y;
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
// Case where a general range of link IDs is specified
|
|
1393
|
+
else for (j = 1; j <= net->Nlinks; j++)
|
|
1394
|
+
{
|
|
1395
|
+
if ((strcmp(parser->Tok[1], net->Link[j].ID) <= 0) &&
|
|
1396
|
+
(strcmp(parser->Tok[2], net->Link[j].ID) >= 0))
|
|
1397
|
+
{
|
|
1398
|
+
if (item == 1) net->Link[j].Kb = y;
|
|
1399
|
+
else net->Link[j].Kw = y;
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
return 0;
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
int mixingdata(Project *pr)
|
|
1407
|
+
/*
|
|
1408
|
+
**-------------------------------------------------------------
|
|
1409
|
+
** Input: none
|
|
1410
|
+
** Output: returns error code
|
|
1411
|
+
** Purpose: processes tank mixing data
|
|
1412
|
+
** Format:
|
|
1413
|
+
** [MIXING]
|
|
1414
|
+
** TankID MixModel FractVolume
|
|
1415
|
+
**-------------------------------------------------------------
|
|
1416
|
+
*/
|
|
1417
|
+
{
|
|
1418
|
+
Network *net = &pr->network;
|
|
1419
|
+
Parser *parser = &pr->parser;
|
|
1420
|
+
|
|
1421
|
+
int i, // Tank index
|
|
1422
|
+
j, // Node index
|
|
1423
|
+
m, // Type of mixing model
|
|
1424
|
+
n; // Number of data items
|
|
1425
|
+
double v; // Mixing zone volume fraction
|
|
1426
|
+
|
|
1427
|
+
// Check for valid data
|
|
1428
|
+
if (net->Nnodes == 0) return setError(parser, 0, 203);
|
|
1429
|
+
n = parser->Ntokens;
|
|
1430
|
+
if (n < 2) return 0;
|
|
1431
|
+
j = findnode(net, parser->Tok[0]);
|
|
1432
|
+
if (j == 0) return setError(parser, 0, 203);
|
|
1433
|
+
if (j <= net->Njuncs) return 0;
|
|
1434
|
+
if ((m = findmatch(parser->Tok[1], MixTxt)) < 0) return setError(parser, 1, 213);
|
|
1435
|
+
|
|
1436
|
+
// Find mixing zone volume fraction (which can't be 0)
|
|
1437
|
+
v = 1.0;
|
|
1438
|
+
if ((m == MIX2) && (n == 3) &&
|
|
1439
|
+
(!getfloat(parser->Tok[2], &v))) return setError(parser, 2, 202);
|
|
1440
|
+
if (v == 0.0) v = 1.0;
|
|
1441
|
+
|
|
1442
|
+
// Assign mixing data to tank (return if tank is a reservoir)
|
|
1443
|
+
i = j - net->Njuncs;
|
|
1444
|
+
if (net->Tank[i].A == 0.0) return 0;
|
|
1445
|
+
net->Tank[i].MixModel = (char)m;
|
|
1446
|
+
net->Tank[i].V1frac = v;
|
|
1447
|
+
return 0;
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
int statusdata(Project *pr)
|
|
1451
|
+
/*
|
|
1452
|
+
**--------------------------------------------------------------
|
|
1453
|
+
** Input: none
|
|
1454
|
+
** Output: returns error code
|
|
1455
|
+
** Purpose: processes link initial status data
|
|
1456
|
+
** Formats:
|
|
1457
|
+
** [STATUS]
|
|
1458
|
+
** link value
|
|
1459
|
+
** link1 (link2) value
|
|
1460
|
+
**--------------------------------------------------------------
|
|
1461
|
+
*/
|
|
1462
|
+
{
|
|
1463
|
+
Network *net = &pr->network;
|
|
1464
|
+
Parser *parser = &pr->parser;
|
|
1465
|
+
|
|
1466
|
+
int j, n;
|
|
1467
|
+
long i, i1, i2;
|
|
1468
|
+
double y = 0.0;
|
|
1469
|
+
char status = ACTIVE;
|
|
1470
|
+
|
|
1471
|
+
if (net->Nlinks == 0) return setError(parser, 0, 204);
|
|
1472
|
+
n = parser->Ntokens - 1;
|
|
1473
|
+
if (n < 1) return 201;
|
|
1474
|
+
|
|
1475
|
+
// Check for legal status setting
|
|
1476
|
+
if (match(parser->Tok[n], w_OPEN)) status = OPEN;
|
|
1477
|
+
else if (match(parser->Tok[n], w_CLOSED)) status = CLOSED;
|
|
1478
|
+
else
|
|
1479
|
+
{
|
|
1480
|
+
if (!getfloat(parser->Tok[n], &y)) return setError(parser, n, 202);
|
|
1481
|
+
if (y < 0.0) return setError(parser, n, 211);
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
// A single link ID was supplied
|
|
1485
|
+
if (n == 1)
|
|
1486
|
+
{
|
|
1487
|
+
if ((j = findlink(net, parser->Tok[0])) == 0) return setError(parser, 0, 204);
|
|
1488
|
+
|
|
1489
|
+
// Cannot change status of a Check Valve
|
|
1490
|
+
if (net->Link[j].Type == CVPIPE) return setError(parser, 0, 207);
|
|
1491
|
+
|
|
1492
|
+
// Cannot change setting for a GPV
|
|
1493
|
+
if (net->Link[j].Type == GPV && status == ACTIVE) return setError(parser, 0, 207);
|
|
1494
|
+
changestatus(net, j, status, y);
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1497
|
+
// A range of numerical link ID's was supplied
|
|
1498
|
+
else if ((i1 = atol(parser->Tok[0])) > 0 &&
|
|
1499
|
+
(i2 = atol(parser->Tok[1])) > 0)
|
|
1500
|
+
{
|
|
1501
|
+
for (j = 1; j <= net->Nlinks; j++)
|
|
1502
|
+
{
|
|
1503
|
+
i = atol(net->Link[j].ID);
|
|
1504
|
+
if (i >= i1 && i <= i2) changestatus(net, j, status, y);
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
// A range of general link ID's was supplied
|
|
1509
|
+
else for (j = 1; j <= net->Nlinks; j++)
|
|
1510
|
+
{
|
|
1511
|
+
if ((strcmp(parser->Tok[0], net->Link[j].ID) <= 0) &&
|
|
1512
|
+
(strcmp(parser->Tok[1], net->Link[j].ID) >= 0)
|
|
1513
|
+
) changestatus(net, j, status, y);
|
|
1514
|
+
}
|
|
1515
|
+
return 0;
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
int energydata(Project *pr)
|
|
1519
|
+
/*
|
|
1520
|
+
**--------------------------------------------------------------
|
|
1521
|
+
** Input: none
|
|
1522
|
+
** Output: returns error code
|
|
1523
|
+
** Purpose: processes pump energy data
|
|
1524
|
+
** Formats:
|
|
1525
|
+
** [ENERGY]
|
|
1526
|
+
** GLOBAL {PRICE/PATTERN/EFFIC} value
|
|
1527
|
+
** PUMP id {PRICE/PATTERN/EFFIC} value
|
|
1528
|
+
** DEMAND CHARGE value
|
|
1529
|
+
**--------------------------------------------------------------
|
|
1530
|
+
*/
|
|
1531
|
+
{
|
|
1532
|
+
Network *net = &pr->network;
|
|
1533
|
+
Hydraul *hyd = &pr->hydraul;
|
|
1534
|
+
Parser *parser = &pr->parser;
|
|
1535
|
+
|
|
1536
|
+
int j, k, n, p, c;
|
|
1537
|
+
double y;
|
|
1538
|
+
|
|
1539
|
+
Slink *Link = net->Link;
|
|
1540
|
+
Spump *Pump = net->Pump;
|
|
1541
|
+
|
|
1542
|
+
// Check for sufficient data
|
|
1543
|
+
n = parser->Ntokens;
|
|
1544
|
+
if (n < 3) return 201;
|
|
1545
|
+
|
|
1546
|
+
// First keyword is DEMAND
|
|
1547
|
+
if (match(parser->Tok[0], w_DMNDCHARGE))
|
|
1548
|
+
{
|
|
1549
|
+
if (!getfloat(parser->Tok[2], &y)) return setError(parser, 2, 202);
|
|
1550
|
+
if (y < 0.0) return setError(parser, 2, 213);
|
|
1551
|
+
hyd->Dcost = y;
|
|
1552
|
+
return 0;
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
// First keyword is GLOBAL (remaining data refer to global options)
|
|
1556
|
+
if (match(parser->Tok[0], w_GLOBAL))
|
|
1557
|
+
{
|
|
1558
|
+
j = 0;
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
// First keyword is PUMP (remaining data refer to a specific pump)
|
|
1562
|
+
else if (match(parser->Tok[0], w_PUMP))
|
|
1563
|
+
{
|
|
1564
|
+
if (n < 4) return 201;
|
|
1565
|
+
k = findlink(net,parser->Tok[1]);
|
|
1566
|
+
if (k == 0) return setError(parser, 1, 216);
|
|
1567
|
+
if (Link[k].Type != PUMP) return setError(parser, 1, 216);
|
|
1568
|
+
j = findpump(net, k);
|
|
1569
|
+
}
|
|
1570
|
+
else return setError(parser, 0, 213);
|
|
1571
|
+
|
|
1572
|
+
// PRICE parameter being set
|
|
1573
|
+
if (match(parser->Tok[n - 2], w_PRICE))
|
|
1574
|
+
{
|
|
1575
|
+
if (!getfloat(parser->Tok[n - 1], &y)) return setError(parser, n-1, 202);
|
|
1576
|
+
if (y < 0.0) return setError(parser, n-1, 217);
|
|
1577
|
+
if (j == 0) hyd->Ecost = y;
|
|
1578
|
+
else Pump[j].Ecost = y;
|
|
1579
|
+
return 0;
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1582
|
+
// Price PATTERN being set
|
|
1583
|
+
else if (match(parser->Tok[n - 2], w_PATTERN))
|
|
1584
|
+
{
|
|
1585
|
+
p = findpattern(net, parser->Tok[n - 1]);
|
|
1586
|
+
if (p < 0) return setError(parser, n - 1, 205);
|
|
1587
|
+
if (j == 0) hyd->Epat = p;
|
|
1588
|
+
else Pump[j].Epat = p;
|
|
1589
|
+
return 0;
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
// Pump EFFIC being set
|
|
1593
|
+
else if (match(parser->Tok[n - 2], w_EFFIC))
|
|
1594
|
+
{
|
|
1595
|
+
if (j == 0)
|
|
1596
|
+
{
|
|
1597
|
+
if (!getfloat(parser->Tok[n - 1], &y)) return setError(parser, n - 1, 202);
|
|
1598
|
+
if (y <= 0.0) return setError(parser, n - 1, 217);
|
|
1599
|
+
hyd->Epump = y;
|
|
1600
|
+
}
|
|
1601
|
+
else
|
|
1602
|
+
{
|
|
1603
|
+
c = findcurve(net, parser->Tok[n - 1]);
|
|
1604
|
+
if (c == 0) return setError(parser, n - 1, 206);
|
|
1605
|
+
Pump[j].Ecurve = c;
|
|
1606
|
+
net->Curve[c].Type = EFFIC_CURVE;
|
|
1607
|
+
}
|
|
1608
|
+
return 0;
|
|
1609
|
+
}
|
|
1610
|
+
return 201;
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
int reportdata(Project *pr)
|
|
1614
|
+
/*
|
|
1615
|
+
**--------------------------------------------------------------
|
|
1616
|
+
** Input: none
|
|
1617
|
+
** Output: returns error code
|
|
1618
|
+
** Purpose: processes report options data
|
|
1619
|
+
** Formats:
|
|
1620
|
+
** PAGE linesperpage
|
|
1621
|
+
** STATUS {NONE/YES/FULL}
|
|
1622
|
+
** SUMMARY {YES/NO}
|
|
1623
|
+
** MESSAGES {YES/NO}
|
|
1624
|
+
** ENERGY {NO/YES}
|
|
1625
|
+
** NODES {NONE/ALL}
|
|
1626
|
+
** NODES node1 node2 ...
|
|
1627
|
+
** LINKS {NONE/ALL}
|
|
1628
|
+
** LINKS link1 link2 ...
|
|
1629
|
+
** FILE filename
|
|
1630
|
+
** variable {YES/NO}
|
|
1631
|
+
** variable {BELOW/ABOVE/PRECISION} value
|
|
1632
|
+
**--------------------------------------------------------------
|
|
1633
|
+
*/
|
|
1634
|
+
{
|
|
1635
|
+
Network *net = &pr->network;
|
|
1636
|
+
Report *rpt = &pr->report;
|
|
1637
|
+
Parser *parser = &pr->parser;
|
|
1638
|
+
|
|
1639
|
+
int i, j, n;
|
|
1640
|
+
double y;
|
|
1641
|
+
|
|
1642
|
+
n = parser->Ntokens - 1;
|
|
1643
|
+
if (n < 1) return 201;
|
|
1644
|
+
|
|
1645
|
+
// Value for page size
|
|
1646
|
+
if (match(parser->Tok[0], w_PAGE))
|
|
1647
|
+
{
|
|
1648
|
+
if (!getfloat(parser->Tok[n], &y)) return setError(parser, n, 202);
|
|
1649
|
+
if (y < 0.0 || y > 255.0) return setError(parser, n, 213);
|
|
1650
|
+
rpt->PageSize = (int)y;
|
|
1651
|
+
return 0;
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
// Request that status reports be written
|
|
1655
|
+
if (match(parser->Tok[0], w_STATUS))
|
|
1656
|
+
{
|
|
1657
|
+
if (match(parser->Tok[n], w_NO)) rpt->Statflag = FALSE;
|
|
1658
|
+
if (match(parser->Tok[n], w_YES)) rpt->Statflag = TRUE;
|
|
1659
|
+
if (match(parser->Tok[n], w_FULL)) rpt->Statflag = FULL;
|
|
1660
|
+
return 0;
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1663
|
+
// Request summary report
|
|
1664
|
+
if (match(parser->Tok[0], w_SUMMARY))
|
|
1665
|
+
{
|
|
1666
|
+
if (match(parser->Tok[n], w_NO)) rpt->Summaryflag = FALSE;
|
|
1667
|
+
if (match(parser->Tok[n], w_YES)) rpt->Summaryflag = TRUE;
|
|
1668
|
+
return 0;
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
// Request error/warning message reporting
|
|
1672
|
+
if (match(parser->Tok[0], w_MESSAGES))
|
|
1673
|
+
{
|
|
1674
|
+
if (match(parser->Tok[n], w_NO)) rpt->Messageflag = FALSE;
|
|
1675
|
+
if (match(parser->Tok[n], w_YES)) rpt->Messageflag = TRUE;
|
|
1676
|
+
return 0;
|
|
1677
|
+
}
|
|
1678
|
+
|
|
1679
|
+
// Request an energy usage report
|
|
1680
|
+
if (match(parser->Tok[0], w_ENERGY))
|
|
1681
|
+
{
|
|
1682
|
+
if (match(parser->Tok[n], w_NO)) rpt->Energyflag = FALSE;
|
|
1683
|
+
if (match(parser->Tok[n], w_YES)) rpt->Energyflag = TRUE;
|
|
1684
|
+
return 0;
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
// Particular reporting nodes specified
|
|
1688
|
+
if (match(parser->Tok[0], w_NODE))
|
|
1689
|
+
{
|
|
1690
|
+
if (match(parser->Tok[n], w_NONE)) rpt->Nodeflag = 0; // No nodes
|
|
1691
|
+
else if (match(parser->Tok[n], w_ALL)) rpt->Nodeflag = 1; // All nodes
|
|
1692
|
+
else
|
|
1693
|
+
{
|
|
1694
|
+
if (net->Nnodes == 0) return setError(parser, 1, 203);
|
|
1695
|
+
for (i = 1; i <= n; i++)
|
|
1696
|
+
{
|
|
1697
|
+
if ((j = findnode(net, parser->Tok[i])) == 0) return setError(parser, i, 203);
|
|
1698
|
+
net->Node[j].Rpt = 1;
|
|
1699
|
+
}
|
|
1700
|
+
rpt->Nodeflag = 2;
|
|
1701
|
+
}
|
|
1702
|
+
return 0;
|
|
1703
|
+
}
|
|
1704
|
+
|
|
1705
|
+
// Particular reporting links specified
|
|
1706
|
+
if (match(parser->Tok[0], w_LINK))
|
|
1707
|
+
{
|
|
1708
|
+
if (match(parser->Tok[n], w_NONE)) rpt->Linkflag = 0;
|
|
1709
|
+
else if (match(parser->Tok[n], w_ALL)) rpt->Linkflag = 1;
|
|
1710
|
+
else
|
|
1711
|
+
{
|
|
1712
|
+
if (net->Nlinks == 0) return setError(parser, 1, 204);
|
|
1713
|
+
for (i = 1; i <= n; i++)
|
|
1714
|
+
{
|
|
1715
|
+
if ((j = findlink(net, parser->Tok[i])) == 0) return setError(parser, i, 204);
|
|
1716
|
+
net->Link[j].Rpt = 1;
|
|
1717
|
+
}
|
|
1718
|
+
rpt->Linkflag = 2;
|
|
1719
|
+
}
|
|
1720
|
+
return 0;
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
// Report fields specified
|
|
1724
|
+
// Special case needed to distinguish "HEAD" from "HEADLOSS"
|
|
1725
|
+
if (strcomp(parser->Tok[0], t_HEADLOSS)) i = HEADLOSS;
|
|
1726
|
+
else i = findmatch(parser->Tok[0], Fldname);
|
|
1727
|
+
if (i >= 0)
|
|
1728
|
+
{
|
|
1729
|
+
if (i > FRICTION) return setError(parser, 0, 213);
|
|
1730
|
+
if (parser->Ntokens == 1 || match(parser->Tok[1], w_YES))
|
|
1731
|
+
{
|
|
1732
|
+
rpt->Field[i].Enabled = TRUE;
|
|
1733
|
+
return 0;
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
if (match(parser->Tok[1], w_NO))
|
|
1737
|
+
{
|
|
1738
|
+
rpt->Field[i].Enabled = FALSE;
|
|
1739
|
+
return 0;
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1742
|
+
// Get field qualifier type
|
|
1743
|
+
if (parser->Ntokens < 3) return 201;
|
|
1744
|
+
if (match(parser->Tok[1], w_BELOW)) j = LOW;
|
|
1745
|
+
else if (match(parser->Tok[1], w_ABOVE)) j = HI;
|
|
1746
|
+
else if (match(parser->Tok[1], w_PRECISION)) j = PREC;
|
|
1747
|
+
else return setError(parser, 1, 213);
|
|
1748
|
+
|
|
1749
|
+
// Get field qualifier value
|
|
1750
|
+
if (!getfloat(parser->Tok[2], &y)) return setError(parser, 2, 202);
|
|
1751
|
+
if (j == PREC)
|
|
1752
|
+
{
|
|
1753
|
+
rpt->Field[i].Enabled = TRUE;
|
|
1754
|
+
rpt->Field[i].Precision = ROUND(y);
|
|
1755
|
+
}
|
|
1756
|
+
else rpt->Field[i].RptLim[j] = y;
|
|
1757
|
+
return (0);
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1760
|
+
// Name of external report file
|
|
1761
|
+
if (match(parser->Tok[0], w_FILE))
|
|
1762
|
+
{
|
|
1763
|
+
strncpy(rpt->Rpt2Fname, parser->Tok[1], MAXFNAME);
|
|
1764
|
+
return 0;
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1767
|
+
// If get to here then return error condition
|
|
1768
|
+
return 201;
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
int timedata(Project *pr)
|
|
1772
|
+
/*
|
|
1773
|
+
**--------------------------------------------------------------
|
|
1774
|
+
** Input: none
|
|
1775
|
+
** Output: returns error code
|
|
1776
|
+
** Purpose: processes time options data
|
|
1777
|
+
** Formats:
|
|
1778
|
+
** STATISTIC {NONE/AVERAGE/MIN/MAX/RANGE}
|
|
1779
|
+
** DURATION value (units)
|
|
1780
|
+
** HYDRAULIC TIMESTEP value (units)
|
|
1781
|
+
** QUALITY TIMESTEP value (units)
|
|
1782
|
+
** MINIMUM TRAVELTIME value (units)
|
|
1783
|
+
** RULE TIMESTEP value (units)
|
|
1784
|
+
** PATTERN TIMESTEP value (units)
|
|
1785
|
+
** PATTERN START value (units)
|
|
1786
|
+
** REPORT TIMESTEP value (units)
|
|
1787
|
+
** REPORT START value (units)
|
|
1788
|
+
** START CLOCKTIME value (AM PM)
|
|
1789
|
+
**-------------------------------------------------------------
|
|
1790
|
+
*/
|
|
1791
|
+
{
|
|
1792
|
+
Report *rpt = &pr->report;
|
|
1793
|
+
Parser *parser = &pr->parser;
|
|
1794
|
+
Times *time = &pr->times;
|
|
1795
|
+
|
|
1796
|
+
int n;
|
|
1797
|
+
long t;
|
|
1798
|
+
double y;
|
|
1799
|
+
|
|
1800
|
+
n = parser->Ntokens - 1;
|
|
1801
|
+
if (n < 1) return 201;
|
|
1802
|
+
|
|
1803
|
+
// Check if setting report time statistic flag
|
|
1804
|
+
if (match(parser->Tok[0], w_STATISTIC))
|
|
1805
|
+
{
|
|
1806
|
+
if (match(parser->Tok[n], w_NONE)) rpt->Tstatflag = SERIES;
|
|
1807
|
+
else if (match(parser->Tok[n], w_NO)) rpt->Tstatflag = SERIES;
|
|
1808
|
+
else if (match(parser->Tok[n], w_AVG)) rpt->Tstatflag = AVG;
|
|
1809
|
+
else if (match(parser->Tok[n], w_MIN)) rpt->Tstatflag = MIN;
|
|
1810
|
+
else if (match(parser->Tok[n], w_MAX)) rpt->Tstatflag = MAX;
|
|
1811
|
+
else if (match(parser->Tok[n], w_RANGE)) rpt->Tstatflag = RANGE;
|
|
1812
|
+
else return setError(parser, n, 213);
|
|
1813
|
+
return 0;
|
|
1814
|
+
}
|
|
1815
|
+
|
|
1816
|
+
// Convert text time value to numerical value in seconds
|
|
1817
|
+
// Examples:
|
|
1818
|
+
// 5 = 5 * 3600 sec
|
|
1819
|
+
// 5 MINUTES = 5 * 60 sec
|
|
1820
|
+
// 13:50 = 13*3600 + 50*60 sec
|
|
1821
|
+
// 1:50 pm = (12+1)*3600 + 50*60 sec
|
|
1822
|
+
|
|
1823
|
+
if (!getfloat(parser->Tok[n], &y))
|
|
1824
|
+
{
|
|
1825
|
+
if ((y = hour(parser->Tok[n], "")) < 0.0)
|
|
1826
|
+
{
|
|
1827
|
+
if ((y = hour(parser->Tok[n - 1], parser->Tok[n])) < 0.0)
|
|
1828
|
+
{
|
|
1829
|
+
return setError(parser, n-1, 213);
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
t = (long)(3600.0 * y + 0.5);
|
|
1834
|
+
|
|
1835
|
+
/// Process the value assigned to the matched parameter
|
|
1836
|
+
if (match(parser->Tok[0], w_DURATION)) time->Dur = t;
|
|
1837
|
+
else if (match(parser->Tok[0], w_HYDRAULIC)) time->Hstep = t;
|
|
1838
|
+
else if (match(parser->Tok[0], w_QUALITY) ) time->Qstep = t;
|
|
1839
|
+
else if (match(parser->Tok[0], w_RULE)) time->Rulestep = t;
|
|
1840
|
+
else if (match(parser->Tok[0], w_MINIMUM)) return 0; // Not used anymore
|
|
1841
|
+
else if (match(parser->Tok[0], w_PATTERN))
|
|
1842
|
+
{
|
|
1843
|
+
if (match(parser->Tok[1], w_TIME)) time->Pstep = t;
|
|
1844
|
+
else if (match(parser->Tok[1], w_START)) time->Pstart = t;
|
|
1845
|
+
else return setError(parser, 1, 213);
|
|
1846
|
+
}
|
|
1847
|
+
else if (match(parser->Tok[0], w_REPORT))
|
|
1848
|
+
{
|
|
1849
|
+
if (match(parser->Tok[1], w_TIME)) time->Rstep = t;
|
|
1850
|
+
else if (match(parser->Tok[1], w_START)) time->Rstart = t;
|
|
1851
|
+
else return setError(parser, 1, 213);
|
|
1852
|
+
}
|
|
1853
|
+
else if (match(parser->Tok[0], w_START)) time->Tstart = t % SECperDAY;
|
|
1854
|
+
else return setError(parser, 0, 213);
|
|
1855
|
+
return 0;
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1858
|
+
int optiondata(Project *pr)
|
|
1859
|
+
/*
|
|
1860
|
+
**--------------------------------------------------------------
|
|
1861
|
+
** Input: none
|
|
1862
|
+
** Output: returns error code
|
|
1863
|
+
** Purpose: processes [OPTIONS] data
|
|
1864
|
+
**--------------------------------------------------------------
|
|
1865
|
+
*/
|
|
1866
|
+
{
|
|
1867
|
+
int i, n;
|
|
1868
|
+
Parser *parser = &pr->parser;
|
|
1869
|
+
|
|
1870
|
+
// Option is a named choice
|
|
1871
|
+
n = parser->Ntokens - 1;
|
|
1872
|
+
i = optionchoice(pr, n);
|
|
1873
|
+
if (i >= 0) return i;
|
|
1874
|
+
|
|
1875
|
+
// Option is a numerical value
|
|
1876
|
+
return (optionvalue(pr, n));
|
|
1877
|
+
}
|
|
1878
|
+
|
|
1879
|
+
int optionchoice(Project *pr, int n)
|
|
1880
|
+
/*
|
|
1881
|
+
**--------------------------------------------------------------
|
|
1882
|
+
** Input: n = index of last input token
|
|
1883
|
+
** Output: returns error code or 0 if option belongs to
|
|
1884
|
+
** those listed below, or -1 otherwise
|
|
1885
|
+
** Purpose: processes fixed choice [OPTIONS] data
|
|
1886
|
+
** Formats:
|
|
1887
|
+
** UNITS CFS/GPM/MGD/IMGD/AFD/LPS/LPM/MLD/CMH/CMD/CMS
|
|
1888
|
+
** PRESSURE PSI/KPA/METERS/BAR/FEET
|
|
1889
|
+
** HEADLOSS H-W/D-W/C-M
|
|
1890
|
+
** HYDRAULICS USE/SAVE filename
|
|
1891
|
+
** QUALITY NONE/AGE/TRACE/CHEMICAL (TraceNode)
|
|
1892
|
+
** MAP filename
|
|
1893
|
+
** VERIFY filename
|
|
1894
|
+
** UNBALANCED STOP/CONTINUE {Niter}
|
|
1895
|
+
** PATTERN id
|
|
1896
|
+
** DEMAND MODEL DDA/PDA
|
|
1897
|
+
** BACKFLOW ALLOWED YES/NO
|
|
1898
|
+
**--------------------------------------------------------------
|
|
1899
|
+
*/
|
|
1900
|
+
{
|
|
1901
|
+
Network *net = &pr->network;
|
|
1902
|
+
Hydraul *hyd = &pr->hydraul;
|
|
1903
|
+
Quality *qual = &pr->quality;
|
|
1904
|
+
Parser *parser = &pr->parser;
|
|
1905
|
+
Outfile *out = &pr->outfile;
|
|
1906
|
+
|
|
1907
|
+
int choice;
|
|
1908
|
+
|
|
1909
|
+
// Check if 1st token matches a parameter name and
|
|
1910
|
+
// process the input for the matched parameter
|
|
1911
|
+
if (n < 0) return 201;
|
|
1912
|
+
|
|
1913
|
+
// Flow UNITS
|
|
1914
|
+
if (match(parser->Tok[0], w_UNITS))
|
|
1915
|
+
{
|
|
1916
|
+
if (n < 1) return 0;
|
|
1917
|
+
if (!getunitsoption(pr, parser->Tok[1]))
|
|
1918
|
+
return setError(parser, 1, 213);
|
|
1919
|
+
}
|
|
1920
|
+
|
|
1921
|
+
// PRESSURE units
|
|
1922
|
+
else if (match(parser->Tok[0], w_PRESSURE))
|
|
1923
|
+
{
|
|
1924
|
+
if (n < 1) return 0;
|
|
1925
|
+
else if (match(parser->Tok[1], w_EXPONENT)) return -1;
|
|
1926
|
+
else if (match(parser->Tok[1], w_PSI)) parser->Pressflag = PSI;
|
|
1927
|
+
else if (match(parser->Tok[1], w_KPA)) parser->Pressflag = KPA;
|
|
1928
|
+
else if (match(parser->Tok[1], w_METERS)) parser->Pressflag = METERS;
|
|
1929
|
+
else if (match(parser->Tok[1], w_BAR)) parser->Pressflag = BAR;
|
|
1930
|
+
else if (match(parser->Tok[1], w_FEET)) parser->Pressflag = FEET;
|
|
1931
|
+
else return setError(parser, 1, 213);
|
|
1932
|
+
}
|
|
1933
|
+
|
|
1934
|
+
// HEADLOSS formula
|
|
1935
|
+
else if (match(parser->Tok[0], w_HEADLOSS))
|
|
1936
|
+
{
|
|
1937
|
+
if (n < 1) return 0;
|
|
1938
|
+
if (!getheadlossoption(pr, parser->Tok[1]))
|
|
1939
|
+
return setError(parser, 1, 213);
|
|
1940
|
+
}
|
|
1941
|
+
|
|
1942
|
+
// HYDRUALICS USE/SAVE file option
|
|
1943
|
+
else if (match(parser->Tok[0], w_HYDRAULIC))
|
|
1944
|
+
{
|
|
1945
|
+
if (n < 2) return 0;
|
|
1946
|
+
else if (match(parser->Tok[1], w_USE)) out->Hydflag = USE;
|
|
1947
|
+
else if (match(parser->Tok[1], w_SAVE)) out->Hydflag = SAVE;
|
|
1948
|
+
else return setError(parser, 1, 213);
|
|
1949
|
+
strncpy(out->HydFname, parser->Tok[2], MAXFNAME);
|
|
1950
|
+
}
|
|
1951
|
+
|
|
1952
|
+
// Water QUALITY option
|
|
1953
|
+
else if (match(parser->Tok[0], w_QUALITY))
|
|
1954
|
+
{
|
|
1955
|
+
if (n < 1) return 0;
|
|
1956
|
+
else if (match(parser->Tok[1], w_NONE)) qual->Qualflag = NONE;
|
|
1957
|
+
else if (match(parser->Tok[1], w_CHEM)) qual->Qualflag = CHEM;
|
|
1958
|
+
else if (match(parser->Tok[1], w_AGE)) qual->Qualflag = AGE;
|
|
1959
|
+
else if (match(parser->Tok[1], w_TRACE)) qual->Qualflag = TRACE;
|
|
1960
|
+
else
|
|
1961
|
+
{
|
|
1962
|
+
qual->Qualflag = CHEM;
|
|
1963
|
+
strncpy(qual->ChemName, parser->Tok[1], MAXID);
|
|
1964
|
+
if (n >= 2) strncpy(qual->ChemUnits, parser->Tok[2], MAXID);
|
|
1965
|
+
}
|
|
1966
|
+
if (qual->Qualflag == TRACE)
|
|
1967
|
+
{
|
|
1968
|
+
if (n < 2) return 201;
|
|
1969
|
+
qual->TraceNode = findnode(net, parser->Tok[2]);
|
|
1970
|
+
if (qual->TraceNode == 0) return setError(parser, 2, 212);
|
|
1971
|
+
strncpy(qual->ChemName, u_PERCENT, MAXID);
|
|
1972
|
+
strncpy(qual->ChemUnits, parser->Tok[2], MAXID);
|
|
1973
|
+
}
|
|
1974
|
+
if (qual->Qualflag == AGE)
|
|
1975
|
+
{
|
|
1976
|
+
strncpy(qual->ChemName, w_AGE, MAXID);
|
|
1977
|
+
strncpy(qual->ChemUnits, u_HOURS, MAXID);
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
|
|
1981
|
+
// MAP file name
|
|
1982
|
+
else if (match(parser->Tok[0], w_MAP))
|
|
1983
|
+
{
|
|
1984
|
+
if (n < 1) return 0;
|
|
1985
|
+
strncpy(pr->MapFname, parser->Tok[1], MAXFNAME);
|
|
1986
|
+
}
|
|
1987
|
+
|
|
1988
|
+
else if (match(parser->Tok[0], w_VERIFY))
|
|
1989
|
+
{
|
|
1990
|
+
// Deprecated
|
|
1991
|
+
}
|
|
1992
|
+
|
|
1993
|
+
// Hydraulics UNBALANCED option
|
|
1994
|
+
else if (match(parser->Tok[0], w_UNBALANCED))
|
|
1995
|
+
{
|
|
1996
|
+
if (n < 1) return 0;
|
|
1997
|
+
if (match(parser->Tok[1], w_STOP)) hyd->ExtraIter = -1;
|
|
1998
|
+
else if (match(parser->Tok[1], w_CONTINUE))
|
|
1999
|
+
{
|
|
2000
|
+
if (n >= 2) hyd->ExtraIter = atoi(parser->Tok[2]);
|
|
2001
|
+
else hyd->ExtraIter = 0;
|
|
2002
|
+
}
|
|
2003
|
+
else return setError(parser, 1, 213);
|
|
2004
|
+
}
|
|
2005
|
+
|
|
2006
|
+
// Default demand PATTERN
|
|
2007
|
+
else if (match(parser->Tok[0], w_PATTERN))
|
|
2008
|
+
{
|
|
2009
|
+
if (n < 1) return 0;
|
|
2010
|
+
strncpy(parser->DefPatID, parser->Tok[1], MAXID);
|
|
2011
|
+
}
|
|
2012
|
+
|
|
2013
|
+
// DEMAND model
|
|
2014
|
+
else if (match(parser->Tok[0], w_DEMAND))
|
|
2015
|
+
{
|
|
2016
|
+
if (n < 2) return 0;
|
|
2017
|
+
if (!match(parser->Tok[1], w_MODEL)) return -1;
|
|
2018
|
+
choice = findmatch(parser->Tok[2], DemandModelTxt);
|
|
2019
|
+
if (choice < 0) return setError(parser, 2, 213);
|
|
2020
|
+
hyd->DemandModel = choice;
|
|
2021
|
+
}
|
|
2022
|
+
|
|
2023
|
+
// Emitter BACKFLOW ALLOWED
|
|
2024
|
+
else if (match(parser->Tok[0], w_BACKFLOW))
|
|
2025
|
+
{
|
|
2026
|
+
if (n < 2) return 0;
|
|
2027
|
+
if (!match(parser->Tok[1], w_ALLOWED)) return -1;
|
|
2028
|
+
choice = findmatch(parser->Tok[2], BackflowTxt);
|
|
2029
|
+
if (choice < 0) return setError(parser, 2, 213);
|
|
2030
|
+
hyd->EmitBackFlag = choice;
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2033
|
+
// Return -1 if keyword did not match any option
|
|
2034
|
+
else return -1;
|
|
2035
|
+
return 0;
|
|
2036
|
+
}
|
|
2037
|
+
|
|
2038
|
+
int optionvalue(Project *pr, int n)
|
|
2039
|
+
/*
|
|
2040
|
+
**-------------------------------------------------------------
|
|
2041
|
+
** Input: n = index of last input token
|
|
2042
|
+
** Output: returns error code
|
|
2043
|
+
** Purpose: processes numerical value [OPTIONS] data
|
|
2044
|
+
** Formats:
|
|
2045
|
+
** DEMAND MULTIPLIER value
|
|
2046
|
+
** EMITTER EXPONENT value
|
|
2047
|
+
** VISCOSITY value
|
|
2048
|
+
** DIFFUSIVITY value
|
|
2049
|
+
** SPECIFIC GRAVITY value
|
|
2050
|
+
** TRIALS value
|
|
2051
|
+
** ACCURACY value
|
|
2052
|
+
|
|
2053
|
+
** HEADERROR value
|
|
2054
|
+
** FLOWCHANGE value
|
|
2055
|
+
** MINIMUM PRESSURE value
|
|
2056
|
+
** REQUIRED PRESSURE value
|
|
2057
|
+
** PRESSURE EXPONENT value
|
|
2058
|
+
|
|
2059
|
+
** TOLERANCE value
|
|
2060
|
+
** SEGMENTS value (not used)
|
|
2061
|
+
** ------ Undocumented Options -----
|
|
2062
|
+
** HTOL value
|
|
2063
|
+
** QTOL value
|
|
2064
|
+
** RQTOL value
|
|
2065
|
+
** CHECKFREQ value
|
|
2066
|
+
** MAXCHECK value
|
|
2067
|
+
** DAMPLIMIT value
|
|
2068
|
+
**--------------------------------------------------------------
|
|
2069
|
+
*/
|
|
2070
|
+
{
|
|
2071
|
+
Hydraul *hyd = &pr->hydraul;
|
|
2072
|
+
Quality *qual = &pr->quality;
|
|
2073
|
+
Parser *parser = &pr->parser;
|
|
2074
|
+
|
|
2075
|
+
int nvalue = 1; // Index of token with numerical value
|
|
2076
|
+
double y;
|
|
2077
|
+
char* tok0 = parser->Tok[0];
|
|
2078
|
+
|
|
2079
|
+
// Check for deprecated SEGMENTS keyword
|
|
2080
|
+
if (match(tok0, w_SEGMENTS)) return 0;
|
|
2081
|
+
|
|
2082
|
+
// Check for missing value (which is permissible)
|
|
2083
|
+
if (match(tok0, w_SPECGRAV) || match(tok0, w_EMITTER) ||
|
|
2084
|
+
match(tok0, w_DEMAND) || match(tok0, w_MINIMUM) ||
|
|
2085
|
+
match(tok0, w_REQUIRED) || match(tok0, w_PRESSURE) ||
|
|
2086
|
+
match(tok0, w_PRECISION)
|
|
2087
|
+
) nvalue = 2;
|
|
2088
|
+
if (n < nvalue) return 0;
|
|
2089
|
+
|
|
2090
|
+
// Check for valid numerical input
|
|
2091
|
+
if (!getfloat(parser->Tok[nvalue], &y)) return setError(parser, nvalue, 202);
|
|
2092
|
+
|
|
2093
|
+
// Quality tolerance option (which can be 0)
|
|
2094
|
+
if (match(tok0, w_TOLERANCE))
|
|
2095
|
+
{
|
|
2096
|
+
if (y < 0.0) return setError(parser, nvalue, 213);
|
|
2097
|
+
qual->Ctol = y;
|
|
2098
|
+
return 0;
|
|
2099
|
+
}
|
|
2100
|
+
|
|
2101
|
+
// Diffusivity
|
|
2102
|
+
if (match(tok0, w_DIFFUSIVITY))
|
|
2103
|
+
{
|
|
2104
|
+
if (y < 0.0) return setError(parser, nvalue, 213);
|
|
2105
|
+
qual->Diffus = y;
|
|
2106
|
+
return 0;
|
|
2107
|
+
}
|
|
2108
|
+
|
|
2109
|
+
// Hydraulic damping limit option */
|
|
2110
|
+
if (match(tok0, w_DAMPLIMIT))
|
|
2111
|
+
{
|
|
2112
|
+
hyd->DampLimit = y;
|
|
2113
|
+
return 0;
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2116
|
+
// Flow change limit
|
|
2117
|
+
else if (match(tok0, w_FLOWCHANGE))
|
|
2118
|
+
{
|
|
2119
|
+
if (y < 0.0) return setError(parser, nvalue, 213);
|
|
2120
|
+
hyd->FlowChangeLimit = y;
|
|
2121
|
+
return 0;
|
|
2122
|
+
}
|
|
2123
|
+
|
|
2124
|
+
// Head loss error limit
|
|
2125
|
+
else if (match(tok0, w_HEADERROR))
|
|
2126
|
+
{
|
|
2127
|
+
if (y < 0.0) return setError(parser, nvalue, 213);
|
|
2128
|
+
hyd->HeadErrorLimit = y;
|
|
2129
|
+
return 0;
|
|
2130
|
+
}
|
|
2131
|
+
|
|
2132
|
+
// Pressure dependent demand parameters
|
|
2133
|
+
else if (match(tok0, w_MINIMUM))
|
|
2134
|
+
{
|
|
2135
|
+
if (y < 0.0) return setError(parser, nvalue, 213);
|
|
2136
|
+
// Required pressure still at default value
|
|
2137
|
+
if (hyd->Preq == MINPDIFF)
|
|
2138
|
+
hyd->Preq = y + MINPDIFF;
|
|
2139
|
+
// Required pressure already entered
|
|
2140
|
+
else if (hyd->Preq - y < MINPDIFF)
|
|
2141
|
+
return setError(parser, nvalue, 208);
|
|
2142
|
+
hyd->Pmin = y;
|
|
2143
|
+
return 0;
|
|
2144
|
+
}
|
|
2145
|
+
else if (match(tok0, w_REQUIRED))
|
|
2146
|
+
{
|
|
2147
|
+
if (y < 0.0) return setError(parser, nvalue, 213);
|
|
2148
|
+
if (y - hyd->Pmin < MINPDIFF)
|
|
2149
|
+
return setError(parser, nvalue, 208);
|
|
2150
|
+
hyd->Preq = y;
|
|
2151
|
+
return 0;
|
|
2152
|
+
}
|
|
2153
|
+
else if (match(tok0, w_PRESSURE))
|
|
2154
|
+
{
|
|
2155
|
+
if (y < 0.0) return setError(parser, nvalue, 213);
|
|
2156
|
+
hyd->Pexp = y;
|
|
2157
|
+
return 0;
|
|
2158
|
+
}
|
|
2159
|
+
|
|
2160
|
+
// All other options must be > 0
|
|
2161
|
+
if (y <= 0.0) return setError(parser, nvalue, 213);
|
|
2162
|
+
|
|
2163
|
+
// Assign value to all other options
|
|
2164
|
+
if (match(tok0, w_VISCOSITY)) hyd->Viscos = y;
|
|
2165
|
+
else if (match(tok0, w_SPECGRAV)) hyd->SpGrav = y;
|
|
2166
|
+
else if (match(tok0, w_TRIALS)) hyd->MaxIter = (int)y;
|
|
2167
|
+
else if (match(tok0, w_ACCURACY))
|
|
2168
|
+
{
|
|
2169
|
+
y = MAX(y, 1.e-5);
|
|
2170
|
+
y = MIN(y, 1.e-1);
|
|
2171
|
+
hyd->Hacc = y;
|
|
2172
|
+
}
|
|
2173
|
+
else if (match(tok0, w_HTOL)) hyd->Htol = y;
|
|
2174
|
+
else if (match(tok0, w_QTOL)) hyd->Qtol = y;
|
|
2175
|
+
else if (match(tok0, w_RQTOL))
|
|
2176
|
+
{
|
|
2177
|
+
if (y >= 1.0) return 213;
|
|
2178
|
+
hyd->RQtol = y;
|
|
2179
|
+
}
|
|
2180
|
+
else if (match(tok0, w_CHECKFREQ)) hyd->CheckFreq = (int)y;
|
|
2181
|
+
else if (match(tok0, w_MAXCHECK)) hyd->MaxCheck = (int)y;
|
|
2182
|
+
else if (match(tok0, w_EMITTER)) hyd->Qexp = 1.0 / y;
|
|
2183
|
+
else if (match(tok0, w_DEMAND)) hyd->Dmult = y;
|
|
2184
|
+
else return 201;
|
|
2185
|
+
return 0;
|
|
2186
|
+
}
|
|
2187
|
+
|
|
2188
|
+
int tagdata(Project *pr)
|
|
2189
|
+
/*
|
|
2190
|
+
**-------------------------------------------------------------
|
|
2191
|
+
** Input: none
|
|
2192
|
+
** Output: returns error code
|
|
2193
|
+
** Purpose: processes [TAGS] data
|
|
2194
|
+
** Formats:
|
|
2195
|
+
** NODE id tag
|
|
2196
|
+
** LINK id tag
|
|
2197
|
+
**--------------------------------------------------------------
|
|
2198
|
+
*/
|
|
2199
|
+
{
|
|
2200
|
+
Network *net = &pr->network;
|
|
2201
|
+
Parser *parser = &pr->parser;
|
|
2202
|
+
|
|
2203
|
+
int j, n;
|
|
2204
|
+
|
|
2205
|
+
// Check for sufficient data
|
|
2206
|
+
n = parser->Ntokens;
|
|
2207
|
+
if (n < 3) return 201;
|
|
2208
|
+
|
|
2209
|
+
// First keyword is NODE
|
|
2210
|
+
if (match(parser->Tok[0], w_NODE))
|
|
2211
|
+
{
|
|
2212
|
+
if ((j = findnode(net, parser->Tok[1])) == 0) return setError(parser, 0, 203);
|
|
2213
|
+
xstrcpy(&net->Node[j].Tag, parser->Tok[2], MAXMSG);
|
|
2214
|
+
}
|
|
2215
|
+
|
|
2216
|
+
// First keyword is LINK
|
|
2217
|
+
else if (match(parser->Tok[0], w_LINK))
|
|
2218
|
+
{
|
|
2219
|
+
if ((j = findlink(net, parser->Tok[1])) == 0) return setError(parser, 0, 203);
|
|
2220
|
+
xstrcpy(&net->Link[j].Tag, parser->Tok[2], MAXMSG);
|
|
2221
|
+
}
|
|
2222
|
+
return 0;
|
|
2223
|
+
}
|
|
2224
|
+
|
|
2225
|
+
void changestatus(Network *net, int j, StatusType status, double y)
|
|
2226
|
+
/*
|
|
2227
|
+
**--------------------------------------------------------------
|
|
2228
|
+
** Input: j = link index
|
|
2229
|
+
** status = status setting (OPEN, CLOSED)
|
|
2230
|
+
** y = numerical setting (pump speed, valve
|
|
2231
|
+
** setting)
|
|
2232
|
+
** Output: none
|
|
2233
|
+
** Purpose: changes initial status or setting of a link
|
|
2234
|
+
**
|
|
2235
|
+
** NOTE: If status = ACTIVE, then a numerical setting (y) was
|
|
2236
|
+
** supplied.
|
|
2237
|
+
**--------------------------------------------------------------
|
|
2238
|
+
*/
|
|
2239
|
+
{
|
|
2240
|
+
Slink *link = &net->Link[j];
|
|
2241
|
+
|
|
2242
|
+
if (link->Type == PIPE || link->Type == GPV)
|
|
2243
|
+
{
|
|
2244
|
+
if (status != ACTIVE) link->InitStatus = status;
|
|
2245
|
+
}
|
|
2246
|
+
else if (link->Type == PUMP)
|
|
2247
|
+
{
|
|
2248
|
+
if (status == ACTIVE)
|
|
2249
|
+
{
|
|
2250
|
+
link->Kc = y;
|
|
2251
|
+
status = OPEN;
|
|
2252
|
+
if (y == 0.0) status = CLOSED;
|
|
2253
|
+
}
|
|
2254
|
+
else if (status == OPEN) link->Kc = 1.0;
|
|
2255
|
+
else if (status == CLOSED) link->Kc = 0.0;
|
|
2256
|
+
link->InitStatus = status;
|
|
2257
|
+
link->InitSetting = link->Kc;
|
|
2258
|
+
}
|
|
2259
|
+
else if (link->Type >= PRV)
|
|
2260
|
+
{
|
|
2261
|
+
if (status == ACTIVE) link->Kc = y;
|
|
2262
|
+
link->InitStatus = status;
|
|
2263
|
+
link->InitSetting = link->Kc;
|
|
2264
|
+
}
|
|
2265
|
+
}
|