epyt-flow 0.14.0__py3-none-any.whl → 0.14.1__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.
Files changed (60) hide show
  1. epyt_flow/EPANET/EPANET/SRC_engines/AUTHORS +40 -8
  2. epyt_flow/EPANET/EPANET/SRC_engines/LICENSE +3 -3
  3. epyt_flow/EPANET/EPANET/SRC_engines/enumstxt.h +24 -7
  4. epyt_flow/EPANET/EPANET/SRC_engines/epanet.c +726 -374
  5. epyt_flow/EPANET/EPANET/SRC_engines/epanet2.c +128 -32
  6. epyt_flow/EPANET/EPANET/SRC_engines/errors.dat +7 -1
  7. epyt_flow/EPANET/EPANET/SRC_engines/flowbalance.c +186 -0
  8. epyt_flow/EPANET/EPANET/SRC_engines/funcs.h +40 -14
  9. epyt_flow/EPANET/EPANET/SRC_engines/hash.c +177 -177
  10. epyt_flow/EPANET/EPANET/SRC_engines/hash.h +28 -28
  11. epyt_flow/EPANET/EPANET/SRC_engines/hydcoeffs.c +192 -40
  12. epyt_flow/EPANET/EPANET/SRC_engines/hydraul.c +101 -46
  13. epyt_flow/EPANET/EPANET/SRC_engines/hydsolver.c +85 -24
  14. epyt_flow/EPANET/EPANET/SRC_engines/hydstatus.c +29 -63
  15. epyt_flow/EPANET/EPANET/SRC_engines/include/epanet2.h +70 -37
  16. epyt_flow/EPANET/EPANET/SRC_engines/include/epanet2_2.h +408 -234
  17. epyt_flow/EPANET/EPANET/SRC_engines/include/epanet2_enums.h +87 -37
  18. epyt_flow/EPANET/EPANET/SRC_engines/inpfile.c +153 -79
  19. epyt_flow/EPANET/EPANET/SRC_engines/input1.c +59 -94
  20. epyt_flow/EPANET/EPANET/SRC_engines/input2.c +73 -202
  21. epyt_flow/EPANET/EPANET/SRC_engines/input3.c +446 -351
  22. epyt_flow/EPANET/EPANET/SRC_engines/leakage.c +527 -0
  23. epyt_flow/EPANET/EPANET/SRC_engines/mempool.c +8 -4
  24. epyt_flow/EPANET/EPANET/SRC_engines/mempool.h +23 -23
  25. epyt_flow/EPANET/EPANET/SRC_engines/output.c +5 -4
  26. epyt_flow/EPANET/EPANET/SRC_engines/project.c +407 -75
  27. epyt_flow/EPANET/EPANET/SRC_engines/quality.c +12 -2
  28. epyt_flow/EPANET/EPANET/SRC_engines/qualreact.c +70 -13
  29. epyt_flow/EPANET/EPANET/SRC_engines/qualroute.c +7 -5
  30. epyt_flow/EPANET/EPANET/SRC_engines/report.c +88 -20
  31. epyt_flow/EPANET/EPANET/SRC_engines/rules.c +144 -6
  32. epyt_flow/EPANET/EPANET/SRC_engines/smatrix.c +19 -19
  33. epyt_flow/EPANET/EPANET/SRC_engines/text.h +16 -5
  34. epyt_flow/EPANET/EPANET/SRC_engines/types.h +73 -19
  35. epyt_flow/EPANET/EPANET/SRC_engines/util/cstr_helper.c +59 -0
  36. epyt_flow/EPANET/EPANET/SRC_engines/util/cstr_helper.h +38 -0
  37. epyt_flow/EPANET/EPANET/SRC_engines/util/errormanager.c +92 -0
  38. epyt_flow/EPANET/EPANET/SRC_engines/util/errormanager.h +39 -0
  39. epyt_flow/EPANET/EPANET/SRC_engines/util/filemanager.c +212 -0
  40. epyt_flow/EPANET/EPANET/SRC_engines/util/filemanager.h +81 -0
  41. epyt_flow/EPANET/EPANET/SRC_engines/validate.c +408 -0
  42. epyt_flow/EPANET/compile_linux.sh +1 -1
  43. epyt_flow/EPANET/compile_macos.sh +1 -1
  44. epyt_flow/VERSION +1 -1
  45. epyt_flow/gym/scenario_control_env.py +26 -3
  46. epyt_flow/simulation/events/quality_events.py +6 -6
  47. epyt_flow/simulation/events/sensor_faults.py +24 -24
  48. epyt_flow/simulation/events/system_event.py +3 -3
  49. epyt_flow/simulation/scada/scada_data.py +1 -1
  50. epyt_flow/simulation/scenario_simulator.py +14 -11
  51. epyt_flow/topology.py +8 -1
  52. epyt_flow/uncertainty/model_uncertainty.py +292 -150
  53. {epyt_flow-0.14.0.dist-info → epyt_flow-0.14.1.dist-info}/METADATA +2 -2
  54. {epyt_flow-0.14.0.dist-info → epyt_flow-0.14.1.dist-info}/RECORD +57 -51
  55. epyt_flow/EPANET/EPANET/SRC_engines/Readme_SRC_Engines.txt +0 -18
  56. epyt_flow/EPANET/EPANET/SRC_engines/epanet2.def +0 -131
  57. epyt_flow/EPANET/EPANET/SRC_engines/main.c +0 -93
  58. {epyt_flow-0.14.0.dist-info → epyt_flow-0.14.1.dist-info}/WHEEL +0 -0
  59. {epyt_flow-0.14.0.dist-info → epyt_flow-0.14.1.dist-info}/licenses/LICENSE +0 -0
  60. {epyt_flow-0.14.0.dist-info → epyt_flow-0.14.1.dist-info}/top_level.txt +0 -0
@@ -1,13 +1,13 @@
1
1
  /*
2
2
  ******************************************************************************
3
3
  Project: OWA EPANET
4
- Version: 2.2
4
+ Version: 2.3
5
5
  Module: input3.c
6
6
  Description: parses network data from a line of an EPANET input file
7
7
  Authors: see AUTHORS
8
8
  Copyright: see AUTHORS
9
9
  License: see LICENSE
10
- Last Updated: 11/29/2019
10
+ Last Updated: 04/19/2025
11
11
  ******************************************************************************
12
12
  */
13
13
 
@@ -25,16 +25,18 @@ Last Updated: 11/29/2019
25
25
  extern char *MixTxt[];
26
26
  extern char *Fldname[];
27
27
  extern char *DemandModelTxt[];
28
-
29
- // Exported functions
30
- int powercurve(double, double, double, double, double, double *, double *,
31
- double *);
28
+ extern char *BackflowTxt[];
29
+ extern char *CurveTypeTxt[];
32
30
 
33
31
  // Imported Functions
34
32
  extern int addnodeID(Network *, int, char *);
35
33
  extern int addlinkID(Network *, int, char *);
34
+ extern int getunitsoption(Project *, char *);
35
+ extern int getheadlossoption(Project *, char *);
36
36
 
37
37
  // Local functions
38
+ static double gettokvalue(Project *, double, int, int *, int *);
39
+ static int getlinknodes(Project *, int *, int *);
38
40
  static int optionchoice(Project *, int);
39
41
  static int optionvalue(Project *, int);
40
42
  static int getpumpcurve(Project *, int);
@@ -76,31 +78,52 @@ int juncdata(Project *pr)
76
78
  int p = 0; // time pattern index
77
79
  int n; // number of tokens
78
80
  int njuncs; // number of network junction nodes
79
- double el, // elevation
80
- y = 0.0; // base demand
81
+ double el = 0.0, // elevation
82
+ d = 0.0, // base demand
83
+ x;
81
84
  Snode *node;
82
- int err = 0;
85
+ int errcode = 0;
86
+ int errtok = -1;
83
87
 
84
88
  // Add new junction to data base
85
- n = parser->Ntokens;
86
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);
87
92
  net->Njuncs++;
88
93
  net->Nnodes++;
89
- njuncs = net->Njuncs;
90
- err = addnodeID(net, net->Njuncs, parser->Tok[0]);
91
- if (err) return setError(parser, 0, err);
92
94
 
93
95
  // 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)
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)
98
116
  {
99
117
  p = findpattern(net, parser->Tok[3]);
100
- if (p < 0) return setError(parser, 3, 205);
118
+ if (p < 0)
119
+ {
120
+ errcode = 205;
121
+ errtok = 3;
122
+ }
101
123
  }
102
124
 
103
125
  // Save junction data
126
+ njuncs = net->Njuncs;
104
127
  node = &net->Node[njuncs];
105
128
  node->X = MISSING;
106
129
  node->Y = MISSING;
@@ -115,11 +138,14 @@ int juncdata(Project *pr)
115
138
 
116
139
  // Create a demand for the junction and use NodeDemand as an indicator
117
140
  // to be used when processing demands from the [DEMANDS] section
118
- if (!adddemand(node, y, p, NULL)) return 101;
119
- hyd->NodeDemand[njuncs] = y;
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);
120
146
  return 0;
121
147
  }
122
-
148
+
123
149
  int tankdata(Project *pr)
124
150
  /*
125
151
  **--------------------------------------------------------------
@@ -130,7 +156,6 @@ int tankdata(Project *pr)
130
156
  ** [RESERVOIRS]
131
157
  ** id elev (pattern)
132
158
  ** [TANKS]
133
- ** id elev (pattern)
134
159
  ** id elev initlevel minlevel maxlevel diam (minvol vcurve)
135
160
  **--------------------------------------------------------------
136
161
  */
@@ -154,68 +179,84 @@ int tankdata(Project *pr)
154
179
  Snode *node;
155
180
  Stank *tank;
156
181
 
157
- int err = 0;
182
+ int errcode = 0;
183
+ int errtok = -1;
184
+ double x;
158
185
 
159
186
  // Add new tank to data base
160
- n = parser->Ntokens;
161
187
  if (net->Ntanks == parser->MaxTanks ||
162
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);
163
192
  net->Ntanks++;
164
193
  net->Nnodes++;
165
194
 
166
- i = parser->MaxJuncs + net->Ntanks;
167
- err = addnodeID(net, i, parser->Tok[0]);
168
- if (err) return setError(parser, 0, err);
169
-
170
195
  // Check for valid data
171
- if (n < 2) return 201;
172
- if (!getfloat(parser->Tok[1], &el)) return setError(parser, 1, 202);
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;
173
204
 
174
- // Tank is reservoir
205
+ // Node is a reservoir
175
206
  if (n <= 3)
176
207
  {
177
208
  // Head pattern supplied
178
- if (n == 3)
209
+ if (n == 3 && !errcode)
179
210
  {
180
211
  pattern = findpattern(net, parser->Tok[2]);
181
- if (pattern < 0) return setError(parser, 2, 205);
212
+ if (pattern < 0)
213
+ {
214
+ errcode = 205;
215
+ errtok = 2;
216
+ }
182
217
  }
183
218
  }
184
- else if (n < 6) return 201;
185
-
186
- // Tank is a storage tank
187
- else
219
+
220
+ // Node is a storage tank
221
+ else if (!errcode)
188
222
  {
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)
223
+ if (n < 6) errcode = 201;
224
+ else
197
225
  {
198
- if (strlen(parser->Tok[7]) > 0 && *(parser->Tok[7]) != '*')
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)
199
235
  {
200
- curve = findcurve(net, parser->Tok[7]);
201
- if (curve == 0) return setError(parser, 7, 206);
202
- net->Curve[curve].Type = VOLUME_CURVE;
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
+ }
203
246
  }
204
- }
205
247
 
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);
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
+ }
212
259
  }
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
260
  }
220
261
  node = &net->Node[i];
221
262
  tank = &net->Tank[net->Ntanks];
@@ -252,10 +293,39 @@ int tankdata(Project *pr)
252
293
 
253
294
  tank->Vcurve = curve;
254
295
  tank->MixModel = MIX1; // Completely mixed
255
- tank->V1max = 1.0; // Mixing compartment size fraction
296
+ tank->V1frac = 1.0; // Mixing compartment size fraction
297
+
298
+ // Return error code
299
+ if (errcode > 0) return setError(parser, errtok, errcode);
256
300
  return 0;
257
301
  }
258
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
+
259
329
  int pipedata(Project *pr)
260
330
  /*
261
331
  **--------------------------------------------------------------
@@ -274,71 +344,104 @@ int pipedata(Project *pr)
274
344
  int j1, // Start-node index
275
345
  j2, // End-node index
276
346
  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
347
+ double x;
283
348
  Slink *link;
284
- int err = 0;
285
-
286
- // Add new pipe to data base
287
- n = parser->Ntokens;
349
+ int errcode = 0;
350
+
351
+ // Check that end nodes exist
288
352
  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;
353
+ n = parser->Ntokens;
354
+ if (n < 3) return setError(parser, -1, errcode);
296
355
  if ((j1 = findnode(net, parser->Tok[1])) == 0) return setError(parser, 1, 203);
297
356
  if ((j2 = findnode(net, parser->Tok[2])) == 0) return setError(parser, 2, 203);
298
357
  if (j1 == j2) return setError(parser, 0, 222);
299
358
 
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);
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++;
306
364
 
307
- // Either a loss coeff. or a status is supplied
308
- if (n == 7)
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)
309
371
  {
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);
372
+ link->Len = 100.0;
373
+ link->Diam = 254.0;
314
374
  }
315
-
316
- // Both a loss coeff. and a status is supplied
317
- if (n == 8)
375
+ else
318
376
  {
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);
377
+ link->Len = 330.0;
378
+ link->Diam = 10.0;
324
379
  }
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;
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;
335
389
  link->Kb = MISSING;
336
390
  link->Kw = MISSING;
337
- link->Type = type;
338
- link->Status = status;
391
+ link->LeakArea = 0.0;
392
+ link->LeakExpan = 0.0;
393
+ link->Type = PIPE;
394
+ link->InitStatus = OPEN;
395
+ link->InitSetting = link->Kc;
339
396
  link->Rpt = 0;
340
397
  link->ResultIndex = 0;
341
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
+ }
342
445
  return 0;
343
446
  }
344
447
 
@@ -350,11 +453,6 @@ int pumpdata(Project *pr)
350
453
  ** Purpose: processes pump data
351
454
  ** Formats:
352
455
  ** [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
456
  ** id node1 node2 KEYWORD value {KEYWORD value ...}
359
457
  ** where KEYWORD = [POWER,HEAD,PATTERN,SPEED]
360
458
  **--------------------------------------------------------------
@@ -363,7 +461,7 @@ int pumpdata(Project *pr)
363
461
  Network *net = &pr->network;
364
462
  Parser *parser = &pr->parser;
365
463
 
366
- int j, m, // Token array indexes
464
+ int m, // Token array indexes
367
465
  j1, // Start-node index
368
466
  j2, // End-node index
369
467
  n, // # data items
@@ -371,24 +469,24 @@ int pumpdata(Project *pr)
371
469
  double y;
372
470
  Slink *link;
373
471
  Spump *pump;
374
- int err = 0;
375
-
376
- /* Add new pump to data base */
377
- n = parser->Ntokens;
472
+ int errcode = 0;
473
+
474
+ // Check that end nodes exist
378
475
  if (net->Nlinks == parser->MaxLinks ||
379
476
  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;
477
+ n = parser->Ntokens;
478
+ if (n < 3) return setError(parser, -1, errcode);
387
479
  if ((j1 = findnode(net, parser->Tok[1])) == 0) return setError(parser, 1, 203);
388
480
  if ((j2 = findnode(net, parser->Tok[2])) == 0) return setError(parser, 2, 203);
389
481
  if (j1 == j2) return setError(parser, 0, 222);
390
482
 
391
- // Save pump data
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
392
490
  link = &net->Link[net->Nlinks];
393
491
  pump = &net->Pump[net->Npumps];
394
492
 
@@ -400,8 +498,11 @@ int pumpdata(Project *pr)
400
498
  link->Km = 0.0;
401
499
  link->Kb = 0.0;
402
500
  link->Kw = 0.0;
501
+ link->LeakArea = 0.0;
502
+ link->LeakExpan = 0.0;
403
503
  link->Type = PUMP;
404
- link->Status = OPEN;
504
+ link->InitStatus = OPEN;
505
+ link->InitSetting = 1.0;
405
506
  link->Rpt = 0;
406
507
  link->ResultIndex = 0;
407
508
  link->Comment = xstrcpy(&link->Comment, parser->Comment, MAXMSG);
@@ -414,28 +515,14 @@ int pumpdata(Project *pr)
414
515
  pump->Epat = 0;
415
516
  if (n < 4) return 0;
416
517
 
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
518
+ // Retrieve keyword/value pairs
432
519
  m = 4;
433
520
  while (m < n)
434
521
  {
435
522
  if (match(parser->Tok[m - 1], w_POWER)) // Const. HP curve
436
523
  {
437
- y = atof(parser->Tok[m]);
438
- if (y <= 0.0) return setError(parser, m, 202);
524
+ if (!getfloat(parser->Tok[m], &y) || y <= 0.0)
525
+ return setError(parser, m, 202);
439
526
  pump->Ptype = CONST_HP;
440
527
  link->Km = y;
441
528
  }
@@ -443,6 +530,7 @@ int pumpdata(Project *pr)
443
530
  {
444
531
  c = findcurve(net, parser->Tok[m]);
445
532
  if (c == 0) return setError(parser, m, 206);
533
+ pump->Ptype = CUSTOM;
446
534
  pump->Hcurve = c;
447
535
  }
448
536
  else if (match(parser->Tok[m - 1], w_PATTERN)) // Speed/status pattern
@@ -453,13 +541,14 @@ int pumpdata(Project *pr)
453
541
  }
454
542
  else if (match(parser->Tok[m - 1], w_SPEED)) // Speed setting
455
543
  {
456
- if (!getfloat(parser->Tok[m], &y)) return setError(parser, m, 202);
457
- if (y < 0.0) return setError(parser, m, 211);
544
+ if (!getfloat(parser->Tok[m], &y) || y < 0.0)
545
+ return setError(parser, m, 202);
458
546
  link->Kc = y;
459
547
  }
460
- else return 201;
548
+ else return setError(parser, m-1, 201);;
461
549
  m = m + 2; // Move to next keyword token
462
550
  }
551
+ link->InitSetting = link->Kc;
463
552
  return 0;
464
553
  }
465
554
 
@@ -471,7 +560,7 @@ int valvedata(Project *pr)
471
560
  ** Purpose: processes valve data
472
561
  ** Format:
473
562
  ** [VALVE]
474
- ** id node1 node2 diam type setting (lcoeff)
563
+ ** id node1 node2 diam type setting (lcoeff lcurve)
475
564
  **--------------------------------------------------------------
476
565
  */
477
566
  {
@@ -484,61 +573,30 @@ int valvedata(Project *pr)
484
573
  n; // # data items
485
574
  char status = ACTIVE, // Valve status
486
575
  type; // Valve type
487
- double diam = 0.0, // Valve diameter
488
- setting, // Valve setting
489
- lcoeff = 0.0; // Minor loss coeff.
576
+ double x;
490
577
  Slink *link;
491
- int err = 0;
578
+ int errcode = 0,
579
+ losscurve = 0; // Loss coeff. curve
492
580
 
493
- // Add new valve to data base
494
- n = parser->Ntokens;
581
+ // Check that end nodes exist
495
582
  if (net->Nlinks == parser->MaxLinks ||
496
583
  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
-
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
+
542
600
  // Check for illegal connections
543
601
  if (valvecheck(pr, net->Nlinks, type, j1, j2))
544
602
  {
@@ -547,22 +605,71 @@ int valvedata(Project *pr)
547
605
  else return setError(parser, -1, 220);
548
606
  }
549
607
 
550
- // Save valve data
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
551
615
  link = &net->Link[net->Nlinks];
552
616
  link->N1 = j1;
553
617
  link->N2 = j2;
554
- link->Diam = diam;
618
+ if (parser->Unitsflag == SI) link->Diam = 254.0;
619
+ else link->Diam = 10.0;
555
620
  link->Len = 0.0;
556
- link->Kc = setting;
557
- link->Km = lcoeff;
621
+ link->Kc = 0.0;
622
+ link->Km = 0.0;
558
623
  link->Kb = 0.0;
559
624
  link->Kw = 0.0;
625
+ link->LeakArea = 0.0;
626
+ link->LeakExpan = 0.0;
560
627
  link->Type = type;
561
- link->Status = status;
628
+ link->InitStatus = ACTIVE;
629
+ link->InitSetting = 0.0;
562
630
  link->Rpt = 0;
563
631
  link->ResultIndex = 0;
564
632
  link->Comment = xstrcpy(&link->Comment, parser->Comment, MAXMSG);
565
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;
566
673
  return 0;
567
674
  }
568
675
 
@@ -613,6 +720,7 @@ int patterndata(Project *pr)
613
720
  pattern->F = realloc(pattern->F, pattern->Length * sizeof(double));
614
721
 
615
722
  // Add parsed multipliers to the pattern
723
+ for (j = 1; j <= n; j++) pattern->F[n1 + j - 1] = 1.0;
616
724
  for (j = 1; j <= n; j++)
617
725
  {
618
726
  if (!getfloat(parser->Tok[j], &x)) return setError(parser, j, 202);
@@ -639,7 +747,7 @@ int curvedata(Project *pr)
639
747
  Network *net = &pr->network;
640
748
  Parser *parser = &pr->parser;
641
749
 
642
- int i;
750
+ int i, ctype;
643
751
  double x, y;
644
752
  Scurve *curve;
645
753
 
@@ -647,6 +755,11 @@ int curvedata(Project *pr)
647
755
  if (parser->Ntokens < 3) return 201;
648
756
  if (!getfloat(parser->Tok[1], &x)) return setError(parser, 1, 202);
649
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
+ }
650
763
 
651
764
  // Check if previous input line was for the same curve
652
765
  if (parser->PrevCurve && strcmp(parser->Tok[0], parser->PrevCurve->ID) == 0)
@@ -676,6 +789,7 @@ int curvedata(Project *pr)
676
789
  curve->X[curve->Npts] = x;
677
790
  curve->Y[curve->Npts] = y;
678
791
  curve->Npts++;
792
+ if (ctype >= 0) curve->Type = (CurveType)ctype;
679
793
 
680
794
  // Save a reference to this curve for processing additional curve data
681
795
  parser->PrevCurve = curve;
@@ -686,11 +800,14 @@ int coordata(Project *pr)
686
800
  /*
687
801
  **--------------------------------------------------------------
688
802
  ** Input: none
689
- ** Output: returns error code
690
- ** Purpose: processes coordinate data
803
+ ** Output: returns 0
804
+ ** Purpose: processes node coordinate data
691
805
  ** Format:
692
806
  ** [COORD]
693
807
  ** id x y
808
+ **
809
+ ** Note: since node coords. are not used in any computations,
810
+ ** invalid data are simply ignored.
694
811
  **--------------------------------------------------------------
695
812
  */
696
813
  {
@@ -702,12 +819,12 @@ int coordata(Project *pr)
702
819
  Snode *node;
703
820
 
704
821
  // 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);
822
+ if (parser->Ntokens < 3) return 0;
823
+ if ((j = findnode(net, parser->Tok[0])) == 0) return 0;
707
824
 
708
825
  // 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);
826
+ if (!getfloat(parser->Tok[1], &x)) return 0;
827
+ if (!getfloat(parser->Tok[2], &y)) return 0;
711
828
 
712
829
  // Save coord data
713
830
  node = &net->Node[j];
@@ -720,11 +837,14 @@ int vertexdata(Project *pr)
720
837
  /*
721
838
  **--------------------------------------------------------------
722
839
  ** Input: none
723
- ** Output: returns error code
840
+ ** Output: returns 0
724
841
  ** Purpose: processes link vertex data
725
842
  ** Format:
726
843
  ** [VERTICES]
727
844
  ** id x y
845
+ **
846
+ ** Note: since vertex coords. are not used in any computations,
847
+ ** invalid data are simply ignored.
728
848
  **--------------------------------------------------------------
729
849
  */
730
850
  {
@@ -735,12 +855,12 @@ int vertexdata(Project *pr)
735
855
  double x, y;
736
856
 
737
857
  // 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);
858
+ if (parser->Ntokens < 3) return 0;
859
+ if ((j = findlink(net, parser->Tok[0])) == 0) return 0;
740
860
 
741
861
  // 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);
862
+ if (!getfloat(parser->Tok[1], &x)) return 0;
863
+ if (!getfloat(parser->Tok[2], &y)) return 0;
744
864
 
745
865
  // Add to link's list of vertex points
746
866
  return addlinkvertex(&net->Link[j], x, y);
@@ -755,7 +875,6 @@ int demanddata(Project *pr)
755
875
  ** Purpose: processes node demand data
756
876
  ** Format:
757
877
  ** [DEMANDS]
758
- ** MULTIPLY factor
759
878
  ** node base_demand (pattern)
760
879
  **
761
880
  ** NOTE: Demands entered in this section replace those
@@ -777,15 +896,7 @@ int demanddata(Project *pr)
777
896
  if (n < 2) return 201;
778
897
  if (!getfloat(parser->Tok[1], &y)) return setError(parser, 1, 202);
779
898
 
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
899
+ // Find node (and pattern) being referenced
789
900
  if ((j = findnode(net, parser->Tok[0])) == 0) return setError(parser, 0, 203);
790
901
  if (j > net->Njuncs) return 0;
791
902
  if (n >= 3)
@@ -822,10 +933,10 @@ int controldata(Project *pr)
822
933
  ** Purpose: processes simple controls
823
934
  ** Formats:
824
935
  ** [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)
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)
829
940
  **--------------------------------------------------------------
830
941
  */
831
942
  {
@@ -834,7 +945,8 @@ int controldata(Project *pr)
834
945
 
835
946
  int i = 0, // Node index
836
947
  k, // Link index
837
- n; // # data items
948
+ n, // # data items
949
+ isEnabled = TRUE; // Control enabled
838
950
  double setting = MISSING, // Link setting
839
951
  time = 0.0, // Simulation time
840
952
  level = 0.0; // Pressure or tank level
@@ -846,6 +958,13 @@ int controldata(Project *pr)
846
958
  // Check for sufficient number of input tokens
847
959
  n = parser->Ntokens;
848
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
+ }
849
968
 
850
969
  // Check that controlled link exists
851
970
  k = findlink(net, parser->Tok[1]);
@@ -901,7 +1020,7 @@ int controldata(Project *pr)
901
1020
  case TIMER:
902
1021
  case TIMEOFDAY:
903
1022
  if (n == 6) time = hour(parser->Tok[5], "");
904
- if (n == 7) time = hour(parser->Tok[5], parser->Tok[6]);
1023
+ if (n >= 7) time = hour(parser->Tok[5], parser->Tok[6]);
905
1024
  if (time < 0.0) return setError(parser, 5, 213);
906
1025
  break;
907
1026
  case LOWLEVEL:
@@ -922,6 +1041,7 @@ int controldata(Project *pr)
922
1041
  control->Time = (long)(3600.0 * time);
923
1042
  if (ctltype == TIMEOFDAY) control->Time %= SECperDAY;
924
1043
  control->Grade = level;
1044
+ control->isEnabled = isEnabled;
925
1045
  return 0;
926
1046
  }
927
1047
 
@@ -1025,6 +1145,41 @@ int emitterdata(Project *pr)
1025
1145
  return 0;
1026
1146
  }
1027
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
+
1028
1183
  int qualdata(Project *pr)
1029
1184
  /*
1030
1185
  **--------------------------------------------------------------
@@ -1288,7 +1443,7 @@ int mixingdata(Project *pr)
1288
1443
  i = j - net->Njuncs;
1289
1444
  if (net->Tank[i].A == 0.0) return 0;
1290
1445
  net->Tank[i].MixModel = (char)m;
1291
- net->Tank[i].V1max = v;
1446
+ net->Tank[i].V1frac = v;
1292
1447
  return 0;
1293
1448
  }
1294
1449
 
@@ -1729,8 +1884,8 @@ int optionchoice(Project *pr, int n)
1729
1884
  ** those listed below, or -1 otherwise
1730
1885
  ** Purpose: processes fixed choice [OPTIONS] data
1731
1886
  ** Formats:
1732
- ** UNITS CFS/GPM/MGD/IMGD/AFD/LPS/LPM/MLD/CMH/CMD/SI
1733
- ** PRESSURE PSI/KPA/M
1887
+ ** UNITS CFS/GPM/MGD/IMGD/AFD/LPS/LPM/MLD/CMH/CMD/CMS
1888
+ ** PRESSURE PSI/KPA/METERS/BAR/FEET
1734
1889
  ** HEADLOSS H-W/D-W/C-M
1735
1890
  ** HYDRAULICS USE/SAVE filename
1736
1891
  ** QUALITY NONE/AGE/TRACE/CHEMICAL (TraceNode)
@@ -1739,6 +1894,7 @@ int optionchoice(Project *pr, int n)
1739
1894
  ** UNBALANCED STOP/CONTINUE {Niter}
1740
1895
  ** PATTERN id
1741
1896
  ** DEMAND MODEL DDA/PDA
1897
+ ** BACKFLOW ALLOWED YES/NO
1742
1898
  **--------------------------------------------------------------
1743
1899
  */
1744
1900
  {
@@ -1758,28 +1914,20 @@ int optionchoice(Project *pr, int n)
1758
1914
  if (match(parser->Tok[0], w_UNITS))
1759
1915
  {
1760
1916
  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);
1917
+ if (!getunitsoption(pr, parser->Tok[1]))
1918
+ return setError(parser, 1, 213);
1773
1919
  }
1774
1920
 
1775
1921
  // PRESSURE units
1776
1922
  else if (match(parser->Tok[0], w_PRESSURE))
1777
1923
  {
1778
- if (n < 1) return 0;
1924
+ if (n < 1) return 0;
1779
1925
  else if (match(parser->Tok[1], w_EXPONENT)) return -1;
1780
1926
  else if (match(parser->Tok[1], w_PSI)) parser->Pressflag = PSI;
1781
1927
  else if (match(parser->Tok[1], w_KPA)) parser->Pressflag = KPA;
1782
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;
1783
1931
  else return setError(parser, 1, 213);
1784
1932
  }
1785
1933
 
@@ -1787,10 +1935,8 @@ int optionchoice(Project *pr, int n)
1787
1935
  else if (match(parser->Tok[0], w_HEADLOSS))
1788
1936
  {
1789
1937
  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);
1938
+ if (!getheadlossoption(pr, parser->Tok[1]))
1939
+ return setError(parser, 1, 213);
1794
1940
  }
1795
1941
 
1796
1942
  // HYDRUALICS USE/SAVE file option
@@ -1819,10 +1965,7 @@ int optionchoice(Project *pr, int n)
1819
1965
  }
1820
1966
  if (qual->Qualflag == TRACE)
1821
1967
  {
1822
- // Copy Trace Node ID to parser->Tok[0] for error reporting
1823
- strcpy(parser->Tok[0], "");
1824
1968
  if (n < 2) return 201;
1825
- strcpy(parser->Tok[0], parser->Tok[2]);
1826
1969
  qual->TraceNode = findnode(net, parser->Tok[2]);
1827
1970
  if (qual->TraceNode == 0) return setError(parser, 2, 212);
1828
1971
  strncpy(qual->ChemName, u_PERCENT, MAXID);
@@ -1876,6 +2019,16 @@ int optionchoice(Project *pr, int n)
1876
2019
  if (choice < 0) return setError(parser, 2, 213);
1877
2020
  hyd->DemandModel = choice;
1878
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
+ }
1879
2032
 
1880
2033
  // Return -1 if keyword did not match any option
1881
2034
  else return -1;
@@ -1885,7 +2038,7 @@ int optionchoice(Project *pr, int n)
1885
2038
  int optionvalue(Project *pr, int n)
1886
2039
  /*
1887
2040
  **-------------------------------------------------------------
1888
- ** Input: *line = line read from input file
2041
+ ** Input: n = index of last input token
1889
2042
  ** Output: returns error code
1890
2043
  ** Purpose: processes numerical value [OPTIONS] data
1891
2044
  ** Formats:
@@ -2032,102 +2185,43 @@ int optionvalue(Project *pr, int n)
2032
2185
  return 0;
2033
2186
  }
2034
2187
 
2035
- int getpumpcurve(Project *pr, int n)
2188
+ int tagdata(Project *pr)
2036
2189
  /*
2037
- **--------------------------------------------------------
2038
- ** Input: n = number of parameters for pump curve
2190
+ **-------------------------------------------------------------
2191
+ ** Input: none
2039
2192
  ** 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
- **---------------------------------------------------------
2193
+ ** Purpose: processes [TAGS] data
2194
+ ** Formats:
2195
+ ** NODE id tag
2196
+ ** LINK id tag
2197
+ **--------------------------------------------------------------
2050
2198
  */
2051
2199
  {
2052
2200
  Network *net = &pr->network;
2053
2201
  Parser *parser = &pr->parser;
2054
2202
 
2055
- double a, b, c, h0, h1, h2, q1, q2;
2056
- Spump *pump = &net->Pump[net->Npumps];
2203
+ int j, n;
2057
2204
 
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
- }
2205
+ // Check for sufficient data
2206
+ n = parser->Ntokens;
2207
+ if (n < 3) return 201;
2065
2208
 
2066
- // Power function curve
2067
- else
2209
+ // First keyword is NODE
2210
+ if (match(parser->Tok[0], w_NODE))
2068
2211
  {
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;
2212
+ if ((j = findnode(net, parser->Tok[1])) == 0) return setError(parser, 0, 203);
2213
+ xstrcpy(&net->Node[j].Tag, parser->Tok[2], MAXMSG);
2097
2214
  }
2098
- return 0;
2099
- }
2100
2215
 
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;
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;
2129
2223
  }
2130
-
2224
+
2131
2225
  void changestatus(Network *net, int j, StatusType status, double y)
2132
2226
  /*
2133
2227
  **--------------------------------------------------------------
@@ -2136,11 +2230,10 @@ void changestatus(Network *net, int j, StatusType status, double y)
2136
2230
  ** y = numerical setting (pump speed, valve
2137
2231
  ** setting)
2138
2232
  ** Output: none
2139
- ** Purpose: changes status or setting of a link
2233
+ ** Purpose: changes initial status or setting of a link
2140
2234
  **
2141
2235
  ** NOTE: If status = ACTIVE, then a numerical setting (y) was
2142
- ** supplied. If status = OPEN/CLOSED, then numerical
2143
- ** setting is 0.
2236
+ ** supplied.
2144
2237
  **--------------------------------------------------------------
2145
2238
  */
2146
2239
  {
@@ -2148,7 +2241,7 @@ void changestatus(Network *net, int j, StatusType status, double y)
2148
2241
 
2149
2242
  if (link->Type == PIPE || link->Type == GPV)
2150
2243
  {
2151
- if (status != ACTIVE) link->Status = status;
2244
+ if (status != ACTIVE) link->InitStatus = status;
2152
2245
  }
2153
2246
  else if (link->Type == PUMP)
2154
2247
  {
@@ -2159,12 +2252,14 @@ void changestatus(Network *net, int j, StatusType status, double y)
2159
2252
  if (y == 0.0) status = CLOSED;
2160
2253
  }
2161
2254
  else if (status == OPEN) link->Kc = 1.0;
2162
- link->Status = status;
2255
+ else if (status == CLOSED) link->Kc = 0.0;
2256
+ link->InitStatus = status;
2257
+ link->InitSetting = link->Kc;
2163
2258
  }
2164
2259
  else if (link->Type >= PRV)
2165
2260
  {
2166
- link->Kc = y;
2167
- link->Status = status;
2168
- if (status != ACTIVE) link->Kc = MISSING;
2261
+ if (status == ACTIVE) link->Kc = y;
2262
+ link->InitStatus = status;
2263
+ link->InitSetting = link->Kc;
2169
2264
  }
2170
2265
  }