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.
- docs/conf.py +67 -0
- epanet-msx-src/dispersion.h +27 -0
- epanet-msx-src/hash.c +107 -0
- epanet-msx-src/hash.h +28 -0
- epanet-msx-src/include/epanetmsx.h +104 -0
- epanet-msx-src/include/epanetmsx_export.h +42 -0
- epanet-msx-src/mathexpr.c +937 -0
- epanet-msx-src/mathexpr.h +39 -0
- epanet-msx-src/mempool.c +204 -0
- epanet-msx-src/mempool.h +24 -0
- epanet-msx-src/msxchem.c +1285 -0
- epanet-msx-src/msxcompiler.c +368 -0
- epanet-msx-src/msxdict.h +42 -0
- epanet-msx-src/msxdispersion.c +586 -0
- epanet-msx-src/msxerr.c +116 -0
- epanet-msx-src/msxfile.c +260 -0
- epanet-msx-src/msxfuncs.c +175 -0
- epanet-msx-src/msxfuncs.h +35 -0
- epanet-msx-src/msxinp.c +1504 -0
- epanet-msx-src/msxout.c +398 -0
- epanet-msx-src/msxproj.c +791 -0
- epanet-msx-src/msxqual.c +2011 -0
- epanet-msx-src/msxrpt.c +400 -0
- epanet-msx-src/msxtank.c +422 -0
- epanet-msx-src/msxtoolkit.c +1164 -0
- epanet-msx-src/msxtypes.h +551 -0
- epanet-msx-src/msxutils.c +524 -0
- epanet-msx-src/msxutils.h +56 -0
- epanet-msx-src/newton.c +158 -0
- epanet-msx-src/newton.h +34 -0
- epanet-msx-src/rk5.c +287 -0
- epanet-msx-src/rk5.h +39 -0
- epanet-msx-src/ros2.c +293 -0
- epanet-msx-src/ros2.h +35 -0
- epanet-msx-src/smatrix.c +816 -0
- epanet-msx-src/smatrix.h +29 -0
- epanet-src/AUTHORS +60 -0
- epanet-src/LICENSE +21 -0
- epanet-src/enumstxt.h +151 -0
- epanet-src/epanet.c +5937 -0
- epanet-src/epanet2.c +961 -0
- epanet-src/epanet2.def +131 -0
- epanet-src/errors.dat +79 -0
- epanet-src/flowbalance.c +186 -0
- epanet-src/funcs.h +219 -0
- epanet-src/genmmd.c +1000 -0
- epanet-src/hash.c +177 -0
- epanet-src/hash.h +28 -0
- epanet-src/hydcoeffs.c +1303 -0
- epanet-src/hydraul.c +1164 -0
- epanet-src/hydsolver.c +781 -0
- epanet-src/hydstatus.c +442 -0
- epanet-src/include/epanet2.h +466 -0
- epanet-src/include/epanet2_2.h +1962 -0
- epanet-src/include/epanet2_enums.h +518 -0
- epanet-src/inpfile.c +884 -0
- epanet-src/input1.c +672 -0
- epanet-src/input2.c +970 -0
- epanet-src/input3.c +2265 -0
- epanet-src/leakage.c +527 -0
- epanet-src/mempool.c +146 -0
- epanet-src/mempool.h +24 -0
- epanet-src/output.c +853 -0
- epanet-src/project.c +1691 -0
- epanet-src/quality.c +695 -0
- epanet-src/qualreact.c +800 -0
- epanet-src/qualroute.c +696 -0
- epanet-src/report.c +1559 -0
- epanet-src/rules.c +1500 -0
- epanet-src/smatrix.c +871 -0
- epanet-src/text.h +508 -0
- epanet-src/types.h +928 -0
- epanet-src/util/cstr_helper.c +59 -0
- epanet-src/util/cstr_helper.h +38 -0
- epanet-src/util/errormanager.c +92 -0
- epanet-src/util/errormanager.h +39 -0
- epanet-src/util/filemanager.c +212 -0
- epanet-src/util/filemanager.h +81 -0
- epanet-src/validate.c +408 -0
- epanet.cpython-313-x86_64-linux-musl.so +0 -0
- epanet_plus/VERSION +1 -0
- epanet_plus/__init__.py +8 -0
- epanet_plus/epanet_plus.c +118 -0
- epanet_plus/epanet_toolkit.py +2730 -0
- epanet_plus/epanet_wrapper.py +2414 -0
- epanet_plus/include/epanet_plus.h +9 -0
- epanet_plus-0.0.1.dist-info/METADATA +152 -0
- epanet_plus-0.0.1.dist-info/RECORD +105 -0
- epanet_plus-0.0.1.dist-info/WHEEL +5 -0
- epanet_plus-0.0.1.dist-info/licenses/LICENSE +21 -0
- epanet_plus-0.0.1.dist-info/top_level.txt +11 -0
- examples/basic_usage.py +35 -0
- python-extension/ext.c +344 -0
- python-extension/pyepanet.c +2133 -0
- python-extension/pyepanet.h +143 -0
- python-extension/pyepanet2.c +1823 -0
- python-extension/pyepanet2.h +141 -0
- python-extension/pyepanet_plus.c +37 -0
- python-extension/pyepanet_plus.h +4 -0
- python-extension/pyepanetmsx.c +388 -0
- python-extension/pyepanetmsx.h +35 -0
- tests/test_epanet.py +16 -0
- tests/test_epanetmsx.py +36 -0
- tests/test_epyt.py +114 -0
- tests/test_load_inp_from_buffer.py +18 -0
|
@@ -0,0 +1,586 @@
|
|
|
1
|
+
/******************************************************************************
|
|
2
|
+
** MODULE: MSXDISPERSION.C
|
|
3
|
+
** PROJECT: EPANET-MSX
|
|
4
|
+
** DESCRIPTION: Dispersion solver for Lagrangian ADR
|
|
5
|
+
******************************************************************************/
|
|
6
|
+
|
|
7
|
+
#include <stdio.h>
|
|
8
|
+
#include <stdlib.h>
|
|
9
|
+
#include <string.h>
|
|
10
|
+
#include <math.h>
|
|
11
|
+
#include <omp.h>
|
|
12
|
+
|
|
13
|
+
#include "msxtypes.h"
|
|
14
|
+
#include "dispersion.h"
|
|
15
|
+
#include "smatrix.h"
|
|
16
|
+
|
|
17
|
+
#define ERRCODE(x) (errcode = ((errcode>100) ? (errcode) : (x)))
|
|
18
|
+
// External variables
|
|
19
|
+
//--------------------
|
|
20
|
+
extern MSXproject MSX; // MSX project data
|
|
21
|
+
|
|
22
|
+
static double* al; //vector helping solve tridaigonal system of eqns.
|
|
23
|
+
static double* bl; //vector helping solve tridaigonal system of eqns.
|
|
24
|
+
static double* cl; //vector helping solve tridaigonal system of eqns.
|
|
25
|
+
static double* rl; //vector helping solve tridaigonal system of eqns.
|
|
26
|
+
static double* sol; //vector helping solve tridaigonal system of eqns.
|
|
27
|
+
|
|
28
|
+
static double* gam;
|
|
29
|
+
|
|
30
|
+
#pragma omp threadprivate(al, bl, cl, rl, sol, gam)
|
|
31
|
+
|
|
32
|
+
int dispersion_open()
|
|
33
|
+
{
|
|
34
|
+
int errcode=0;
|
|
35
|
+
#pragma omp parallel
|
|
36
|
+
{
|
|
37
|
+
al = (double*)calloc(MSX.MaxSegments + 2, sizeof(double));
|
|
38
|
+
bl = (double*)calloc(MSX.MaxSegments + 2, sizeof(double));
|
|
39
|
+
cl = (double*)calloc(MSX.MaxSegments + 2, sizeof(double));
|
|
40
|
+
rl = (double*)calloc(MSX.MaxSegments + 2, sizeof(double));
|
|
41
|
+
sol = (double*)calloc(MSX.MaxSegments + 2, sizeof(double));
|
|
42
|
+
gam = (double*)calloc(MSX.MaxSegments + 2, sizeof(double));
|
|
43
|
+
#pragma omp critical
|
|
44
|
+
{
|
|
45
|
+
ERRCODE(MEMCHECK(al));
|
|
46
|
+
ERRCODE(MEMCHECK(bl));
|
|
47
|
+
ERRCODE(MEMCHECK(cl));
|
|
48
|
+
ERRCODE(MEMCHECK(rl));
|
|
49
|
+
ERRCODE(MEMCHECK(sol));
|
|
50
|
+
ERRCODE(MEMCHECK(gam));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return errcode;
|
|
54
|
+
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
int dispersion_close()
|
|
58
|
+
{
|
|
59
|
+
int errcode = 0;
|
|
60
|
+
#pragma omp parallel
|
|
61
|
+
{
|
|
62
|
+
FREE(al);
|
|
63
|
+
FREE(bl);
|
|
64
|
+
FREE(cl);
|
|
65
|
+
FREE(rl);
|
|
66
|
+
FREE(sol);
|
|
67
|
+
FREE(gam);
|
|
68
|
+
}
|
|
69
|
+
return errcode;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
void dispersion_pipe(int m, double tstep)
|
|
73
|
+
{
|
|
74
|
+
|
|
75
|
+
double cons = 0.0;
|
|
76
|
+
double ldispersion = 0.0;
|
|
77
|
+
double flowrate = 0.0, velocity = 0.0, area = 0.0;
|
|
78
|
+
int nseg = 0, k;
|
|
79
|
+
double diam = 0.0;
|
|
80
|
+
double vd = 0.0, vu = 0.0, vself = 0.0, asquare = 0.0, dh = 0.0, frictionfactor = 0.0;
|
|
81
|
+
double reynolds=0, shearvelocity=0;
|
|
82
|
+
Pseg seg = NULL;
|
|
83
|
+
|
|
84
|
+
double elpt = 0.0;
|
|
85
|
+
double d0 = 1.292e-8; //molecular diffusivity 1.292e-8 ft^2/s 1.2e-9 m^2/s
|
|
86
|
+
|
|
87
|
+
d0 = MSX.Dispersion.md[m];
|
|
88
|
+
#pragma omp parallel
|
|
89
|
+
{
|
|
90
|
+
#pragma omp for private(seg, cons, vd, vu, vself, k, nseg, asquare, velocity, diam, area, flowrate, reynolds, dh, frictionfactor, shearvelocity, ldispersion, elpt)
|
|
91
|
+
for (k = 1; k <= MSX.Nobjects[LINK]; k++)
|
|
92
|
+
{
|
|
93
|
+
|
|
94
|
+
velocity = 0;
|
|
95
|
+
if (MSX.FirstSeg[k] == NULL)
|
|
96
|
+
continue;
|
|
97
|
+
diam = MSX.Link[k].diam;
|
|
98
|
+
// Compute Reynolds No.
|
|
99
|
+
flowrate = (MSX.S[k] <= CLOSED) ? 0.0 : MSX.Q[k];
|
|
100
|
+
area = PI * diam * diam / 4.0; // pipe area
|
|
101
|
+
if (area > 0.0 && MSX.Link[k].len > 0.0 && ABS(flowrate) > 0.0)
|
|
102
|
+
{
|
|
103
|
+
velocity = fabs(flowrate) / area; // flow velocity
|
|
104
|
+
reynolds = velocity * diam / MSX.Dispersion.viscosity; // Reynolds number //#define VISCOS 1.1E-5 // Kinematic viscosity of water // @ 20 deg C (sq ft/sec)
|
|
105
|
+
dh = ABS(MSX.H[MSX.Link[k].n1] - MSX.H[MSX.Link[k].n2]);
|
|
106
|
+
if (dh > 0.00001)
|
|
107
|
+
frictionfactor = 39.725 * dh * pow(diam, 5) / (MSX.Link[k].len * SQR(flowrate));
|
|
108
|
+
else
|
|
109
|
+
frictionfactor = 0.0;
|
|
110
|
+
shearvelocity = velocity * sqrt(frictionfactor / 8);
|
|
111
|
+
|
|
112
|
+
if (d0 < 0)
|
|
113
|
+
{
|
|
114
|
+
ldispersion = MSX.Dispersion.ld[m];
|
|
115
|
+
}
|
|
116
|
+
else if (reynolds > 2300) //Basha 2007
|
|
117
|
+
{
|
|
118
|
+
ldispersion = 0.5 * diam * shearvelocity * (10.1 + 577 * pow(reynolds / 1000.0, -2.2));
|
|
119
|
+
|
|
120
|
+
}
|
|
121
|
+
/* else //Basha 2007
|
|
122
|
+
{
|
|
123
|
+
ldispersion = SQR(0.5 * diam * velocity) / (48 * d0);
|
|
124
|
+
elpt = MSX.Link[k].len / velocity;
|
|
125
|
+
ldispersion = ldispersion * (1 - exp(-12.425 * d0 * elpt / SQR(0.5 * diam)));
|
|
126
|
+
ldispersion += d0;
|
|
127
|
+
}*/
|
|
128
|
+
else //Lee 2004 averaged
|
|
129
|
+
{
|
|
130
|
+
ldispersion = SQR(0.5 * diam * velocity) / (48 * d0);
|
|
131
|
+
elpt = MSX.Link[k].len / velocity;
|
|
132
|
+
double interv = 16.0 * d0 * elpt / (0.25 * diam * diam);
|
|
133
|
+
ldispersion = ldispersion * (1 - (1 - exp(-interv))/interv);
|
|
134
|
+
ldispersion += d0;
|
|
135
|
+
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
}
|
|
139
|
+
else
|
|
140
|
+
{
|
|
141
|
+
ldispersion = 0;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (ldispersion < 0.0)
|
|
145
|
+
{
|
|
146
|
+
ldispersion = 0;
|
|
147
|
+
MSX.Dispersion.pipeDispersionCoeff[k] = 0;
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
double domi;
|
|
152
|
+
|
|
153
|
+
if (velocity > 0)
|
|
154
|
+
domi = ldispersion / (velocity * velocity * tstep);
|
|
155
|
+
else
|
|
156
|
+
domi = 1000;
|
|
157
|
+
if (domi >= 0.000 && MSX.Link[k].len*velocity/ldispersion < MSX.Dispersion.PecletLimit) //Peclet numer
|
|
158
|
+
{
|
|
159
|
+
MSX.Dispersion.pipeDispersionCoeff[k] = ldispersion;
|
|
160
|
+
}
|
|
161
|
+
else
|
|
162
|
+
{
|
|
163
|
+
MSX.Dispersion.pipeDispersionCoeff[k] = 0;
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
asquare = area * area;
|
|
167
|
+
seg = MSX.FirstSeg[k]; //downstream
|
|
168
|
+
cons = 2.0 * ldispersion * asquare * tstep;
|
|
169
|
+
vd = 0.0;
|
|
170
|
+
bl[0] = 1.0;
|
|
171
|
+
cl[0] = 0.0;
|
|
172
|
+
rl[0] = 0.0;
|
|
173
|
+
nseg = 0;
|
|
174
|
+
|
|
175
|
+
while (seg != NULL)
|
|
176
|
+
{
|
|
177
|
+
nseg++;
|
|
178
|
+
vself = seg->v;
|
|
179
|
+
rl[nseg] = seg->c[m];
|
|
180
|
+
seg = seg->prev;
|
|
181
|
+
if (seg)
|
|
182
|
+
vu = seg->v;
|
|
183
|
+
else
|
|
184
|
+
vu = 0.0;
|
|
185
|
+
al[nseg] = -cons / (vself * vself + vself * vd);
|
|
186
|
+
cl[nseg] = -cons / (vself * vself + vself * vu);
|
|
187
|
+
bl[nseg] = 1 - al[nseg] - cl[nseg];
|
|
188
|
+
|
|
189
|
+
vd = vself;
|
|
190
|
+
}
|
|
191
|
+
if (nseg == 0)
|
|
192
|
+
continue;
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
al[nseg + 1] = 0.0;
|
|
196
|
+
bl[nseg + 1] = 1.0;
|
|
197
|
+
rl[nseg + 1] = 0.0;
|
|
198
|
+
|
|
199
|
+
if (reynolds >= 0)
|
|
200
|
+
tridiag(nseg + 2, al, bl, cl, rl, sol); //nseg+2 <= 1000 here
|
|
201
|
+
else
|
|
202
|
+
{
|
|
203
|
+
for (int p = 0; p <= nseg + 1; p++)
|
|
204
|
+
sol[p] = rl[p];
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
seg = MSX.FirstSeg[k]; //downstream segment
|
|
208
|
+
int segindex = 1;
|
|
209
|
+
while (seg != NULL)
|
|
210
|
+
{
|
|
211
|
+
seg->hresponse = sol[segindex];
|
|
212
|
+
seg = seg->prev;
|
|
213
|
+
segindex++;
|
|
214
|
+
}
|
|
215
|
+
/*clear initial condition*/
|
|
216
|
+
for (int p = 1; p < nseg + 1; p++)
|
|
217
|
+
rl[p] = 0.0;
|
|
218
|
+
|
|
219
|
+
/*downstream unit boundary condition*/
|
|
220
|
+
rl[0] = 1.0;
|
|
221
|
+
if (reynolds >= 0)
|
|
222
|
+
tridiag(nseg + 2, al, bl, cl, rl, sol);
|
|
223
|
+
else
|
|
224
|
+
{
|
|
225
|
+
for (int p = 0; p <= nseg + 1; p++)
|
|
226
|
+
sol[p] = rl[p];
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
seg = MSX.FirstSeg[k]; //downstream
|
|
230
|
+
segindex = 1;
|
|
231
|
+
while (seg != NULL)
|
|
232
|
+
{
|
|
233
|
+
seg->dresponse = sol[segindex];
|
|
234
|
+
seg = seg->prev;
|
|
235
|
+
segindex++;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/*upstream unit boundary condition*/
|
|
239
|
+
rl[0] = 0.0;
|
|
240
|
+
rl[nseg + 1] = 1.0;
|
|
241
|
+
if (reynolds >= 0)
|
|
242
|
+
tridiag(nseg + 2, al, bl, cl, rl, sol); //nseg+2 <= 100 here
|
|
243
|
+
else
|
|
244
|
+
{
|
|
245
|
+
for (int p = 0; p <= nseg + 1; p++)
|
|
246
|
+
sol[p] = rl[p];
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
seg = MSX.FirstSeg[k]; //downstream
|
|
250
|
+
segindex = 1;
|
|
251
|
+
while (seg != NULL)
|
|
252
|
+
{
|
|
253
|
+
seg->uresponse = sol[segindex];
|
|
254
|
+
seg = seg->prev;
|
|
255
|
+
segindex++;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
void solve_nodequal(int m, double tstep)
|
|
262
|
+
{
|
|
263
|
+
|
|
264
|
+
Pseg firstseg;
|
|
265
|
+
Pseg lastseg;
|
|
266
|
+
Psource source;
|
|
267
|
+
int n1, n2;
|
|
268
|
+
double diam, area, asquare;
|
|
269
|
+
|
|
270
|
+
// double dispersion = 147.25;
|
|
271
|
+
double ldispersion;
|
|
272
|
+
double coelastseg, coefirstseg;
|
|
273
|
+
|
|
274
|
+
int njuncs = MSX.Nobjects[NODE] - MSX.Nobjects[TANK];
|
|
275
|
+
int found = 0;
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
//let's take a look of the matrix
|
|
279
|
+
|
|
280
|
+
memset(MSX.Dispersion.Aii, 0, (MSX.Nobjects[NODE] + 1) * sizeof(double));
|
|
281
|
+
memset(MSX.Dispersion.Aij, 0, (MSX.Dispersion.Ncoeffs + 1) * sizeof(double));
|
|
282
|
+
memset(MSX.Dispersion.F, 0, (MSX.Nobjects[NODE] + 1) * sizeof(double));
|
|
283
|
+
for (int k = 1; k <= MSX.Nobjects[LINK]; k++)
|
|
284
|
+
{
|
|
285
|
+
ldispersion = MSX.Dispersion.pipeDispersionCoeff[k];
|
|
286
|
+
if (ldispersion <= 0)
|
|
287
|
+
continue;
|
|
288
|
+
n1 = MSX.Link[k].n1; //upstream
|
|
289
|
+
n2 = MSX.Link[k].n2; //downstream
|
|
290
|
+
if (MSX.FlowDir[k] < 0)
|
|
291
|
+
{
|
|
292
|
+
n1 = MSX.Link[k].n2; //upstream
|
|
293
|
+
n2 = MSX.Link[k].n1; //downstream
|
|
294
|
+
}
|
|
295
|
+
diam = MSX.Link[k].diam;
|
|
296
|
+
area = 0.25 * PI * diam * diam;
|
|
297
|
+
asquare = area * area;
|
|
298
|
+
firstseg = MSX.FirstSeg[k]; //downstream
|
|
299
|
+
lastseg = MSX.LastSeg[k]; //upstream
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
if (firstseg == NULL)
|
|
303
|
+
continue;
|
|
304
|
+
|
|
305
|
+
coefirstseg = ldispersion * asquare / firstseg->v; //dispersion should be pipe by pipe
|
|
306
|
+
coelastseg = ldispersion * asquare / lastseg->v; //dispersion should be pipe by pipe
|
|
307
|
+
MSX.Dispersion.Aij[MSX.Dispersion.Ndx[k]] -= coefirstseg * firstseg->uresponse; //coefirstseg*firstseg->greenu = coelastseg*lastseg->greend
|
|
308
|
+
|
|
309
|
+
found = 0;
|
|
310
|
+
source = MSX.Node[n2].sources;
|
|
311
|
+
while(source != NULL)
|
|
312
|
+
{
|
|
313
|
+
if (source->species == m)
|
|
314
|
+
{
|
|
315
|
+
found = 1;
|
|
316
|
+
break;
|
|
317
|
+
}
|
|
318
|
+
else
|
|
319
|
+
source = source->next;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if (n2 <= njuncs)
|
|
323
|
+
{
|
|
324
|
+
if (source == NULL || source->c0 <= 0.0)
|
|
325
|
+
{
|
|
326
|
+
MSX.Dispersion.Aii[MSX.Dispersion.Row[n2]] += coefirstseg * (1.0 - firstseg->dresponse);
|
|
327
|
+
|
|
328
|
+
MSX.Dispersion.F[MSX.Dispersion.Row[n2]] += coefirstseg * firstseg->hresponse;
|
|
329
|
+
}
|
|
330
|
+
else
|
|
331
|
+
{
|
|
332
|
+
MSX.Dispersion.Aij[MSX.Dispersion.Ndx[k]] = 0;
|
|
333
|
+
MSX.Dispersion.F[MSX.Dispersion.Row[n1]] += coelastseg * MSX.LastSeg[k]->dresponse * MSX.Node[n2].c[m];
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
else
|
|
337
|
+
{
|
|
338
|
+
MSX.Dispersion.F[MSX.Dispersion.Row[n1]] += coelastseg * MSX.LastSeg[k]->dresponse * MSX.Node[n2].c[m];
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
found = 0;
|
|
343
|
+
source = MSX.Node[n1].sources;
|
|
344
|
+
while (source != NULL)
|
|
345
|
+
{
|
|
346
|
+
if (source->species == m)
|
|
347
|
+
{
|
|
348
|
+
found = 1;
|
|
349
|
+
break;
|
|
350
|
+
}
|
|
351
|
+
else
|
|
352
|
+
source = source->next;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
if (n1 <= njuncs)
|
|
356
|
+
{
|
|
357
|
+
source = MSX.Node[n1].sources;
|
|
358
|
+
if (source == NULL || source->c0 <= 0.0)
|
|
359
|
+
{
|
|
360
|
+
MSX.Dispersion.Aii[MSX.Dispersion.Row[n1]] += coelastseg * (1.0 - lastseg->uresponse);
|
|
361
|
+
MSX.Dispersion.F[MSX.Dispersion.Row[n1]] += coelastseg * lastseg->hresponse;
|
|
362
|
+
}
|
|
363
|
+
else
|
|
364
|
+
{
|
|
365
|
+
MSX.Dispersion.Aij[MSX.Dispersion.Ndx[k]] = 0; //sure
|
|
366
|
+
MSX.Dispersion.F[MSX.Dispersion.Row[n2]] += coefirstseg * firstseg->uresponse * MSX.Node[n1].c[m];
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
}
|
|
370
|
+
else
|
|
371
|
+
{
|
|
372
|
+
MSX.Dispersion.F[MSX.Dispersion.Row[n2]] += coefirstseg * firstseg->uresponse * MSX.Node[n1].c[m];
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
for (int i = 1; i <= njuncs; i++)
|
|
376
|
+
{
|
|
377
|
+
if (MSX.Dispersion.Aii[MSX.Dispersion.Row[i]] == 0.0) //no dispersion around the junction at all
|
|
378
|
+
{
|
|
379
|
+
MSX.Dispersion.Aii[MSX.Dispersion.Row[i]] = 1.0;
|
|
380
|
+
|
|
381
|
+
MSX.Dispersion.F[MSX.Dispersion.Row[i]] = 1.0 * MSX.Node[i].c[m];
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
int errcode = msx_linsolve(njuncs, MSX.Dispersion.Aii, MSX.Dispersion.Aij, MSX.Dispersion.F);
|
|
386
|
+
|
|
387
|
+
for (int i = 1; i <= njuncs; i++)
|
|
388
|
+
{
|
|
389
|
+
MSX.Node[i].c[m] = MSX.Dispersion.F[MSX.Dispersion.Row[i]];
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
void segqual_update(int m, double tstep)
|
|
396
|
+
{
|
|
397
|
+
|
|
398
|
+
Pseg seg = NULL;
|
|
399
|
+
Psource source = NULL;
|
|
400
|
+
int n1 = 0, n2 = 0, k;
|
|
401
|
+
double mass1 = 0;
|
|
402
|
+
double mass2 = 0;
|
|
403
|
+
double dispersedin = 0;
|
|
404
|
+
double ldispersion = 0, massin = 0;
|
|
405
|
+
double area = 0.0;
|
|
406
|
+
int njuncs = MSX.Nobjects[NODE] - MSX.Nobjects[TANK];
|
|
407
|
+
#pragma omp parallel
|
|
408
|
+
{
|
|
409
|
+
#pragma omp for private(k, n1, n2, seg, source, mass1, mass2, ldispersion, massin, area)
|
|
410
|
+
for (k = 1; k <= MSX.Nobjects[LINK]; k++)
|
|
411
|
+
{
|
|
412
|
+
mass1 = 0;
|
|
413
|
+
mass2 = 0;
|
|
414
|
+
ldispersion = MSX.Dispersion.pipeDispersionCoeff[k];
|
|
415
|
+
if (ldispersion <= 0.0)
|
|
416
|
+
continue;
|
|
417
|
+
area = 0.25 * PI * MSX.Link[k].diam * MSX.Link[k].diam;
|
|
418
|
+
n1 = MSX.Link[k].n1;
|
|
419
|
+
n2 = MSX.Link[k].n2;
|
|
420
|
+
if (MSX.FlowDir[k] < 0.0)
|
|
421
|
+
{
|
|
422
|
+
n1 = MSX.Link[k].n2;
|
|
423
|
+
n2 = MSX.Link[k].n1;
|
|
424
|
+
}
|
|
425
|
+
seg = MSX.FirstSeg[k];
|
|
426
|
+
while (seg != NULL) //update segment concentration based on new up/down node quality
|
|
427
|
+
{
|
|
428
|
+
mass1 += seg->c[m] * seg->v;
|
|
429
|
+
seg->c[m] = seg->hresponse + MSX.Node[n2].c[m] * seg->dresponse + MSX.Node[n1].c[m] * seg->uresponse;
|
|
430
|
+
|
|
431
|
+
mass2 += seg->c[m] * seg->v;
|
|
432
|
+
seg = seg->prev;
|
|
433
|
+
}
|
|
434
|
+
if (MSX.FirstSeg[k] == NULL)
|
|
435
|
+
continue;
|
|
436
|
+
|
|
437
|
+
source = MSX.Node[n2].sources;
|
|
438
|
+
while (source != NULL)
|
|
439
|
+
{
|
|
440
|
+
if (source->species == m)
|
|
441
|
+
break;
|
|
442
|
+
source = source->next;
|
|
443
|
+
}
|
|
444
|
+
massin = 0;
|
|
445
|
+
if (source != NULL && source->c0 > 0)
|
|
446
|
+
{
|
|
447
|
+
massin = 2.0 * ldispersion * tstep * area * area * (MSX.Node[n2].c[m] - MSX.FirstSeg[k]->c[m]) * LperFT3 / MSX.FirstSeg[k]->v;
|
|
448
|
+
}
|
|
449
|
+
else if (n2 > njuncs && MSX.Tank[n2 - njuncs].a == 0) //we assume constant tank and reservoir concentration during dispersion which may not be true for small tanks
|
|
450
|
+
{
|
|
451
|
+
massin = 2.0 * ldispersion * tstep * area * area * (MSX.Node[n2].c[m] - MSX.FirstSeg[k]->c[m]) * LperFT3 / MSX.FirstSeg[k]->v;
|
|
452
|
+
}
|
|
453
|
+
else if (n2 > njuncs && MSX.Tank[n2 - njuncs].a > 0.0)
|
|
454
|
+
{
|
|
455
|
+
massin = 2.0 * ldispersion * tstep * area * area * (MSX.Node[n2].c[m] - MSX.FirstSeg[k]->c[m]) * LperFT3 / MSX.FirstSeg[k]->v;
|
|
456
|
+
|
|
457
|
+
}
|
|
458
|
+
#pragma omp critical
|
|
459
|
+
{
|
|
460
|
+
dispersedin += massin;
|
|
461
|
+
}
|
|
462
|
+
source = MSX.Node[n1].sources;
|
|
463
|
+
while (source != NULL)
|
|
464
|
+
{
|
|
465
|
+
if (source->species == m)
|
|
466
|
+
break;
|
|
467
|
+
source = source->next;
|
|
468
|
+
}
|
|
469
|
+
massin = 0;
|
|
470
|
+
if (source != NULL && source->c0 > 0)
|
|
471
|
+
{
|
|
472
|
+
massin = 2.0 * ldispersion * tstep * area * area * (MSX.Node[n1].c[m] - MSX.LastSeg[k]->c[m]) * LperFT3 / MSX.LastSeg[k]->v;
|
|
473
|
+
}
|
|
474
|
+
else if (n1 > njuncs && MSX.Tank[n1 - njuncs].a == 0)
|
|
475
|
+
{
|
|
476
|
+
massin = 2.0 * ldispersion * tstep * area * area * (MSX.Node[n1].c[m] - MSX.LastSeg[k]->c[m]) * LperFT3 / MSX.LastSeg[k]->v;
|
|
477
|
+
}
|
|
478
|
+
else if (n1 > njuncs && MSX.Tank[n1 - njuncs].a > 0.0)
|
|
479
|
+
{
|
|
480
|
+
|
|
481
|
+
massin = 2.0 * ldispersion * tstep * area * area * (MSX.Node[n1].c[m] - MSX.LastSeg[k]->c[m]) * LperFT3 / MSX.LastSeg[k]->v;
|
|
482
|
+
|
|
483
|
+
}
|
|
484
|
+
#pragma omp critical
|
|
485
|
+
{
|
|
486
|
+
dispersedin += massin;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
MSX.MassBalance.indisperse[m] += dispersedin;
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
void disperse_tankqual(int n, int m, double massin)
|
|
497
|
+
{
|
|
498
|
+
int j, tm, k;
|
|
499
|
+
Pseg seg;
|
|
500
|
+
double c, v;
|
|
501
|
+
|
|
502
|
+
j = MSX.Node[n].tank;
|
|
503
|
+
if (j < 0)
|
|
504
|
+
return;
|
|
505
|
+
else if (MSX.Tank[j].a == 0)
|
|
506
|
+
return;
|
|
507
|
+
|
|
508
|
+
k = MSX.Nobjects[LINK] + j;
|
|
509
|
+
tm = MSX.Tank[j].mixModel;
|
|
510
|
+
|
|
511
|
+
if (tm == MIX1|| tm == MIX2)
|
|
512
|
+
{
|
|
513
|
+
seg = MSX.LastSeg[k];
|
|
514
|
+
if (seg)
|
|
515
|
+
{
|
|
516
|
+
v = seg->v;
|
|
517
|
+
c = seg->c[m];
|
|
518
|
+
if (v > 0)
|
|
519
|
+
c = (c * v * LperFT3 + massin) / (v * LperFT3);
|
|
520
|
+
|
|
521
|
+
c = MAX(0, c);
|
|
522
|
+
seg->c[m] = c;
|
|
523
|
+
MSX.Tank[j].c[m] = c;
|
|
524
|
+
MSX.Node[n].c[m] = c;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
else if (tm == FIFO)
|
|
528
|
+
{
|
|
529
|
+
seg = MSX.FirstSeg[k];
|
|
530
|
+
if (seg)
|
|
531
|
+
{
|
|
532
|
+
v = seg->v;
|
|
533
|
+
c = seg->c[m];
|
|
534
|
+
if (v > 0)
|
|
535
|
+
c = (c * v * LperFT3 + massin) / (v * LperFT3);
|
|
536
|
+
|
|
537
|
+
if( c < 0)
|
|
538
|
+
c = MAX(0, c);
|
|
539
|
+
seg->c[m] = c;
|
|
540
|
+
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
else if (tm == LIFO)
|
|
544
|
+
{
|
|
545
|
+
seg = MSX.FirstSeg[k];
|
|
546
|
+
if (seg)
|
|
547
|
+
{
|
|
548
|
+
v = seg->v;
|
|
549
|
+
c = seg->c[m];
|
|
550
|
+
if (v > 0)
|
|
551
|
+
c = (c * v * LperFT3 + massin) / (v * LperFT3);
|
|
552
|
+
|
|
553
|
+
c = MAX(0, c);
|
|
554
|
+
seg->c[m] = c;
|
|
555
|
+
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
// Solve tri-daigonal system of eqns. using Thomas' algorithm
|
|
568
|
+
|
|
569
|
+
void tridiag(int n, double *a, double *b, double *c, double *r, double *y)
|
|
570
|
+
{
|
|
571
|
+
int j;
|
|
572
|
+
double bet;
|
|
573
|
+
|
|
574
|
+
bet = b[0];
|
|
575
|
+
y[0] = r[0] / bet;
|
|
576
|
+
for (j = 1; j < n; j++)
|
|
577
|
+
{
|
|
578
|
+
gam[j] = c[j - 1] / bet;
|
|
579
|
+
bet = b[j] - a[j] * gam[j];
|
|
580
|
+
y[j] = (r[j] - a[j] * y[j - 1]) / bet;
|
|
581
|
+
}
|
|
582
|
+
for (j = n - 2; j >= 0; j--)
|
|
583
|
+
{
|
|
584
|
+
y[j] -= gam[j + 1] * y[j + 1];
|
|
585
|
+
}
|
|
586
|
+
}
|
epanet-msx-src/msxerr.c
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/******************************************************************************
|
|
2
|
+
** MODULE: MSXERR.C
|
|
3
|
+
** PROJECT: EPANET-MSX
|
|
4
|
+
** DESCRIPTION: Math error reporting routines.
|
|
5
|
+
** AUTHORS: see AUTHORS
|
|
6
|
+
** Copyright: see AUTHORS
|
|
7
|
+
** License: see LICENSE
|
|
8
|
+
** VERSION: 2.0.00
|
|
9
|
+
** LAST UPDATE: 04/14/2021
|
|
10
|
+
******************************************************************************/
|
|
11
|
+
|
|
12
|
+
#include <stdio.h>
|
|
13
|
+
#include <string.h>
|
|
14
|
+
|
|
15
|
+
#include "msxtypes.h"
|
|
16
|
+
#include "epanet2.h"
|
|
17
|
+
|
|
18
|
+
// External variables
|
|
19
|
+
//--------------------
|
|
20
|
+
extern MSXproject MSX; // MSX project data
|
|
21
|
+
|
|
22
|
+
// Local variables
|
|
23
|
+
//-----------------
|
|
24
|
+
static int mathError; // math error flag
|
|
25
|
+
static char mathErrorMsg[1024]; // math error message
|
|
26
|
+
static char* elementTxt[] = // see ObjectType in msxtypes.h
|
|
27
|
+
{"", "pipe", "tank"};
|
|
28
|
+
static char* exprTypeTxt[] = // see ExpressionType in msxtypes.h
|
|
29
|
+
{"", "rate", "formula", "equilibrium"};
|
|
30
|
+
|
|
31
|
+
// Exported functions
|
|
32
|
+
//--------------------
|
|
33
|
+
void MSXerr_clearMathError(void);
|
|
34
|
+
int MSXerr_mathError(void);
|
|
35
|
+
double MSXerr_validate(double x, int index, int element, int exprType);
|
|
36
|
+
void MSXerr_writeMathErrorMsg(void);
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
//=============================================================================
|
|
40
|
+
|
|
41
|
+
void MSXerr_clearMathError()
|
|
42
|
+
/*
|
|
43
|
+
** Purpose:
|
|
44
|
+
** clears the math error flag.
|
|
45
|
+
*/
|
|
46
|
+
{
|
|
47
|
+
mathError = 0;
|
|
48
|
+
strcpy(mathErrorMsg, "");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
//=============================================================================
|
|
52
|
+
|
|
53
|
+
int MSXerr_mathError()
|
|
54
|
+
/*
|
|
55
|
+
** Purpose:
|
|
56
|
+
** returns the current state of the math error flag.
|
|
57
|
+
*/
|
|
58
|
+
{
|
|
59
|
+
return mathError;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
//=============================================================================
|
|
63
|
+
|
|
64
|
+
void MSXerr_writeMathErrorMsg()
|
|
65
|
+
/*
|
|
66
|
+
** Purpose:
|
|
67
|
+
** writes math error message to EPANET report file.
|
|
68
|
+
*/
|
|
69
|
+
{
|
|
70
|
+
ENwriteline(mathErrorMsg);
|
|
71
|
+
ENwriteline("");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
//=============================================================================
|
|
75
|
+
|
|
76
|
+
double MSXerr_validate(double x, int index, int element, int exprType)
|
|
77
|
+
/*
|
|
78
|
+
** Purpose:
|
|
79
|
+
** checks if a number is valid or not.
|
|
80
|
+
**
|
|
81
|
+
** Input:
|
|
82
|
+
** x = the number to check
|
|
83
|
+
** index = array index of species or term that x was computed for
|
|
84
|
+
** element = LINK for a pipe element or TANK for a tank element
|
|
85
|
+
** exprType = type of expression that produced x
|
|
86
|
+
**
|
|
87
|
+
** Returns:
|
|
88
|
+
** the value of x if it's a valid number or 0 otherwise.
|
|
89
|
+
*/
|
|
90
|
+
{
|
|
91
|
+
// return x if it's a valid number
|
|
92
|
+
if (x == x) return x;
|
|
93
|
+
|
|
94
|
+
// return 0 if the math error flag has previously been set
|
|
95
|
+
// (we only want the first math error identified since others
|
|
96
|
+
// may have propagated from it)
|
|
97
|
+
if (mathError) return 0.0;
|
|
98
|
+
|
|
99
|
+
// construct a math error message
|
|
100
|
+
if ( exprType == TERM )
|
|
101
|
+
{
|
|
102
|
+
sprintf(mathErrorMsg,
|
|
103
|
+
"Ilegal math operation occurred for term:\n %s",
|
|
104
|
+
MSX.Term[index].id);
|
|
105
|
+
}
|
|
106
|
+
else
|
|
107
|
+
{
|
|
108
|
+
sprintf(mathErrorMsg,
|
|
109
|
+
"Ilegal math operation occurred in %s %s expression for species:\n %s",
|
|
110
|
+
elementTxt[element], exprTypeTxt[exprType], MSX.Species[index].id);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// set the math error flag and return 0
|
|
114
|
+
mathError = 1;
|
|
115
|
+
return 0.0;
|
|
116
|
+
}
|