epanet-plus 0.2.1__cp311-cp311-macosx_11_0_arm64.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 (106) hide show
  1. docs/conf.py +67 -0
  2. epanet-msx-src/dispersion.h +27 -0
  3. epanet-msx-src/hash.c +107 -0
  4. epanet-msx-src/hash.h +28 -0
  5. epanet-msx-src/include/epanetmsx.h +104 -0
  6. epanet-msx-src/include/epanetmsx_export.h +42 -0
  7. epanet-msx-src/mathexpr.c +937 -0
  8. epanet-msx-src/mathexpr.h +39 -0
  9. epanet-msx-src/mempool.c +204 -0
  10. epanet-msx-src/mempool.h +24 -0
  11. epanet-msx-src/msxchem.c +1285 -0
  12. epanet-msx-src/msxcompiler.c +368 -0
  13. epanet-msx-src/msxdict.h +42 -0
  14. epanet-msx-src/msxdispersion.c +586 -0
  15. epanet-msx-src/msxerr.c +116 -0
  16. epanet-msx-src/msxfile.c +260 -0
  17. epanet-msx-src/msxfuncs.c +175 -0
  18. epanet-msx-src/msxfuncs.h +35 -0
  19. epanet-msx-src/msxinp.c +1504 -0
  20. epanet-msx-src/msxout.c +398 -0
  21. epanet-msx-src/msxproj.c +791 -0
  22. epanet-msx-src/msxqual.c +2011 -0
  23. epanet-msx-src/msxrpt.c +400 -0
  24. epanet-msx-src/msxtank.c +422 -0
  25. epanet-msx-src/msxtoolkit.c +1164 -0
  26. epanet-msx-src/msxtypes.h +551 -0
  27. epanet-msx-src/msxutils.c +524 -0
  28. epanet-msx-src/msxutils.h +56 -0
  29. epanet-msx-src/newton.c +158 -0
  30. epanet-msx-src/newton.h +34 -0
  31. epanet-msx-src/rk5.c +287 -0
  32. epanet-msx-src/rk5.h +39 -0
  33. epanet-msx-src/ros2.c +293 -0
  34. epanet-msx-src/ros2.h +35 -0
  35. epanet-msx-src/smatrix.c +816 -0
  36. epanet-msx-src/smatrix.h +29 -0
  37. epanet-src/AUTHORS +60 -0
  38. epanet-src/LICENSE +21 -0
  39. epanet-src/enumstxt.h +151 -0
  40. epanet-src/epanet.c +5937 -0
  41. epanet-src/epanet2.c +961 -0
  42. epanet-src/epanet2.def +131 -0
  43. epanet-src/errors.dat +79 -0
  44. epanet-src/flowbalance.c +186 -0
  45. epanet-src/funcs.h +219 -0
  46. epanet-src/genmmd.c +1000 -0
  47. epanet-src/hash.c +177 -0
  48. epanet-src/hash.h +28 -0
  49. epanet-src/hydcoeffs.c +1303 -0
  50. epanet-src/hydraul.c +1164 -0
  51. epanet-src/hydsolver.c +781 -0
  52. epanet-src/hydstatus.c +442 -0
  53. epanet-src/include/epanet2.h +466 -0
  54. epanet-src/include/epanet2_2.h +1962 -0
  55. epanet-src/include/epanet2_enums.h +518 -0
  56. epanet-src/inpfile.c +884 -0
  57. epanet-src/input1.c +672 -0
  58. epanet-src/input2.c +970 -0
  59. epanet-src/input3.c +2265 -0
  60. epanet-src/leakage.c +527 -0
  61. epanet-src/mempool.c +146 -0
  62. epanet-src/mempool.h +24 -0
  63. epanet-src/output.c +853 -0
  64. epanet-src/project.c +1691 -0
  65. epanet-src/quality.c +695 -0
  66. epanet-src/qualreact.c +800 -0
  67. epanet-src/qualroute.c +696 -0
  68. epanet-src/report.c +1559 -0
  69. epanet-src/rules.c +1500 -0
  70. epanet-src/smatrix.c +871 -0
  71. epanet-src/text.h +508 -0
  72. epanet-src/types.h +928 -0
  73. epanet-src/util/cstr_helper.c +59 -0
  74. epanet-src/util/cstr_helper.h +38 -0
  75. epanet-src/util/errormanager.c +92 -0
  76. epanet-src/util/errormanager.h +39 -0
  77. epanet-src/util/filemanager.c +212 -0
  78. epanet-src/util/filemanager.h +81 -0
  79. epanet-src/validate.c +408 -0
  80. epanet.cpython-311-darwin.so +0 -0
  81. epanet_plus/VERSION +1 -0
  82. epanet_plus/__init__.py +8 -0
  83. epanet_plus/epanet_plus.c +118 -0
  84. epanet_plus/epanet_toolkit.py +2833 -0
  85. epanet_plus/epanet_wrapper.py +2434 -0
  86. epanet_plus/include/epanet_plus.h +9 -0
  87. epanet_plus-0.2.1.dist-info/METADATA +157 -0
  88. epanet_plus-0.2.1.dist-info/RECORD +106 -0
  89. epanet_plus-0.2.1.dist-info/WHEEL +6 -0
  90. epanet_plus-0.2.1.dist-info/licenses/LICENSE +21 -0
  91. epanet_plus-0.2.1.dist-info/top_level.txt +11 -0
  92. examples/basic_usage.py +35 -0
  93. examples/epanet_msx.py +35 -0
  94. python-extension/ext.c +344 -0
  95. python-extension/pyepanet.c +2771 -0
  96. python-extension/pyepanet.h +144 -0
  97. python-extension/pyepanet2.c +2453 -0
  98. python-extension/pyepanet2.h +142 -0
  99. python-extension/pyepanet_plus.c +43 -0
  100. python-extension/pyepanet_plus.h +4 -0
  101. python-extension/pyepanetmsx.c +524 -0
  102. python-extension/pyepanetmsx.h +35 -0
  103. tests/test_epanet.py +18 -0
  104. tests/test_epanetmsx.py +38 -0
  105. tests/test_epyt.py +115 -0
  106. tests/test_load_inp_from_buffer.py +59 -0
epanet-src/leakage.c ADDED
@@ -0,0 +1,527 @@
1
+ /*
2
+ ******************************************************************************
3
+ Project: OWA EPANET
4
+ Version: 2.3
5
+ Module: leakage.c
6
+ Description: models additional nodal demands due to pipe leaks.
7
+ Authors: see AUTHORS
8
+ Copyright: see AUTHORS
9
+ License: see LICENSE
10
+ Last Updated: 06/14/2024
11
+ ******************************************************************************
12
+ */
13
+ /*
14
+ This module uses the FAVAD (Fixed and Variable Discharge) equation to model
15
+ leaky pipes:
16
+
17
+ Q = Co * L * (Ao + m * H) * sqrt(H)
18
+
19
+ where Q = pipe leak flow rate, Co = an orifice coefficient (= 0.6*sqrt(2g)),
20
+ L = pipe length, Ao = initial area of leak per unit of pipe length,
21
+ m = change in leak area per unit of pressure head, and H = pressure head.
22
+
23
+ The inverted form of this equation is used to model the leakage demand from
24
+ a pipe's end node using a pair of equivalent emitters as follows:
25
+
26
+ H = Cfa * Qfa^2
27
+ H = Cva * Qva^(2/3)
28
+
29
+ where Qfa = fixed area node leakage rate, Qva = variable area node leakage rate,
30
+ Cfa = 1 / SUM(Co*(L/2)*Ao)^2, Cva = 1 / SUM(Co*(L/2)*m)^2/3, and
31
+ SUM(x) is the summation of x over all pipes connected to the node.
32
+
33
+ In implementing this model, the pipe property "LeakArea" represents Ao in
34
+ sq. mm per 100 units of pipe length and "LeakExpan" represents m in sq. mm
35
+ per unit of pressure head.
36
+
37
+ */
38
+ #include <stdlib.h>
39
+ #include <math.h>
40
+
41
+ #include "types.h"
42
+ #include "funcs.h"
43
+
44
+ // Exported functions (declared in funcs.h)
45
+ //int openleakage(Project *);
46
+ //void closeleakage(Project *);
47
+ //double findlinkleakage(Project *, int);
48
+ //void leakagecoeffs(Project *);
49
+ //double leakageflowchange(Project *, int);
50
+ //int leakagehasconverged(Project *);
51
+
52
+ // Local functions
53
+ static int check_for_leakage(Project *pr);
54
+ static int create_leakage_objects(Project *pr);
55
+ static void convert_pipe_to_node_leakage(Project *pr);
56
+ static void init_node_leakage(Project *pr);
57
+ static int leakage_headloss(Project* pr, int i, double *hfa,
58
+ double *gfa, double *hva, double *gva);
59
+ static void eval_leak_headloss(double q, double c,
60
+ double n, double *hloss, double *hgrad);
61
+ static void add_lower_barrier(double q, double *hloss, double *hgrad);
62
+
63
+
64
+ int openleakage(Project *pr)
65
+ /*-------------------------------------------------------------
66
+ ** Input: none
67
+ ** Output: returns an error code
68
+ ** Purpose: opens the pipe leakage modeling system
69
+ **-------------------------------------------------------------
70
+ */
71
+ {
72
+ Hydraul *hyd = &pr->hydraul;
73
+
74
+ int err;
75
+
76
+ // Check if project includes leakage
77
+ closeleakage(pr);
78
+ hyd->HasLeakage = check_for_leakage(pr);
79
+ if (!hyd->HasLeakage) return 0;
80
+
81
+ // Allocate memory for leakage data objects
82
+ err = create_leakage_objects(pr);
83
+ if (err > 0) return err;
84
+
85
+ // Convert pipe leakage coeffs. to node coeffs.
86
+ convert_pipe_to_node_leakage(pr);
87
+ init_node_leakage(pr);
88
+ return 0;
89
+ }
90
+
91
+
92
+ int check_for_leakage(Project *pr)
93
+ /*-------------------------------------------------------------
94
+ ** Input: none
95
+ ** Output: returns TRUE if any pipes can leak, FALSE otherwise
96
+ ** Purpose: checks if any pipes can leak.
97
+ **-------------------------------------------------------------
98
+ */
99
+ {
100
+ Network *net = &pr->network;
101
+ int i;
102
+ Slink *link;
103
+
104
+ for (i = 1; i <= net->Nlinks; i++)
105
+ {
106
+ // Only pipes have leakage
107
+ link = &net->Link[i];
108
+ if (link->Type > PIPE) continue;
109
+ if (link->LeakArea > 0.0 || link->LeakExpan > 0.0) return TRUE;
110
+ }
111
+ return FALSE;
112
+ }
113
+
114
+
115
+ int create_leakage_objects(Project *pr)
116
+ /*-------------------------------------------------------------
117
+ ** Input: none
118
+ ** Output: returns an error code
119
+ ** Purpose: allocates an array of node leakage objects.
120
+ **-------------------------------------------------------------
121
+ */
122
+ {
123
+ Network *net = &pr->network;
124
+ Hydraul *hyd = &pr->hydraul;
125
+ int i;
126
+
127
+ hyd->Leakage = (Sleakage *)calloc(net->Njuncs + 1, sizeof(Sleakage));
128
+ if (hyd->Leakage == NULL) return 101;
129
+ for (i = 1; i <= net->Njuncs; i++)
130
+ {
131
+ hyd->Leakage[i].cfa = 0.0;
132
+ hyd->Leakage[i].cva = 0.0;
133
+ hyd->Leakage[i].qfa = 0.0;
134
+ hyd->Leakage[i].qva = 0.0;
135
+ }
136
+ return 0;
137
+ }
138
+
139
+ void convert_pipe_to_node_leakage(Project *pr)
140
+ /*-------------------------------------------------------------
141
+ ** Input: none
142
+ ** Output: none
143
+ ** Purpose: converts pipe leakage parameters into node leakage
144
+ ** coefficients.
145
+ **-------------------------------------------------------------
146
+ */
147
+ {
148
+ Network *net = &pr->network;
149
+ Hydraul *hyd = &pr->hydraul;
150
+
151
+ int i;
152
+ double c_area, c_expan, c_orif, len;
153
+ Slink *link;
154
+ Snode *node1;
155
+ Snode *node2;
156
+
157
+ // Orifice coeff. with conversion from sq. mm to sq. m
158
+ c_orif = 4.8149866 * 1.e-6;
159
+
160
+ // Examine each link
161
+ for (i = 1; i <= net->Nlinks; i++)
162
+ {
163
+ // Only pipes have leakage
164
+ link = &net->Link[i];
165
+ if (link->Type > PIPE) continue;
166
+
167
+ // Ignore leakage in a pipe connecting two tanks or
168
+ // reservoirs (since those nodes don't have demands)
169
+ node1 = &net->Node[link->N1];
170
+ node2 = &net->Node[link->N2];
171
+ if (node1->Type != JUNCTION && node2->Type != JUNCTION) continue;
172
+
173
+ // Get pipe's fixed and variable area leak coeffs.
174
+ if (link->LeakArea == 0.0 && link->LeakExpan == 0.0) continue;
175
+ c_area = c_orif * link->LeakArea / SQR(MperFT);
176
+ c_expan = c_orif * link->LeakExpan;
177
+
178
+ // Adjust for number of 100-ft pipe sections
179
+ len = link->Len * pr->Ucf[LENGTH] / 100.;
180
+ if (node1->Type == JUNCTION && node2->Type == JUNCTION)
181
+ {
182
+ len *= 0.5;
183
+ }
184
+ c_area *= len;
185
+ c_expan *= len;
186
+
187
+ // Add these coeffs. to pipe's end nodes
188
+ if (node1->Type == JUNCTION)
189
+ {
190
+ hyd->Leakage[link->N1].cfa += c_area;
191
+ hyd->Leakage[link->N1].cva += c_expan;
192
+ }
193
+ if (node2->Type == JUNCTION)
194
+ {
195
+ hyd->Leakage[link->N2].cfa += c_area;
196
+ hyd->Leakage[link->N2].cva += c_expan;
197
+ }
198
+ }
199
+ }
200
+
201
+ void init_node_leakage(Project *pr)
202
+ /*-------------------------------------------------------------
203
+ ** Input: none
204
+ ** Output: none
205
+ ** Purpose: initializes node leakage coeffs. and flows.
206
+ **-------------------------------------------------------------
207
+ */
208
+ {
209
+ Network *net = &pr->network;
210
+ Hydraul *hyd = &pr->hydraul;
211
+
212
+ int i;
213
+ double c_area, c_expan;
214
+
215
+ for (i = 1; i <= net->Njuncs; i++)
216
+ {
217
+ // Coeff. for fixed area leakage
218
+ c_area = hyd->Leakage[i].cfa;
219
+ if (c_area > 0.0)
220
+ hyd->Leakage[i].cfa = 1.0 / (c_area * c_area);
221
+ else
222
+ hyd->Leakage[i].cfa = 0.0;
223
+
224
+ // Coeff. for variable area leakage
225
+ c_expan = hyd->Leakage[i].cva;
226
+ if (c_expan > 0.0)
227
+ hyd->Leakage[i].cva = 1.0 / pow(c_expan, 2./3.);
228
+ else
229
+ hyd->Leakage[i].cva = 0.0;
230
+
231
+ // Initialize leakage flow to a non-zero value (as required by
232
+ // the hydraulic solver)
233
+ if (hyd->Leakage[i].cfa > 0.0)
234
+ hyd->Leakage[i].qfa = 0.001;
235
+ if (hyd->Leakage[i].cva > 0.0)
236
+ hyd->Leakage[i].qva = 0.001;
237
+ }
238
+ }
239
+
240
+ void closeleakage(Project *pr)
241
+ /*-------------------------------------------------------------
242
+ ** Input: none
243
+ ** Output: none
244
+ ** Purpose: frees memory for nodal leakage objects.
245
+ **-------------------------------------------------------------
246
+ */
247
+ {
248
+ Hydraul *hyd = &pr->hydraul;
249
+ if (hyd->Leakage) free(hyd->Leakage);
250
+ hyd->Leakage = NULL;
251
+ hyd->HasLeakage = FALSE;
252
+ }
253
+
254
+ double findlinkleakage(Project *pr, int i)
255
+ /*-------------------------------------------------------------
256
+ ** Input: i = link index
257
+ ** Output: returns link leakage flow (cfs)
258
+ ** Purpose: computes leakage flow from link i at current
259
+ ** hydraulic solution.
260
+ **-------------------------------------------------------------
261
+ */
262
+ {
263
+ Network *net = &pr->network;
264
+ Hydraul *hyd = &pr->hydraul;
265
+ Smatrix *sm = &hyd->smatrix;
266
+ Slink *link = &net->Link[i];
267
+
268
+ int n1, n2;
269
+ double h1, h2, hsqrt, a, m, c, len, q1, q2;
270
+
271
+ // Only pipes can leak
272
+ link = &net->Link[i];
273
+ if (link->Type > PIPE) return 0.0;
274
+
275
+ // No leakage if area & expansion are 0
276
+ if (link->LeakArea == 0.0 && link->LeakExpan == 0.0) return 0.0;
277
+
278
+ // No leakage if link's end nodes are both fixed grade
279
+ n1 = link->N1;
280
+ n2 = link->N2;
281
+ if (n1 > net->Njuncs && n2 > net->Njuncs) return 0.0;
282
+
283
+ // Pressure head of end nodes
284
+ h1 = hyd->NodeHead[n1] - net->Node[n1].El;
285
+ h1 = MAX(h1, 0.0);
286
+ h2 = hyd->NodeHead[n2] - net->Node[n2].El;
287
+ h2 = MAX(h2, 0.0);
288
+
289
+ // Pipe leak parameters converted to feet
290
+ a = link->LeakArea / SQR(MperFT);
291
+ m = link->LeakExpan;
292
+ len = link->Len * pr->Ucf[LENGTH] / 100.; // # 100 ft pipe lengths
293
+ c = 4.8149866 * len / 2.0 * 1.e-6;
294
+
295
+ // Leakage from 1st half of pipe connected to node n1
296
+ q1 = 0.0;
297
+ if (n1 <= net->Njuncs)
298
+ {
299
+ hsqrt = sqrt(h1);
300
+ q1 = c * (a + m * h1) * hsqrt;
301
+ }
302
+
303
+ // Leakage from 2nd half of pipe connected to node n2
304
+ q2 = 0.0;
305
+ if (n2 <= net->Njuncs)
306
+ {
307
+ hsqrt = sqrt(h2);
308
+ q2 = c * (a + m * h2) * hsqrt;
309
+ }
310
+
311
+ // Adjust leakage flows to account for one node being fixed grade
312
+ if (n2 > net->Njuncs) q1 *= 2.0;
313
+ if (n1 > net->Njuncs) q2 *= 2.0;
314
+ return q1 + q2;
315
+ }
316
+
317
+ void leakagecoeffs(Project *pr)
318
+ /*
319
+ **--------------------------------------------------------------
320
+ ** Input: none
321
+ ** Output: none
322
+ ** Purpose: computes coeffs. of the linearized hydraulic eqns.
323
+ ** contributed by node leakages.
324
+ **--------------------------------------------------------------
325
+ */
326
+ {
327
+ Network *net = &pr->network;
328
+ Hydraul *hyd = &pr->hydraul;
329
+ Smatrix *sm = &hyd->smatrix;
330
+
331
+ int i, row;
332
+ double hfa, // head loss producing current fixed area leakage
333
+ gfa, // gradient of fixed area head loss
334
+ hva, // head loss producing current variable area leakage
335
+ gva; // gradient of variable area head loss
336
+
337
+ Snode* node;
338
+
339
+ for (i = 1; i <= net->Njuncs; i++)
340
+ {
341
+ // Skip junctions that don't leak
342
+ node = &net->Node[i];
343
+ if (!leakage_headloss(pr, i, &hfa, &gfa, &hva, &gva)) continue;
344
+
345
+ // Addition to matrix diagonal & r.h.s
346
+ row = sm->Row[i];
347
+ if (gfa > 0.0)
348
+ {
349
+ sm->Aii[row] += 1.0 / gfa;
350
+ sm->F[row] += (hfa + node->El) / gfa;
351
+ }
352
+ if (gva > 0.0)
353
+ {
354
+ sm->Aii[row] += 1.0 / gva;
355
+ sm->F[row] += (hva + node->El) / gva;
356
+ }
357
+
358
+ // Update node's flow excess (inflow - outflow)
359
+ hyd->Xflow[i] -= (hyd->Leakage[i].qfa + hyd->Leakage[i].qva);
360
+ }
361
+ }
362
+
363
+ double leakageflowchange(Project *pr, int i)
364
+ /*
365
+ **--------------------------------------------------------------
366
+ ** Input: i = node index
367
+ ** Output: returns change in leakage flow rate
368
+ ** Purpose: finds new leakage flow rate at a node after new
369
+ ** heads are computed by the hydraulic solver.
370
+ **--------------------------------------------------------------
371
+ */
372
+ {
373
+ Network *net = &pr->network;
374
+ Hydraul *hyd = &pr->hydraul;
375
+
376
+ double hfa, gfa, hva, gva; // same as defined in leakage_solvercoeffs()
377
+ double h, dqfa, dqva; // pressure head, change in leakage flows
378
+
379
+ // Find the head loss and gradient of the inverted leakage
380
+ // equation for both fixed and variable area leakage at the
381
+ // current leakage flow rates
382
+ if (!leakage_headloss(pr, i, &hfa, &gfa, &hva, &gva)) return 0.0;
383
+
384
+ // Pressure head using latest head solution
385
+ h = hyd->NodeHead[i] - net->Node[i].El;
386
+
387
+ // GGA flow update formula for fixed area leakage
388
+ dqfa = 0.0;
389
+ if (gfa > 0.0)
390
+ {
391
+ dqfa = (hfa - h) / gfa * hyd->RelaxFactor;
392
+ hyd->Leakage[i].qfa -= dqfa;
393
+ }
394
+
395
+ // GGA flow update formula for variable area leakage
396
+ dqva = 0.0;
397
+ if (gva > 0.0)
398
+ {
399
+ dqva = (hva - h) / gva * hyd->RelaxFactor;
400
+ hyd->Leakage[i].qva -= dqva;
401
+ }
402
+
403
+ // New leakage flow at the node
404
+ hyd->LeakageFlow[i] = hyd->Leakage[i].qfa + hyd->Leakage[i].qva;
405
+ return dqfa + dqva;
406
+ }
407
+
408
+ int leakagehasconverged(Project *pr)
409
+ /*
410
+ **--------------------------------------------------------------
411
+ ** Input: none
412
+ ** Output: returns TRUE if leakage calculations converged,
413
+ ** FALSE if not
414
+ ** Purpose: checks if leakage calculations have converged.
415
+ **--------------------------------------------------------------
416
+ */
417
+ {
418
+ Network *net = &pr->network;
419
+ Hydraul *hyd = &pr->hydraul;
420
+
421
+ int i;
422
+ double h, qref, qtest;
423
+ const double QTOL = 0.0001; // 0.0001 cfs ~= 0.005 gpm ~= 0.2 lpm)
424
+
425
+ for (i = 1; i <= net->Njuncs; i++)
426
+ {
427
+ // Skip junctions that don't leak
428
+ if (hyd->Leakage[i].cfa == 0 && hyd->Leakage[i].cva == 0) continue;
429
+
430
+ // Evaluate node's pressure head
431
+ h = hyd->NodeHead[i] - net->Node[i].El;
432
+
433
+ // Directly compute a reference leakage at this pressure head
434
+ qref = 0.0;
435
+ // Contribution from pipes with fixed area leaks
436
+ if (hyd->Leakage[i].cfa > 0.0)
437
+ qref = sqrt(h / hyd->Leakage[i].cfa);
438
+ // Contribution from pipes with variable area leaks
439
+ if (hyd->Leakage[i].cva > 0.0)
440
+ qref += pow((h / hyd->Leakage[i].cva), 1.5);
441
+
442
+ // Compare reference leakage to solution leakage
443
+ qtest = hyd->Leakage[i].qfa + hyd->Leakage[i].qva;
444
+ if (fabs(qref - qtest) > QTOL) return FALSE;
445
+ }
446
+ return TRUE;
447
+ }
448
+
449
+ int leakage_headloss(Project* pr, int i, double *hfa, double *gfa,
450
+ double *hva, double *gva)
451
+ /*
452
+ **--------------------------------------------------------------
453
+ ** Input: i = node index
454
+ ** Output: hfa = fixed area leak head loss (ft)
455
+ ** gfa = gradient of fixed area head loss (ft/cfs)
456
+ ** hva = variable area leak head loss (ft)
457
+ ** gva = gradient of variable area head loss (ft/cfs)
458
+ ** returns TRUE if node has leakage, FALSE otherwise
459
+ ** Purpose: finds head loss and its gradient for a node's
460
+ ** leakage as a function of leakage flow.
461
+ **--------------------------------------------------------------
462
+ */
463
+ {
464
+ Hydraul *hyd = &pr->hydraul;
465
+
466
+ if (hyd->Leakage[i].cfa == 0.0 && hyd->Leakage[i].cva == 0.0) return FALSE;
467
+ if (hyd->Leakage[i].cfa == 0.0)
468
+ {
469
+ *hfa = 0.0;
470
+ *gfa = 0.0;
471
+ }
472
+ else
473
+ eval_leak_headloss(hyd->Leakage[i].qfa, hyd->Leakage[i].cfa,
474
+ 0.5, hfa, gfa);
475
+ if (hyd->Leakage[i].cva == 0.0)
476
+ {
477
+ *hva = 0.0;
478
+ *gva = 0.0;
479
+ }
480
+ else
481
+ eval_leak_headloss(hyd->Leakage[i].qva, hyd->Leakage[i].cva,
482
+ 1.5, hva, gva);
483
+ return TRUE;
484
+ }
485
+
486
+ void eval_leak_headloss(double q, double c, double n,
487
+ double *hloss, double *hgrad)
488
+ /*
489
+ **--------------------------------------------------------------
490
+ ** Input: q = leakage flow rate (cfs)
491
+ ** c = leakage head loss coefficient
492
+ ** n = leakage head loss exponent
493
+ ** Output: hloss = leakage head loss (ft)
494
+ ** hgrad = gradient of leakage head loss (ft/cfs)
495
+ ** Purpose: evaluates inverted form of leakage equation to
496
+ ** compute head loss and its gradient as a function
497
+ ** flow.
498
+ **
499
+ ** Note: Inverted leakage equation is:
500
+ ** hloss = c * q ^ (1/n)
501
+ **--------------------------------------------------------------
502
+ */
503
+ {
504
+ n = 1.0 / n;
505
+ *hgrad = n * c * pow(fabs(q), n - 1.0);
506
+ *hloss = (*hgrad) * q / n;
507
+
508
+ // Prevent leakage from going negative
509
+ add_lower_barrier(q, hloss, hgrad);
510
+ }
511
+
512
+ void add_lower_barrier(double q, double* hloss, double* hgrad)
513
+ /*
514
+ **--------------------------------------------------------------------
515
+ ** Input: q = current flow rate
516
+ ** Output: hloss = head loss value
517
+ ** hgrad = head loss gradient value
518
+ ** Purpose: adds a head loss barrier to prevent flow from falling
519
+ ** below 0.
520
+ **--------------------------------------------------------------------
521
+ */
522
+ {
523
+ double a = 1.e9 * q;
524
+ double b = sqrt(a*a + 1.e-6);
525
+ *hloss += (a - b) / 2.;
526
+ *hgrad += (1.e9 / 2.) * ( 1.0 - a / b);
527
+ }
epanet-src/mempool.c ADDED
@@ -0,0 +1,146 @@
1
+ /*
2
+ ******************************************************************************
3
+ Project: OWA EPANET
4
+ Version: 2.3
5
+ Module: mempool.c
6
+ Description: a simple fast poooled memory allocation package
7
+ Authors: see AUTHORS
8
+ Copyright: see AUTHORS
9
+ License: see LICENSE
10
+ Last Updated: 08/02/2023
11
+
12
+ This module is based on code by Steve Hill in Graphics Gems III,
13
+ David Kirk (ed.), Academic Press, Boston, MA, 1992
14
+ ******************************************************************************
15
+ */
16
+
17
+ #include <stdlib.h>
18
+
19
+ #include "mempool.h"
20
+
21
+ /*
22
+ ** ALLOC_BLOCK_SIZE - adjust this size to suit your installation - it
23
+ ** should be reasonably large otherwise you will be mallocing a lot.
24
+ */
25
+
26
+ #define ALLOC_BLOCK_SIZE 64000 /*(62*1024)*/
27
+
28
+ struct MemBlock
29
+ {
30
+ struct MemBlock *next; // Next block
31
+ char *block, // Start of block
32
+ *free, // Next free position in block
33
+ *end; // block + block size
34
+ };
35
+
36
+ struct Mempool
37
+ {
38
+ struct MemBlock *first;
39
+ struct MemBlock *current;
40
+ };
41
+
42
+ static struct MemBlock* createMemBlock()
43
+ {
44
+ struct MemBlock* memBlock = malloc(sizeof(struct MemBlock));
45
+ if (memBlock)
46
+ {
47
+ memBlock->block = malloc(ALLOC_BLOCK_SIZE * sizeof(char));
48
+ if (memBlock->block == NULL)
49
+ {
50
+ free(memBlock);
51
+ return NULL;
52
+ }
53
+ memBlock->free = memBlock->block;
54
+ memBlock->next = NULL;
55
+ memBlock->end = memBlock->block + ALLOC_BLOCK_SIZE;
56
+ }
57
+ return memBlock;
58
+ }
59
+
60
+
61
+ static void deleteMemBlock(struct MemBlock* memBlock)
62
+ {
63
+ free(memBlock->block);
64
+ free(memBlock);
65
+ }
66
+
67
+
68
+ struct Mempool * mempool_create()
69
+ {
70
+ struct Mempool *mempool;
71
+ mempool = (struct Mempool *)malloc(sizeof(struct Mempool));
72
+ if (mempool == NULL) return NULL;
73
+ mempool->first = createMemBlock();
74
+ mempool->current = mempool->first;
75
+ if (mempool->first == NULL)
76
+ {
77
+ free(mempool);
78
+ return NULL;
79
+ }
80
+ return mempool;
81
+ }
82
+
83
+ void mempool_delete(struct Mempool *mempool)
84
+ {
85
+ if (mempool == NULL) return;
86
+ while (mempool->first)
87
+ {
88
+ mempool->current = mempool->first->next;
89
+ deleteMemBlock(mempool->first);
90
+ mempool->first = mempool->current;
91
+ }
92
+ free(mempool);
93
+ mempool = NULL;
94
+ }
95
+
96
+ void mempool_reset(struct Mempool *mempool)
97
+ {
98
+ mempool->current = mempool->first;
99
+ mempool->current->free = mempool->current->block;
100
+ }
101
+
102
+
103
+ char * mempool_alloc(struct Mempool *mempool, size_t size)
104
+ {
105
+ char* ptr;
106
+
107
+ /*
108
+ ** Align to 4 byte boundary - should be ok for most machines.
109
+ ** Change this if your machine has weird alignment requirements.
110
+ */
111
+ size = (size + 3) & 0xfffffffc;
112
+
113
+ if (!mempool->current) return NULL;
114
+ ptr = mempool->current->free;
115
+ mempool->current->free += size;
116
+
117
+ // Check if the current block is exhausted
118
+
119
+ if (mempool->current->free >= mempool->current->end)
120
+ {
121
+ // Is the next block already allocated?
122
+
123
+ if (mempool->current->next)
124
+ {
125
+ // re-use block
126
+ mempool->current->next->free = mempool->current->next->block;
127
+ mempool->current = mempool->current->next;
128
+ }
129
+ else
130
+ {
131
+ // extend the pool with a new block
132
+ mempool->current->next = createMemBlock();
133
+ if (!mempool->current->next) return NULL;
134
+ mempool->current = mempool->current->next;
135
+ }
136
+
137
+ // set ptr to the first location in the next block
138
+
139
+ ptr = mempool->current->free;
140
+ mempool->current->free += size;
141
+ }
142
+
143
+ // Return pointer to allocated memory
144
+
145
+ return ptr;
146
+ }
epanet-src/mempool.h ADDED
@@ -0,0 +1,24 @@
1
+ /*
2
+ ******************************************************************************
3
+ Project: OWA EPANET
4
+ Version: 2.3
5
+ Module: mempool.h
6
+ Description: header for a simple pooled memory allocator
7
+ Authors: see AUTHORS
8
+ Copyright: see AUTHORS
9
+ License: see LICENSE
10
+ Last Updated: 11/27/2018
11
+ ******************************************************************************
12
+ */
13
+
14
+ #ifndef MEMPOOL_H
15
+ #define MEMPOOL_H
16
+
17
+ struct Mempool;
18
+
19
+ struct Mempool * mempool_create();
20
+ void mempool_delete(struct Mempool *mempool);
21
+ void mempool_reset(struct Mempool *mempool);
22
+ char * mempool_alloc(struct Mempool *mempool, size_t size);
23
+
24
+ #endif