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,743 +0,0 @@
1
- /*
2
- ******************************************************************************
3
- Project: OWA EPANET
4
- Version: 2.2
5
- Module: qualreact.c
6
- Description: computes water quality reactions within pipes and tanks
7
- Authors: see AUTHORS
8
- Copyright: see AUTHORS
9
- License: see LICENSE
10
- Last Updated: 05/15/2019
11
- ******************************************************************************
12
- */
13
-
14
- #include <stdlib.h>
15
- #include <stdio.h>
16
- #include <math.h>
17
- #include "types.h"
18
-
19
- // Exported functions
20
- char setreactflag(Project *);
21
- double getucf(double);
22
- void ratecoeffs(Project *);
23
- void reactpipes(Project *, long);
24
- void reacttanks(Project *, long);
25
- double mixtank(Project *, int, double, double ,double);
26
-
27
- // Imported functions
28
- extern void addseg(Project *, int, double, double);
29
- extern void reversesegs(Project *, int);
30
-
31
- // Local functions
32
- static double piperate(Project *, int);
33
- static double pipereact(Project *, int, double, double, long);
34
- static double tankreact(Project *, double, double, double, long);
35
- static double bulkrate(Project *, double, double, double);
36
- static double wallrate(Project *, double, double, double, double);
37
-
38
- static void tankmix1(Project *, int, double, double, double);
39
- static void tankmix2(Project *, int, double, double, double);
40
- static void tankmix3(Project *, int, double, double, double);
41
- static void tankmix4(Project *, int, double, double, double);
42
-
43
-
44
- char setreactflag(Project *pr)
45
- /*
46
- **-----------------------------------------------------------
47
- ** Input: none
48
- ** Output: returns 1 for reactive WQ constituent, 0 otherwise
49
- ** Purpose: checks if reactive chemical being simulated
50
- **-----------------------------------------------------------
51
- */
52
- {
53
- Network *net = &pr->network;
54
- int i;
55
-
56
- if (pr->quality.Qualflag == TRACE) return 0;
57
- else if (pr->quality.Qualflag == AGE) return 1;
58
- else
59
- {
60
- for (i = 1; i <= net->Nlinks; i++)
61
- {
62
- if (net->Link[i].Type <= PIPE)
63
- {
64
- if (net->Link[i].Kb != 0.0 || net->Link[i].Kw != 0.0) return 1;
65
- }
66
- }
67
- for (i = 1; i <= net->Ntanks; i++)
68
- {
69
- if (net->Tank[i].Kb != 0.0) return 1;
70
- }
71
- }
72
- return 0;
73
- }
74
-
75
-
76
- double getucf(double order)
77
- /*
78
- **--------------------------------------------------------------
79
- ** Input: order = bulk reaction order
80
- ** Output: returns a unit conversion factor
81
- ** Purpose: converts bulk reaction rates from per Liter to
82
- ** per FT3 basis
83
- **--------------------------------------------------------------
84
- */
85
- {
86
- if (order < 0.0) order = 0.0;
87
- if (order == 1.0) return (1.0);
88
- else return (1. / pow(LperFT3, (order - 1.0)));
89
- }
90
-
91
-
92
- void ratecoeffs(Project *pr)
93
- /*
94
- **--------------------------------------------------------------
95
- ** Input: none
96
- ** Output: none
97
- ** Purpose: determines wall reaction coeff. for each pipe
98
- **--------------------------------------------------------------
99
- */
100
- {
101
- Network *net = &pr->network;
102
- Quality *qual = &pr->quality;
103
-
104
- int k;
105
- double kw;
106
-
107
- for (k = 1; k <= net->Nlinks; k++)
108
- {
109
- kw = net->Link[k].Kw;
110
- if (kw != 0.0) kw = piperate(pr, k);
111
- net->Link[k].Rc = kw;
112
- qual->PipeRateCoeff[k] = 0.0;
113
- }
114
- }
115
-
116
-
117
- void reactpipes(Project *pr, long dt)
118
- /*
119
- **--------------------------------------------------------------
120
- ** Input: dt = time step
121
- ** Output: none
122
- ** Purpose: reacts water within each pipe over a time step.
123
- **--------------------------------------------------------------
124
- */
125
- {
126
- Network *net = &pr->network;
127
- Quality *qual = &pr->quality;
128
-
129
- int k;
130
- Pseg seg;
131
- double cseg, rsum, vsum;
132
-
133
- // Examine each link in network
134
- for (k = 1; k <= net->Nlinks; k++)
135
- {
136
- // Skip non-pipe links (pumps & valves)
137
- if (net->Link[k].Type != PIPE) continue;
138
- rsum = 0.0;
139
- vsum = 0.0;
140
-
141
- // Examine each segment of the pipe
142
- seg = qual->FirstSeg[k];
143
- while (seg != NULL)
144
- {
145
- // React segment over time dt
146
- cseg = seg->c;
147
- seg->c = pipereact(pr, k, seg->c, seg->v, dt);
148
-
149
- // Update reaction component of mass balance
150
- qual->MassBalance.reacted += (cseg - seg->c) * seg->v;
151
-
152
- // Accumulate volume-weighted reaction rate
153
- if (qual->Qualflag == CHEM)
154
- {
155
- rsum += fabs(seg->c - cseg) * seg->v;
156
- vsum += seg->v;
157
- }
158
- seg = seg->prev;
159
- }
160
-
161
- // Normalize volume-weighted reaction rate
162
- if (vsum > 0.0) qual->PipeRateCoeff[k] = rsum / vsum / dt * SECperDAY;
163
- else qual->PipeRateCoeff[k] = 0.0;
164
- }
165
- }
166
-
167
-
168
- void reacttanks(Project *pr, long dt)
169
- /*
170
- **--------------------------------------------------------------
171
- ** Input: dt = time step
172
- ** Output: none
173
- ** Purpose: reacts water within each tank over a time step.
174
- **--------------------------------------------------------------
175
- */
176
- {
177
- Network *net = &pr->network;
178
- Quality *qual = &pr->quality;
179
-
180
- int i, k;
181
- double c;
182
- Pseg seg;
183
- Stank *tank;
184
-
185
- // Examine each tank in network
186
- for (i = 1; i <= net->Ntanks; i++)
187
- {
188
- // Skip reservoirs
189
- tank = &net->Tank[i];
190
- if (tank->A == 0.0) continue;
191
-
192
- // k is segment chain belonging to tank i
193
- k = net->Nlinks + i;
194
-
195
- // React each volume segment in the chain
196
- seg = qual->FirstSeg[k];
197
- while (seg != NULL)
198
- {
199
- c = seg->c;
200
- seg->c = tankreact(pr, seg->c, seg->v, tank->Kb, dt);
201
- qual->MassBalance.reacted += (c - seg->c) * seg->v;
202
- seg = seg->prev;
203
- }
204
- }
205
- }
206
-
207
-
208
- double piperate(Project *pr, int k)
209
- /*
210
- **--------------------------------------------------------------
211
- ** Input: k = link index
212
- ** Output: returns reaction rate coeff. for 1st-order wall
213
- ** reactions or mass transfer rate coeff. for 0-order
214
- ** reactions
215
- ** Purpose: finds wall reaction rate coeffs.
216
- **--------------------------------------------------------------
217
- */
218
- {
219
- Network *net = &pr->network;
220
- Hydraul *hyd = &pr->hydraul;
221
- Quality *qual = &pr->quality;
222
-
223
- double a, d, u, q, kf, kw, y, Re, Sh;
224
-
225
- d = net->Link[k].Diam; // Pipe diameter, ft
226
-
227
- // Ignore mass transfer if Schmidt No. is 0
228
- if (qual->Sc == 0.0)
229
- {
230
- if (qual->WallOrder == 0.0) return BIG;
231
- else return (net->Link[k].Kw * (4.0 / d) / pr->Ucf[ELEV]);
232
- }
233
-
234
- // Compute Reynolds No.
235
- // Flow rate made consistent with how its saved to hydraulics file
236
- q = (hyd->LinkStatus[k] <= CLOSED) ? 0.0 : hyd->LinkFlow[k];
237
- a = PI * d * d / 4.0; // pipe area
238
- u = fabs(q) / a; // flow velocity
239
- Re = u * d / hyd->Viscos; // Reynolds number
240
-
241
- // Compute Sherwood No. for stagnant flow
242
- // (mass transfer coeff. = Diffus./radius)
243
- if (Re < 1.0) Sh = 2.0;
244
-
245
- // Compute Sherwood No. for turbulent flow using the Notter-Sleicher formula.
246
- else if (Re >= 2300.0) Sh = 0.0149 * pow(Re, 0.88) * pow(qual->Sc, 0.333);
247
-
248
- // Compute Sherwood No. for laminar flow using Graetz solution formula.
249
- else
250
- {
251
- y = d / net->Link[k].Len * Re * qual->Sc;
252
- Sh = 3.65 + 0.0668 * y / (1.0 + 0.04 * pow(y, 0.667));
253
- }
254
-
255
- // Compute mass transfer coeff. (in ft/sec)
256
- kf = Sh * qual->Diffus / d;
257
-
258
- // For zero-order reaction, return mass transfer coeff.
259
- if (qual->WallOrder == 0.0) return kf;
260
-
261
- // For first-order reaction, return apparent wall coeff.
262
- kw = net->Link[k].Kw / pr->Ucf[ELEV]; // Wall coeff, ft/sec
263
- kw = (4.0 / d) * kw * kf / (kf + fabs(kw)); // Wall coeff, 1/sec
264
- return kw;
265
- }
266
-
267
-
268
- double pipereact(Project *pr, int k, double c, double v, long dt)
269
- /*
270
- **------------------------------------------------------------
271
- ** Input: k = link index
272
- ** c = current quality in segment
273
- ** v = segment volume
274
- ** dt = time step
275
- ** Output: returns new WQ value
276
- ** Purpose: computes new quality in a pipe segment after
277
- ** reaction occurs
278
- **------------------------------------------------------------
279
- */
280
- {
281
- Network *net = &pr->network;
282
- Quality *qual = &pr->quality;
283
-
284
- double cnew, dc, dcbulk, dcwall, rbulk, rwall;
285
-
286
- // For water age (hrs), update concentration by timestep
287
- if (qual->Qualflag == AGE)
288
- {
289
- dc = (double)dt / 3600.0;
290
- cnew = c + dc;
291
- cnew = MAX(0.0, cnew);
292
- return cnew;
293
- }
294
-
295
- // Otherwise find bulk & wall reaction rates
296
- rbulk = bulkrate(pr, c, net->Link[k].Kb, qual->BulkOrder) * qual->Bucf;
297
- rwall = wallrate(pr, c, net->Link[k].Diam, net->Link[k].Kw, net->Link[k].Rc);
298
-
299
- // Find change in concentration over timestep
300
- dcbulk = rbulk * (double)dt;
301
- dcwall = rwall * (double)dt;
302
-
303
- // Update cumulative mass reacted
304
- if (pr->times.Htime >= pr->times.Rstart)
305
- {
306
- qual->Wbulk += fabs(dcbulk) * v;
307
- qual->Wwall += fabs(dcwall) * v;
308
- }
309
-
310
- // Update concentration
311
- dc = dcbulk + dcwall;
312
- cnew = c + dc;
313
- cnew = MAX(0.0, cnew);
314
- return cnew;
315
- }
316
-
317
-
318
- double tankreact(Project *pr, double c, double v, double kb, long dt)
319
- /*
320
- **-------------------------------------------------------
321
- ** Input: c = current quality in tank
322
- ** v = tank volume
323
- ** kb = reaction coeff.
324
- ** dt = time step
325
- ** Output: returns new WQ value
326
- ** Purpose: computes new quality in a tank after
327
- ** reaction occurs
328
- **-------------------------------------------------------
329
- */
330
- {
331
- Quality *qual = &pr->quality;
332
-
333
- double cnew, dc, rbulk;
334
-
335
- // For water age, update concentration by timestep
336
- if (qual->Qualflag == AGE)
337
- {
338
- dc = (double)dt / 3600.0;
339
- }
340
-
341
- // For chemical analysis apply bulk reaction rate
342
- else
343
- {
344
- // Find bulk reaction rate
345
- rbulk = bulkrate(pr, c, kb, qual->TankOrder) * qual->Tucf;
346
-
347
- // Find concentration change & update quality
348
- dc = rbulk * (double)dt;
349
- if (pr->times.Htime >= pr->times.Rstart)
350
- {
351
- qual->Wtank += fabs(dc) * v;
352
- }
353
- }
354
- cnew = c + dc;
355
- cnew = MAX(0.0, cnew);
356
- return cnew;
357
- }
358
-
359
-
360
- double bulkrate(Project *pr, double c, double kb, double order)
361
- /*
362
- **-----------------------------------------------------------
363
- ** Input: c = current WQ concentration
364
- ** kb = bulk reaction coeff.
365
- ** order = bulk reaction order
366
- ** Output: returns bulk reaction rate
367
- ** Purpose: computes bulk reaction rate (mass/volume/time)
368
- **-----------------------------------------------------------
369
- */
370
- {
371
- Quality *qual = &pr->quality;
372
-
373
- double c1;
374
-
375
- // Find bulk reaction potential taking into account
376
- // limiting potential & reaction order.
377
-
378
- // Zero-order kinetics:
379
- if (order == 0.0) c = 1.0;
380
-
381
- // Michaelis-Menton kinetics:
382
- else if (order < 0.0)
383
- {
384
- c1 = qual->Climit + SGN(kb) * c;
385
- if (fabs(c1) < TINY) c1 = SGN(c1) * TINY;
386
- c = c / c1;
387
- }
388
-
389
- // N-th order kinetics:
390
- else
391
- {
392
- // Account for limiting potential
393
- if (qual->Climit == 0.0) c1 = c;
394
- else c1 = MAX(0.0, SGN(kb) * (qual->Climit - c));
395
-
396
- // Compute concentration potential
397
- if (order == 1.0) c = c1;
398
- else if (order == 2.0) c = c1 * c;
399
- else c = c1 * pow(MAX(0.0, c), order - 1.0);
400
- }
401
-
402
- // Reaction rate = bulk coeff. * potential
403
- if (c < 0) c = 0;
404
- return kb * c;
405
- }
406
-
407
-
408
- double wallrate(Project *pr, double c, double d, double kw, double kf)
409
- /*
410
- **------------------------------------------------------------
411
- ** Input: c = current WQ concentration
412
- ** d = pipe diameter
413
- ** kw = intrinsic wall reaction coeff.
414
- ** kf = mass transfer coeff. for 0-order reaction
415
- ** (ft/sec) or apparent wall reaction coeff.
416
- ** for 1-st order reaction (1/sec)
417
- ** Output: returns wall reaction rate in mass/ft3/sec
418
- ** Purpose: computes wall reaction rate
419
- **------------------------------------------------------------
420
- */
421
- {
422
- Quality *qual = &pr->quality;
423
-
424
- if (kw == 0.0 || d == 0.0) return (0.0);
425
-
426
- if (qual->WallOrder == 0.0) // 0-order reaction */
427
- {
428
- kf = SGN(kw) * c * kf; //* Mass transfer rate (mass/ft2/sec)
429
- kw = kw * SQR(pr->Ucf[ELEV]); // Reaction rate (mass/ft2/sec)
430
- if (fabs(kf) < fabs(kw)) kw = kf; // Reaction mass transfer limited
431
- return (kw * 4.0 / d); // Reaction rate (mass/ft3/sec)
432
- }
433
- else return (c * kf); // 1st-order reaction
434
- }
435
-
436
-
437
- double mixtank(Project *pr, int n, double volin, double massin, double volout)
438
- /*
439
- **------------------------------------------------------------
440
- ** Input: n = node index
441
- ** volin = inflow volume to tank over time step
442
- ** massin = mass inflow to tank over time step
443
- ** volout = outflow volume from tank over time step
444
- ** Output: returns new quality for tank
445
- ** Purpose: mixes inflow with tank's contents to update its quality.
446
- **------------------------------------------------------------
447
- */
448
- {
449
- Network *net = &pr->network;
450
-
451
- int i;
452
- double vnet;
453
- i = n - net->Njuncs;
454
- vnet = volin - volout;
455
- switch (net->Tank[i].MixModel)
456
- {
457
- case MIX1: tankmix1(pr, i, volin, massin, vnet); break;
458
- case MIX2: tankmix2(pr, i, volin, massin, vnet); break;
459
- case FIFO: tankmix3(pr, i, volin, massin, vnet); break;
460
- case LIFO: tankmix4(pr, i, volin, massin, vnet); break;
461
- }
462
- return net->Tank[i].C;
463
- }
464
-
465
-
466
- void tankmix1(Project *pr, int i, double vin, double win, double vnet)
467
- /*
468
- **---------------------------------------------
469
- ** Input: i = tank index
470
- ** vin = inflow volume
471
- ** win = mass inflow
472
- ** vnet = inflow - outflow
473
- ** Output: none
474
- ** Purpose: updates quality in a complete mix tank model
475
- **---------------------------------------------
476
- */
477
- {
478
- Network *net = &pr->network;
479
- Quality *qual = &pr->quality;
480
-
481
- int k;
482
- double vnew;
483
- Pseg seg;
484
- Stank *tank = &net->Tank[i];
485
-
486
- k = net->Nlinks + i;
487
- seg = qual->FirstSeg[k];
488
- if (seg)
489
- {
490
- vnew = seg->v + vin;
491
- if (vnew > 0.0) seg->c = (seg->c * seg->v + win) / vnew;
492
- seg->v += vnet;
493
- seg->v = MAX(0.0, seg->v);
494
- tank->C = seg->c;
495
- }
496
- }
497
-
498
-
499
- void tankmix2(Project *pr, int i, double vin, double win, double vnet)
500
- /*
501
- **------------------------------------------------
502
- ** Input: i = tank index
503
- ** vin = inflow volume
504
- ** win = mass inflow
505
- ** vnet = inflow - outflow
506
- ** Output: none
507
- ** Purpose: updates quality in a 2-compartment tank model
508
- **------------------------------------------------
509
- */
510
- {
511
- Network *net = &pr->network;
512
- Quality *qual = &pr->quality;
513
-
514
- int k;
515
- double vt, // Transferred volume
516
- vmz; // Full mixing zone volume
517
- Pseg mixzone, // Mixing zone segment
518
- stagzone; // Stagnant zone segment
519
- Stank *tank = &pr->network.Tank[i];
520
-
521
- // Identify segments for each compartment
522
- k = net->Nlinks + i;
523
- mixzone = qual->LastSeg[k];
524
- stagzone = qual->FirstSeg[k];
525
- if (mixzone == NULL || stagzone == NULL) return;
526
-
527
- // Full mixing zone volume
528
- vmz = tank->V1max;
529
-
530
- // Tank is filling
531
- vt = 0.0;
532
- if (vnet > 0.0)
533
- {
534
- vt = MAX(0.0, (mixzone->v + vnet - vmz));
535
- if (vin > 0.0)
536
- {
537
- mixzone->c = ((mixzone->c) * (mixzone->v) + win) /
538
- (mixzone->v + vin);
539
- }
540
- if (vt > 0.0)
541
- {
542
- stagzone->c = ((stagzone->c) * (stagzone->v) +
543
- (mixzone->c) * vt) / (stagzone->v + vt);
544
- }
545
- }
546
-
547
- // Tank is emptying
548
- else if (vnet < 0.0)
549
- {
550
- if (stagzone->v > 0.0) vt = MIN(stagzone->v, (-vnet));
551
- if (vin + vt > 0.0)
552
- {
553
- mixzone->c = ((mixzone->c) * (mixzone->v) + win +
554
- (stagzone->c) * vt) / (mixzone->v + vin + vt);
555
- }
556
- }
557
-
558
- // Update segment volumes
559
- if (vt > 0.0)
560
- {
561
- mixzone->v = vmz;
562
- if (vnet > 0.0) stagzone->v += vt;
563
- else stagzone->v = MAX(0.0, ((stagzone->v) - vt));
564
- }
565
- else
566
- {
567
- mixzone->v += vnet;
568
- mixzone->v = MIN(mixzone->v, vmz);
569
- mixzone->v = MAX(0.0, mixzone->v);
570
- stagzone->v = 0.0;
571
- }
572
-
573
- // Use quality of mixing zone to represent quality of
574
- // tank since this is where outflow begins to flow from
575
- tank->C = mixzone->c;
576
- }
577
-
578
-
579
- void tankmix3(Project *pr, int i, double vin, double win, double vnet)
580
- /*
581
- **----------------------------------------------------------
582
- ** Input: i = tank index
583
- ** vin = inflow volume
584
- ** win = mass inflow
585
- ** vnet = inflow - outflow
586
- ** Output: none
587
- ** Purpose: Updates quality in a First-In-First-Out (FIFO) tank model.
588
- **----------------------------------------------------------
589
- */
590
- {
591
- Network *net = &pr->network;
592
- Quality *qual = &pr->quality;
593
-
594
- int k;
595
- double vout, vseg;
596
- double cin, vsum, wsum;
597
- Pseg seg;
598
- Stank *tank = &pr->network.Tank[i];
599
-
600
- k = net->Nlinks + i;
601
- if (qual->LastSeg[k] == NULL || qual->FirstSeg[k] == NULL) return;
602
-
603
- // Add new last segment for flow entering the tank
604
- if (vin > 0.0)
605
- {
606
- // ... increase segment volume if inflow has same quality as segment
607
- cin = win / vin;
608
- seg = qual->LastSeg[k];
609
- if (fabs(seg->c - cin) < qual->Ctol) seg->v += vin;
610
-
611
- // ... otherwise add a new last segment to the tank
612
- else addseg(pr, k, vin, cin);
613
- }
614
-
615
- // Withdraw flow from first segment
616
- vsum = 0.0;
617
- wsum = 0.0;
618
- vout = vin - vnet;
619
- while (vout > 0.0)
620
- {
621
- seg = qual->FirstSeg[k];
622
- if (seg == NULL) break;
623
- vseg = seg->v; // Flow volume from leading seg
624
- vseg = MIN(vseg, vout);
625
- if (seg == qual->LastSeg[k]) vseg = vout;
626
- vsum += vseg;
627
- wsum += (seg->c) * vseg;
628
- vout -= vseg; // Remaining flow volume
629
- if (vout >= 0.0 && vseg >= seg->v) // Seg used up
630
- {
631
- if (seg->prev)
632
- {
633
- qual->FirstSeg[k] = seg->prev;
634
- seg->prev = qual->FreeSeg;
635
- qual->FreeSeg = seg;
636
- }
637
- }
638
- else seg->v -= vseg; // Remaining volume in segment
639
- }
640
-
641
- // Use quality withdrawn from 1st segment
642
- // to represent overall quality of tank
643
- if (vsum > 0.0) tank->C = wsum / vsum;
644
- else if (qual->FirstSeg[k] == NULL) tank->C = 0.0;
645
- else tank->C = qual->FirstSeg[k]->c;
646
- }
647
-
648
-
649
- void tankmix4(Project *pr, int i, double vin, double win, double vnet)
650
- /*
651
- **----------------------------------------------------------
652
- ** Input: i = tank index
653
- ** vin = inflow volume
654
- ** win = mass inflow
655
- ** vnet = inflow - outflow
656
- ** Output: none
657
- ** Purpose: Updates quality in a Last In-First Out (LIFO) tank model.
658
- **----------------------------------------------------------
659
- */
660
- {
661
- Network *net = &pr->network;
662
- Quality *qual = &pr->quality;
663
-
664
- int k;
665
- double cin, vsum, wsum, vseg;
666
- Pseg seg;
667
- Stank *tank = &pr->network.Tank[i];
668
-
669
- k = net->Nlinks + i;
670
- if (qual->LastSeg[k] == NULL || qual->FirstSeg[k] == NULL) return;
671
-
672
- // Find inflows & outflows
673
- if (vin > 0.0) cin = win / vin;
674
- else cin = 0.0;
675
-
676
- // If tank filling, then create new last seg
677
- tank->C = qual->LastSeg[k]->c;
678
- seg = qual->LastSeg[k];
679
- if (vnet > 0.0)
680
- {
681
- // ... inflow quality is same as last segment's quality,
682
- // so just add inflow volume to last segment
683
- if (fabs(seg->c - cin) < qual->Ctol) seg->v += vnet;
684
-
685
- // ... otherwise add a new last segment with inflow quality
686
- else addseg(pr, k, vnet, cin);
687
-
688
- // Update reported tank quality
689
- tank->C = qual->LastSeg[k]->c;
690
- }
691
-
692
- // If tank emptying then remove last segments until vnet consumed
693
- else if (vnet < 0.0)
694
- {
695
- vsum = 0.0;
696
- wsum = 0.0;
697
- vnet = -vnet;
698
-
699
- // Reverse segment chain so segments are processed from last to first
700
- reversesegs(pr, k);
701
-
702
- // While there is still volume to remove
703
- while (vnet > 0.0)
704
- {
705
- // ... start with reversed first segment
706
- seg = qual->FirstSeg[k];
707
- if (seg == NULL) break;
708
-
709
- // ... find volume to remove from it
710
- vseg = seg->v;
711
- vseg = MIN(vseg, vnet);
712
- if (seg == qual->LastSeg[k]) vseg = vnet;
713
-
714
- // ... update total volume & mass removed
715
- vsum += vseg;
716
- wsum += (seg->c) * vseg;
717
-
718
- // ... update remiaing volume to remove
719
- vnet -= vseg;
720
-
721
- // ... if no more volume left in current segment
722
- if (vnet >= 0.0 && vseg >= seg->v)
723
- {
724
- // ... replace current segment with previous one
725
- if (seg->prev)
726
- {
727
- qual->FirstSeg[k] = seg->prev;
728
- seg->prev = qual->FreeSeg;
729
- qual->FreeSeg = seg;
730
- }
731
- }
732
-
733
- // ... otherwise reduce volume of current segment
734
- else seg->v -= vseg;
735
- }
736
-
737
- // Restore original orientation of segment chain
738
- reversesegs(pr, k);
739
-
740
- // Reported tank quality is mixture of flow released and any inflow
741
- tank->C = (wsum + win) / (vsum + vin);
742
- }
743
- }