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,694 +0,0 @@
1
- /*
2
- ******************************************************************************
3
- Project: OWA EPANET
4
- Version: 2.2
5
- Module: qualroute.c
6
- Description: computes water quality transport over a single time step
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
-
18
- #include "mempool.h"
19
- #include "types.h"
20
-
21
- // Macro to compute the volume of a link
22
- #define LINKVOL(k) (0.785398 * net->Link[(k)].Len * SQR(net->Link[(k)].Diam))
23
-
24
- // Macro to get link flow compatible with flow saved to hydraulics file
25
- #define LINKFLOW(k) ((hyd->LinkStatus[k] <= CLOSED) ? 0.0 : hyd->LinkFlow[k])
26
-
27
- // Exported functions
28
- int sortnodes(Project *);
29
- void transport(Project *, long);
30
- void initsegs(Project *);
31
- void reversesegs(Project *, int);
32
- void addseg(Project *, int, double, double);
33
-
34
- // Imported functions
35
- extern double findsourcequal(Project *, int, double, long);
36
- extern void reactpipes(Project *, long);
37
- extern void reacttanks(Project *, long);
38
- extern double mixtank(Project *, int, double, double, double);
39
-
40
- // Local functions
41
- static void evalnodeinflow(Project *, int, long, double *, double *);
42
- static void evalnodeoutflow(Project *, int, double, long);
43
- static double findnodequal(Project *, int, double, double, double, long);
44
- static double noflowqual(Project *, int);
45
- static void updatemassbalance(Project *, int, double, double, long);
46
- static int selectnonstacknode(Project *, int, int *);
47
-
48
-
49
- void transport(Project *pr, long tstep)
50
- /*
51
- **--------------------------------------------------------------
52
- ** Input: tstep = length of current time step
53
- ** Output: none
54
- ** Purpose: transports constituent mass through the pipe network
55
- ** under a period of constant hydraulic conditions.
56
- **--------------------------------------------------------------
57
- */
58
- {
59
- Network *net = &pr->network;
60
- Hydraul *hyd = &pr->hydraul;
61
- Quality *qual = &pr->quality;
62
-
63
- int j, k, m, n;
64
- double volin, massin, volout, nodequal;
65
- Padjlist alink;
66
-
67
- // React contents of each pipe and tank
68
- if (qual->Reactflag)
69
- {
70
- reactpipes(pr, tstep);
71
- reacttanks(pr, tstep);
72
- }
73
-
74
- // Analyze each node in topological order
75
- for (j = 1; j <= net->Nnodes; j++)
76
- {
77
- // ... index of node to be processed
78
- n = qual->SortedNodes[j];
79
-
80
- // ... zero out mass & flow volumes for this node
81
- volin = 0.0;
82
- massin = 0.0;
83
- volout = 0.0;
84
-
85
- // ... examine each link with flow into the node
86
- for (alink = net->Adjlist[n]; alink != NULL; alink = alink->next)
87
- {
88
- // ... k is index of next link incident on node n
89
- k = alink->link;
90
-
91
- // ... link has flow into node - add it to node's inflow
92
- // (m is index of link's downstream node)
93
- m = net->Link[k].N2;
94
- if (qual->FlowDir[k] < 0) m = net->Link[k].N1;
95
- if (m == n)
96
- {
97
- evalnodeinflow(pr, k, tstep, &volin, &massin);
98
- }
99
-
100
- // ... link has flow out of node - add it to node's outflow
101
- else volout += fabs(LINKFLOW(k));
102
- }
103
-
104
- // ... if node is a junction, add on any external outflow (e.g., demands)
105
- if (net->Node[n].Type == JUNCTION)
106
- {
107
- volout += MAX(0.0, hyd->NodeDemand[n]);
108
- }
109
-
110
- // ... convert from outflow rate to volume
111
- volout *= tstep;
112
-
113
- // ... find the concentration of flow leaving the node
114
- nodequal = findnodequal(pr, n, volin, massin, volout, tstep);
115
-
116
- // ... examine each link with flow out of the node
117
- for (alink = net->Adjlist[n]; alink != NULL; alink = alink->next)
118
- {
119
- // ... link k incident on node n has upstream node m equal to n
120
- k = alink->link;
121
- m = net->Link[k].N1;
122
- if (qual->FlowDir[k] < 0) m = net->Link[k].N2;
123
- if (m == n)
124
- {
125
- // ... send flow at new node concen. into link
126
- evalnodeoutflow(pr, k, nodequal, tstep);
127
- }
128
- }
129
- updatemassbalance(pr, n, massin, volout, tstep);
130
- }
131
- }
132
-
133
- void evalnodeinflow(Project *pr, int k, long tstep, double *volin,
134
- double *massin)
135
- /*
136
- **--------------------------------------------------------------
137
- ** Input: k = link index
138
- ** tstep = quality routing time step
139
- ** Output: volin = flow volume entering a node
140
- ** massin = constituent mass entering a node
141
- ** Purpose: adds the contribution of a link's outflow volume
142
- ** and constituent mass to the total inflow into its
143
- ** downstream node over a time step.
144
- **--------------------------------------------------------------
145
- */
146
- {
147
- Hydraul *hyd = &pr->hydraul;
148
- Quality *qual = &pr->quality;
149
-
150
- double q, v, vseg;
151
- Pseg seg;
152
-
153
- // Get flow rate (q) and flow volume (v) through link
154
- q = LINKFLOW(k);
155
- v = fabs(q) * tstep;
156
-
157
- // Transport flow volume v from link's leading segments into downstream
158
- // node, removing segments once their full volume is consumed
159
- while (v > 0.0)
160
- {
161
- seg = qual->FirstSeg[k];
162
- if (!seg) break;
163
-
164
- // ... volume transported from first segment is smaller of
165
- // remaining flow volume & segment volume
166
- vseg = seg->v;
167
- vseg = MIN(vseg, v);
168
-
169
- // ... update total volume & mass entering downstream node
170
- *volin += vseg;
171
- *massin += vseg * seg->c;
172
-
173
- // ... reduce remaining flow volume by amount transported
174
- v -= vseg;
175
-
176
- // ... if all of segment's volume was transferred
177
- if (v >= 0.0 && vseg >= seg->v)
178
- {
179
- // ... replace this leading segment with the one behind it
180
- qual->FirstSeg[k] = seg->prev;
181
- if (qual->FirstSeg[k] == NULL) qual->LastSeg[k] = NULL;
182
-
183
- // ... recycle the used up segment
184
- seg->prev = qual->FreeSeg;
185
- qual->FreeSeg = seg;
186
- }
187
-
188
- // ... otherwise just reduce this segment's volume
189
- else seg->v -= vseg;
190
- }
191
- }
192
-
193
-
194
- double findnodequal(Project *pr, int n, double volin,
195
- double massin, double volout, long tstep)
196
- /*
197
- **--------------------------------------------------------------
198
- ** Input: n = node index
199
- ** volin = flow volume entering node
200
- ** massin = mass entering node
201
- ** volout = flow volume leaving node
202
- ** tstep = length of current time step
203
- ** Output: returns water quality in a node's outflow
204
- ** Purpose: computes a node's new quality from its inflow
205
- ** volume and mass, including any source contribution.
206
- **--------------------------------------------------------------
207
- */
208
- {
209
- Network *net = &pr->network;
210
- Hydraul *hyd = &pr->hydraul;
211
- Quality *qual = &pr->quality;
212
-
213
- // Node is a junction - update its water quality
214
- if (net->Node[n].Type == JUNCTION)
215
- {
216
- // ... dilute inflow with any external negative demand
217
- volin -= MIN(0.0, hyd->NodeDemand[n]) * tstep;
218
-
219
- // ... new concen. is mass inflow / volume inflow
220
- if (volin > 0.0) qual->NodeQual[n] = massin / volin;
221
-
222
- // ... if no inflow adjust quality for reaction in connecting pipes
223
- else if (qual->Reactflag) qual->NodeQual[n] = noflowqual(pr, n);
224
- }
225
-
226
- // Node is a tank - use its mixing model to update its quality
227
- else if (net->Node[n].Type == TANK)
228
- {
229
- qual->NodeQual[n] = mixtank(pr, n, volin, massin, volout);
230
- }
231
-
232
- // Add any external quality source onto node's concen.
233
- qual->SourceQual = 0.0;
234
-
235
- // For source tracing analysis find tracer added at source node
236
- if (qual->Qualflag == TRACE)
237
- {
238
- if (n == qual->TraceNode)
239
- {
240
- // ... quality added to network is difference between tracer
241
- // concentration (100 mg/L) and current node quality
242
- if (net->Node[n].Type == RESERVOIR) qual->SourceQual = 100.0;
243
- else qual->SourceQual = MAX(100.0 - qual->NodeQual[n], 0.0);
244
- qual->NodeQual[n] = 100.0;
245
- }
246
- return qual->NodeQual[n];
247
- }
248
-
249
- // Find quality contribued by any external chemical source
250
- else qual->SourceQual = findsourcequal(pr, n, volout, tstep);
251
- if (qual->SourceQual == 0.0) return qual->NodeQual[n];
252
-
253
- // Combine source quality with node quality
254
- switch (net->Node[n].Type)
255
- {
256
- case JUNCTION:
257
- qual->NodeQual[n] += qual->SourceQual;
258
- return qual->NodeQual[n];
259
-
260
- case TANK:
261
- return qual->NodeQual[n] + qual->SourceQual;
262
-
263
- case RESERVOIR:
264
- qual->NodeQual[n] = qual->SourceQual;
265
- return qual->SourceQual;
266
- }
267
- return qual->NodeQual[n];
268
- }
269
-
270
-
271
- double noflowqual(Project *pr, int n)
272
- /*
273
- **--------------------------------------------------------------
274
- ** Input: n = node index
275
- ** Output: quality for node n
276
- ** Purpose: sets the quality for a junction node that has no
277
- ** inflow to the average of the quality in its
278
- ** adjoining link segments.
279
- ** Note: this function is only used for reactive substances.
280
- **--------------------------------------------------------------
281
- */
282
- {
283
- Network *net = &pr->network;
284
- Quality *qual = &pr->quality;
285
-
286
- int k, inflow, kount = 0;
287
- double c = 0.0;
288
- FlowDirection dir;
289
- Padjlist alink;
290
-
291
- // Examine each link incident on the node
292
- for (alink = net->Adjlist[n]; alink != NULL; alink = alink->next)
293
- {
294
- // ... index of an incident link
295
- k = alink->link;
296
- dir = qual->FlowDir[k];
297
-
298
- // Node n is link's downstream node - add quality
299
- // of link's first segment to average
300
- if (net->Link[k].N2 == n && dir >= 0) inflow = TRUE;
301
- else if (net->Link[k].N1 == n && dir < 0) inflow = TRUE;
302
- else inflow = FALSE;
303
- if (inflow == TRUE && qual->FirstSeg[k] != NULL)
304
- {
305
- c += qual->FirstSeg[k]->c;
306
- kount++;
307
- }
308
-
309
- // Node n is link's upstream node - add quality
310
- // of link's last segment to average
311
- else if (inflow == FALSE && qual->LastSeg[k] != NULL)
312
- {
313
- c += qual->LastSeg[k]->c;
314
- kount++;
315
- }
316
- }
317
- if (kount > 0) c = c / (double)kount;
318
- return c;
319
- }
320
-
321
-
322
- void evalnodeoutflow(Project *pr, int k, double c, long tstep)
323
- /*
324
- **--------------------------------------------------------------
325
- ** Input: k = link index
326
- ** c = quality from upstream node
327
- ** tstep = time step
328
- ** Output: none
329
- ** Purpose: releases flow volume and mass from the upstream
330
- ** node of a link over a time step.
331
- **--------------------------------------------------------------
332
- */
333
- {
334
- Hydraul *hyd = &pr->hydraul;
335
- Quality *qual = &pr->quality;
336
-
337
- double v;
338
- Pseg seg;
339
-
340
- // Find flow volume (v) released over time step
341
- v = fabs(LINKFLOW(k)) * tstep;
342
- if (v == 0.0) return;
343
-
344
- // Release flow and mass into upstream end of the link
345
-
346
- // ... case where link has a last (most upstream) segment
347
- seg = qual->LastSeg[k];
348
- if (seg)
349
- {
350
- // ... if node quality close to segment quality then mix
351
- // the nodal outflow volume with the segment's volume
352
- if (fabs(seg->c - c) < qual->Ctol)
353
- {
354
- seg->c = (seg->c*seg->v + c*v) / (seg->v + v);
355
- seg->v += v;
356
- }
357
-
358
- // ... otherwise add a new segment at upstream end of link
359
- else addseg(pr, k, v, c);
360
- }
361
-
362
- // ... link has no segments so add one
363
- else addseg(pr, k, v, c);
364
- }
365
-
366
-
367
- void updatemassbalance(Project *pr, int n, double massin,
368
- double volout, long tstep)
369
- /*
370
- **--------------------------------------------------------------
371
- ** Input: n = node index
372
- ** massin = mass inflow to node
373
- ** volout = outflow volume from node
374
- ** Output: none
375
- ** Purpose: Adds a node's external mass inflow and outflow
376
- ** over the current time step to the network's
377
- ** overall mass balance.
378
- **--------------------------------------------------------------
379
- */
380
- {
381
- Network *net = &pr->network;
382
- Hydraul *hyd = &pr->hydraul;
383
- Quality *qual = &pr->quality;
384
-
385
- double masslost = 0.0,
386
- massadded = 0.0;
387
-
388
- switch (net->Node[n].Type)
389
- {
390
- // Junctions lose mass from outflow demand & gain it from source inflow
391
- case JUNCTION:
392
- masslost = MAX(0.0, hyd->NodeDemand[n]) * tstep * qual->NodeQual[n];
393
- massadded = qual->SourceQual * volout;
394
- break;
395
-
396
- // Reservoirs add mass from quality source if specified or from a fixed
397
- // initial quality
398
- case RESERVOIR:
399
- masslost = massin;
400
- if (qual->SourceQual > 0.0) massadded = qual->SourceQual * volout;
401
- else massadded = qual->NodeQual[n] * volout;
402
- break;
403
-
404
- // Tanks add mass only from external source inflow
405
- case TANK:
406
- massadded = qual->SourceQual * volout;
407
- break;
408
- }
409
- qual->MassBalance.outflow += masslost;
410
- qual->MassBalance.inflow += massadded;
411
- }
412
-
413
-
414
- int sortnodes(Project *pr)
415
- /*
416
- **--------------------------------------------------------------
417
- ** Input: none
418
- ** Output: returns an error code
419
- ** Purpose: topologically sorts nodes from upstream to downstream.
420
- ** Note: links with negligible flow are ignored since they can
421
- ** create spurious cycles that cause the sort to fail.
422
- **--------------------------------------------------------------
423
- */
424
- {
425
- Network *net = &pr->network;
426
- Quality *qual = &pr->quality;
427
-
428
- int i, j, k, n;
429
- int *indegree = NULL;
430
- int *stack = NULL;
431
- int stacksize = 0;
432
- int numsorted = 0;
433
- int errcode = 0;
434
- FlowDirection dir;
435
- Padjlist alink;
436
-
437
- // Allocate an array to count # links with inflow to each node
438
- // and for a stack to hold nodes waiting to be processed
439
- indegree = (int *)calloc(net->Nnodes + 1, sizeof(int));
440
- stack = (int *)calloc(net->Nnodes + 1, sizeof(int));
441
- if (indegree && stack)
442
- {
443
- // Count links with "non-negligible" inflow to each node
444
- for (k = 1; k <= net->Nlinks; k++)
445
- {
446
- dir = qual->FlowDir[k];
447
- if (dir == POSITIVE) n = net->Link[k].N2;
448
- else if (dir == NEGATIVE) n = net->Link[k].N1;
449
- else continue;
450
- indegree[n]++;
451
- }
452
-
453
- // Place nodes with no inflow onto a stack
454
- for (i = 1; i <= net->Nnodes; i++)
455
- {
456
- if (indegree[i] == 0)
457
- {
458
- stacksize++;
459
- stack[stacksize] = i;
460
- }
461
- }
462
-
463
- // Examine each node on the stack until none are left
464
- while (numsorted < net->Nnodes)
465
- {
466
- // ... if stack is empty then a cycle exists
467
- if (stacksize == 0)
468
- {
469
- // ... add a non-sorted node connected to a sorted one to stack
470
- j = selectnonstacknode(pr, numsorted, indegree);
471
- if (j == 0) break; // This shouldn't happen.
472
- indegree[j] = 0;
473
- stacksize++;
474
- stack[stacksize] = j;
475
- }
476
-
477
- // ... make the last node added to the stack the next
478
- // in sorted order & remove it from the stack
479
- i = stack[stacksize];
480
- stacksize--;
481
- numsorted++;
482
- qual->SortedNodes[numsorted] = i;
483
-
484
- // ... for each outflow link from this node reduce the in-degree
485
- // of its downstream node
486
- for (alink = net->Adjlist[i]; alink != NULL; alink = alink->next)
487
- {
488
- // ... k is the index of the next link incident on node i
489
- k = alink->link;
490
-
491
- // ... skip link if flow is negligible
492
- if (qual->FlowDir[k] == 0) continue;
493
-
494
- // ... link has flow out of node (downstream node n not equal to i)
495
- n = net->Link[k].N2;
496
- if (qual->FlowDir[k] < 0) n = net->Link[k].N1;
497
-
498
- // ... reduce degree of node n
499
- if (n != i && indegree[n] > 0)
500
- {
501
- indegree[n]--;
502
-
503
- // ... no more degree left so add node n to stack
504
- if (indegree[n] == 0)
505
- {
506
- stacksize++;
507
- stack[stacksize] = n;
508
- }
509
- }
510
- }
511
- }
512
- }
513
- else errcode = 101;
514
- if (numsorted < net->Nnodes) errcode = 120;
515
- FREE(indegree);
516
- FREE(stack);
517
- return errcode;
518
- }
519
-
520
-
521
- int selectnonstacknode(Project *pr, int numsorted, int *indegree)
522
- /*
523
- **--------------------------------------------------------------
524
- ** Input: numsorted = number of nodes that have been sorted
525
- ** indegree = number of inflow links to each node
526
- ** Output: returns a node index
527
- ** Purpose: selects a next node for sorting when a cycle exists.
528
- **--------------------------------------------------------------
529
- */
530
- {
531
- Network *net = &pr->network;
532
- Quality *qual = &pr->quality;
533
-
534
- int i, m, n;
535
- Padjlist alink;
536
-
537
- // Examine each sorted node in last in - first out order
538
- for (i = numsorted; i > 0; i--)
539
- {
540
- // For each link connected to the sorted node
541
- m = qual->SortedNodes[i];
542
- for (alink = net->Adjlist[m]; alink != NULL; alink = alink->next)
543
- {
544
- // ... n is the node of link k opposite to node m
545
- n = alink->node;
546
-
547
- // ... select node n if it still has inflow links
548
- if (indegree[n] > 0) return n;
549
- }
550
- }
551
-
552
- // If no node was selected by the above process then return the
553
- // first node that still has inflow links remaining
554
- for (i = 1; i <= net->Nnodes; i++)
555
- {
556
- if (indegree[i] > 0) return i;
557
- }
558
-
559
- // If all else fails return 0 indicating that no node was selected
560
- return 0;
561
- }
562
-
563
-
564
- void initsegs(Project *pr)
565
- /*
566
- **--------------------------------------------------------------
567
- ** Input: none
568
- ** Output: none
569
- ** Purpose: initializes water quality volume segments in each
570
- ** pipe and tank.
571
- **--------------------------------------------------------------
572
- */
573
- {
574
- Network *net = &pr->network;
575
- Quality *qual = &pr->quality;
576
-
577
- int j, k;
578
- double c, v, v1;
579
-
580
- // Add one segment with assigned downstream node quality to each pipe
581
- for (k = 1; k <= net->Nlinks; k++)
582
- {
583
- qual->FirstSeg[k] = NULL;
584
- qual->LastSeg[k] = NULL;
585
- if (net->Link[k].Type == PIPE)
586
- {
587
- v = LINKVOL(k);
588
- j = net->Link[k].N2;
589
- c = qual->NodeQual[j];
590
- addseg(pr, k, v, c);
591
- }
592
- }
593
-
594
- // Initialize segments in tanks
595
- for (j = 1; j <= net->Ntanks; j++)
596
- {
597
- // Skip reservoirs
598
- if (net->Tank[j].A == 0.0) continue;
599
-
600
- // Establish initial tank quality & volume
601
- k = net->Tank[j].Node;
602
- c = net->Node[k].C0;
603
- v = net->Tank[j].V0;
604
-
605
- // Create one volume segment for entire tank
606
- k = net->Nlinks + j;
607
- qual->FirstSeg[k] = NULL;
608
- qual->LastSeg[k] = NULL;
609
- addseg(pr, k, v, c);
610
-
611
- // Create a 2nd segment for the 2-compartment tank model
612
- if (net->Tank[j].MixModel == MIX2)
613
- {
614
- // ... mixing zone segment
615
- v1 = MAX(0, v - net->Tank[j].V1max);
616
- qual->FirstSeg[k]->v = v1;
617
-
618
- // ... stagnant zone segment
619
- v = v - v1;
620
- addseg(pr, k, v, c);
621
- }
622
- }
623
- }
624
-
625
-
626
- void reversesegs(Project *pr, int k)
627
- /*
628
- **--------------------------------------------------------------
629
- ** Input: k = link index
630
- ** Output: none
631
- ** Purpose: re-orients a link's segments when flow reverses.
632
- **--------------------------------------------------------------
633
- */
634
- {
635
- Quality *qual = &pr->quality;
636
- Pseg seg, nseg, pseg;
637
-
638
- seg = qual->FirstSeg[k];
639
- qual->FirstSeg[k] = qual->LastSeg[k];
640
- qual->LastSeg[k] = seg;
641
- pseg = NULL;
642
- while (seg != NULL)
643
- {
644
- nseg = seg->prev;
645
- seg->prev = pseg;
646
- pseg = seg;
647
- seg = nseg;
648
- }
649
- }
650
-
651
-
652
- void addseg(Project *pr, int k, double v, double c)
653
- /*
654
- **-------------------------------------------------------------
655
- ** Input: k = segment chain index
656
- ** v = segment volume
657
- ** c = segment quality
658
- ** Output: none
659
- ** Purpose: adds a segment to the start of a link
660
- ** upstream of its current last segment.
661
- **-------------------------------------------------------------
662
- */
663
- {
664
- Quality *qual = &pr->quality;
665
- Pseg seg;
666
-
667
- // Grab the next free segment from the segment pool if available
668
- if (qual->FreeSeg != NULL)
669
- {
670
- seg = qual->FreeSeg;
671
- qual->FreeSeg = seg->prev;
672
- }
673
-
674
- // Otherwise allocate a new segment
675
- else
676
- {
677
- seg = (struct Sseg *) mempool_alloc(qual->SegPool, sizeof(struct Sseg));
678
- if (seg == NULL)
679
- {
680
- qual->OutOfMemory = TRUE;
681
- return;
682
- }
683
- }
684
-
685
- // Assign volume and quality to the segment
686
- seg->v = v;
687
- seg->c = c;
688
-
689
- // Add the new segment to the end of the segment chain
690
- seg->prev = NULL;
691
- if (qual->FirstSeg[k] == NULL) qual->FirstSeg[k] = seg;
692
- if (qual->LastSeg[k] != NULL) qual->LastSeg[k]->prev = seg;
693
- qual->LastSeg[k] = seg;
694
- }