epanet-plus 0.0.1__cp313-cp313-musllinux_1_2_x86_64.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.

Potentially problematic release.


This version of epanet-plus might be problematic. Click here for more details.

Files changed (105) 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-313-x86_64-linux-musl.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 +2730 -0
  85. epanet_plus/epanet_wrapper.py +2414 -0
  86. epanet_plus/include/epanet_plus.h +9 -0
  87. epanet_plus-0.0.1.dist-info/METADATA +152 -0
  88. epanet_plus-0.0.1.dist-info/RECORD +105 -0
  89. epanet_plus-0.0.1.dist-info/WHEEL +5 -0
  90. epanet_plus-0.0.1.dist-info/licenses/LICENSE +21 -0
  91. epanet_plus-0.0.1.dist-info/top_level.txt +11 -0
  92. examples/basic_usage.py +35 -0
  93. python-extension/ext.c +344 -0
  94. python-extension/pyepanet.c +2133 -0
  95. python-extension/pyepanet.h +143 -0
  96. python-extension/pyepanet2.c +1823 -0
  97. python-extension/pyepanet2.h +141 -0
  98. python-extension/pyepanet_plus.c +37 -0
  99. python-extension/pyepanet_plus.h +4 -0
  100. python-extension/pyepanetmsx.c +388 -0
  101. python-extension/pyepanetmsx.h +35 -0
  102. tests/test_epanet.py +16 -0
  103. tests/test_epanetmsx.py +36 -0
  104. tests/test_epyt.py +114 -0
  105. tests/test_load_inp_from_buffer.py +18 -0
epanet-src/output.c ADDED
@@ -0,0 +1,853 @@
1
+ /*
2
+ ******************************************************************************
3
+ Project: OWA EPANET
4
+ Version: 2.3
5
+ Module: output.c
6
+ Description: binary file read/write routines
7
+ Authors: see AUTHORS
8
+ Copyright: see AUTHORS
9
+ License: see LICENSE
10
+ Last Updated: 08/13/2022
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 "hash.h"
22
+ #include "text.h"
23
+
24
+ // Local functions
25
+ static int nodeoutput(Project *, int, REAL4 *, double);
26
+ static int linkoutput(Project *, int, REAL4 *, double);
27
+ static int savetimestat(Project *, REAL4 *, HdrType);
28
+ static int savenetreacts(Project *, double, double, double, double);
29
+ static int saveepilog(Project *);
30
+
31
+ // Functions to write/read x[1] to x[n] to/from binary file
32
+ size_t f_save(REAL4 *x, int n, FILE *file)
33
+ {
34
+ return fwrite(x + 1, sizeof(REAL4), n, file);
35
+ }
36
+ size_t f_read(REAL4 *x, int n, FILE *file)
37
+ {
38
+ return fread(x + 1, sizeof(REAL4), n, file);
39
+ }
40
+
41
+ int savenetdata(Project *pr)
42
+ /*
43
+ **---------------------------------------------------------------
44
+ ** Input: none
45
+ ** Output: returns error code
46
+ ** Purpose: saves input data in original units to binary
47
+ ** output file using fixed-sized (4-byte) records
48
+ **---------------------------------------------------------------
49
+ */
50
+ {
51
+ Network *net = &pr->network;
52
+ Outfile *out = &pr->outfile;
53
+ Report *rpt = &pr->report;
54
+ Quality *qual = &pr->quality;
55
+ Parser *parser = &pr->parser;
56
+ Times *time = &pr->times;
57
+
58
+ int i, nmax;
59
+ int errcode = 0;
60
+ INT4 *ibuf;
61
+ REAL4 *x;
62
+ Snode *node;
63
+ FILE *outFile = out->OutFile;
64
+
65
+ // Allocate buffer arrays
66
+ nmax = MAX(net->Nnodes, net->Nlinks) + 1;
67
+ nmax = MAX(nmax, 15);
68
+ ibuf = (INT4 *)calloc(nmax, sizeof(INT4));
69
+ x = (REAL4 *)calloc(nmax, sizeof(REAL4));
70
+ ERRCODE(MEMCHECK(ibuf));
71
+ ERRCODE(MEMCHECK(x));
72
+
73
+ // Write prolog section of binary output file
74
+ if (!errcode)
75
+ {
76
+ // Write integer variables to outFile
77
+ ibuf[0] = MAGICNUMBER;
78
+ ibuf[1] = 20012; // keep version at 2.00.12 so that GUI will run
79
+ ibuf[2] = net->Nnodes;
80
+ ibuf[3] = net->Ntanks;
81
+ ibuf[4] = net->Nlinks;
82
+ ibuf[5] = net->Npumps;
83
+ ibuf[6] = net->Nvalves;
84
+ ibuf[7] = qual->Qualflag;
85
+ ibuf[8] = qual->TraceNode;
86
+ ibuf[9] = parser->Flowflag;
87
+ ibuf[10] = parser->Pressflag;
88
+ ibuf[11] = rpt->Tstatflag;
89
+ ibuf[12] = (INT4)time->Rstart;
90
+ ibuf[13] = (INT4)time->Rstep;
91
+ ibuf[14] = (INT4)time->Dur;
92
+ fwrite(ibuf, sizeof(INT4), 15, outFile);
93
+
94
+ // Write string variables to outFile
95
+ fwrite(pr->Title[0], sizeof(char), TITLELEN + 1, outFile);
96
+ fwrite(pr->Title[1], sizeof(char), TITLELEN + 1, outFile);
97
+ fwrite(pr->Title[2], sizeof(char), TITLELEN + 1, outFile);
98
+ fwrite(parser->InpFname, sizeof(char), MAXFNAME + 1, outFile);
99
+ fwrite(rpt->Rpt2Fname, sizeof(char), MAXFNAME + 1, outFile);
100
+ fwrite(qual->ChemName, sizeof(char), MAXID + 1, outFile);
101
+ fwrite(rpt->Field[QUALITY].Units, sizeof(char), MAXID + 1, outFile);
102
+
103
+ // Write node ID information to outFile
104
+ for (i = 1; i <= net->Nnodes; i++)
105
+ {
106
+ node = &net->Node[i];
107
+ fwrite(node->ID, MAXID + 1, 1, outFile);
108
+ }
109
+
110
+ // Write link information to outFile
111
+ // (Note: first transfer values to buffer array,
112
+ // then fwrite buffer array at offset of 1 )
113
+ for (i = 1; i <= net->Nlinks; i++)
114
+ {
115
+ fwrite(net->Link[i].ID, MAXID + 1, 1, outFile);
116
+ }
117
+
118
+ for (i = 1; i <= net->Nlinks; i++) ibuf[i] = net->Link[i].N1;
119
+ fwrite(ibuf + 1, sizeof(INT4), net->Nlinks, outFile);
120
+
121
+ for (i = 1; i <= net->Nlinks; i++) ibuf[i] = net->Link[i].N2;
122
+ fwrite(ibuf + 1, sizeof(INT4), net->Nlinks, outFile);
123
+
124
+ for (i = 1; i <= net->Nlinks; i++) ibuf[i] = net->Link[i].Type;
125
+ fwrite(ibuf + 1, sizeof(INT4), net->Nlinks, outFile);
126
+
127
+ // Write tank information to outFile
128
+ for (i = 1; i <= net->Ntanks; i++) ibuf[i] = net->Tank[i].Node;
129
+ fwrite(ibuf + 1, sizeof(INT4), net->Ntanks, outFile);
130
+
131
+ for (i = 1; i <= net->Ntanks; i++) x[i] = (REAL4)net->Tank[i].A;
132
+ f_save(x, net->Ntanks, outFile);
133
+
134
+ // Save node elevations to outFile
135
+ for (i = 1; i <= net->Nnodes; i++)
136
+ {
137
+ x[i] = (REAL4)(net->Node[i].El * pr->Ucf[ELEV]);
138
+ }
139
+ f_save(x, net->Nnodes, outFile);
140
+
141
+ // Save link lengths & diameters to outFile
142
+ for (i = 1; i <= net->Nlinks; i++)
143
+ {
144
+ x[i] = (REAL4)(net->Link[i].Len * pr->Ucf[ELEV]);
145
+ }
146
+ f_save(x, net->Nlinks, outFile);
147
+
148
+ for (i = 1; i <= net->Nlinks; i++)
149
+ {
150
+ if (net->Link[i].Type != PUMP)
151
+ {
152
+ x[i] = (REAL4)(net->Link[i].Diam * pr->Ucf[DIAM]);
153
+ }
154
+ else x[i] = 0.0f;
155
+ }
156
+ if (f_save(x, net->Nlinks, outFile) < (unsigned)net->Nlinks) errcode = 308;
157
+ }
158
+
159
+ // Free memory used for buffer arrays
160
+ free(ibuf);
161
+ free(x);
162
+ return errcode;
163
+ }
164
+
165
+ int savehyd(Project *pr, long *htime)
166
+ /*
167
+ **--------------------------------------------------------------
168
+ ** Input: *htime = current time
169
+ ** Output: returns error code
170
+ ** Purpose: saves current hydraulic solution to file HydFile
171
+ ** in binary format
172
+ **--------------------------------------------------------------
173
+ */
174
+ {
175
+ Network *net = &pr->network;
176
+ Outfile *out = &pr->outfile;
177
+ Hydraul *hyd = &pr->hydraul;
178
+
179
+ int i;
180
+ INT4 t;
181
+ int errcode = 0;
182
+ REAL4 *x;
183
+ FILE *HydFile = out->HydFile;
184
+
185
+ x = (REAL4 *)calloc(MAX(net->Nnodes, net->Nlinks) + 1, sizeof(REAL4));
186
+ if (x == NULL) return 101;
187
+
188
+ // Save current time (htime)
189
+ t = (INT4)(*htime);
190
+ fwrite(&t, sizeof(INT4), 1, HydFile);
191
+
192
+ // Save current nodal demands (D)
193
+ for (i = 1; i <= net->Nnodes; i++) x[i] = (REAL4)hyd->NodeDemand[i];
194
+ fwrite(x + 1, sizeof(REAL4), net->Nnodes, HydFile);
195
+ //f_save(x, net->Nnodes, HydFile);
196
+
197
+ // Save current nodal heads
198
+ for (i = 1; i <= net->Nnodes; i++) x[i] = (REAL4)hyd->NodeHead[i];
199
+ fwrite(x + 1, sizeof(REAL4), net->Nnodes, HydFile);
200
+ //f_save(x, net->Nnodes, HydFile);
201
+
202
+ // Force flow in closed links to be zero then save flows
203
+ for (i = 1; i <= net->Nlinks; i++)
204
+ {
205
+ if (hyd->LinkStatus[i] <= CLOSED) x[i] = 0.0f;
206
+ else x[i] = (REAL4)hyd->LinkFlow[i];
207
+ }
208
+ fwrite(x + 1, sizeof(REAL4), net->Nlinks, HydFile);
209
+ //f_save(x, net->Nlinks, HydFile);
210
+
211
+ // Save link status
212
+ for (i = 1; i <= net->Nlinks; i++) x[i] = (REAL4)hyd->LinkStatus[i];
213
+ fwrite(x + 1, sizeof(REAL4), net->Nlinks, HydFile);
214
+ //f_save(x, net->Nlinks, HydFile);
215
+
216
+ // Save link settings & check for successful write-to-disk
217
+ // (We assume that if any of the previous fwrites failed,
218
+ // then this one will also fail.)
219
+ for (i = 1; i <= net->Nlinks; i++) x[i] = (REAL4)hyd->LinkSetting[i];
220
+ if (fwrite(x + 1, sizeof(REAL4), net->Nlinks, HydFile) <
221
+ (unsigned)net->Nlinks
222
+ ) errcode = 308;
223
+ //if (f_save(x, net->Nlinks, HydFile) < (unsigned)net->Nlinks) errcode = 308;
224
+ free(x);
225
+ fflush(HydFile);
226
+ return errcode;
227
+ }
228
+
229
+ int savehydstep(Project *pr, long *hydstep)
230
+ /*
231
+ **--------------------------------------------------------------
232
+ ** Input: *hydstep = next time step
233
+ ** Output: returns error code
234
+ ** Purpose: saves next hydraulic timestep to file HydFile
235
+ ** in binary format
236
+ **--------------------------------------------------------------
237
+ */
238
+ {
239
+ Outfile *out = &pr->outfile;
240
+
241
+ INT4 t;
242
+ int errcode = 0;
243
+
244
+ t = (INT4)(*hydstep);
245
+ if (fwrite(&t, sizeof(INT4), 1, out->HydFile) < 1) errcode = 308;
246
+ if (t == 0) fputc(EOFMARK, out->HydFile);
247
+ fflush(out->HydFile);
248
+ return errcode;
249
+ }
250
+
251
+ int saveenergy(Project *pr)
252
+ /*
253
+ **--------------------------------------------------------------
254
+ ** Input: none
255
+ ** Output: returns error code
256
+ ** Purpose: saves energy usage by each pump to outFile
257
+ ** in binary format
258
+ **--------------------------------------------------------------
259
+ */
260
+ {
261
+ Network *net = &pr->network;
262
+ Hydraul *hyd = &pr->hydraul;
263
+ Outfile *out = &pr->outfile;
264
+ Parser *parser = &pr->parser;
265
+ Times *time = &pr->times;
266
+
267
+ int i;
268
+ INT4 index;
269
+ REAL4 x[6]; // work array
270
+ double hdur, // total simulation duration in hours
271
+ t; // total pumping time duration
272
+ Spump *pump;
273
+ FILE *outFile = out->OutFile;
274
+
275
+ hdur = time->Dur / 3600.0;
276
+ for (i = 1; i <= net->Npumps; i++)
277
+ {
278
+ pump = &net->Pump[i];
279
+ if (hdur == 0.0) pump->Energy.TotalCost *= 24.0;
280
+ else
281
+ {
282
+ // ... convert total hrs. online to fraction of total time online
283
+ t = pump->Energy.TimeOnLine; //currently holds total hrs. online
284
+ pump->Energy.TimeOnLine = t / hdur;
285
+
286
+ // ... convert cumulative values to time-averaged ones
287
+ if (t > 0.0)
288
+ {
289
+ pump->Energy.Efficiency /= t;
290
+ pump->Energy.KwHrsPerFlow /= t;
291
+ pump->Energy.KwHrs /= t;
292
+ }
293
+
294
+ // ... convert total cost to cost per day
295
+ pump->Energy.TotalCost *= 24.0 / hdur;
296
+ }
297
+
298
+ // ... express time online and avg. efficiency as percentages
299
+ pump->Energy.TimeOnLine *= 100.0;
300
+ pump->Energy.Efficiency *= 100.0;
301
+
302
+ // ... compute KWH per Million Gallons or per Cubic Meter
303
+ if (parser->Unitsflag == SI)
304
+ {
305
+ pump->Energy.KwHrsPerFlow *= (1000. / LPSperCFS / 3600.);
306
+ }
307
+ else pump->Energy.KwHrsPerFlow *= (1.0e6 / GPMperCFS / 60.);
308
+
309
+ // ... save energy stats to REAL4 work array
310
+ x[0] = (REAL4)pump->Energy.TimeOnLine;
311
+ x[1] = (REAL4)pump->Energy.Efficiency;
312
+ x[2] = (REAL4)pump->Energy.KwHrsPerFlow;
313
+ x[3] = (REAL4)pump->Energy.KwHrs;
314
+ x[4] = (REAL4)pump->Energy.MaxKwatts;
315
+ x[5] = (REAL4)pump->Energy.TotalCost;
316
+
317
+ // ... save energy results to output file
318
+ index = pump->Link;
319
+ if (fwrite(&index, sizeof(INT4), 1, outFile) < 1) return 308;
320
+ if (fwrite(x, sizeof(REAL4), 6, outFile) < 6) return 308;
321
+ }
322
+
323
+ // ... compute and save demand charge
324
+ hyd->Emax = hyd->Emax * hyd->Dcost;
325
+ x[0] = (REAL4)hyd->Emax;
326
+ if (fwrite(&x[0], sizeof(REAL4), 1, outFile) < 1) return 308;
327
+ return (0);
328
+ }
329
+
330
+ int readhyd(Project *pr, long *hydtime)
331
+ /*
332
+ **--------------------------------------------------------------
333
+ ** Input: none
334
+ ** Output: *hydtime = time of hydraulic solution
335
+ ** Returns: 1 if successful, 0 if not
336
+ ** Purpose: reads hydraulic solution from file HydFile
337
+ **
338
+ ** NOTE: A hydraulic solution consists of the current time
339
+ ** (hydtime), nodal demands (D) and heads (H), link
340
+ ** flows (Q), link status (S), and link settings (K).
341
+ **--------------------------------------------------------------
342
+ */
343
+ {
344
+ Network *net = &pr->network;
345
+ Hydraul *hyd = &pr->hydraul;
346
+ Outfile *out = &pr->outfile;
347
+
348
+ int i;
349
+ INT4 t;
350
+ int result = 1;
351
+ REAL4 *x;
352
+ FILE *HydFile = out->HydFile;
353
+
354
+ x = (REAL4 *)calloc(MAX(net->Nnodes, net->Nlinks) + 1, sizeof(REAL4));
355
+ if (x == NULL) return 0;
356
+
357
+ if (fread(&t, sizeof(INT4), 1, HydFile) < 1) result = 0;
358
+ *hydtime = t;
359
+
360
+ if (f_read(x, net->Nnodes, HydFile) < (unsigned)net->Nnodes) result = 0;
361
+ else for (i = 1; i <= net->Nnodes; i++) hyd->NodeDemand[i] = x[i];
362
+
363
+ if (f_read(x, net->Nnodes, HydFile) < (unsigned)net->Nnodes) result = 0;
364
+ else for (i = 1; i <= net->Nnodes; i++) hyd->NodeHead[i] = x[i];
365
+
366
+ if (f_read(x, net->Nlinks, HydFile) < (unsigned)net->Nlinks) result = 0;
367
+ else for (i = 1; i <= net->Nlinks; i++) hyd->LinkFlow[i] = x[i];
368
+
369
+ if (f_read(x, net->Nlinks, HydFile) < (unsigned)net->Nlinks) result = 0;
370
+ else for (i = 1; i <= net->Nlinks; i++) hyd->LinkStatus[i] = (char)x[i];
371
+
372
+ if (f_read(x, net->Nlinks, HydFile) < (unsigned)net->Nlinks) result = 0;
373
+ else for (i = 1; i <= net->Nlinks; i++) hyd->LinkSetting[i] = x[i];
374
+
375
+ free(x);
376
+ return result;
377
+ }
378
+
379
+ int readhydstep(Project *pr, long *hydstep)
380
+ /*
381
+ **--------------------------------------------------------------
382
+ ** Input: none
383
+ ** Output: *hydstep = next hydraulic time step (sec)
384
+ ** Returns: 1 if successful, 0 if not
385
+ ** Purpose: reads hydraulic time step from file HydFile
386
+ **--------------------------------------------------------------
387
+ */
388
+ {
389
+ FILE *hydFile = pr->outfile.HydFile;
390
+ INT4 t;
391
+
392
+ if (fread(&t, sizeof(INT4), 1, hydFile) < 1) return 0;
393
+ *hydstep = t;
394
+ return 1;
395
+ }
396
+
397
+ int saveoutput(Project *pr)
398
+ /*
399
+ **--------------------------------------------------------------
400
+ ** Input: none
401
+ ** Output: returns error code
402
+ ** Purpose: writes simulation results to output file
403
+ **--------------------------------------------------------------
404
+ */
405
+ {
406
+ Network *net = &pr->network;
407
+
408
+ int j;
409
+ int errcode = 0;
410
+ REAL4 *x;
411
+
412
+ x = (REAL4 *)calloc(MAX(net->Nnodes, net->Nlinks) + 1, sizeof(REAL4));
413
+ if (x == NULL) return 101;
414
+
415
+ // Write out node results, then link results
416
+ for (j = DEMAND; j <= QUALITY; j++) ERRCODE(nodeoutput(pr, j, x, pr->Ucf[j]));
417
+ for (j = FLOW; j <= FRICTION; j++) ERRCODE(linkoutput(pr, j, x, pr->Ucf[j]));
418
+ free(x);
419
+ return errcode;
420
+ }
421
+
422
+ int nodeoutput(Project *pr, int j, REAL4 *x, double ucf)
423
+ /*
424
+ **--------------------------------------------------------------
425
+ ** Input: j = type of node variable
426
+ ** *x = buffer for node values
427
+ ** ucf = units conversion factor
428
+ ** Output: returns error code
429
+ ** Purpose: writes results for node variable j to output file
430
+ **-----------------------------------------------------------------
431
+ */
432
+ {
433
+ Network *net = &pr->network;
434
+ Hydraul *hyd = &pr->hydraul;
435
+ Quality *qual = &pr->quality;
436
+ Outfile *out = &pr->outfile;
437
+
438
+ int i;
439
+ FILE *outFile = out->TmpOutFile;
440
+
441
+ // Load computed results (in proper units) into buffer x
442
+ switch (j)
443
+ {
444
+ case DEMAND:
445
+ for (i = 1; i <= net->Nnodes; i++)
446
+ {
447
+ x[i] = (REAL4)(hyd->NodeDemand[i] * ucf);
448
+ }
449
+ break;
450
+
451
+ case HEAD:
452
+ for (i = 1; i <= net->Nnodes; i++)
453
+ {
454
+ x[i] = (REAL4)(hyd->NodeHead[i] * ucf);
455
+ }
456
+ break;
457
+
458
+ case PRESSURE:
459
+ for (i = 1; i <= net->Nnodes; i++)
460
+ {
461
+ x[i] = (REAL4)((hyd->NodeHead[i] - net->Node[i].El) * ucf);
462
+ }
463
+ break;
464
+
465
+ case QUALITY:
466
+ for (i = 1; i <= net->Nnodes; i++)
467
+ {
468
+ x[i] = (REAL4)(qual->NodeQual[i] * ucf);
469
+ }
470
+ }
471
+
472
+ // Write x[1] to x[net->Nnodes] to output file
473
+ if (f_save(x, net->Nnodes, outFile) < (unsigned)net->Nnodes) return 308;
474
+ return 0;
475
+ }
476
+
477
+ int linkoutput(Project *pr, int j, REAL4 *x, double ucf)
478
+ /*
479
+ **----------------------------------------------------------------
480
+ ** Input: j = type of link variable
481
+ ** *x = buffer for link values
482
+ ** ucf = units conversion factor
483
+ ** Output: returns error code
484
+ ** Purpose: writes results for link variable j to output file
485
+ **----------------------------------------------------------------
486
+ */
487
+ {
488
+ Network *net = &pr->network;
489
+ Hydraul *hyd = &pr->hydraul;
490
+ Quality *qual = &pr->quality;
491
+ Outfile *out = &pr->outfile;
492
+
493
+ int i;
494
+ double a, h, q, f, setting;
495
+ FILE *outFile = out->TmpOutFile;
496
+
497
+ // Load computed results (in proper units) into buffer x
498
+ switch (j)
499
+ {
500
+ case FLOW:
501
+ for (i = 1; i <= net->Nlinks; i++)
502
+ {
503
+ x[i] = (REAL4)(hyd->LinkFlow[i] * ucf);
504
+ }
505
+ break;
506
+
507
+ case VELOCITY:
508
+ for (i = 1; i <= net->Nlinks; i++)
509
+ {
510
+ if (net->Link[i].Type == PUMP) x[i] = 0.0f;
511
+ else
512
+ {
513
+ q = ABS(hyd->LinkFlow[i]);
514
+ a = PI * SQR(net->Link[i].Diam) / 4.0;
515
+ x[i] = (REAL4)(q / a * ucf);
516
+ }
517
+ }
518
+ break;
519
+
520
+ case HEADLOSS:
521
+ for (i = 1; i <= net->Nlinks; i++)
522
+ {
523
+ if (hyd->LinkStatus[i] <= CLOSED) x[i] = 0.0f;
524
+ else
525
+ {
526
+ h = hyd->NodeHead[net->Link[i].N1] -
527
+ hyd->NodeHead[net->Link[i].N2];
528
+ if (net->Link[i].Type != PUMP) h = ABS(h);
529
+ if (net->Link[i].Type <= PIPE)
530
+ {
531
+ x[i] = (REAL4)(1000.0 * h / net->Link[i].Len);
532
+ }
533
+ else x[i] = (REAL4)(h * ucf);
534
+ }
535
+ }
536
+ break;
537
+
538
+ case LINKQUAL:
539
+ for (i = 1; i <= net->Nlinks; i++)
540
+ {
541
+ x[i] = (REAL4)(avgqual(pr,i) * ucf);
542
+ }
543
+ break;
544
+
545
+ case STATUS:
546
+ for (i = 1; i <= net->Nlinks; i++)
547
+ {
548
+ x[i] = (REAL4)hyd->LinkStatus[i];
549
+ }
550
+ break;
551
+
552
+ case SETTING:
553
+ for (i = 1; i <= net->Nlinks; i++)
554
+ {
555
+ setting = hyd->LinkSetting[i];
556
+ if (setting != MISSING) switch (net->Link[i].Type)
557
+ {
558
+ case CVPIPE:
559
+ case PIPE:
560
+ x[i] = (REAL4)setting; break;
561
+ case PUMP:
562
+ x[i] = (REAL4)setting; break;
563
+ case PRV:
564
+ case PSV:
565
+ case PBV:
566
+ x[i] = (REAL4)(setting * pr->Ucf[PRESSURE]); break;
567
+ case FCV:
568
+ x[i] = (REAL4)(setting * pr->Ucf[FLOW]); break;
569
+ case TCV:
570
+ case PCV:
571
+ x[i] = (REAL4)setting; break;
572
+ default: x[i] = 0.0f;
573
+ }
574
+ else x[i] = 0.0f;
575
+ }
576
+ break;
577
+
578
+ case REACTRATE: // Overall reaction rate in mass/L/day
579
+ if (qual->Qualflag == NONE)
580
+ {
581
+ memset(x, 0, (net->Nlinks + 1) * sizeof(REAL4));
582
+ }
583
+ else for (i = 1; i <= net->Nlinks; i++)
584
+ {
585
+ x[i] = (REAL4)(qual->PipeRateCoeff[i] * ucf);
586
+ }
587
+ break;
588
+
589
+ case FRICTION: // Friction factor
590
+ // f = 2ghd/(Lu^2) where f = friction factor
591
+ // u = velocity, g = grav. accel., h = head
592
+ // loss, d = diam., & L = pipe length
593
+ for (i = 1; i <= net->Nlinks; i++)
594
+ {
595
+ if (net->Link[i].Type <= PIPE && ABS(hyd->LinkFlow[i]) > TINY)
596
+ {
597
+ h = ABS(hyd->NodeHead[net->Link[i].N1] -
598
+ hyd->NodeHead[net->Link[i].N2]);
599
+ f = 39.725 * h * pow(net->Link[i].Diam, 5) /
600
+ net->Link[i].Len / SQR(hyd->LinkFlow[i]);
601
+ x[i] = (REAL4)f;
602
+ }
603
+ else x[i] = 0.0f;
604
+ }
605
+ break;
606
+ }
607
+
608
+ // Write x[1] to x[net->Nlinks] to output file
609
+ if (f_save(x, net->Nlinks, outFile) < (unsigned)net->Nlinks) return 308;
610
+ return 0;
611
+ }
612
+
613
+ int savefinaloutput(Project *pr)
614
+ /*
615
+ **--------------------------------------------------------------
616
+ ** Input: none
617
+ ** Output: returns error code
618
+ ** Purpose: saves time series statistics, reaction rates &
619
+ ** epilog to output file.
620
+ **--------------------------------------------------------------
621
+ */
622
+ {
623
+ Network *net = &pr->network;
624
+ Outfile *out = &pr->outfile;
625
+ Report *rpt = &pr->report;
626
+ Quality *qual = &pr->quality;
627
+
628
+ int errcode = 0;
629
+ REAL4 *x;
630
+ FILE *outFile = out->OutFile;
631
+
632
+ // Save time series statistic if computed
633
+ if (rpt->Tstatflag != SERIES && out->TmpOutFile != NULL)
634
+ {
635
+ x = (REAL4 *)calloc(MAX(net->Nnodes, net->Nlinks) + 1, sizeof(REAL4));
636
+ if (x == NULL) return 101;
637
+ ERRCODE(savetimestat(pr, x, NODEHDR));
638
+ ERRCODE(savetimestat(pr, x, LINKHDR));
639
+ if (!errcode) rpt->Nperiods = 1;
640
+ fclose(out->TmpOutFile);
641
+ out->TmpOutFile = NULL;
642
+ free(x);
643
+ }
644
+
645
+ // Save avg. reaction rates & file epilog
646
+ if (outFile != NULL)
647
+ {
648
+ ERRCODE(savenetreacts(pr, qual->Wbulk, qual->Wwall, qual->Wtank,
649
+ qual->Wsource));
650
+ ERRCODE(saveepilog(pr));
651
+ }
652
+ return errcode;
653
+ }
654
+
655
+ int savetimestat(Project *pr, REAL4 *x, HdrType objtype)
656
+ /*
657
+ **--------------------------------------------------------------
658
+ ** Input: *x = buffer for node values
659
+ ** objtype = NODEHDR (for nodes) or LINKHDR (for links)
660
+ ** Output: returns error code
661
+ ** Purpose: computes time series statistic for nodes or links
662
+ ** and saves to normal output file.
663
+ **
664
+ ** NOTE: This routine is dependent on how the output reporting
665
+ ** variables were assigned to FieldType in TYPES.H.
666
+ **--------------------------------------------------------------
667
+ */
668
+ {
669
+ Network *net = &pr->network;
670
+ Hydraul *hyd = &pr->hydraul;
671
+ Quality *qual = &pr->quality;
672
+ Outfile *out = &pr->outfile;
673
+ Report *rpt = &pr->report;
674
+
675
+ int n, n1, n2;
676
+ int i, j, p, errcode = 0;
677
+ long startbyte, skipbytes;
678
+ float *stat1, *stat2, xx;
679
+ FILE *outFile = out->OutFile;
680
+
681
+ // Compute number of bytes in temp output file to skip over (skipbytes)
682
+ // when moving from one time period to the next for a particular variable
683
+ if (objtype == NODEHDR)
684
+ {
685
+ // For nodes, we start at 0 and skip over node output for all
686
+ // node variables minus 1 plus link output for all link variables.
687
+ startbyte = 0;
688
+ skipbytes = (net->Nnodes * (QUALITY - DEMAND) +
689
+ net->Nlinks * (FRICTION - FLOW + 1)) * sizeof(REAL4);
690
+ n = net->Nnodes;
691
+ n1 = DEMAND;
692
+ n2 = QUALITY;
693
+ }
694
+ else
695
+ {
696
+ // For links, we start at the end of all node variables and skip
697
+ // over node output for all node variables plus link output for
698
+ // all link variables minus 1
699
+ startbyte = net->Nnodes * (QUALITY - DEMAND + 1) * sizeof(REAL4);
700
+ skipbytes = (net->Nnodes * (QUALITY - DEMAND + 1) +
701
+ net->Nlinks * (FRICTION - FLOW)) * sizeof(REAL4);
702
+ n = net->Nlinks;
703
+ n1 = FLOW;
704
+ n2 = FRICTION;
705
+ }
706
+ stat1 = (float *)calloc(n + 1, sizeof(float));
707
+ stat2 = (float *)calloc(n + 1, sizeof(float));
708
+ ERRCODE(MEMCHECK(stat1));
709
+ ERRCODE(MEMCHECK(stat2));
710
+
711
+ // Process each output reporting variable
712
+ if (!errcode) for (j = n1; j <= n2; j++)
713
+ {
714
+ // Initialize stat arrays
715
+ if (rpt->Tstatflag == AVG) memset(stat1, 0, (n + 1) * sizeof(float));
716
+ else for (i = 1; i <= n; i++)
717
+ {
718
+ stat1[i] = -MISSING;
719
+ stat2[i] = MISSING;
720
+ }
721
+
722
+ // Position temp output file at start of output
723
+ fseek(out->TmpOutFile, startbyte + (j - n1) * n * sizeof(REAL4),
724
+ SEEK_SET);
725
+
726
+ // Process each time period
727
+ for (p = 1; p <= rpt->Nperiods; p++)
728
+ {
729
+ // Get output results for time period & update stats
730
+ f_read(x, n, out->TmpOutFile);
731
+ for (i = 1; i <= n; i++)
732
+ {
733
+ xx = x[i];
734
+ if (objtype == LINKHDR)
735
+ {
736
+ if (j == FLOW) xx = ABS(xx);
737
+ if (j == STATUS)
738
+ {
739
+ if (xx >= OPEN) xx = 1.0;
740
+ else xx = 0.0;
741
+ }
742
+ }
743
+ if (rpt->Tstatflag == AVG) stat1[i] += xx;
744
+ else
745
+ {
746
+ stat1[i] = MIN(stat1[i], xx);
747
+ stat2[i] = MAX(stat2[i], xx);
748
+ }
749
+ }
750
+
751
+ // Advance file to next period
752
+ if (p < rpt->Nperiods) fseek(out->TmpOutFile, skipbytes, SEEK_CUR);
753
+ }
754
+
755
+ // Compute resultant stat & save to regular output file
756
+ switch (rpt->Tstatflag)
757
+ {
758
+ case AVG:
759
+ for (i = 1; i <= n; i++) x[i] = stat1[i] / (float)rpt->Nperiods;
760
+ break;
761
+ case MIN:
762
+ for (i = 1; i <= n; i++) x[i] = stat1[i];
763
+ break;
764
+ case MAX:
765
+ for (i = 1; i <= n; i++) x[i] = stat2[i];
766
+ break;
767
+ case RANGE:
768
+ for (i = 1; i <= n; i++) x[i] = stat2[i] - stat1[i];
769
+ break;
770
+ }
771
+ if (objtype == LINKHDR && j == STATUS)
772
+ {
773
+ for (i = 1; i <= n; i++)
774
+ {
775
+ if (x[i] < 0.5f) x[i] = CLOSED;
776
+ else x[i] = OPEN;
777
+ }
778
+ }
779
+ if (f_save(x, n, outFile) < (unsigned)n) errcode = 308;
780
+
781
+ // Update internal output variables where applicable
782
+ if (objtype == NODEHDR) switch (j)
783
+ {
784
+ case DEMAND:
785
+ for (i = 1; i <= n; i++) hyd->NodeDemand[i] = x[i] / pr->Ucf[DEMAND];
786
+ break;
787
+ case HEAD:
788
+ for (i = 1; i <= n; i++) hyd->NodeHead[i] = x[i] / pr->Ucf[HEAD];
789
+ break;
790
+ case QUALITY:
791
+ for (i = 1; i <= n; i++) qual->NodeQual[i] = x[i] / pr->Ucf[QUALITY];
792
+ break;
793
+ }
794
+ else if (j == FLOW)
795
+ {
796
+ for (i = 1; i <= n; i++) hyd->LinkFlow[i] = x[i] / pr->Ucf[FLOW];
797
+ }
798
+ }
799
+
800
+ // Free allocated memory
801
+ free(stat1);
802
+ free(stat2);
803
+ return errcode;
804
+ }
805
+
806
+ int savenetreacts(Project *pr, double wbulk, double wwall, double wtank, double wsource)
807
+ /*
808
+ **-----------------------------------------------------
809
+ ** Writes average network-wide reaction rates (in
810
+ ** mass/hr) to binary output file.
811
+ **-----------------------------------------------------
812
+ */
813
+ {
814
+ Outfile *out = &pr->outfile;
815
+ Times *time = &pr->times;
816
+
817
+ int errcode = 0;
818
+ double t;
819
+ REAL4 w[4];
820
+ FILE *outFile = out->OutFile;
821
+
822
+ if (time->Dur > 0) t = (double)time->Dur / 3600.;
823
+ else t = 1.;
824
+ w[0] = (REAL4)(wbulk / t);
825
+ w[1] = (REAL4)(wwall / t);
826
+ w[2] = (REAL4)(wtank / t);
827
+ w[3] = (REAL4)(wsource / t);
828
+ if (fwrite(w, sizeof(REAL4), 4, outFile) < 4) errcode = 308;
829
+ return errcode;
830
+ }
831
+
832
+ int saveepilog(Project *pr)
833
+ /*
834
+ **-------------------------------------------------
835
+ ** Writes Nperiods, Warnflag, & Magic Number to
836
+ ** end of binary output file.
837
+ **-------------------------------------------------
838
+ */
839
+ {
840
+ Outfile *out = &pr->outfile;
841
+ Report *rpt = &pr->report;
842
+
843
+ int errcode = 0;
844
+ INT4 i;
845
+ FILE *outFile = out->OutFile;
846
+
847
+ i = rpt->Nperiods;
848
+ if (fwrite(&i, sizeof(INT4), 1, outFile) < 1) errcode = 308;
849
+ i = pr->Warnflag;
850
+ if (fwrite(&i, sizeof(INT4), 1, outFile) < 1) errcode = 308;
851
+ i = MAGICNUMBER; if (fwrite(&i, sizeof(INT4), 1, outFile) < 1) errcode = 308;
852
+ return errcode;
853
+ }