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