epanet-plus 0.0.1__cp313-cp313-win_amd64.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.cp313-win_amd64.pyd +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/input1.c ADDED
@@ -0,0 +1,672 @@
1
+ /*
2
+ ******************************************************************************
3
+ Project: OWA EPANET
4
+ Version: 2.3
5
+ Module: input1.c
6
+ Description: retrieves network data from an EPANET input 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
+ // Default values
25
+ #define MAXITER 200 // Default max. # hydraulic iterations
26
+ #define HACC 0.001 // Default hydraulics convergence ratio
27
+ #define HTOL 0.0005 // Default hydraulic head tolerance (ft)
28
+ #define QTOL 0.0001 // Default flow rate tolerance (cfs)
29
+ #define AGETOL 0.01 // Default water age tolerance (hrs)
30
+ #define CHEMTOL 0.01 // Default concentration tolerance
31
+ #define PAGESIZE 0 // Default uses no page breaks
32
+ #define SPGRAV 1.0 // Default specific gravity
33
+ #define EPUMP 75 // Default pump efficiency
34
+ #define DEFPATID "1" // Default demand pattern ID
35
+ #define RQTOL 1E-7 // Default low flow resistance tolerance
36
+ #define CHECKFREQ 2 // Default status check frequency
37
+ #define MAXCHECK 10 // Default # iterations for status checks
38
+ #define DAMPLIMIT 0 // Default damping threshold
39
+
40
+ // Defined in ENUMSTXT.H
41
+ extern char *Fldname[];
42
+ extern char *RptFlowUnitsTxt[];
43
+ extern char *PressUnitsTxt[];
44
+ extern void reindextanks(Project *pr);
45
+
46
+
47
+ int getdata(Project *pr)
48
+ /*
49
+ **----------------------------------------------------------------
50
+ ** Input: none
51
+ ** Output: returns error code
52
+ ** Purpose: reads in network data from disk file
53
+ **----------------------------------------------------------------
54
+ */
55
+ {
56
+ int errcode = 0;
57
+
58
+ // Assign default data values & reporting options
59
+ setdefaults(pr);
60
+ initreport(&pr->report);
61
+
62
+ // Read in network data
63
+ rewind(pr->parser.InFile);
64
+ errcode = readdata(pr);
65
+
66
+ // Adjust data and convert it to internal units
67
+ // (error code 200 means there are non-fatal errors in input file)
68
+ if (errcode == 0 || errcode == 200)
69
+ {
70
+ reindextanks(pr);
71
+ adjustdata(pr);
72
+ inittanks(pr);
73
+ initunits(pr);
74
+ convertunits(pr);
75
+ }
76
+ return errcode;
77
+ }
78
+
79
+ void setdefaults(Project *pr)
80
+ /*
81
+ **----------------------------------------------------------------
82
+ ** Input: none
83
+ ** Output: none
84
+ ** Purpose: assigns default values to a project's variables
85
+ **----------------------------------------------------------------
86
+ */
87
+ {
88
+ Parser *parser = &pr->parser;
89
+ Report *rpt = &pr->report;
90
+ Hydraul *hyd = &pr->hydraul;
91
+ Quality *qual = &pr->quality;
92
+ Times *time = &pr->times;
93
+ Outfile *out = &pr->outfile;
94
+
95
+ strncpy(pr->Title[0], "", TITLELEN);
96
+ strncpy(pr->Title[1], "", TITLELEN);
97
+ strncpy(pr->Title[2], "", TITLELEN);
98
+ strncpy(out->HydFname, "", MAXFNAME);
99
+ strncpy(pr->MapFname, "", MAXFNAME);
100
+ strncpy(qual->ChemName, t_CHEMICAL, MAXID);
101
+ strncpy(qual->ChemUnits, u_MGperL, MAXID);
102
+ strncpy(parser->DefPatID, DEFPATID, MAXID);
103
+
104
+ pr->Warnflag = FALSE; // Warning flag is off
105
+ parser->Unitsflag = US; // US unit system
106
+ parser->Flowflag = GPM; // Flow units are gpm
107
+ parser->Pressflag = DEFAULTUNIT; // Pressure units set based on unit system
108
+ out->Hydflag = SCRATCH; // No external hydraulics file
109
+ rpt->Tstatflag = SERIES; // Generate time series output
110
+
111
+ hyd->Formflag = HW; // Use Hazen-Williams formula
112
+ hyd->Htol = HTOL; // Default head tolerance
113
+ hyd->Qtol = QTOL; // Default flow tolerance
114
+ hyd->Hacc = HACC; // Default hydraulic accuracy
115
+ hyd->FlowChangeLimit = 0.0; // Default flow change limit
116
+ hyd->HeadErrorLimit = 0.0; // Default head error limit
117
+ hyd->DemandModel = DDA; // Demand driven analysis
118
+ hyd->Pmin = 0.0; // Minimum demand pressure (ft)
119
+ hyd->Preq = MINPDIFF; // Required demand pressure (ft)
120
+ hyd->Pexp = 0.5; // Pressure function exponent
121
+ hyd->MaxIter = MAXITER; // Default max. hydraulic trials
122
+ hyd->ExtraIter = -1; // Stop if network unbalanced
123
+ hyd->Viscos = MISSING; // Temporary viscosity
124
+ hyd->SpGrav = SPGRAV; // Default specific gravity
125
+ hyd->Epat = 0; // No energy price pattern
126
+ hyd->Ecost = 0.0; // Zero unit energy cost
127
+ hyd->Dcost = 0.0; // Zero energy demand charge
128
+ hyd->Epump = EPUMP; // Default pump efficiency
129
+ hyd->Emax = 0.0; // Zero peak energy usage
130
+ hyd->Qexp = 2.0; // Flow exponent for emitters
131
+ hyd->EmitBackFlag = 1; // Allow emitter backflow
132
+ hyd->DefPat = 0; // Default demand pattern index
133
+ hyd->Dmult = 1.0; // Demand multiplier
134
+ hyd->RQtol = RQTOL; // Default hydraulics parameters
135
+ hyd->CheckFreq = CHECKFREQ;
136
+ hyd->MaxCheck = MAXCHECK;
137
+ hyd->DampLimit = DAMPLIMIT;
138
+
139
+ qual->Qualflag = NONE; // No quality simulation
140
+ qual->Ctol = MISSING; // No pre-set quality tolerance
141
+ qual->TraceNode = 0; // No source tracing
142
+ qual->BulkOrder = 1.0; // 1st-order bulk reaction rate
143
+ qual->WallOrder = 1.0; // 1st-order wall reaction rate
144
+ qual->TankOrder = 1.0; // 1st-order tank reaction rate
145
+ qual->Kbulk = 0.0; // No global bulk reaction
146
+ qual->Kwall = 0.0; // No global wall reaction
147
+ qual->Climit = 0.0; // No limiting potential quality
148
+ qual->Diffus = MISSING; // Temporary diffusivity
149
+ qual->Rfactor = 0.0; // No roughness-reaction factor
150
+ qual->MassBalance.ratio = 0.0;
151
+
152
+ time->Dur = 0; // 0 sec duration (steady state)
153
+ time->Tstart = 0; // Starting time of day
154
+ time->Pstart = 0; // Starting pattern period
155
+ time->Hstep = 3600; // 1 hr hydraulic time step
156
+ time->Qstep = 0; // No pre-set quality time step
157
+ time->Pstep = 3600; // 1 hr time pattern period
158
+ time->Rstep = 3600; // 1 hr reporting period
159
+ time->Rulestep = 0; // No pre-set rule time step
160
+ time->Rstart = 0; // Start reporting at time 0
161
+ }
162
+
163
+ void initreport(Report *rpt)
164
+ /*
165
+ **----------------------------------------------------------------------
166
+ ** Input: none
167
+ ** Output: none
168
+ ** Purpose: initializes reporting options
169
+ **----------------------------------------------------------------------
170
+ */
171
+ {
172
+ int i;
173
+ strncpy(rpt->Rpt2Fname, "", MAXFNAME);
174
+
175
+ // Initialize general reporting options
176
+ rpt->PageSize = PAGESIZE; // Default page size for report
177
+ rpt->Summaryflag = TRUE; // Write summary report
178
+ rpt->Messageflag = TRUE; // Report error/warning messages
179
+ rpt->Statflag = FALSE; // No hydraulic status reports
180
+ rpt->Energyflag = FALSE; // No energy usage report
181
+ rpt->Nodeflag = 0; // No reporting on nodes
182
+ rpt->Linkflag = 0; // No reporting on links
183
+
184
+ // Initialize options for each reported variable field
185
+ for (i = 0; i < MAXVAR; i++)
186
+ {
187
+ strncpy(rpt->Field[i].Name, Fldname[i], MAXID);
188
+ rpt->Field[i].Enabled = FALSE; // Not included in report
189
+ rpt->Field[i].Precision = 2; // 2 decimal precision
190
+ rpt->Field[i].RptLim[LOW] = SQR(BIG); // No reporting limits
191
+ rpt->Field[i].RptLim[HI] = -SQR(BIG);
192
+ }
193
+ rpt->Field[FRICTION].Precision = 3;
194
+
195
+ // Set default set of variables reported on
196
+ for (i = DEMAND; i <= QUALITY; i++)
197
+ {
198
+ rpt->Field[i].Enabled = TRUE;
199
+ }
200
+ for (i = FLOW; i <= HEADLOSS; i++)
201
+ {
202
+ rpt->Field[i].Enabled = TRUE;
203
+ }
204
+ }
205
+
206
+ void adjustdata(Project *pr)
207
+ /*
208
+ **----------------------------------------------------------------------
209
+ ** Input: none
210
+ ** Output: none
211
+ ** Purpose: adjusts project data after input file has been processed
212
+ **----------------------------------------------------------------------
213
+ */
214
+ {
215
+ Network *net = &pr->network;
216
+ Hydraul *hyd = &pr->hydraul;
217
+ Quality *qual = &pr->quality;
218
+ Times *time = &pr->times;
219
+ Parser *parser = &pr->parser;
220
+ Report *rpt = &pr->report;
221
+
222
+ int i;
223
+ double ucf; // Unit conversion factor
224
+ Slink *link;
225
+ Stank *tank;
226
+
227
+ // Use 1 hr pattern & report time step if none specified
228
+ if (time->Pstep <= 0) time->Pstep = 3600;
229
+ if (time->Rstep == 0) time->Rstep = time->Pstep;
230
+
231
+ // Hydraulic time step cannot be greater than pattern or report time step
232
+ if (time->Hstep <= 0) time->Hstep = 3600;
233
+ if (time->Hstep > time->Pstep) time->Hstep = time->Pstep;
234
+ if (time->Hstep > time->Rstep) time->Hstep = time->Rstep;
235
+
236
+ // Report start time cannot be greater than simulation duration
237
+ if (time->Rstart > time->Dur) time->Rstart = 0;
238
+
239
+ // If no quality timestep, then make it 1/10 of hydraulic timestep
240
+ if (time->Qstep == 0) time->Qstep = time->Hstep / 10;
241
+
242
+ // If no rule time step then make it 1/10 of hydraulic time step
243
+ // but not greater than hydraulic time step
244
+ if (time->Rulestep == 0) time->Rulestep = time->Hstep / 10;
245
+ time->Rulestep = MIN(time->Rulestep, time->Hstep);
246
+
247
+ // Quality timestep cannot exceed hydraulic timestep
248
+ time->Qstep = MIN(time->Qstep, time->Hstep);
249
+
250
+ // If no quality tolerance, then use default values
251
+ if (qual->Ctol == MISSING)
252
+ {
253
+ if (qual->Qualflag == AGE) qual->Ctol = AGETOL;
254
+ else qual->Ctol = CHEMTOL;
255
+ }
256
+
257
+ // Determine units system based on flow units
258
+ switch (parser->Flowflag)
259
+ {
260
+ case LPS: // Liters/sec
261
+ case LPM: // Liters/min
262
+ case MLD: // megaliters/day
263
+ case CMH: // cubic meters/hr
264
+ case CMD: // cubic meters/day
265
+ case CMS: // cubic meters/second
266
+ parser->Unitsflag = SI;
267
+ break;
268
+ default:
269
+ parser->Unitsflag = US;
270
+ }
271
+
272
+ // Revise pressure units depending on flow units
273
+ if (parser->Pressflag == DEFAULTUNIT)
274
+ {
275
+ if (parser->Unitsflag == SI) parser->Pressflag = METERS;
276
+ else parser->Pressflag = PSI;
277
+ }
278
+
279
+ // Store value of viscosity & diffusivity
280
+ ucf = 1.0;
281
+ if (parser->Unitsflag == SI) ucf = SQR(MperFT);
282
+ if (hyd->Viscos == MISSING)
283
+ {
284
+ hyd->Viscos = VISCOS; // No viscosity supplied
285
+ }
286
+ else if (hyd->Viscos > 1.e-3)
287
+ {
288
+ hyd->Viscos = hyd->Viscos * VISCOS; // Multiplier supplied
289
+ }
290
+ else hyd->Viscos = hyd->Viscos / ucf; // Actual value supplied
291
+ if (qual->Diffus == MISSING)
292
+ {
293
+ qual->Diffus = DIFFUS; // No viscosity supplied
294
+ }
295
+ else if (qual->Diffus > 1.e-4)
296
+ {
297
+ qual->Diffus = qual->Diffus * DIFFUS; // Multiplier supplied
298
+ }
299
+ else qual->Diffus = qual->Diffus / ucf; // Actual value supplied
300
+
301
+ // Set exponent in head loss equation and adjust flow-resistance tolerance.
302
+ if (hyd->Formflag == HW) hyd->Hexp = 1.852;
303
+ else hyd->Hexp = 2.0;
304
+
305
+ // See if default reaction coeffs. apply
306
+ for (i = 1; i <= net->Nlinks; i++)
307
+ {
308
+ link = &net->Link[i];
309
+ if (link->Type > PIPE) continue;
310
+ if (link->Kb == MISSING) link->Kb = qual->Kbulk; // Bulk coeff.
311
+ if (link->Kw == MISSING) // Wall coeff.
312
+ {
313
+ // Rfactor is the pipe roughness correlation factor
314
+ if (qual->Rfactor == 0.0) link->Kw = qual->Kwall;
315
+ else if ((link->Kc > 0.0) && (link->Diam > 0.0))
316
+ {
317
+ if (hyd->Formflag == HW) link->Kw = qual->Rfactor / link->Kc;
318
+ if (hyd->Formflag == DW)
319
+ {
320
+ link->Kw = qual->Rfactor / ABS(log(link->Kc / link->Diam));
321
+ }
322
+ if (hyd->Formflag == CM) link->Kw = qual->Rfactor * link->Kc;
323
+ }
324
+ else link->Kw = 0.0;
325
+ }
326
+ }
327
+ for (i = 1; i <= net->Ntanks; i++)
328
+ {
329
+ tank = &net->Tank[i];
330
+ if (tank->Kb == MISSING) tank->Kb = qual->Kbulk;
331
+ }
332
+
333
+ // Set default pattern index
334
+ i = findpattern(net, parser->DefPatID);
335
+ if (i > 0)
336
+ hyd->DefPat = i;
337
+
338
+ // Remove QUALITY as a reporting variable if no WQ analysis
339
+ if (qual->Qualflag == NONE) rpt->Field[QUALITY].Enabled = FALSE;
340
+ }
341
+
342
+ void inittanks(Project *pr)
343
+ /*
344
+ **---------------------------------------------------------------
345
+ ** Input: none
346
+ ** Output: none
347
+ ** Purpose: initializes volumes in non-cylindrical tanks
348
+ **---------------------------------------------------------------
349
+ */
350
+ {
351
+ Network *net = &pr->network;
352
+
353
+ int i, j, n = 0;
354
+ double a;
355
+ int errcode = 0;
356
+ char errmsg[MAXMSG+1] = "";
357
+ Stank *tank;
358
+ Scurve *curve;
359
+
360
+ for (j = 1; j <= net->Ntanks; j++)
361
+ {
362
+ tank = &net->Tank[j];
363
+ if (tank->A == 0.0) continue; // Skip reservoirs
364
+
365
+ // See if tank has a volume curve
366
+ i = tank->Vcurve;
367
+ if (i > 0)
368
+ {
369
+ curve = &net->Curve[i];
370
+ n = curve->Npts - 1;
371
+
372
+ // Find min., max., and initial volumes from curve
373
+ tank->Vmin = interp(curve->Npts, curve->X, curve->Y, tank->Hmin);
374
+ tank->Vmax = interp(curve->Npts, curve->X, curve->Y, tank->Hmax);
375
+ tank->V0 = interp(curve->Npts, curve->X, curve->Y, tank->H0);
376
+
377
+ // Find a "nominal" diameter for tank
378
+ a = (curve->Y[n] - curve->Y[0]) / (curve->X[n] - curve->X[0]);
379
+ tank->A = sqrt(4.0 * a / PI);
380
+ }
381
+ }
382
+ }
383
+
384
+ void initunits(Project *pr)
385
+ /*
386
+ **--------------------------------------------------------------
387
+ ** Input: none
388
+ ** Output: none
389
+ ** Purpose: determines unit conversion factors
390
+ **--------------------------------------------------------------
391
+ */
392
+ {
393
+ Parser *parser = &pr->parser;
394
+ Report *rpt = &pr->report;
395
+ Hydraul *hyd = &pr->hydraul;
396
+ Quality *qual = &pr->quality;
397
+ Times *time = &pr->times;
398
+
399
+ double dcf, // distance conversion factor
400
+ ccf, // concentration conversion factor
401
+ qcf, // flow conversion factor
402
+ hcf, // head conversion factor
403
+ pcf, // pressure conversion factor
404
+ wcf; // energy conversion factor
405
+
406
+ if (parser->Unitsflag == SI) // SI units
407
+ {
408
+ strcpy(rpt->Field[DEMAND].Units, RptFlowUnitsTxt[parser->Flowflag]);
409
+ strcpy(rpt->Field[ELEV].Units, u_METERS);
410
+ strcpy(rpt->Field[HEAD].Units, u_METERS);
411
+ strcpy(rpt->Field[LENGTH].Units, u_METERS);
412
+ strcpy(rpt->Field[DIAM].Units, u_MMETERS);
413
+ strcpy(rpt->Field[FLOW].Units, RptFlowUnitsTxt[parser->Flowflag]);
414
+ strcpy(rpt->Field[VELOCITY].Units, u_MperSEC);
415
+ strcpy(rpt->Field[HEADLOSS].Units, u_per1000M);
416
+ strcpy(rpt->Field[FRICTION].Units, "");
417
+ strcpy(rpt->Field[POWER].Units, u_KW);
418
+
419
+ dcf = 1000.0 * MperFT;
420
+ qcf = LPSperCFS;
421
+ if (parser->Flowflag == LPM) qcf = LPMperCFS;
422
+ if (parser->Flowflag == MLD) qcf = MLDperCFS;
423
+ if (parser->Flowflag == CMH) qcf = CMHperCFS;
424
+ if (parser->Flowflag == CMD) qcf = CMDperCFS;
425
+ if (parser->Flowflag == CMS) qcf = CMSperCFS;
426
+
427
+ hcf = MperFT;
428
+ wcf = KWperHP;
429
+ }
430
+ else // US units
431
+ {
432
+ strcpy(rpt->Field[DEMAND].Units, RptFlowUnitsTxt[parser->Flowflag]);
433
+ strcpy(rpt->Field[ELEV].Units, u_FEET);
434
+ strcpy(rpt->Field[HEAD].Units, u_FEET);
435
+ strcpy(rpt->Field[LENGTH].Units, u_FEET);
436
+ strcpy(rpt->Field[DIAM].Units, u_INCHES);
437
+ strcpy(rpt->Field[FLOW].Units, RptFlowUnitsTxt[parser->Flowflag]);
438
+ strcpy(rpt->Field[VELOCITY].Units, u_FTperSEC);
439
+ strcpy(rpt->Field[HEADLOSS].Units, u_per1000FT);
440
+ strcpy(rpt->Field[FRICTION].Units, "");
441
+ strcpy(rpt->Field[POWER].Units, u_HP);
442
+
443
+ dcf = 12.0;
444
+ qcf = 1.0;
445
+ if (parser->Flowflag == GPM) qcf = GPMperCFS;
446
+ if (parser->Flowflag == MGD) qcf = MGDperCFS;
447
+ if (parser->Flowflag == IMGD) qcf = IMGDperCFS;
448
+ if (parser->Flowflag == AFD) qcf = AFDperCFS;
449
+ hcf = 1.0;
450
+ wcf = 1.0;
451
+ }
452
+
453
+ strcpy(rpt->Field[PRESSURE].Units, PressUnitsTxt[parser->Pressflag]);
454
+ pcf = PSIperFT * hyd->SpGrav; // Default to PSI
455
+ if (parser->Pressflag == METERS) pcf = MperFT;
456
+ if (parser->Pressflag == KPA) pcf = KPAperPSI * PSIperFT * hyd->SpGrav;
457
+ if (parser->Pressflag == BAR) pcf = BARperPSI * PSIperFT * hyd->SpGrav;
458
+ if (parser->Pressflag == FEET) pcf = 1.0;
459
+
460
+ strcpy(rpt->Field[QUALITY].Units, "");
461
+ ccf = 1.0;
462
+ if (qual->Qualflag == CHEM)
463
+ {
464
+ ccf = 1.0 / LperFT3;
465
+ strncpy(rpt->Field[QUALITY].Units, qual->ChemUnits, MAXID);
466
+ strncpy(rpt->Field[REACTRATE].Units, qual->ChemUnits, MAXID);
467
+ strcat(rpt->Field[REACTRATE].Units, t_PERDAY);
468
+ }
469
+ else if (qual->Qualflag == AGE) strcpy(rpt->Field[QUALITY].Units, u_HOURS);
470
+ else if (qual->Qualflag == TRACE) strcpy(rpt->Field[QUALITY].Units, u_PERCENT);
471
+
472
+ pr->Ucf[DEMAND] = qcf;
473
+ pr->Ucf[ELEV] = hcf;
474
+ pr->Ucf[HEAD] = hcf;
475
+ pr->Ucf[PRESSURE] = pcf;
476
+ pr->Ucf[QUALITY] = ccf;
477
+ pr->Ucf[LENGTH] = hcf;
478
+ pr->Ucf[DIAM] = dcf;
479
+ pr->Ucf[FLOW] = qcf;
480
+ pr->Ucf[VELOCITY] = hcf;
481
+ pr->Ucf[HEADLOSS] = hcf;
482
+ pr->Ucf[LINKQUAL] = ccf;
483
+ pr->Ucf[REACTRATE] = ccf;
484
+ pr->Ucf[FRICTION] = 1.0;
485
+ pr->Ucf[POWER] = wcf;
486
+ pr->Ucf[VOLUME] = hcf * hcf * hcf;
487
+
488
+ // Report time in minutes if hyd. time step < 1/2 hr.
489
+ if (time->Hstep < 1800)
490
+ {
491
+ pr->Ucf[TIME] = 1.0 / 60.0;
492
+ strcpy(rpt->Field[TIME].Units, u_MINUTES);
493
+ }
494
+ else
495
+ {
496
+ pr->Ucf[TIME] = 1.0 / 3600.0;
497
+ strcpy(rpt->Field[TIME].Units, u_HOURS);
498
+ }
499
+ }
500
+
501
+ void convertunits(Project *pr)
502
+ /*
503
+ **--------------------------------------------------------------
504
+ ** Input: none
505
+ ** Output: none
506
+ ** Purpose: converts units of input data
507
+ **--------------------------------------------------------------
508
+ */
509
+ {
510
+ Network *net = &pr->network;
511
+ Hydraul *hyd = &pr->hydraul;
512
+ Quality *qual = &pr->quality;
513
+ Parser *parser = &pr->parser;
514
+
515
+ int i, j, k;
516
+ double ucf, ecf; // Unit conversion factor
517
+ Pdemand demand; // Pointer to demand record
518
+ Snode *node;
519
+ Stank *tank;
520
+ Slink *link;
521
+ Scontrol *control;
522
+
523
+ // Convert nodal elevations & initial WQ
524
+ // (WQ source units are converted in QUALITY.C
525
+ for (i = 1; i <= net->Nnodes; i++)
526
+ {
527
+ node = &net->Node[i];
528
+ node->El /= pr->Ucf[ELEV];
529
+ node->C0 /= pr->Ucf[QUALITY];
530
+ }
531
+
532
+ // Convert demands
533
+ for (i = 1; i <= net->Njuncs; i++)
534
+ {
535
+ node = &net->Node[i];
536
+ for (demand = node->D; demand != NULL; demand = demand->next)
537
+ {
538
+ demand->Base /= pr->Ucf[DEMAND];
539
+ }
540
+ }
541
+
542
+ // Convert PDA pressure limits
543
+ hyd->Pmin /= pr->Ucf[PRESSURE];
544
+ hyd->Preq /= pr->Ucf[PRESSURE];
545
+
546
+ // Convert emitter discharge coeffs. to head loss coeff.
547
+ ecf = (parser->Unitsflag == US) ? (PSIperFT * hyd->SpGrav) : (MperFT);
548
+
549
+ ucf = pow(pr->Ucf[FLOW], hyd->Qexp) / ecf;
550
+ for (i = 1; i <= net->Njuncs; i++)
551
+ {
552
+ node = &net->Node[i];
553
+ if (node->Ke > 0.0) node->Ke = ucf / pow(node->Ke, hyd->Qexp);
554
+ }
555
+
556
+ // Initialize tank variables (convert tank levels to elevations)
557
+ for (j = 1; j <= net->Ntanks; j++)
558
+ {
559
+ tank = &net->Tank[j];
560
+ i = tank->Node;
561
+ node = &net->Node[i];
562
+ tank->H0 = node->El + tank->H0 / pr->Ucf[ELEV];
563
+ tank->Hmin = node->El + tank->Hmin / pr->Ucf[ELEV];
564
+ tank->Hmax = node->El + tank->Hmax / pr->Ucf[ELEV];
565
+ tank->A = PI * SQR(tank->A / pr->Ucf[ELEV]) / 4.0;
566
+ tank->V0 /= pr->Ucf[VOLUME];
567
+ tank->Vmin /= pr->Ucf[VOLUME];
568
+ tank->Vmax /= pr->Ucf[VOLUME];
569
+ tank->Kb /= SECperDAY;
570
+ tank->V = tank->V0;
571
+ tank->C = node->C0;
572
+ }
573
+
574
+ // Convert hydraulic convergence criteria
575
+ hyd->FlowChangeLimit /= pr->Ucf[FLOW];
576
+ hyd->HeadErrorLimit /= pr->Ucf[HEAD];
577
+
578
+ // Convert water quality concentration options
579
+ qual->Climit /= pr->Ucf[QUALITY];
580
+ qual->Ctol /= pr->Ucf[QUALITY];
581
+
582
+ // Convert global reaction coeffs.
583
+ qual->Kbulk /= SECperDAY;
584
+ qual->Kwall /= SECperDAY;
585
+
586
+ // Convert units of link parameters
587
+ for (k = 1; k <= net->Nlinks; k++)
588
+ {
589
+ link = &net->Link[k];
590
+ if (link->Type <= PIPE)
591
+ {
592
+ // Convert D-W roughness from millifeet (or mm) to ft
593
+ if (hyd->Formflag == DW) link->Kc /= (1000.0 * pr->Ucf[ELEV]);
594
+ link->Diam /= pr->Ucf[DIAM];
595
+ link->Len /= pr->Ucf[LENGTH];
596
+
597
+ // Convert minor loss coeff. from V^2/2g basis to Q^2 basis
598
+ link->Km = 0.02517 * link->Km / SQR(link->Diam) / SQR(link->Diam);
599
+
600
+ // Convert units on reaction coeffs.
601
+ link->Kb /= SECperDAY;
602
+ link->Kw /= SECperDAY;
603
+
604
+ // Convert leakage parameters
605
+ link->LeakArea /= pr->Ucf[LENGTH];
606
+ link->LeakExpan /= pr->Ucf[LENGTH];
607
+ }
608
+
609
+ else if (link->Type == PUMP)
610
+ {
611
+ link->Km /= pr->Ucf[POWER];
612
+ }
613
+
614
+ else
615
+ {
616
+ // For flow control valves, convert flow setting
617
+ // while for other valves convert pressure setting
618
+ link->Diam /= pr->Ucf[DIAM];
619
+ link->Km = 0.02517 * link->Km / SQR(link->Diam) / SQR(link->Diam);
620
+ if (link->Kc != MISSING) switch (link->Type)
621
+ {
622
+ case FCV:
623
+ link->Kc /= pr->Ucf[FLOW];
624
+ break;
625
+ case PRV:
626
+ case PSV:
627
+ case PBV:
628
+ link->Kc /= pr->Ucf[PRESSURE];
629
+ break;
630
+ default:
631
+ break;
632
+ }
633
+ }
634
+ link->InitSetting = link->Kc;
635
+ }
636
+
637
+ // Convert units on control settings
638
+ for (i = 1; i <= net->Ncontrols; i++)
639
+ {
640
+ control = &net->Control[i];
641
+ if ((k = control->Link) == 0) continue;
642
+ link = &net->Link[k];
643
+ if ((j = control->Node) > 0)
644
+ {
645
+ node = &net->Node[j];
646
+ // control is based on tank level
647
+ if (j > net->Njuncs)
648
+ {
649
+ control->Grade = node->El + control->Grade / pr->Ucf[ELEV];
650
+ }
651
+ // control is based on nodal pressure
652
+ else control->Grade = node->El + control->Grade / pr->Ucf[PRESSURE];
653
+ }
654
+
655
+ // Convert units on valve settings
656
+ if (control->Setting != MISSING)
657
+ {
658
+ switch (link->Type)
659
+ {
660
+ case PRV:
661
+ case PSV:
662
+ case PBV:
663
+ control->Setting /= pr->Ucf[PRESSURE];
664
+ break;
665
+ case FCV:
666
+ control->Setting /= pr->Ucf[FLOW];
667
+ default:
668
+ break;
669
+ }
670
+ }
671
+ }
672
+ }