epanet-plus 0.0.1__cp313-cp313-macosx_10_13_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-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 +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 +6 -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/inpfile.c ADDED
@@ -0,0 +1,884 @@
1
+ /*
2
+ ******************************************************************************
3
+ Project: OWA EPANET
4
+ Version: 2.3
5
+ Module: inpfile.c
6
+ Description: saves network data to an EPANET formatted text file
7
+ Authors: see AUTHORS
8
+ Copyright: see AUTHORS
9
+ License: see LICENSE
10
+ Last Updated: 04/19/2025
11
+ ******************************************************************************
12
+ */
13
+
14
+ #include <stdlib.h>
15
+ #include <stdio.h>
16
+ #include <string.h>
17
+ #include <math.h>
18
+
19
+ #include "types.h"
20
+ #include "funcs.h"
21
+ #include "hash.h"
22
+ #include "text.h"
23
+
24
+ // Defined in enumstxt.h in EPANET.C
25
+ extern char *LinkTxt[];
26
+ extern char *FormTxt[];
27
+ extern char *StatTxt[];
28
+ extern char *FlowUnitsTxt[];
29
+ extern char *PressUnitsTxt[];
30
+ extern char *ControlTxt[];
31
+ extern char *SourceTxt[];
32
+ extern char *MixTxt[];
33
+ extern char *TstatTxt[];
34
+ extern char *RptFlagTxt[];
35
+ extern char *SectTxt[];
36
+ extern char *BackflowTxt[];
37
+ extern char *CurveTypeTxt[];
38
+
39
+ void saveauxdata(Project *pr, FILE *f)
40
+ /*
41
+ ------------------------------------------------------------
42
+ Writes auxiliary data from original input file to new file.
43
+ ------------------------------------------------------------
44
+ */
45
+ {
46
+ int sect, newsect;
47
+ char *tok;
48
+ char line[MAXLINE + 1];
49
+ char s[MAXLINE + 1];
50
+ FILE *InFile = pr->parser.InFile;
51
+
52
+ // Re-open the input file
53
+ if (InFile == NULL)
54
+ {
55
+ InFile = fopen(pr->parser.InpFname, "rt");
56
+ if (InFile == NULL) return;
57
+ }
58
+ rewind(InFile);
59
+ sect = -1;
60
+
61
+ // Read each line of the input file
62
+ while (fgets(line, MAXLINE, InFile) != NULL)
63
+ {
64
+ strcpy(s, line);
65
+ tok = strtok(s, SEPSTR);
66
+ if (tok == NULL) continue;
67
+
68
+ // Check if line begins with a new section heading
69
+ if (*tok == '[')
70
+ {
71
+ newsect = findmatch(tok, SectTxt);
72
+ if (newsect >= 0)
73
+ {
74
+ sect = newsect;
75
+ if (sect == _END) break;
76
+
77
+ // Write section heading to file
78
+ switch (sect)
79
+ {
80
+ case _LABELS:
81
+ case _BACKDROP:
82
+ fprintf(f, "\n%s", line);
83
+ }
84
+ }
85
+ }
86
+
87
+ // Write line of auxiliary data to file
88
+ else
89
+ {
90
+ switch (sect)
91
+ {
92
+ case _LABELS:
93
+ case _BACKDROP:
94
+ fprintf(f, "%s", line);
95
+ break;
96
+ default:
97
+ break;
98
+ }
99
+ }
100
+ }
101
+ fclose(InFile);
102
+ InFile = NULL;
103
+ }
104
+
105
+ int saveinpfile(Project *pr, const char *fname)
106
+ /*
107
+ -------------------------------------------------
108
+ Writes network data to text file.
109
+ -------------------------------------------------
110
+ */
111
+ {
112
+ Network *net = &pr->network;
113
+ Parser *parser = &pr->parser;
114
+ Report *rpt = &pr->report;
115
+ Outfile *out = &pr->outfile;
116
+ Hydraul *hyd = &pr->hydraul;
117
+ Quality *qual = &pr->quality;
118
+ Times *time = &pr->times;
119
+
120
+ int i, j, n;
121
+ double d, kc, ke, km, ucf;
122
+ char s[MAXLINE + 1], s1[MAXLINE + 1], s2[MAXLINE + 1];
123
+ Pdemand demand;
124
+ Psource source;
125
+ FILE *f;
126
+ Slink *link;
127
+ Stank *tank;
128
+ Snode *node;
129
+ Spump *pump;
130
+ Scontrol *control;
131
+ Scurve *curve;
132
+
133
+ // Open the new text file
134
+ if ((f = fopen(fname, "wt")) == NULL) return 302;
135
+
136
+ // Write [TITLE] section
137
+ fprintf(f, s_TITLE);
138
+ for (i = 0; i < 3; i++)
139
+ {
140
+ if (strlen(pr->Title[i]) > 0) fprintf(f, "\n%s", pr->Title[i]);
141
+ }
142
+
143
+ // Write [JUNCTIONS] section
144
+ // (Leave demands for [DEMANDS] section)
145
+ fprintf(f, "\n\n");
146
+ fprintf(f, s_JUNCTIONS);
147
+ fprintf(f, "\n;;%-31s\t%-12s\t%-12s\t%-31s",
148
+ "ID", "Elev", "Demand", "Pattern");
149
+ for (i = 1; i <= net->Njuncs; i++)
150
+ {
151
+ node = &net->Node[i];
152
+ fprintf(f, "\n %-31s\t%-12.4f", node->ID, node->El * pr->Ucf[ELEV]);
153
+ if (node->Comment) fprintf(f, "\t;%s", node->Comment);
154
+ }
155
+
156
+ // Write [RESERVOIRS] section
157
+ fprintf(f, "\n\n");
158
+ fprintf(f, s_RESERVOIRS);
159
+ fprintf(f, "\n;;%-31s\t%-12s\t%-31s",
160
+ "ID", "Head", "Pattern");
161
+ for (i = 1; i <= net->Ntanks; i++)
162
+ {
163
+ tank = &net->Tank[i];
164
+ if (tank->A == 0.0)
165
+ {
166
+ node = &net->Node[tank->Node];
167
+ sprintf(s, " %-31s\t%-12.4f", node->ID, node->El * pr->Ucf[ELEV]);
168
+ if ((j = tank->Pat) > 0) sprintf(s1, "%s", net->Pattern[j].ID);
169
+ else strcpy(s1, " ");
170
+ fprintf(f, "\n%s\t%-31s", s, s1);
171
+ if (node->Comment) fprintf(f, "\t;%s", node->Comment);
172
+ }
173
+ }
174
+
175
+ // Write [TANKS] section
176
+ fprintf(f, "\n\n");
177
+ fprintf(f, s_TANKS);
178
+ fprintf(f, "\n;;%-31s\t%-12s\t%-12s\t%-12s\t%-12s\t%-12s\t%-12s\t%-31s\t%-12s",
179
+ "ID", "Elevation", "InitLevel", "MinLevel", "MaxLevel", "Diameter", "MinVol", "VolCurve", "Overflow");
180
+ for (i = 1; i <= net->Ntanks; i++)
181
+ {
182
+ tank = &net->Tank[i];
183
+ if (tank->A > 0.0)
184
+ {
185
+ node = &net->Node[tank->Node];
186
+ sprintf(s, " %-31s\t%-12.4f\t%-12.4f\t%-12.4f\t%-12.4f\t%-12.4f\t%-12.4f",
187
+ node->ID, node->El * pr->Ucf[ELEV],
188
+ (tank->H0 - node->El) * pr->Ucf[ELEV],
189
+ (tank->Hmin - node->El) * pr->Ucf[ELEV],
190
+ (tank->Hmax - node->El) * pr->Ucf[ELEV],
191
+ sqrt(4.0 * tank->A / PI) * pr->Ucf[ELEV],
192
+ tank->Vmin * SQR(pr->Ucf[ELEV]) * pr->Ucf[ELEV]);
193
+ if ((j = tank->Vcurve) > 0) sprintf(s1, "%s", net->Curve[j].ID);
194
+ else if (tank->CanOverflow) strcpy(s1, "*");
195
+ else strcpy(s1, " ");
196
+ fprintf(f, "\n%s\t%-31s", s, s1);
197
+ if (tank->CanOverflow) fprintf(f, "\t%-12s", "YES");
198
+ if (node->Comment) fprintf(f, "\t;%s", node->Comment);
199
+ }
200
+ }
201
+
202
+ // Write [PIPES] section
203
+ fprintf(f, "\n\n");
204
+ fprintf(f, s_PIPES);
205
+ fprintf(f, "\n;;%-31s\t%-31s\t%-31s\t%-12s\t%-12s\t%-12s\t%-12s\t%-6s",
206
+ "ID", "Node1", "Node2", "Length", "Diameter", "Roughness", "MinorLoss", "Status");
207
+ for (i = 1; i <= net->Nlinks; i++)
208
+ {
209
+ link = &net->Link[i];
210
+ if (link->Type <= PIPE)
211
+ {
212
+ d = link->Diam;
213
+ kc = link->InitSetting;
214
+ if (hyd->Formflag == DW) kc = kc * pr->Ucf[ELEV] * 1000.0;
215
+ km = link->Km * SQR(d) * SQR(d) / 0.02517;
216
+
217
+ sprintf(s, " %-31s\t%-31s\t%-31s\t%-12.4f\t%-12.4f\t%-12.4f\t%-12.4f",
218
+ link->ID, net->Node[link->N1].ID, net->Node[link->N2].ID,
219
+ link->Len * pr->Ucf[LENGTH], d * pr->Ucf[DIAM], kc, km);
220
+
221
+ if (link->Type == CVPIPE) sprintf(s2, "CV");
222
+ else if (link->InitStatus == CLOSED) sprintf(s2, "CLOSED");
223
+ else strcpy(s2, " ");
224
+ fprintf(f, "\n%s\t%-6s", s, s2);
225
+ if (link->Comment) fprintf(f, "\t;%s", link->Comment);
226
+ }
227
+ }
228
+
229
+ // Write [PUMPS] section
230
+ fprintf(f, "\n\n");
231
+ fprintf(f, s_PUMPS);
232
+ fprintf(f, "\n;;%-31s\t%-31s\t%-31s\t%-12s",
233
+ "ID", "Node1", "Node2", "Parameters");
234
+ for (i = 1; i <= net->Npumps; i++)
235
+ {
236
+ n = net->Pump[i].Link;
237
+ link = &net->Link[n];
238
+ pump = &net->Pump[i];
239
+ sprintf(s, " %-31s\t%-31s\t%-31s", link->ID, net->Node[link->N1].ID,
240
+ net->Node[link->N2].ID);
241
+
242
+ // Pump has constant power
243
+ if (pump->Ptype == CONST_HP) sprintf(s1, "\tPOWER %.4f", link->Km);
244
+
245
+ // Pump has a head curve
246
+ else if ((j = pump->Hcurve) > 0)
247
+ {
248
+ sprintf(s1, "\tHEAD %s", net->Curve[j].ID);
249
+ }
250
+
251
+ // Old format used for pump curve
252
+ else
253
+ {
254
+ fprintf(f, "\n%s %12.4f %12.4f %12.4f 0.0 %12.4f", s,
255
+ -pump->H0 * pr->Ucf[HEAD],
256
+ (-pump->H0 - pump->R * pow(pump->Q0, pump->N)) * pr->Ucf[HEAD],
257
+ pump->Q0 * pr->Ucf[FLOW], pump->Qmax * pr->Ucf[FLOW]);
258
+ continue;
259
+ }
260
+ strcat(s, s1);
261
+
262
+ // Optional speed pattern
263
+ if ((j = pump->Upat) > 0)
264
+ {
265
+ sprintf(s1, "\tPATTERN %s", net->Pattern[j].ID);
266
+ strcat(s, s1);
267
+ }
268
+
269
+ // Optional speed setting
270
+ if (link->InitSetting != 1.0)
271
+ {
272
+ sprintf(s1, "\tSPEED %.4f", link->InitSetting);
273
+ strcat(s, s1);
274
+ }
275
+
276
+ fprintf(f, "\n%s", s);
277
+ if (link->Comment) fprintf(f, "\t;%s", link->Comment);
278
+ }
279
+
280
+ // Write [VALVES] section
281
+ fprintf(f, "\n\n");
282
+ fprintf(f, s_VALVES);
283
+ fprintf(f, "\n;;%-31s\t%-31s\t%-31s\t%-12s\t%-6s\t%-12s\t%-12s",
284
+ "ID", "Node1", "Node2", "Diameter", "Type", "Setting", "MinorLoss");
285
+ for (i = 1; i <= net->Nvalves; i++)
286
+ {
287
+ n = net->Valve[i].Link;
288
+ link = &net->Link[n];
289
+ d = link->Diam;
290
+
291
+ // Valve setting
292
+ kc = link->InitSetting;
293
+ switch (link->Type)
294
+ {
295
+ case FCV:
296
+ kc *= pr->Ucf[FLOW];
297
+ break;
298
+ case PRV:
299
+ case PSV:
300
+ case PBV:
301
+ kc *= pr->Ucf[PRESSURE];
302
+ break;
303
+ default:
304
+ break;
305
+ }
306
+ km = link->Km * SQR(d) * SQR(d) / 0.02517;
307
+
308
+ sprintf(s, " %-31s\t%-31s\t%-31s\t%-12.4f\t%-6s",
309
+ link->ID, net->Node[link->N1].ID,
310
+ net->Node[link->N2].ID, d * pr->Ucf[DIAM],
311
+ LinkTxt[link->Type]);
312
+
313
+ // For GPV, setting = head curve index
314
+ if (link->Type == GPV && (j = ROUND(kc)) > 0)
315
+ {
316
+ sprintf(s1, "%-31s\t%-12.4f", net->Curve[j].ID, km);
317
+ }
318
+ // For PCV add loss curve if present
319
+ else if (link->Type == PCV && (j = net->Valve[i].Curve) > 0)
320
+ {
321
+ sprintf(s1, "%-12.4f\t%-12.4f\t%-31s", kc, km, net->Curve[j].ID);
322
+ }
323
+ else sprintf(s1, "%-12.4f\t%-12.4f", kc, km);
324
+ fprintf(f, "\n%s\t%s", s, s1);
325
+ if (link->Comment) fprintf(f, "\t;%s", link->Comment);
326
+ }
327
+
328
+
329
+ // Write [DEMANDS] section
330
+ fprintf(f, "\n\n");
331
+ fprintf(f, s_DEMANDS);
332
+ fprintf(f, "\n;;%-31s\t%-14s\t%-31s\t%-31s",
333
+ "Junction", "Demand", "Pattern", "Category");
334
+ ucf = pr->Ucf[DEMAND];
335
+ for (i = 1; i <= net->Njuncs; i++)
336
+ {
337
+ node = &net->Node[i];
338
+ for (demand = node->D; demand != NULL; demand = demand->next)
339
+ {
340
+ if (demand->Base == 0.0) continue;
341
+ sprintf(s, " %-31s\t%-14.6f", node->ID, ucf * demand->Base);
342
+ if ((j = demand->Pat) > 0) sprintf(s1, "%-31s", net->Pattern[j].ID);
343
+ else strcpy(s1, " ");
344
+ fprintf(f, "\n%s\t%-31s", s, s1);
345
+ if (demand->Name) fprintf(f, "\t;%s", demand->Name);
346
+ }
347
+ }
348
+
349
+
350
+ // Write [EMITTERS] section
351
+ fprintf(f, "\n\n");
352
+ fprintf(f, s_EMITTERS);
353
+ fprintf(f, "\n;;%-31s\t%-14s",
354
+ "Junction", "Coefficient");
355
+ for (i = 1; i <= net->Njuncs; i++)
356
+ {
357
+ node = &net->Node[i];
358
+ if (node->Ke == 0.0) continue;
359
+ ke = pr->Ucf[FLOW] / pow(pr->Ucf[PRESSURE] * node->Ke, (1.0 / hyd->Qexp));
360
+ fprintf(f, "\n %-31s\t%-14.6f", node->ID, ke);
361
+ }
362
+
363
+ // Write [LEAKAGE] section
364
+ fprintf(f, "\n\n");
365
+ fprintf(f, s_LEAKAGE);
366
+ fprintf(f, "\n;;%-31s\t%-14s\t%-14s",
367
+ "Pipe", "Leak Area", "Leak Expansion");
368
+ for (i = 1; i <= net->Nlinks; i++)
369
+ {
370
+ link = &net->Link[i];
371
+ if (link->LeakArea == 0.0 && link->LeakExpan == 0.0) continue;
372
+ fprintf(f, "\n %-31s %14.6f %14.6f", link->ID,
373
+ link->LeakArea * pr->Ucf[LENGTH], link->LeakExpan * pr->Ucf[LENGTH]);
374
+ }
375
+
376
+ // Write [STATUS] section
377
+ fprintf(f, "\n\n");
378
+ fprintf(f, s_STATUS);
379
+ fprintf(f, "\n;;%-31s\t%-12s",
380
+ "ID", "Status/Setting");
381
+ for (i = 1; i <= net->Nlinks; i++)
382
+ {
383
+ link = &net->Link[i];
384
+ if (link->Type <= PUMP)
385
+ {
386
+ if (link->InitStatus == CLOSED)
387
+ {
388
+ fprintf(f, "\n %-31s\t%s", link->ID, StatTxt[CLOSED]);
389
+ }
390
+
391
+ // Write pump speed here for pumps with old-style pump curve input
392
+ else if (link->Type == PUMP)
393
+ {
394
+ n = findpump(net, i);
395
+ pump = &net->Pump[n];
396
+ if (pump->Hcurve == 0 && pump->Ptype != CONST_HP &&
397
+ link->InitSetting != 1.0)
398
+ {
399
+ fprintf(f, "\n %-31s\t%-.4f", link->ID, link->InitSetting);
400
+ }
401
+ }
402
+ }
403
+
404
+ // Write fixed-status valves
405
+ else
406
+ {
407
+ if (link->InitStatus == OPEN)
408
+ {
409
+ fprintf(f, "\n %-31s\t%s", link->ID, StatTxt[OPEN]);
410
+ }
411
+ if (link->InitStatus == CLOSED)
412
+ {
413
+ fprintf(f, "\n%-31s\t%s", link->ID, StatTxt[CLOSED]);
414
+ }
415
+ }
416
+ }
417
+
418
+ // Write [PATTERNS] section
419
+ // (Use 6 pattern factors per line)
420
+ fprintf(f, "\n\n");
421
+ fprintf(f, s_PATTERNS);
422
+ fprintf(f, "\n;;%-31s\t%-12s",
423
+ "ID", "Multipliers");
424
+ for (i = 1; i <= net->Npats; i++)
425
+ {
426
+ if (net->Pattern[i].Comment) fprintf(f, "\n;%s", net->Pattern[i].Comment);
427
+ for (j = 0; j < net->Pattern[i].Length; j++)
428
+ {
429
+ if (j % 6 == 0) fprintf(f, "\n %-31s", net->Pattern[i].ID);
430
+ fprintf(f, "\t%-12.4f", net->Pattern[i].F[j]);
431
+ }
432
+ }
433
+
434
+ // Write [CURVES] section
435
+ fprintf(f, "\n\n");
436
+ fprintf(f, s_CURVES);
437
+ fprintf(f, "\n;;%-31s\t%-12s\t%-12s", "ID", "X-Value", "Y-Value");
438
+ for (i = 1; i <= net->Ncurves; i++)
439
+ {
440
+ curve = &net->Curve[i];
441
+ if (curve->Comment) fprintf(f, "\n;%s", curve->Comment);
442
+ if (curve->Npts > 0)
443
+ {
444
+ fprintf(f, "\n %-31s\t%-12.4f\t%-12.4f\t%s", curve->ID,
445
+ curve->X[0], curve->Y[0], CurveTypeTxt[curve->Type]);
446
+ for (j = 1; j < curve->Npts; j++)
447
+ {
448
+ fprintf(f, "\n %-31s\t%-12.4f\t%-12.4f", curve->ID,
449
+ curve->X[j], curve->Y[j]);
450
+ }
451
+ }
452
+ }
453
+
454
+ // Write [CONTROLS] section
455
+ fprintf(f, "\n\n");
456
+ fprintf(f, s_CONTROLS);
457
+ for (i = 1; i <= net->Ncontrols; i++)
458
+ {
459
+ // Check that controlled link exists
460
+ control = &net->Control[i];
461
+ if ((j = control->Link) <= 0) continue;
462
+ link = &net->Link[j];
463
+
464
+ // Get text of control's link status/setting
465
+ if (control->Setting == MISSING || link->Type == GPV || link->Type == PIPE)
466
+ {
467
+ sprintf(s, " LINK %s %s ", link->ID, StatTxt[control->Status]);
468
+ }
469
+ else if (link->Type == PUMP &&
470
+ (control->Setting == 0.0 || control->Setting == 1.0))
471
+ {
472
+ sprintf(s, " LINK %s %s ", link->ID, StatTxt[control->Status]);
473
+ }
474
+ else
475
+ {
476
+ kc = control->Setting;
477
+ switch (link->Type)
478
+ {
479
+ case PRV:
480
+ case PSV:
481
+ case PBV:
482
+ kc *= pr->Ucf[PRESSURE];
483
+ break;
484
+ case FCV:
485
+ kc *= pr->Ucf[FLOW];
486
+ break;
487
+ default:
488
+ break;
489
+ }
490
+ sprintf(s, " LINK %s %.4f", link->ID, kc);
491
+ }
492
+
493
+ switch (control->Type)
494
+ {
495
+ // Print level control
496
+ case LOWLEVEL:
497
+ case HILEVEL:
498
+ n = control->Node;
499
+ node = &net->Node[n];
500
+ kc = control->Grade - node->El;
501
+ if (n > net->Njuncs) kc *= pr->Ucf[HEAD];
502
+ else kc *= pr->Ucf[PRESSURE];
503
+ fprintf(f, "\n%s IF NODE %s %s %.4f", s, node->ID,
504
+ ControlTxt[control->Type], kc);
505
+ break;
506
+
507
+ // Print timer control
508
+ case TIMER:
509
+ fprintf(f, "\n%s AT %s %.4f HOURS", s, ControlTxt[TIMER],
510
+ control->Time / 3600.);
511
+ break;
512
+
513
+ // Print time-of-day control
514
+ case TIMEOFDAY:
515
+ fprintf(f, "\n%s AT %s %s", s, ControlTxt[TIMEOFDAY],
516
+ clocktime(rpt->Atime, control->Time));
517
+ break;
518
+
519
+ default: continue;
520
+ }
521
+ if (control->isEnabled == FALSE) fprintf(f, " DISABLED");
522
+ }
523
+
524
+ // Write [RULES] section
525
+ fprintf(f, "\n\n");
526
+ fprintf(f, s_RULES);
527
+ for (i = 1; i <= net->Nrules; i++)
528
+ {
529
+ fprintf(f, "\nRULE %s", pr->network.Rule[i].label);
530
+ writerule(pr, f, i); // see RULES.C
531
+ if (pr->network.Rule[i].isEnabled == FALSE) fprintf(f, "\nDISABLED");
532
+ fprintf(f, "\n");
533
+ }
534
+
535
+ // Write [QUALITY] section
536
+ // (Skip nodes with default quality of 0)
537
+ fprintf(f, "\n\n");
538
+ fprintf(f, s_QUALITY);
539
+ fprintf(f, "\n;;%-31s\t%-14s", "ID", "InitQual");
540
+ for (i = 1; i <= net->Nnodes; i++)
541
+ {
542
+ node = &net->Node[i];
543
+ if (node->C0 == 0.0) continue;
544
+ fprintf(f, "\n %-31s\t%-14.6f", node->ID, node->C0 * pr->Ucf[QUALITY]);
545
+ }
546
+
547
+ // Write [SOURCES] section
548
+ fprintf(f, "\n\n");
549
+ fprintf(f, s_SOURCES);
550
+ fprintf(f, "\n;;%-31s\t%-9s\t%-14s\t%-31s", "ID", "Type", "Quality", "Pattern");
551
+ for (i = 1; i <= net->Nnodes; i++)
552
+ {
553
+ node = &net->Node[i];
554
+ source = node->S;
555
+ if (source == NULL) continue;
556
+ sprintf(s, " %-31s\t%-9s\t%-14.6f", node->ID, SourceTxt[source->Type],
557
+ source->C0);
558
+ if ((j = source->Pat) > 0)
559
+ {
560
+ sprintf(s1, "%s", net->Pattern[j].ID);
561
+ }
562
+ else strcpy(s1, "");
563
+ fprintf(f, "\n%s\t%s", s, s1);
564
+ }
565
+
566
+ // Write [MIXING] section
567
+ fprintf(f, "\n\n");
568
+ fprintf(f, s_MIXING);
569
+ fprintf(f, "\n;;%-31s\t%-8s", "ID", "Model");
570
+ for (i = 1; i <= net->Ntanks; i++)
571
+ {
572
+ tank = &net->Tank[i];
573
+ if (tank->A == 0.0) continue;
574
+ fprintf(f, "\n %-31s\t%-8s\t%12.4f", net->Node[tank->Node].ID,
575
+ MixTxt[tank->MixModel], tank->V1frac);
576
+ }
577
+
578
+ // Write [REACTIONS] section
579
+ fprintf(f, "\n\n");
580
+ fprintf(f, s_REACTIONS);
581
+
582
+ // General parameters
583
+ fprintf(f, "\n ORDER BULK %-.2f", qual->BulkOrder);
584
+ fprintf(f, "\n ORDER WALL %-.0f", qual->WallOrder);
585
+ fprintf(f, "\n ORDER TANK %-.2f", qual->TankOrder);
586
+ fprintf(f, "\n GLOBAL BULK %-.6f", qual->Kbulk * SECperDAY);
587
+ fprintf(f, "\n GLOBAL WALL %-.6f", qual->Kwall * SECperDAY);
588
+
589
+ if (qual->Climit > 0.0)
590
+ {
591
+ fprintf(f, "\n LIMITING POTENTIAL %-.6f", qual->Climit * pr->Ucf[QUALITY]);
592
+ }
593
+ if (qual->Rfactor != MISSING && qual->Rfactor != 0.0)
594
+ {
595
+ fprintf(f, "\n ROUGHNESS CORRELATION %-.6f", qual->Rfactor);
596
+ }
597
+
598
+ fprintf(f, "\n\n");
599
+ fprintf(f, s_REACTIONS);
600
+ fprintf(f, "\n;%-9s\t%-31s\t%-12s", "Type", "Pipe/Tank", "Coefficient");
601
+
602
+ // Pipe-specific parameters
603
+ for (i = 1; i <= net->Nlinks; i++)
604
+ {
605
+ link = &net->Link[i];
606
+ if (link->Type > PIPE) continue;
607
+ if (link->Kb != qual->Kbulk)
608
+ {
609
+ fprintf(f, "\n %-9s\t%-31s\t%-.6f", "BULK", link->ID, link->Kb * SECperDAY);
610
+ }
611
+ if (link->Kw != qual->Kwall)
612
+ {
613
+ fprintf(f, "\n %-9s\t%-31s\t%-.6f", "WALL", link->ID, link->Kw * SECperDAY);
614
+ }
615
+ }
616
+
617
+ // Tank parameters
618
+ for (i = 1; i <= net->Ntanks; i++)
619
+ {
620
+ tank = &net->Tank[i];
621
+ if (tank->A == 0.0) continue;
622
+ if (tank->Kb != qual->Kbulk)
623
+ {
624
+ fprintf(f, "\n %-9s\t%-31s\t%-.6f", "TANK", net->Node[tank->Node].ID,
625
+ tank->Kb * SECperDAY);
626
+ }
627
+ }
628
+
629
+ // Write [ENERGY] section
630
+ fprintf(f, "\n\n");
631
+ fprintf(f, s_ENERGY);
632
+
633
+ // General parameters
634
+ if (hyd->Ecost != 0.0)
635
+ {
636
+ fprintf(f, "\n GLOBAL PRICE %-.4f", hyd->Ecost);
637
+ }
638
+ if (hyd->Epat != 0)
639
+ {
640
+ fprintf(f, "\n GLOBAL PATTERN %s", net->Pattern[hyd->Epat].ID);
641
+ }
642
+ fprintf(f, "\n GLOBAL EFFIC %-.4f", hyd->Epump);
643
+ fprintf(f, "\n DEMAND CHARGE %-.4f", hyd->Dcost);
644
+
645
+ // Pump-specific parameters
646
+ for (i = 1; i <= net->Npumps; i++)
647
+ {
648
+ pump = &net->Pump[i];
649
+ if (pump->Ecost > 0.0)
650
+ {
651
+ fprintf(f, "\n PUMP %-31s PRICE %-.4f", net->Link[pump->Link].ID,
652
+ pump->Ecost);
653
+ }
654
+ if (pump->Epat > 0.0)
655
+ {
656
+ fprintf(f, "\n PUMP %-31s PATTERN %s", net->Link[pump->Link].ID,
657
+ net->Pattern[pump->Epat].ID);
658
+ }
659
+ if (pump->Ecurve > 0.0)
660
+ {
661
+ fprintf(f, "\n PUMP %-31s EFFIC %s", net->Link[pump->Link].ID,
662
+ net->Curve[pump->Ecurve].ID);
663
+ }
664
+ }
665
+
666
+ // Write [TIMES] section
667
+ fprintf(f, "\n\n");
668
+ fprintf(f, s_TIMES);
669
+ fprintf(f, "\n DURATION %s", clocktime(rpt->Atime, time->Dur));
670
+ fprintf(f, "\n HYDRAULIC TIMESTEP %s", clocktime(rpt->Atime, time->Hstep));
671
+ fprintf(f, "\n QUALITY TIMESTEP %s", clocktime(rpt->Atime, time->Qstep));
672
+ fprintf(f, "\n REPORT TIMESTEP %s", clocktime(rpt->Atime, time->Rstep));
673
+ fprintf(f, "\n REPORT START %s", clocktime(rpt->Atime, time->Rstart));
674
+ fprintf(f, "\n PATTERN TIMESTEP %s", clocktime(rpt->Atime, time->Pstep));
675
+ fprintf(f, "\n PATTERN START %s", clocktime(rpt->Atime, time->Pstart));
676
+ fprintf(f, "\n RULE TIMESTEP %s", clocktime(rpt->Atime, time->Rulestep));
677
+ fprintf(f, "\n START CLOCKTIME %s", clocktime(rpt->Atime, time->Tstart));
678
+ fprintf(f, "\n STATISTIC %s", TstatTxt[rpt->Tstatflag]);
679
+
680
+ // Write [OPTIONS] section
681
+ fprintf(f, "\n\n");
682
+ fprintf(f, s_OPTIONS);
683
+ fprintf(f, "\n UNITS %s", FlowUnitsTxt[parser->Flowflag]);
684
+ fprintf(f, "\n PRESSURE %s", PressUnitsTxt[parser->Pressflag]);
685
+ fprintf(f, "\n HEADLOSS %s", FormTxt[hyd->Formflag]);
686
+ switch (out->Hydflag)
687
+ {
688
+ case USE:
689
+ fprintf(f, "\n HYDRAULICS USE %s", out->HydFname);
690
+ break;
691
+ case SAVE:
692
+ fprintf(f, "\n HYDRAULICS SAVE %s", out->HydFname);
693
+ break;
694
+ }
695
+ if (hyd->ExtraIter == -1)
696
+ {
697
+ fprintf(f, "\n UNBALANCED STOP");
698
+ }
699
+ if (hyd->ExtraIter >= 0)
700
+ {
701
+ fprintf(f, "\n UNBALANCED CONTINUE %d", hyd->ExtraIter);
702
+ }
703
+
704
+ switch (qual->Qualflag)
705
+ {
706
+ case CHEM:
707
+ fprintf(f, "\n QUALITY %s %s",
708
+ qual->ChemName, qual->ChemUnits);
709
+ break;
710
+ case TRACE:
711
+ fprintf(f, "\n QUALITY TRACE %-31s",
712
+ net->Node[qual->TraceNode].ID);
713
+ break;
714
+ case AGE:
715
+ fprintf(f, "\n QUALITY AGE");
716
+ break;
717
+ case NONE:
718
+ fprintf(f, "\n QUALITY NONE");
719
+ break;
720
+ }
721
+
722
+ if (hyd->DefPat > 0)
723
+ fprintf(f, "\n PATTERN %s", net->Pattern[hyd->DefPat].ID);
724
+ fprintf(f, "\n DEMAND MULTIPLIER %-.4f", hyd->Dmult);
725
+ fprintf(f, "\n EMITTER EXPONENT %-.4f", 1.0 / hyd->Qexp);
726
+ fprintf(f, "\n BACKFLOW ALLOWED %s", BackflowTxt[hyd->EmitBackFlag]);
727
+ fprintf(f, "\n VISCOSITY %-.6f", hyd->Viscos / VISCOS);
728
+ fprintf(f, "\n DIFFUSIVITY %-.6f", qual->Diffus / DIFFUS);
729
+ fprintf(f, "\n SPECIFIC GRAVITY %-.6f", hyd->SpGrav);
730
+ fprintf(f, "\n TRIALS %-d", hyd->MaxIter);
731
+ fprintf(f, "\n ACCURACY %-.8f", hyd->Hacc);
732
+ fprintf(f, "\n TOLERANCE %-.8f", qual->Ctol * pr->Ucf[QUALITY]);
733
+ fprintf(f, "\n CHECKFREQ %-d", hyd->CheckFreq);
734
+ fprintf(f, "\n MAXCHECK %-d", hyd->MaxCheck);
735
+ fprintf(f, "\n DAMPLIMIT %-.8f", hyd->DampLimit);
736
+ if (hyd->HeadErrorLimit > 0.0)
737
+ {
738
+ fprintf(f, "\n HEADERROR %-.8f",
739
+ hyd->HeadErrorLimit * pr->Ucf[HEAD]);
740
+ }
741
+ if (hyd->FlowChangeLimit > 0.0)
742
+ {
743
+ fprintf(f, "\n FLOWCHANGE %-.8f",
744
+ hyd->FlowChangeLimit * pr->Ucf[FLOW]);
745
+ }
746
+ if (hyd->DemandModel == PDA)
747
+ {
748
+ fprintf(f, "\n DEMAND MODEL PDA");
749
+ fprintf(f, "\n MINIMUM PRESSURE %-.4f", hyd->Pmin * pr->Ucf[PRESSURE]);
750
+ fprintf(f, "\n REQUIRED PRESSURE %-.4f", hyd->Preq * pr->Ucf[PRESSURE]);
751
+ fprintf(f, "\n PRESSURE EXPONENT %-.4f", hyd->Pexp);
752
+ }
753
+
754
+ // Write [REPORT] section
755
+ fprintf(f, "\n\n");
756
+ fprintf(f, s_REPORT);
757
+
758
+ // General options
759
+ fprintf(f, "\n PAGESIZE %d", rpt->PageSize);
760
+ fprintf(f, "\n STATUS %s", RptFlagTxt[rpt->Statflag]);
761
+ fprintf(f, "\n SUMMARY %s", RptFlagTxt[rpt->Summaryflag]);
762
+ fprintf(f, "\n ENERGY %s", RptFlagTxt[rpt->Energyflag]);
763
+ fprintf(f, "\n MESSAGES %s", RptFlagTxt[rpt->Messageflag]);
764
+ if (strlen(rpt->Rpt2Fname) > 0)
765
+ {
766
+ fprintf(f, "\n FILE %s", rpt->Rpt2Fname);
767
+ }
768
+
769
+ // Node reporting
770
+ switch (rpt->Nodeflag)
771
+ {
772
+ case 0:
773
+ fprintf(f, "\n NODES NONE");
774
+ break;
775
+ case 1:
776
+ fprintf(f, "\n NODES ALL");
777
+ break;
778
+ default:
779
+ j = 0;
780
+ for (i = 1; i <= net->Nnodes; i++)
781
+ {
782
+ node = &net->Node[i];
783
+ if (node->Rpt == 1)
784
+ {
785
+ if (j % 5 == 0) fprintf(f, "\n NODES ");
786
+ fprintf(f, "%s ", node->ID);
787
+ j++;
788
+ }
789
+ }
790
+ }
791
+
792
+ // Link reporting
793
+ switch (rpt->Linkflag)
794
+ {
795
+ case 0:
796
+ fprintf(f, "\n LINKS NONE");
797
+ break;
798
+ case 1:
799
+ fprintf(f, "\n LINKS ALL");
800
+ break;
801
+ default:
802
+ j = 0;
803
+ for (i = 1; i <= net->Nlinks; i++)
804
+ {
805
+ link = &net->Link[i];
806
+ if (link->Rpt == 1)
807
+ {
808
+ if (j % 5 == 0) fprintf(f, "\n LINKS ");
809
+ fprintf(f, "%s ", link->ID);
810
+ j++;
811
+ }
812
+ }
813
+ }
814
+
815
+ // Field formatting options
816
+ for (i = 0; i < FRICTION; i++)
817
+ {
818
+ SField *field = &rpt->Field[i];
819
+ if (field->Enabled == TRUE)
820
+ {
821
+ fprintf(f, "\n %-20sPRECISION %d", field->Name, field->Precision);
822
+ if (field->RptLim[LOW] < BIG)
823
+ {
824
+ fprintf(f, "\n %-20sBELOW %.6f", field->Name, field->RptLim[LOW]);
825
+ }
826
+ if (field->RptLim[HI] > -BIG)
827
+ {
828
+ fprintf(f, "\n %-20sABOVE %.6f", field->Name, field->RptLim[HI]);
829
+ }
830
+ }
831
+ else fprintf(f, "\n %-20sNO",field->Name);
832
+ }
833
+
834
+ // Write [TAGS] section
835
+ fprintf(f, "\n\n");
836
+ fprintf(f, s_TAGS);
837
+ fprintf(f, "\n;;%-8s\t%-31s\t%s", "Object", "ID", "Tag");
838
+ for (i = 1; i <= net->Nnodes; i++)
839
+ {
840
+ node = &net->Node[i];
841
+ if (node->Tag == NULL || strlen(node->Tag) == 0) continue;
842
+ fprintf(f, "\n %-8s\t%-31s\t%s", "NODE", node->ID, node->Tag);
843
+ }
844
+ for (i = 1; i <= net->Nlinks; i++)
845
+ {
846
+ link = &net->Link[i];
847
+ if (link->Tag == NULL || strlen(link->Tag) == 0) continue;
848
+ fprintf(f, "\n %-8s\t%-31s\t%s", "LINK", link->ID, link->Tag);
849
+ }
850
+ // Write [COORDINATES] section
851
+ fprintf(f, "\n\n");
852
+ fprintf(f, s_COORDS);
853
+ fprintf(f, "\n;;%-31s\t%-14s\t%-14s", "ID", "X-Coord", "Y-Coord");
854
+ for (i = 1; i <= net->Nnodes; i++)
855
+ {
856
+ node = &net->Node[i];
857
+ if (node->X == MISSING || node->Y == MISSING) continue;
858
+ fprintf(f, "\n %-31s\t%-14.6f\t%-14.6f", node->ID, node->X, node->Y);
859
+ }
860
+
861
+ // Write [VERTICES] section
862
+ fprintf(f, "\n\n");
863
+ fprintf(f, s_VERTICES);
864
+ fprintf(f, "\n;;%-31s\t%-14s\t%-14s", "ID", "X-Coord", "Y-Coord");
865
+ for (i = 1; i <= net->Nlinks; i++)
866
+ {
867
+ link = &net->Link[i];
868
+ if (link->Vertices != NULL)
869
+ {
870
+ for (j = 0; j < link->Vertices->Npts; j++)
871
+ fprintf(f, "\n %-31s\t%-14.6f\t%-14.6f",
872
+ link->ID, link->Vertices->X[j], link->Vertices->Y[j]);
873
+ }
874
+ }
875
+
876
+ // Save auxiliary data to new input file
877
+ fprintf(f, "\n");
878
+ saveauxdata(pr, f);
879
+
880
+ // Close the new input file
881
+ fprintf(f, "\n%s\n", s_END);
882
+ fclose(f);
883
+ return 0;
884
+ }