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