epyt-flow 0.14.2__py3-none-any.whl → 0.15.0b1__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 (102) hide show
  1. epyt_flow/VERSION +1 -1
  2. epyt_flow/__init__.py +0 -37
  3. epyt_flow/data/benchmarks/battledim.py +2 -2
  4. epyt_flow/data/benchmarks/leakdb.py +12 -9
  5. epyt_flow/gym/scenario_control_env.py +32 -33
  6. epyt_flow/simulation/events/actuator_events.py +24 -18
  7. epyt_flow/simulation/events/leakages.py +59 -57
  8. epyt_flow/simulation/events/quality_events.py +21 -30
  9. epyt_flow/simulation/events/system_event.py +3 -3
  10. epyt_flow/simulation/scada/complex_control.py +14 -12
  11. epyt_flow/simulation/scada/custom_control.py +22 -21
  12. epyt_flow/simulation/scada/scada_data.py +107 -104
  13. epyt_flow/simulation/scada/simple_control.py +38 -31
  14. epyt_flow/simulation/scenario_simulator.py +367 -395
  15. epyt_flow/simulation/sensor_config.py +31 -32
  16. epyt_flow/topology.py +11 -10
  17. epyt_flow/uncertainty/model_uncertainty.py +146 -122
  18. epyt_flow/utils.py +0 -66
  19. epyt_flow/visualization/visualization_utils.py +2 -4
  20. {epyt_flow-0.14.2.dist-info → epyt_flow-0.15.0b1.dist-info}/METADATA +12 -18
  21. epyt_flow-0.15.0b1.dist-info/RECORD +65 -0
  22. epyt_flow/EPANET/EPANET/SRC_engines/AUTHORS +0 -28
  23. epyt_flow/EPANET/EPANET/SRC_engines/LICENSE +0 -21
  24. epyt_flow/EPANET/EPANET/SRC_engines/Readme_SRC_Engines.txt +0 -18
  25. epyt_flow/EPANET/EPANET/SRC_engines/enumstxt.h +0 -134
  26. epyt_flow/EPANET/EPANET/SRC_engines/epanet.c +0 -5578
  27. epyt_flow/EPANET/EPANET/SRC_engines/epanet2.c +0 -865
  28. epyt_flow/EPANET/EPANET/SRC_engines/epanet2.def +0 -131
  29. epyt_flow/EPANET/EPANET/SRC_engines/errors.dat +0 -73
  30. epyt_flow/EPANET/EPANET/SRC_engines/funcs.h +0 -193
  31. epyt_flow/EPANET/EPANET/SRC_engines/genmmd.c +0 -1000
  32. epyt_flow/EPANET/EPANET/SRC_engines/hash.c +0 -177
  33. epyt_flow/EPANET/EPANET/SRC_engines/hash.h +0 -28
  34. epyt_flow/EPANET/EPANET/SRC_engines/hydcoeffs.c +0 -1151
  35. epyt_flow/EPANET/EPANET/SRC_engines/hydraul.c +0 -1117
  36. epyt_flow/EPANET/EPANET/SRC_engines/hydsolver.c +0 -720
  37. epyt_flow/EPANET/EPANET/SRC_engines/hydstatus.c +0 -476
  38. epyt_flow/EPANET/EPANET/SRC_engines/include/epanet2.h +0 -431
  39. epyt_flow/EPANET/EPANET/SRC_engines/include/epanet2_2.h +0 -1786
  40. epyt_flow/EPANET/EPANET/SRC_engines/include/epanet2_enums.h +0 -468
  41. epyt_flow/EPANET/EPANET/SRC_engines/inpfile.c +0 -810
  42. epyt_flow/EPANET/EPANET/SRC_engines/input1.c +0 -707
  43. epyt_flow/EPANET/EPANET/SRC_engines/input2.c +0 -864
  44. epyt_flow/EPANET/EPANET/SRC_engines/input3.c +0 -2170
  45. epyt_flow/EPANET/EPANET/SRC_engines/main.c +0 -93
  46. epyt_flow/EPANET/EPANET/SRC_engines/mempool.c +0 -142
  47. epyt_flow/EPANET/EPANET/SRC_engines/mempool.h +0 -24
  48. epyt_flow/EPANET/EPANET/SRC_engines/output.c +0 -852
  49. epyt_flow/EPANET/EPANET/SRC_engines/project.c +0 -1359
  50. epyt_flow/EPANET/EPANET/SRC_engines/quality.c +0 -685
  51. epyt_flow/EPANET/EPANET/SRC_engines/qualreact.c +0 -743
  52. epyt_flow/EPANET/EPANET/SRC_engines/qualroute.c +0 -694
  53. epyt_flow/EPANET/EPANET/SRC_engines/report.c +0 -1489
  54. epyt_flow/EPANET/EPANET/SRC_engines/rules.c +0 -1362
  55. epyt_flow/EPANET/EPANET/SRC_engines/smatrix.c +0 -871
  56. epyt_flow/EPANET/EPANET/SRC_engines/text.h +0 -497
  57. epyt_flow/EPANET/EPANET/SRC_engines/types.h +0 -874
  58. epyt_flow/EPANET/EPANET-MSX/MSX_Updates.txt +0 -53
  59. epyt_flow/EPANET/EPANET-MSX/Src/dispersion.h +0 -27
  60. epyt_flow/EPANET/EPANET-MSX/Src/hash.c +0 -107
  61. epyt_flow/EPANET/EPANET-MSX/Src/hash.h +0 -28
  62. epyt_flow/EPANET/EPANET-MSX/Src/include/epanetmsx.h +0 -102
  63. epyt_flow/EPANET/EPANET-MSX/Src/include/epanetmsx_export.h +0 -42
  64. epyt_flow/EPANET/EPANET-MSX/Src/mathexpr.c +0 -937
  65. epyt_flow/EPANET/EPANET-MSX/Src/mathexpr.h +0 -39
  66. epyt_flow/EPANET/EPANET-MSX/Src/mempool.c +0 -204
  67. epyt_flow/EPANET/EPANET-MSX/Src/mempool.h +0 -24
  68. epyt_flow/EPANET/EPANET-MSX/Src/msxchem.c +0 -1285
  69. epyt_flow/EPANET/EPANET-MSX/Src/msxcompiler.c +0 -368
  70. epyt_flow/EPANET/EPANET-MSX/Src/msxdict.h +0 -42
  71. epyt_flow/EPANET/EPANET-MSX/Src/msxdispersion.c +0 -586
  72. epyt_flow/EPANET/EPANET-MSX/Src/msxerr.c +0 -116
  73. epyt_flow/EPANET/EPANET-MSX/Src/msxfile.c +0 -260
  74. epyt_flow/EPANET/EPANET-MSX/Src/msxfuncs.c +0 -175
  75. epyt_flow/EPANET/EPANET-MSX/Src/msxfuncs.h +0 -35
  76. epyt_flow/EPANET/EPANET-MSX/Src/msxinp.c +0 -1504
  77. epyt_flow/EPANET/EPANET-MSX/Src/msxout.c +0 -401
  78. epyt_flow/EPANET/EPANET-MSX/Src/msxproj.c +0 -791
  79. epyt_flow/EPANET/EPANET-MSX/Src/msxqual.c +0 -2010
  80. epyt_flow/EPANET/EPANET-MSX/Src/msxrpt.c +0 -400
  81. epyt_flow/EPANET/EPANET-MSX/Src/msxtank.c +0 -422
  82. epyt_flow/EPANET/EPANET-MSX/Src/msxtoolkit.c +0 -1164
  83. epyt_flow/EPANET/EPANET-MSX/Src/msxtypes.h +0 -551
  84. epyt_flow/EPANET/EPANET-MSX/Src/msxutils.c +0 -524
  85. epyt_flow/EPANET/EPANET-MSX/Src/msxutils.h +0 -56
  86. epyt_flow/EPANET/EPANET-MSX/Src/newton.c +0 -158
  87. epyt_flow/EPANET/EPANET-MSX/Src/newton.h +0 -34
  88. epyt_flow/EPANET/EPANET-MSX/Src/rk5.c +0 -287
  89. epyt_flow/EPANET/EPANET-MSX/Src/rk5.h +0 -39
  90. epyt_flow/EPANET/EPANET-MSX/Src/ros2.c +0 -293
  91. epyt_flow/EPANET/EPANET-MSX/Src/ros2.h +0 -35
  92. epyt_flow/EPANET/EPANET-MSX/Src/smatrix.c +0 -816
  93. epyt_flow/EPANET/EPANET-MSX/Src/smatrix.h +0 -29
  94. epyt_flow/EPANET/EPANET-MSX/readme.txt +0 -14
  95. epyt_flow/EPANET/compile_linux.sh +0 -4
  96. epyt_flow/EPANET/compile_macos.sh +0 -4
  97. epyt_flow/simulation/backend/__init__.py +0 -1
  98. epyt_flow/simulation/backend/my_epyt.py +0 -1101
  99. epyt_flow-0.14.2.dist-info/RECORD +0 -142
  100. {epyt_flow-0.14.2.dist-info → epyt_flow-0.15.0b1.dist-info}/WHEEL +0 -0
  101. {epyt_flow-0.14.2.dist-info → epyt_flow-0.15.0b1.dist-info}/licenses/LICENSE +0 -0
  102. {epyt_flow-0.14.2.dist-info → epyt_flow-0.15.0b1.dist-info}/top_level.txt +0 -0
@@ -1,1117 +0,0 @@
1
- /*
2
- ******************************************************************************
3
- Project: OWA EPANET
4
- Version: 2.2
5
- Module: hydraul.c
6
- Description: implements EPANET's hydraulic engine
7
- Authors: see AUTHORS
8
- Copyright: see AUTHORS
9
- License: see LICENSE
10
- Last Updated: 12/05/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 "text.h"
22
-
23
- const double QZERO = 1.e-6; // Equivalent to zero flow in cfs
24
-
25
- // Imported functions
26
- extern int createsparse(Project *);
27
- extern void freesparse(Project *);
28
- extern int hydsolve(Project *, int *, double *);
29
-
30
- // Local functions
31
- int allocmatrix(Project *);
32
- void freematrix(Project *);
33
- void initlinkflow(Project *, int, char, double);
34
- void demands(Project *);
35
- int controls(Project *);
36
- long timestep(Project *);
37
- void controltimestep(Project *, long *);
38
- void ruletimestep(Project *, long *);
39
- void addenergy(Project *, long);
40
- void tanklevels(Project *, long);
41
- void resetpumpflow(Project *, int);
42
-
43
- int openhyd(Project *pr)
44
- /*
45
- *--------------------------------------------------------------
46
- * Input: none
47
- * Output: returns error code
48
- * Purpose: opens hydraulics solver system
49
- *--------------------------------------------------------------
50
- */
51
- {
52
- int i;
53
- int errcode = 0;
54
- Slink *link;
55
-
56
- // Check for too few nodes & no fixed grade nodes
57
- if (pr->network.Nnodes < 2) errcode = 223;
58
- else if (pr->network.Ntanks == 0) errcode = 224;
59
-
60
- // Allocate memory for sparse matrix structures (see SMATRIX.C)
61
- ERRCODE(createsparse(pr));
62
-
63
- // Allocate memory for hydraulic variables
64
- ERRCODE(allocmatrix(pr));
65
-
66
- // Check for unconnected nodes
67
- if (!errcode) for (i = 1; i <= pr->network.Njuncs; i++)
68
- {
69
- if (pr->network.Adjlist[i] == NULL)
70
- {
71
- errcode = 233;
72
- break;
73
- }
74
- }
75
-
76
- // Initialize link flows
77
- if (!errcode) for (i = 1; i <= pr->network.Nlinks; i++)
78
- {
79
- link = &pr->network.Link[i];
80
- initlinkflow(pr, i, link->Status, link->Kc);
81
- }
82
- return errcode;
83
- }
84
-
85
- void inithyd(Project *pr, int initflag)
86
- /*
87
- **--------------------------------------------------------------
88
- ** Input: initflag > 0 if link flows should be re-initialized
89
- ** = 0 if not
90
- ** Output: none
91
- ** Purpose: initializes hydraulics solver system
92
- **--------------------------------------------------------------
93
- */
94
- {
95
- Network *net = &pr->network;
96
- Hydraul *hyd = &pr->hydraul;
97
- Outfile *out = &pr->outfile;
98
- Times *time = &pr->times;
99
-
100
- int i;
101
- Stank *tank;
102
- Slink *link;
103
- Spump *pump;
104
-
105
- // Initialize tanks
106
- for (i = 1; i <= net->Ntanks; i++)
107
- {
108
- tank = &net->Tank[i];
109
- tank->V = tank->V0;
110
- hyd->NodeHead[tank->Node] = tank->H0;
111
- hyd->NodeDemand[tank->Node] = 0.0;
112
- hyd->OldStatus[net->Nlinks+i] = TEMPCLOSED;
113
- }
114
-
115
- // Initialize emitter flows
116
- memset(hyd->EmitterFlow,0,(net->Nnodes+1)*sizeof(double));
117
- for (i = 1; i <= net->Nnodes; i++)
118
- {
119
- net->Node[i].ResultIndex = i;
120
- if (net->Node[i].Ke > 0.0) hyd->EmitterFlow[i] = 1.0;
121
- }
122
-
123
- // Initialize links
124
- for (i = 1; i <= net->Nlinks; i++)
125
- {
126
- link = &net->Link[i];
127
- link->ResultIndex = i;
128
-
129
- // Initialize status and setting
130
- hyd->LinkStatus[i] = link->Status;
131
- hyd->LinkSetting[i] = link->Kc;
132
-
133
- // Compute flow resistance
134
- resistcoeff(pr, i);
135
-
136
- // Start active control valves in ACTIVE position
137
- if (
138
- (link->Type == PRV || link->Type == PSV
139
- || link->Type == FCV) && (link->Kc != MISSING)
140
- ) hyd->LinkStatus[i] = ACTIVE;
141
-
142
- // Initialize flows if necessary
143
- if (hyd->LinkStatus[i] <= CLOSED)
144
- {
145
- hyd->LinkFlow[i] = QZERO;
146
- }
147
- else if (ABS(hyd->LinkFlow[i]) <= QZERO || initflag > 0)
148
- {
149
- initlinkflow(pr, i, hyd->LinkStatus[i], hyd->LinkSetting[i]);
150
- }
151
-
152
- // Save initial status
153
- hyd->OldStatus[i] = hyd->LinkStatus[i];
154
- }
155
-
156
- // Initialize pump energy usage
157
- for (i = 1; i <= net->Npumps; i++)
158
- {
159
- pump = &net->Pump[i];
160
- pump->Energy.Efficiency = 0.0;
161
- pump->Energy.TimeOnLine = 0.0;
162
- pump->Energy.KwHrs = 0.0;
163
- pump->Energy.KwHrsPerFlow = 0.0;
164
- pump->Energy.MaxKwatts = 0.0;
165
- pump->Energy.TotalCost = 0.0;
166
- }
167
-
168
- // Re-position hydraulics file
169
- if (pr->outfile.Saveflag)
170
- {
171
- fseek(out->HydFile,out->HydOffset,SEEK_SET);
172
- }
173
-
174
- // Initialize current time
175
- hyd->Haltflag = 0;
176
- time->Htime = 0;
177
- time->Hydstep = 0;
178
- time->Rtime = time->Rstep;
179
- }
180
-
181
-
182
- int runhyd(Project *pr, long *t)
183
- /*
184
- **--------------------------------------------------------------
185
- ** Input: none
186
- ** Output: t = pointer to current time (in seconds)
187
- ** Returns: error code
188
- ** Purpose: solves network hydraulics in a single time period
189
- **--------------------------------------------------------------
190
- */
191
- {
192
- Hydraul *hyd = &pr->hydraul;
193
- Times *time = &pr->times;
194
- Report *rpt = &pr->report;
195
-
196
- int iter; // Iteration count
197
- int errcode; // Error code
198
- double relerr; // Solution accuracy
199
-
200
- // Find new demands & control actions
201
- *t = time->Htime;
202
- demands(pr);
203
- controls(pr);
204
-
205
- // Solve network hydraulic equations
206
- errcode = hydsolve(pr,&iter,&relerr);
207
- if (!errcode)
208
- {
209
- // Report new status & save results
210
- if (rpt->Statflag) writehydstat(pr,iter,relerr);
211
-
212
- // If system unbalanced and no extra trials
213
- // allowed, then activate the Haltflag
214
- if (relerr > hyd->Hacc && hyd->ExtraIter == -1)
215
- {
216
- hyd->Haltflag = 1;
217
- }
218
-
219
- // Report any warning conditions
220
- if (!errcode) errcode = writehydwarn(pr,iter,relerr);
221
- }
222
- return errcode;
223
- }
224
-
225
- int nexthyd(Project *pr, long *tstep)
226
- /*
227
- **--------------------------------------------------------------
228
- ** Input: none
229
- ** Output: tstep = pointer to time step (in seconds)
230
- ** Returns: error code
231
- ** Purpose: finds length of next time step & updates tank
232
- ** levels and rule-based contol actions
233
- **--------------------------------------------------------------
234
- */
235
- {
236
- Hydraul *hyd = &pr->hydraul;
237
- Times *time = &pr->times;
238
-
239
- long hydstep; // Actual time step
240
- int errcode = 0; // Error code
241
-
242
- // Save current results to hydraulics file and
243
- // force end of simulation if Haltflag is active
244
- if (pr->outfile.Saveflag) errcode = savehyd(pr, &time->Htime);
245
- if (hyd->Haltflag) time->Htime = time->Dur;
246
-
247
- // Compute next time step & update tank levels
248
- *tstep = 0;
249
- hydstep = 0;
250
- if (time->Htime < time->Dur) hydstep = timestep(pr);
251
- if (pr->outfile.Saveflag) errcode = savehydstep(pr,&hydstep);
252
-
253
- // Compute pumping energy
254
- if (time->Dur == 0) addenergy(pr,0);
255
- else if (time->Htime < time->Dur) addenergy(pr,hydstep);
256
-
257
- // More time remains - update current time
258
- if (time->Htime < time->Dur)
259
- {
260
- time->Htime += hydstep;
261
- if (!pr->quality.OpenQflag)
262
- {
263
- if (time->Htime >= time->Rtime) time->Rtime += time->Rstep;
264
- }
265
- }
266
-
267
- // No more time remains - force completion of analysis
268
- else
269
- {
270
- time->Htime++;
271
- if (pr->quality.OpenQflag) time->Qtime++;
272
- }
273
- *tstep = hydstep;
274
- return errcode;
275
- }
276
-
277
-
278
- void closehyd(Project *pr)
279
- /*
280
- **--------------------------------------------------------------
281
- ** Input: none
282
- ** Output: returns error code
283
- ** Purpose: closes hydraulics solver system
284
- **--------------------------------------------------------------
285
- */
286
- {
287
- freesparse(pr);
288
- freematrix(pr);
289
- }
290
-
291
-
292
- int allocmatrix(Project *pr)
293
- /*
294
- **--------------------------------------------------------------
295
- ** Input: none
296
- ** Output: returns error code
297
- ** Purpose: allocates memory used for solution matrix coeffs.
298
- **--------------------------------------------------------------
299
- */
300
- {
301
- Network *net = &pr->network;
302
- Hydraul *hyd = &pr->hydraul;
303
-
304
- int errcode = 0;
305
-
306
- hyd->P = (double *) calloc(net->Nlinks+1,sizeof(double));
307
- hyd->Y = (double *) calloc(net->Nlinks+1,sizeof(double));
308
- hyd->DemandFlow = (double *) calloc(net->Nnodes + 1, sizeof(double));
309
- hyd->EmitterFlow = (double *) calloc(net->Nnodes+1, sizeof(double));
310
- hyd->Xflow = (double *) calloc(MAX((net->Nnodes+1), (net->Nlinks+1)),
311
- sizeof(double));
312
- hyd->OldStatus = (StatusType *) calloc(net->Nlinks+net->Ntanks+1,
313
- sizeof(StatusType));
314
- ERRCODE(MEMCHECK(hyd->P));
315
- ERRCODE(MEMCHECK(hyd->Y));
316
- ERRCODE(MEMCHECK(hyd->DemandFlow));
317
- ERRCODE(MEMCHECK(hyd->EmitterFlow));
318
- ERRCODE(MEMCHECK(hyd->Xflow));
319
- ERRCODE(MEMCHECK(hyd->OldStatus));
320
- return errcode;
321
- }
322
-
323
-
324
- void freematrix(Project *pr)
325
- /*
326
- **--------------------------------------------------------------
327
- ** Input: none
328
- ** Output: none
329
- ** Purpose: frees memory used for solution matrix coeffs.
330
- **--------------------------------------------------------------
331
- */
332
- {
333
- Hydraul *hyd = &pr->hydraul;
334
-
335
- free(hyd->P);
336
- free(hyd->Y);
337
- free(hyd->DemandFlow);
338
- free(hyd->EmitterFlow);
339
- free(hyd->Xflow);
340
- free(hyd->OldStatus);
341
- }
342
-
343
-
344
- void initlinkflow(Project *pr, int i, char s, double k)
345
- /*
346
- **--------------------------------------------------------------------
347
- ** Input: i = link index
348
- ** s = link status
349
- ** k = link setting (i.e., pump speed)
350
- ** Output: none
351
- ** Purpose: sets initial flow in link to QZERO if link is closed,
352
- ** to design flow for a pump, or to flow at velocity of
353
- ** 1 fps for other links.
354
- **--------------------------------------------------------------------
355
- */
356
- {
357
- Hydraul *hyd = &pr->hydraul;
358
- Network *n = &pr->network;
359
-
360
- Slink *link = &n->Link[i];
361
-
362
- if (s == CLOSED)
363
- {
364
- hyd->LinkFlow[i] = QZERO;
365
- }
366
- else if (link->Type == PUMP)
367
- {
368
- hyd->LinkFlow[i] = k * n->Pump[findpump(n,i)].Q0;
369
- }
370
- else
371
- {
372
- hyd->LinkFlow[i] = PI * SQR(link->Diam)/4.0;
373
- }
374
- }
375
-
376
-
377
- void setlinkstatus(Project *pr, int index, char value, StatusType *s, double *k)
378
- /*----------------------------------------------------------------
379
- ** Input: index = link index
380
- ** value = 0 (CLOSED) or 1 (OPEN)
381
- ** s = pointer to link status
382
- ** k = pointer to link setting
383
- ** Output: none
384
- ** Purpose: sets link status to OPEN or CLOSED
385
- **----------------------------------------------------------------
386
- */
387
- {
388
- Network *net = &pr->network;
389
-
390
- Slink *link = &net->Link[index];
391
- LinkType t = link->Type;
392
-
393
- // Status set to open
394
- if (value == 1)
395
- {
396
- // Adjust link setting for pumps & valves
397
- if (t == PUMP)
398
- {
399
- *k = 1.0;
400
- // Check if a re-opened pump needs its flow reset
401
- if (*s == CLOSED) resetpumpflow(pr, index);
402
- }
403
- if (t > PUMP && t != GPV) *k = MISSING;
404
- *s = OPEN;
405
- }
406
-
407
- // Status set to closed
408
- else if (value == 0)
409
- {
410
- // Adjust link setting for pumps & valves
411
- if (t == PUMP) *k = 0.0;
412
- if (t > PUMP && t != GPV) *k = MISSING;
413
- *s = CLOSED;
414
- }
415
- }
416
-
417
-
418
- void setlinksetting(Project *pr, int index, double value, StatusType *s,
419
- double *k)
420
- /*----------------------------------------------------------------
421
- ** Input: index = link index
422
- ** value = pump speed or valve setting
423
- ** s = pointer to link status
424
- ** k = pointer to link setting
425
- ** Output: none
426
- ** Purpose: sets pump speed or valve setting, adjusting link
427
- ** status and flow when necessary
428
- **----------------------------------------------------------------
429
- */
430
- {
431
- Network *net = &pr->network;
432
-
433
- Slink *link = &net->Link[index];
434
- LinkType t = link->Type;
435
-
436
- // For a pump, status is OPEN if speed > 0, CLOSED otherwise
437
- if (t == PUMP)
438
- {
439
- *k = value;
440
- if (value > 0 && *s <= CLOSED)
441
- {
442
- // Check if a re-opened pump needs its flow reset
443
- resetpumpflow(pr, index);
444
- *s = OPEN;
445
- }
446
- if (value == 0 && *s > CLOSED) *s = CLOSED;
447
- }
448
-
449
- // For FCV, activate it
450
- else if (t == FCV)
451
- {
452
- *k = value;
453
- *s = ACTIVE;
454
- }
455
-
456
- // Open closed control valve with fixed status (setting = MISSING)
457
- else
458
- {
459
- if (*k == MISSING && *s <= CLOSED) *s = OPEN;
460
- *k = value;
461
- }
462
- }
463
-
464
-
465
- void demands(Project *pr)
466
- /*
467
- **--------------------------------------------------------------------
468
- ** Input: none
469
- ** Output: none
470
- ** Purpose: computes demands at nodes during current time period
471
- **--------------------------------------------------------------------
472
- */
473
- {
474
- Network *net = &pr->network;
475
- Hydraul *hyd = &pr->hydraul;
476
- Times *time = &pr->times;
477
-
478
- int i ,j, n;
479
- long k, p;
480
- double djunc, sum;
481
- Pdemand demand;
482
-
483
- // Determine total elapsed number of pattern periods
484
- p = (time->Htime + time->Pstart) / time->Pstep;
485
-
486
- // Update demand at each node according to its assigned pattern
487
- hyd->Dsystem = 0.0; // System-wide demand
488
- for (i = 1; i <= net->Njuncs; i++)
489
- {
490
- sum = 0.0;
491
- for (demand = net->Node[i].D; demand != NULL; demand = demand->next)
492
- {
493
- // pattern period (k) = (elapsed periods) modulus (periods per pattern)
494
- j = demand->Pat;
495
- k = p % (long)net->Pattern[j].Length;
496
- djunc = (demand->Base) * net->Pattern[j].F[k] * hyd->Dmult;
497
- if (djunc > 0.0) hyd->Dsystem += djunc;
498
- sum += djunc;
499
- }
500
- hyd->NodeDemand[i] = sum;
501
-
502
- // Initialize pressure dependent demand
503
- hyd->DemandFlow[i] = sum;
504
- }
505
-
506
- // Update head at fixed grade nodes with time patterns
507
- for (n = 1; n <= net->Ntanks; n++)
508
- {
509
- Stank *tank = &net->Tank[n];
510
- if (tank->A == 0.0)
511
- {
512
- j = tank->Pat;
513
- if (j > 0)
514
- {
515
- k = p % (long) net->Pattern[j].Length;
516
- i = tank->Node;
517
- hyd->NodeHead[i] = net->Node[i].El * net->Pattern[j].F[k];
518
- }
519
- }
520
- }
521
-
522
- // Update status of pumps with utilization patterns
523
- for (n = 1; n <= net->Npumps; n++)
524
- {
525
- Spump *pump = &net->Pump[n];
526
- j = pump->Upat;
527
- if (j > 0)
528
- {
529
- i = pump->Link;
530
- k = p % (long) net->Pattern[j].Length;
531
- setlinksetting(pr, i, net->Pattern[j].F[k], &hyd->LinkStatus[i],
532
- &hyd->LinkSetting[i]);
533
- }
534
- }
535
- }
536
-
537
-
538
- int controls(Project *pr)
539
- /*
540
- **---------------------------------------------------------------------
541
- ** Input: none
542
- ** Output: number of links whose setting changes
543
- ** Purpose: implements simple controls based on time or tank levels
544
- **---------------------------------------------------------------------
545
- */
546
- {
547
- Network *net = &pr->network;
548
- Hydraul *hyd = &pr->hydraul;
549
- Times *time = &pr->times;
550
-
551
- int i, k, n, reset, setsum;
552
- double h, vplus;
553
- double v1, v2;
554
- double k1, k2;
555
- char s1, s2;
556
- Slink *link;
557
- Scontrol *control;
558
-
559
- // Examine each control statement
560
- setsum = 0;
561
- for (i=1; i <= net->Ncontrols; i++)
562
- {
563
- // Make sure that link is defined
564
- control = &net->Control[i];
565
- reset = 0;
566
- if ( (k = control->Link) <= 0) continue;
567
- link = &net->Link[k];
568
-
569
- // Link is controlled by tank level
570
- if ((n = control->Node) > 0 && n > net->Njuncs)
571
- {
572
- h = hyd->NodeHead[n];
573
- vplus = ABS(hyd->NodeDemand[n]);
574
- v1 = tankvolume(pr,n - net->Njuncs,h);
575
- v2 = tankvolume(pr,n - net->Njuncs, control->Grade);
576
- if (control->Type == LOWLEVEL && v1 <= v2 + vplus) reset = 1;
577
- if (control->Type == HILEVEL && v1 >= v2 - vplus) reset = 1;
578
- }
579
-
580
- // Link is time-controlled
581
- if (control->Type == TIMER)
582
- {
583
- if (control->Time == time->Htime) reset = 1;
584
- }
585
-
586
- //* Link is time-of-day controlled
587
- if (control->Type == TIMEOFDAY)
588
- {
589
- if ((time->Htime + time->Tstart) % SECperDAY == control->Time)
590
- {
591
- reset = 1;
592
- }
593
- }
594
-
595
- // Update link status & pump speed or valve setting
596
- if (reset == 1)
597
- {
598
- if (hyd->LinkStatus[k] <= CLOSED) s1 = CLOSED;
599
- else s1 = OPEN;
600
- s2 = control->Status;
601
- k1 = hyd->LinkSetting[k];
602
- k2 = k1;
603
- if (link->Type > PIPE) k2 = control->Setting;
604
-
605
- // Check if a re-opened pump needs its flow reset
606
- if (link->Type == PUMP && s1 == CLOSED && s2 == OPEN)
607
- resetpumpflow(pr, k);
608
-
609
- if (s1 != s2 || k1 != k2)
610
- {
611
- hyd->LinkStatus[k] = s2;
612
- hyd->LinkSetting[k] = k2;
613
- if (pr->report.Statflag) writecontrolaction(pr,k,i);
614
- setsum++;
615
- }
616
- }
617
- }
618
- return setsum;
619
- }
620
-
621
-
622
- long timestep(Project *pr)
623
- /*
624
- **----------------------------------------------------------------
625
- ** Input: none
626
- ** Output: returns time step until next change in hydraulics
627
- ** Purpose: computes time step to advance hydraulic simulation
628
- **----------------------------------------------------------------
629
- */
630
- {
631
- Network *net = &pr->network;
632
- Times *time = &pr->times;
633
-
634
- long n, t, tstep;
635
-
636
- // Normal time step is hydraulic time step
637
- tstep = time->Hstep;
638
-
639
- // Revise time step based on time until next demand period
640
- // (n = next pattern period, t = time till next period)
641
- n = ((time->Htime + time->Pstart) / time->Pstep) + 1;
642
- t = n * time->Pstep - time->Htime;
643
- if (t > 0 && t < tstep) tstep = t;
644
-
645
- // Revise time step based on time until next reporting period
646
- t = time->Rtime - time->Htime;
647
- if (t > 0 && t < tstep) tstep = t;
648
-
649
- // Revise time step based on smallest time to fill or drain a tank
650
- tanktimestep(pr, &tstep);
651
-
652
- // Revise time step based on smallest time to activate a control
653
- controltimestep(pr, &tstep);
654
-
655
- // Evaluate rule-based controls (which will also update tank levels)
656
- if (net->Nrules > 0) ruletimestep(pr, &tstep);
657
- else tanklevels(pr, tstep);
658
- return tstep;
659
- }
660
-
661
-
662
- int tanktimestep(Project *pr, long *tstep)
663
- /*
664
- **-----------------------------------------------------------------
665
- ** Input: *tstep = current time step
666
- ** Output: *tstep = modified current time step
667
- ** Purpose: revises time step based on shortest time to fill or
668
- ** drain a tank
669
- **-----------------------------------------------------------------
670
- */
671
- {
672
- Network *net = &pr->network;
673
- Hydraul *hyd = &pr->hydraul;
674
-
675
- int i, n, tankIdx = 0;
676
- double h, q, v;
677
- long t;
678
- Stank *tank;
679
-
680
- // Examine each tank
681
- for (i = 1; i <= net->Ntanks; i++)
682
- {
683
- // Skip reservoirs
684
- tank = &net->Tank[i];
685
- if (tank->A == 0.0) continue;
686
-
687
- // Get current tank grade (h) & inflow (q)
688
- n = tank->Node;
689
- h = hyd->NodeHead[n];
690
- q = hyd->NodeDemand[n];
691
- if (ABS(q) <= QZERO) continue;
692
-
693
- // Find volume to fill/drain tank
694
- if (q > 0.0 && h < tank->Hmax) v = tank->Vmax - tank->V;
695
- else if (q < 0.0 && h > tank->Hmin) v = tank->Vmin - tank->V;
696
- else continue;
697
-
698
- // Find time to fill/drain tank
699
- t = (long)ROUND(v / q);
700
- if (t > 0 && t < *tstep)
701
- {
702
- *tstep = t;
703
- tankIdx = n;
704
- }
705
- }
706
- return tankIdx;
707
- }
708
-
709
-
710
- void controltimestep(Project *pr, long *tstep)
711
- /*
712
- **------------------------------------------------------------------
713
- ** Input: *tstep = current time step
714
- ** Output: *tstep = modified current time step
715
- ** Purpose: revises time step based on shortest time to activate
716
- ** a simple control
717
- **------------------------------------------------------------------
718
- */
719
- {
720
- Network *net = &pr->network;
721
- Hydraul *hyd = &pr->hydraul;
722
-
723
- int i, j, k, n;
724
- double h, q, v;
725
- long t, t1, t2;
726
- Slink *link;
727
- Scontrol *control;
728
-
729
- // Examine each control
730
- for (i = 1; i <= net->Ncontrols; i++)
731
- {
732
- t = 0;
733
- control = &net->Control[i];
734
-
735
- // Control depends on a tank level
736
- if ( (n = control->Node) > 0)
737
- {
738
- // Skip node if not a tank or reservoir
739
- if ((j = n - net->Njuncs) <= 0) continue;
740
-
741
- // Find current head and flow into tank
742
- h = hyd->NodeHead[n];
743
- q = hyd->NodeDemand[n];
744
- if (ABS(q) <= QZERO) continue;
745
-
746
- // Find time to reach upper or lower control level
747
- if ( (h < control->Grade && control->Type == HILEVEL && q > 0.0)
748
- || (h > control->Grade && control->Type == LOWLEVEL && q < 0.0) )
749
- {
750
- v = tankvolume(pr, j, control->Grade) - net->Tank[j].V;
751
- t = (long)ROUND(v/q);
752
- }
753
- }
754
-
755
- // Control is based on elapsed time
756
- if (control->Type == TIMER)
757
- {
758
- if (control->Time > pr->times.Htime)
759
- {
760
- t = control->Time - pr->times.Htime;
761
- }
762
- }
763
-
764
- // Control is based on time of day
765
- if (control->Type == TIMEOFDAY)
766
- {
767
- t1 = (pr->times.Htime + pr->times.Tstart) % SECperDAY;
768
- t2 = control->Time;
769
- if (t2 >= t1) t = t2 - t1;
770
- else t = SECperDAY - t1 + t2;
771
- }
772
-
773
- // Revise the current estimated next time step
774
- if (t > 0 && t < *tstep)
775
- {
776
- // Check if rule actually changes link status or setting
777
- k = control->Link;
778
- link = &net->Link[k];
779
- if ( (link->Type > PIPE && hyd->LinkSetting[k] != control->Setting)
780
- || (hyd->LinkStatus[k] != control->Status) ) *tstep = t;
781
- }
782
- }
783
- }
784
-
785
-
786
- void ruletimestep(Project *pr, long *tstep)
787
- /*
788
- **--------------------------------------------------------------
789
- ** Input: *tstep = current time step (sec)
790
- ** Output: *tstep = modified time step
791
- ** Purpose: updates next time step by checking if any rules
792
- ** will fire before then; also updates tank levels.
793
- **--------------------------------------------------------------
794
- */
795
- {
796
- Network *net = &pr->network;
797
- Times *time = &pr->times;
798
-
799
- long tnow, // Start of time interval for rule evaluation
800
- tmax, // End of time interval for rule evaluation
801
- dt, // Normal time increment for rule evaluation
802
- dt1; // Actual time increment for rule evaluation
803
-
804
- // Find interval of time for rule evaluation
805
- tnow = time->Htime;
806
- tmax = tnow + *tstep;
807
-
808
- // If no rules, then time increment equals current time step
809
- if (net->Nrules == 0)
810
- {
811
- dt = *tstep;
812
- dt1 = dt;
813
- }
814
-
815
- // Otherwise, time increment equals rule evaluation time step and
816
- // first actual increment equals time until next even multiple of
817
- // Rulestep occurs.
818
- else
819
- {
820
- dt = time->Rulestep;
821
- dt1 = time->Rulestep - (tnow % time->Rulestep);
822
- }
823
-
824
- // Make sure time increment is no larger than current time step
825
- dt = MIN(dt, *tstep);
826
- dt1 = MIN(dt1, *tstep);
827
- if (dt1 == 0) dt1 = dt;
828
-
829
- // Step through time, updating tank levels, until either
830
- // a rule fires or we reach the end of evaluation period.
831
- //
832
- // Note: we are updating the global simulation time (Htime)
833
- // here because it is used by functions in RULES.C
834
- // to evaluate rules when checkrules() is called.
835
- // It is restored to its original value after the
836
- // rule evaluation process is completed (see below).
837
- // Also note that dt1 will equal dt after the first
838
- // time increment is taken.
839
- //
840
- do
841
- {
842
- time->Htime += dt1; // Update simulation clock
843
- tanklevels(pr, dt1); // Find new tank levels
844
- if (checkrules(pr, dt1)) break; // Stop if any rule fires
845
- dt = MIN(dt, tmax - time->Htime); // Update time increment
846
- dt1 = dt; // Update actual increment
847
- } while (dt > 0); // Stop if no time left
848
-
849
- // Compute an updated simulation time step (*tstep)
850
- // and return simulation time to its original value
851
- *tstep = time->Htime - tnow;
852
- time->Htime = tnow;
853
- }
854
-
855
-
856
- void addenergy(Project *pr, long hstep)
857
- /*
858
- **-------------------------------------------------------------
859
- ** Input: hstep = time step (sec)
860
- ** Output: none
861
- ** Purpose: accumulates pump energy usage
862
- **-------------------------------------------------------------
863
- */
864
- {
865
- Network *net = &pr->network;
866
- Hydraul *hyd = &pr->hydraul;
867
- Times *time = &pr->times;
868
-
869
- int i, j, k;
870
- long m, n;
871
- double c0, c, // Energy cost (cost/kwh)
872
- f0, // Energy cost factor
873
- dt, // Time interval (hr)
874
- e, // Pump efficiency (fraction)
875
- q, // Pump flow (cfs)
876
- p, // Pump energy (kw)
877
- psum = 0.0; // Total energy (kw)
878
- Spump *pump;
879
-
880
- // Determine current time interval in hours
881
- if (time->Dur == 0) dt = 1.0;
882
- else if (time->Htime < time->Dur)
883
- {
884
- dt = (double) hstep / 3600.0;
885
- }
886
- else dt = 0.0;
887
- if (dt == 0.0) return;
888
- n = (time->Htime + time->Pstart) / time->Pstep;
889
-
890
- // Compute default energy cost at current time
891
- c0 = hyd->Ecost;
892
- f0 = 1.0;
893
- if (hyd->Epat > 0)
894
- {
895
- m = n % (long)net->Pattern[hyd->Epat].Length;
896
- f0 = net->Pattern[hyd->Epat].F[m];
897
- }
898
-
899
- // Examine each pump
900
- for (j = 1; j <= net->Npumps; j++)
901
- {
902
- // Skip closed pumps
903
- pump = &net->Pump[j];
904
- k = pump->Link;
905
- if (hyd->LinkStatus[k] <= CLOSED) continue;
906
- q = MAX(QZERO, ABS(hyd->LinkFlow[k]));
907
-
908
- // Find pump-specific energy cost
909
- if (pump->Ecost > 0.0) c = pump->Ecost;
910
- else c = c0;
911
- if ( (i = pump->Epat) > 0)
912
- {
913
- m = n % (long)net->Pattern[i].Length;
914
- c *= net->Pattern[i].F[m];
915
- }
916
- else c *= f0;
917
-
918
- // Find pump energy & efficiency
919
- getenergy(pr, k, &p, &e);
920
- psum += p;
921
-
922
- // Update pump's cumulative statistics
923
- pump->Energy.TimeOnLine += dt;
924
- pump->Energy.Efficiency += e * dt;
925
- pump->Energy.KwHrsPerFlow += p / q * dt;
926
- pump->Energy.KwHrs += p * dt;
927
- pump->Energy.MaxKwatts = MAX(pump->Energy.MaxKwatts, p);
928
- pump->Energy.TotalCost += c * p * dt;
929
- }
930
-
931
- // Update maximum kw value
932
- hyd->Emax = MAX(hyd->Emax, psum);
933
- }
934
-
935
-
936
- void getenergy(Project *pr, int k, double *kw, double *eff)
937
- /*
938
- **----------------------------------------------------------------
939
- ** Input: k = link index
940
- ** Output: *kw = kwatt energy used
941
- ** *eff = efficiency (pumps only)
942
- ** Purpose: computes flow energy associated with link k
943
- **----------------------------------------------------------------
944
- */
945
- {
946
- Network *net = &pr->network;
947
- Hydraul *hyd = &pr->hydraul;
948
-
949
- int i, // efficiency curve index
950
- j; // pump index
951
- double dh, // head across pump (ft)
952
- q, // flow through pump (cfs)
953
- e; // pump efficiency
954
- double q4eff; // flow at nominal pump speed of 1.0
955
- double speed; // current speed setting
956
- Scurve *curve;
957
- Slink *link = &net->Link[k];
958
-
959
- // No energy if link is closed
960
- if (hyd->LinkStatus[k] <= CLOSED)
961
- {
962
- *kw = 0.0;
963
- *eff = 0.0;
964
- return;
965
- }
966
-
967
- // Determine flow and head difference
968
- q = ABS(hyd->LinkFlow[k]);
969
- dh = ABS(hyd->NodeHead[link->N1] - hyd->NodeHead[link->N2]);
970
-
971
- // For pumps, find effic. at current flow
972
- if (link->Type == PUMP)
973
- {
974
- j = findpump(net, k);
975
- e = hyd->Epump;
976
- speed = hyd->LinkSetting[k];
977
- if ((i = net->Pump[j].Ecurve) > 0)
978
- {
979
- q4eff = q / speed * pr->Ucf[FLOW];
980
- curve = &net->Curve[i];
981
- e = interp(curve->Npts,curve->X, curve->Y, q4eff);
982
-
983
- // Sarbu and Borza pump speed adjustment
984
- e = 100.0 - ((100.0-e) * pow(1.0/speed, 0.1));
985
- }
986
- e = MIN(e, 100.0);
987
- e = MAX(e, 1.0);
988
- e /= 100.0;
989
- }
990
- else e = 1.0;
991
-
992
- // Compute energy
993
- *kw = dh * q * hyd->SpGrav / 8.814 / e * KWperHP;
994
- *eff = e;
995
- }
996
-
997
-
998
- void tanklevels(Project *pr, long tstep)
999
- /*
1000
- **----------------------------------------------------------------
1001
- ** Input: tstep = current time step
1002
- ** Output: none
1003
- ** Purpose: computes new water levels in tanks after current
1004
- ** time step
1005
- **----------------------------------------------------------------
1006
- */
1007
- {
1008
- Network *net = &pr->network;
1009
- Hydraul *hyd = &pr->hydraul;
1010
-
1011
- int i, n;
1012
- double dv;
1013
-
1014
- for (i = 1; i <= net->Ntanks; i++)
1015
- {
1016
- Stank *tank = &net->Tank[i];
1017
- if (tank->A == 0.0) continue; // Skip reservoirs
1018
-
1019
- // Update the tank's volume & water elevation
1020
- n = tank->Node;
1021
- dv = hyd->NodeDemand[n] * tstep;
1022
- tank->V += dv;
1023
-
1024
- // Check if tank full/empty within next second
1025
- if (tank->V + hyd->NodeDemand[n] >= tank->Vmax)
1026
- {
1027
- tank->V = tank->Vmax;
1028
- }
1029
- else if (tank->V - hyd->NodeDemand[n] <= tank->Vmin)
1030
- {
1031
- tank->V = tank->Vmin;
1032
- }
1033
- hyd->NodeHead[n] = tankgrade(pr, i, tank->V);
1034
- }
1035
- }
1036
-
1037
-
1038
- double tankvolume(Project *pr, int i, double h)
1039
- /*
1040
- **--------------------------------------------------------------------
1041
- ** Input: i = tank index
1042
- ** h = water elevation in tank
1043
- ** Output: returns water volume in tank
1044
- ** Purpose: finds water volume in tank i corresponding to elev. h.
1045
- **--------------------------------------------------------------------
1046
- */
1047
- {
1048
- Network *net = &pr->network;
1049
-
1050
- int j;
1051
- double y, v;
1052
- Stank *tank = &net->Tank[i];
1053
- Scurve *curve;
1054
-
1055
- // Use level*area if no volume curve
1056
- j = tank->Vcurve;
1057
- if (j == 0) return(tank->Vmin + (h - tank->Hmin) * tank->A);
1058
-
1059
- // If curve exists, interpolate on h to find volume v
1060
- // remembering that volume curve is in original units.
1061
- else
1062
- {
1063
- curve = &net->Curve[j];
1064
- y = (h - net->Node[tank->Node].El) * pr->Ucf[HEAD];
1065
- v = interp(curve->Npts, curve->X, curve->Y, y) / pr->Ucf[VOLUME];
1066
- return v;
1067
- }
1068
- }
1069
-
1070
-
1071
- double tankgrade(Project *pr, int i, double v)
1072
- /*
1073
- **-------------------------------------------------------------------
1074
- ** Input: i = tank index
1075
- ** v = volume in tank
1076
- ** Output: returns water level in tank
1077
- ** Purpose: finds water level in tank i corresponding to volume v.
1078
- **-------------------------------------------------------------------
1079
- */
1080
- {
1081
- Network *net = &pr->network;
1082
-
1083
- int j;
1084
- double y, h;
1085
- Stank *tank = &net->Tank[i];
1086
-
1087
- // Use area if no volume curve
1088
- j = tank->Vcurve;
1089
- if (j == 0) return(tank->Hmin + (v - tank->Vmin) / tank->A);
1090
-
1091
- // If curve exists, interpolate on volume (originally the Y-variable
1092
- // but used here as the X-variable) to find new level above bottom.
1093
- // Remember that volume curve is stored in original units.
1094
- else
1095
- {
1096
- Scurve *curve = &net->Curve[j];
1097
- y = interp(curve->Npts, curve->Y, curve->X, v * pr->Ucf[VOLUME]);
1098
- h = net->Node[tank->Node].El + y / pr->Ucf[HEAD];
1099
- return h;
1100
- }
1101
- }
1102
-
1103
- void resetpumpflow(Project *pr, int i)
1104
- /*
1105
- **-------------------------------------------------------------------
1106
- ** Input: i = link index
1107
- ** Output: none
1108
- ** Purpose: resets flow in a constant HP pump to its initial value.
1109
- **-------------------------------------------------------------------
1110
- */
1111
- {
1112
- Network *net = &pr->network;
1113
- Spump *pump = &net->Pump[findpump(net, i)];
1114
- if (pump->Ptype == CONST_HP)
1115
- pr->hydraul.LinkFlow[i] = pump->Q0;
1116
- }
1117
-