epanet-plus 0.1.0__cp314-cp314-macosx_10_15_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-314-darwin.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 +2429 -0
- epanet_plus/include/epanet_plus.h +9 -0
- epanet_plus-0.1.0.dist-info/METADATA +153 -0
- epanet_plus-0.1.0.dist-info/RECORD +106 -0
- epanet_plus-0.1.0.dist-info/WHEEL +6 -0
- epanet_plus-0.1.0.dist-info/licenses/LICENSE +21 -0
- epanet_plus-0.1.0.dist-info/top_level.txt +11 -0
- examples/basic_usage.py +35 -0
- examples/epanet_msx.py +35 -0
- python-extension/ext.c +344 -0
- python-extension/pyepanet.c +2150 -0
- python-extension/pyepanet.h +144 -0
- python-extension/pyepanet2.c +1835 -0
- python-extension/pyepanet2.h +142 -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
epanet-msx-src/msxtank.c
ADDED
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
/******************************************************************************
|
|
2
|
+
** MODULE: MSXTANK.C
|
|
3
|
+
** PROJECT: EPANET-MSX
|
|
4
|
+
** DESCRIPTION: Storage tank mixing 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 <math.h>
|
|
14
|
+
|
|
15
|
+
#include "msxtypes.h"
|
|
16
|
+
|
|
17
|
+
// External variables
|
|
18
|
+
//--------------------
|
|
19
|
+
extern MSXproject MSX; // MSX project data
|
|
20
|
+
|
|
21
|
+
// Imported functions
|
|
22
|
+
//--------------------
|
|
23
|
+
extern void MSXqual_removeSeg(Pseg seg);
|
|
24
|
+
extern Pseg MSXqual_getFreeSeg(double v, double c[]);
|
|
25
|
+
extern void MSXqual_addSeg(int k, Pseg seg);
|
|
26
|
+
extern int MSXqual_isSame(double c1[], double c2[]);
|
|
27
|
+
extern int MSXchem_equil(int zone, int k, double *c);
|
|
28
|
+
extern void MSXqual_reversesegs(int k);
|
|
29
|
+
|
|
30
|
+
// Exported functions
|
|
31
|
+
//--------------------
|
|
32
|
+
void MSXtank_mix1(int i, double vin, double *massin, double vnet);
|
|
33
|
+
void MSXtank_mix2(int i, double vin, double *massin, double vnet);
|
|
34
|
+
void MSXtank_mix3(int i, double vin, double *massin, double vnet);
|
|
35
|
+
void MSXtank_mix4(int i, double vin, double *massin, double vnet);
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
//=============================================================================
|
|
39
|
+
|
|
40
|
+
void MSXtank_mix1(int i, double vin, double *massin, double vnet)
|
|
41
|
+
/*
|
|
42
|
+
** Purpose:
|
|
43
|
+
** computes new WQ at end of time step in a completely mixed tank
|
|
44
|
+
** (after contents have been reacted).
|
|
45
|
+
**
|
|
46
|
+
** Input:
|
|
47
|
+
** i = tank index
|
|
48
|
+
** vin = volume of inflow to tank (ft3)
|
|
49
|
+
** massin = massinflow
|
|
50
|
+
** vnet = inflow - outflow
|
|
51
|
+
*/
|
|
52
|
+
{
|
|
53
|
+
int k, m, n;
|
|
54
|
+
double c;
|
|
55
|
+
double vnew;
|
|
56
|
+
Pseg seg;
|
|
57
|
+
|
|
58
|
+
// --- blend inflow with contents
|
|
59
|
+
|
|
60
|
+
n = MSX.Tank[i].node;
|
|
61
|
+
k = MSX.Nobjects[LINK] + i;
|
|
62
|
+
seg = MSX.FirstSeg[k];
|
|
63
|
+
if (seg)
|
|
64
|
+
{
|
|
65
|
+
vnew = seg->v + vin;
|
|
66
|
+
for (m = 1; m <= MSX.Nobjects[SPECIES]; m++)
|
|
67
|
+
{
|
|
68
|
+
if (MSX.Species[m].type != BULK) continue;
|
|
69
|
+
c = seg->c[m];
|
|
70
|
+
if (vnew > 0.0)
|
|
71
|
+
c = (c*seg->v*LperFT3+massin[m])/(vnew*LperFT3);
|
|
72
|
+
|
|
73
|
+
c = MAX(0.0, c);
|
|
74
|
+
seg->c[m] = c;
|
|
75
|
+
MSX.Tank[i].c[m] = c;
|
|
76
|
+
}
|
|
77
|
+
seg->v += vnet;
|
|
78
|
+
seg->v = MAX(0, seg->v);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// --- update species equilibrium
|
|
82
|
+
|
|
83
|
+
if ( vin > 0.0 ) MSXchem_equil(NODE, i, MSX.Tank[i].c);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
//=============================================================================
|
|
87
|
+
|
|
88
|
+
void MSXtank_mix2(int i, double vin, double *massin, double vnet)
|
|
89
|
+
/*
|
|
90
|
+
** Purpose: 2-compartment tank model
|
|
91
|
+
**
|
|
92
|
+
** Input: i = tank index
|
|
93
|
+
** vIn = volume of inflow to tank (ft3)
|
|
94
|
+
** massin = massinflow
|
|
95
|
+
** vnet = inflow - outflow
|
|
96
|
+
*/
|
|
97
|
+
{
|
|
98
|
+
int k, m, n;
|
|
99
|
+
double vt, //transferred volume
|
|
100
|
+
vmz; //full mixing zone volume
|
|
101
|
+
Pseg mixzone, // Mixing zone segment
|
|
102
|
+
stagzone; // Stagnant zone segment
|
|
103
|
+
|
|
104
|
+
// --- find inflows & outflows
|
|
105
|
+
|
|
106
|
+
n = MSX.Tank[i].node;
|
|
107
|
+
|
|
108
|
+
// --- get segments for each zone
|
|
109
|
+
|
|
110
|
+
k = MSX.Nobjects[LINK] + i;
|
|
111
|
+
mixzone = MSX.LastSeg[k];
|
|
112
|
+
stagzone = MSX.FirstSeg[k];
|
|
113
|
+
if (mixzone == NULL || stagzone == NULL) return;
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
// Full mixing zone volume
|
|
117
|
+
vmz = MSX.Tank[i].vMix;
|
|
118
|
+
|
|
119
|
+
vt = 0.0;
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
// --- case of net filling (vnet > 0)
|
|
123
|
+
|
|
124
|
+
if (vnet > 0.0)
|
|
125
|
+
{
|
|
126
|
+
vt = MAX(0.0, (mixzone->v + vnet - vmz));
|
|
127
|
+
if (vin > 0)
|
|
128
|
+
{
|
|
129
|
+
for (m = 1; m <= MSX.Nobjects[SPECIES]; m++)
|
|
130
|
+
{
|
|
131
|
+
if (MSX.Species[m].type != BULK) continue;
|
|
132
|
+
|
|
133
|
+
// --- new quality in mixing zone
|
|
134
|
+
mixzone->c[m] = (mixzone->c[m] * mixzone->v * LperFT3 + massin[m]) / ((mixzone->v + vin)*LperFT3);
|
|
135
|
+
mixzone->c[m] = MAX(0.0, mixzone->c[m]);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (vt > 0)
|
|
139
|
+
{
|
|
140
|
+
for (m = 1; m <= MSX.Nobjects[SPECIES]; m++)
|
|
141
|
+
{
|
|
142
|
+
if (MSX.Species[m].type != BULK) continue;
|
|
143
|
+
|
|
144
|
+
// --- new quality in stagnant zone
|
|
145
|
+
|
|
146
|
+
stagzone->c[m] = (stagzone->c[m] * stagzone->v + mixzone->c[m] * vt) / (stagzone->v + vt);
|
|
147
|
+
stagzone->c[m] = MAX(0.0, stagzone->c[m]);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
else if (vnet < 0) //tank is draining
|
|
155
|
+
{
|
|
156
|
+
if (stagzone->v > 0.0) vt = MIN(stagzone->v, (-vnet));
|
|
157
|
+
if (vin + vt > 0.0)
|
|
158
|
+
{
|
|
159
|
+
for (m = 1; m <= MSX.Nobjects[SPECIES]; m++)
|
|
160
|
+
{
|
|
161
|
+
if (MSX.Species[m].type != BULK) continue;
|
|
162
|
+
|
|
163
|
+
// --- new quality in mixing zone
|
|
164
|
+
mixzone->c[m] = (mixzone->c[m] * mixzone->v * LperFT3 + massin[m] + stagzone->c[m]*vt*LperFT3) / ((mixzone->v + vin + vt)*LperFT3);
|
|
165
|
+
mixzone->c[m] = MAX(0.0, mixzone->c[m]);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Update segment volumes
|
|
171
|
+
if (vt > 0.0)
|
|
172
|
+
{
|
|
173
|
+
mixzone->v = vmz;
|
|
174
|
+
if (vnet > 0.0) stagzone->v += vt;
|
|
175
|
+
else stagzone->v = MAX(0.0, ((stagzone->v) - vt));
|
|
176
|
+
}
|
|
177
|
+
else
|
|
178
|
+
{
|
|
179
|
+
mixzone->v += vnet;
|
|
180
|
+
mixzone->v = MIN(mixzone->v, vmz);
|
|
181
|
+
mixzone->v = MAX(0.0, mixzone->v);
|
|
182
|
+
stagzone->v = 0.0;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (mixzone->v > 0.0) MSXchem_equil(NODE, i, mixzone->c);
|
|
186
|
+
if (stagzone->v > 0.0) MSXchem_equil(NODE, i, stagzone->c);
|
|
187
|
+
|
|
188
|
+
// --- use quality of mixed compartment (mixzone) to represent quality
|
|
189
|
+
// of tank since this is where outflow begins to flow from
|
|
190
|
+
|
|
191
|
+
for (m=1; m<=MSX.Nobjects[SPECIES]; m++) MSX.Tank[i].c[m] = mixzone->c[m];
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
//=============================================================================
|
|
195
|
+
|
|
196
|
+
void MSXtank_mix3(int i, double vin, double *massin, double vnet)
|
|
197
|
+
/*
|
|
198
|
+
** Purpose: computes concentrations in the segments that form a
|
|
199
|
+
** first-in-first-out (FIFO) tank model.
|
|
200
|
+
**
|
|
201
|
+
** Input: i = tank index
|
|
202
|
+
** vIn = volume of inflow to tank (ft3)
|
|
203
|
+
** massin = mass inflow
|
|
204
|
+
** vnet = inflow - outflow
|
|
205
|
+
*/
|
|
206
|
+
{
|
|
207
|
+
int k, m, n;
|
|
208
|
+
double vout, vseg, vsum;
|
|
209
|
+
Pseg seg;
|
|
210
|
+
|
|
211
|
+
// --- find inflows & outflows
|
|
212
|
+
|
|
213
|
+
k = MSX.Nobjects[LINK] + i;
|
|
214
|
+
n = MSX.Tank[i].node;
|
|
215
|
+
vout = vin - vnet;
|
|
216
|
+
|
|
217
|
+
if (MSX.LastSeg[k] == NULL || MSX.FirstSeg[k] == NULL) return;
|
|
218
|
+
|
|
219
|
+
if (vin > 0.0)
|
|
220
|
+
{
|
|
221
|
+
|
|
222
|
+
// --- quality is the same, so just add flow volume to last seg
|
|
223
|
+
seg = MSX.LastSeg[k];
|
|
224
|
+
for (m = 1; m <= MSX.Nobjects[SPECIES]; m++)
|
|
225
|
+
{
|
|
226
|
+
MSX.C1[m] = massin[m] / (vin*LperFT3);
|
|
227
|
+
}
|
|
228
|
+
if (seg != NULL && MSXqual_isSame(seg->c, MSX.C1))
|
|
229
|
+
{
|
|
230
|
+
for (m = 1; m <= MSX.Nobjects[SPECIES]; m++)
|
|
231
|
+
seg->c[m] = (seg->c[m] * seg->v + MSX.C1[m] * vin) / (seg->v + vin);
|
|
232
|
+
seg->v += vin;
|
|
233
|
+
}
|
|
234
|
+
// --- Otherwise add a new seg to tank
|
|
235
|
+
else
|
|
236
|
+
{
|
|
237
|
+
seg = MSXqual_getFreeSeg(vin, MSX.C1);
|
|
238
|
+
MSXqual_addSeg(k, seg);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
// --- initialize outflow volume & concentration
|
|
244
|
+
|
|
245
|
+
vsum = 0.0;
|
|
246
|
+
for (m=1; m<=MSX.Nobjects[SPECIES]; m++)
|
|
247
|
+
MSX.C1[m] = 0.0;
|
|
248
|
+
// --- withdraw flow from first segment
|
|
249
|
+
|
|
250
|
+
while (vout > 0.0)
|
|
251
|
+
{
|
|
252
|
+
// --- get volume of current first segment
|
|
253
|
+
seg = MSX.FirstSeg[k];
|
|
254
|
+
if (seg == NULL) break;
|
|
255
|
+
vseg = seg->v;
|
|
256
|
+
vseg = MIN(vseg, vout);
|
|
257
|
+
if ( seg == MSX.LastSeg[k] ) vseg = vout;
|
|
258
|
+
|
|
259
|
+
// --- update mass & volume removed
|
|
260
|
+
vsum += vseg;
|
|
261
|
+
for (m=1; m<=MSX.Nobjects[SPECIES]; m++)
|
|
262
|
+
{
|
|
263
|
+
MSX.C1[m] += (seg->c[m]) * vseg * LperFT3;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// --- decrease vOut by volume of first segment
|
|
267
|
+
vout -= vseg;
|
|
268
|
+
|
|
269
|
+
// --- remove segment if all its volume is consumed
|
|
270
|
+
if (vout >= 0.0 && vseg >= seg->v)
|
|
271
|
+
{
|
|
272
|
+
if (seg->prev)
|
|
273
|
+
{
|
|
274
|
+
MSX.FirstSeg[k] = seg->prev;
|
|
275
|
+
// MSXqual_removeSeg(seg);
|
|
276
|
+
seg->prev = MSX.FreeSeg;
|
|
277
|
+
MSX.FreeSeg = seg;
|
|
278
|
+
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// --- otherwise just adjust volume of first segment
|
|
283
|
+
else seg->v -= vseg;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// --- use quality from first segment to represent overall
|
|
287
|
+
// quality of tank since this is where outflow flows from
|
|
288
|
+
|
|
289
|
+
for (m=1; m<=MSX.Nobjects[SPECIES]; m++)
|
|
290
|
+
{
|
|
291
|
+
if (vsum > 0.0) MSX.Tank[i].c[m] = MSX.C1[m]/(vsum * LperFT3);
|
|
292
|
+
else if (MSX.FirstSeg[k] == NULL) MSX.Tank[i].c[m] = 0.0;
|
|
293
|
+
else MSX.Tank[i].c[m] = MSX.FirstSeg[k]->c[m];
|
|
294
|
+
}
|
|
295
|
+
// --- add new last segment for new flow entering tank
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
//=============================================================================
|
|
299
|
+
|
|
300
|
+
void MSXtank_mix4(int i, double vin, double *massin, double vnet)
|
|
301
|
+
/*
|
|
302
|
+
**----------------------------------------------------------
|
|
303
|
+
** Input: i = tank index
|
|
304
|
+
** vin = volume of inflow to tank (ft3)
|
|
305
|
+
** massin = mass inflow
|
|
306
|
+
** vnet = vin - vout
|
|
307
|
+
** Output: none
|
|
308
|
+
** Purpose: Last In-First Out (LIFO) tank model
|
|
309
|
+
**----------------------------------------------------------
|
|
310
|
+
*/
|
|
311
|
+
{
|
|
312
|
+
int k, m, n;
|
|
313
|
+
double vsum, vseg;
|
|
314
|
+
Pseg seg;
|
|
315
|
+
|
|
316
|
+
// --- find inflows & outflows
|
|
317
|
+
|
|
318
|
+
k = MSX.Nobjects[LINK] + i;
|
|
319
|
+
n = MSX.Tank[i].node;
|
|
320
|
+
|
|
321
|
+
if (MSX.LastSeg[k] == NULL || MSX.FirstSeg[k] == NULL) return;
|
|
322
|
+
|
|
323
|
+
// --- keep track of total volume & mass removed from tank
|
|
324
|
+
|
|
325
|
+
vsum = 0.0;
|
|
326
|
+
if (vin > 0)
|
|
327
|
+
{
|
|
328
|
+
for (m = 1; m <= MSX.Nobjects[SPECIES]; m++)
|
|
329
|
+
MSX.C1[m] = massin[m] / (vin*LperFT3);
|
|
330
|
+
}
|
|
331
|
+
else
|
|
332
|
+
{
|
|
333
|
+
for (m = 1; m <= MSX.Nobjects[SPECIES]; m++)
|
|
334
|
+
MSX.C1[m] = 0;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
for (m = 1; m <= MSX.Nobjects[SPECIES]; m++)
|
|
338
|
+
MSX.Tank[i].c[m] = MSX.LastSeg[k]->c[m];
|
|
339
|
+
|
|
340
|
+
seg = MSX.LastSeg[k];
|
|
341
|
+
// --- if tank filling, then create a new last segment
|
|
342
|
+
if ( vnet > 0.0 )
|
|
343
|
+
{
|
|
344
|
+
|
|
345
|
+
// --- inflow quality = last segment quality so just expand last segment
|
|
346
|
+
if (seg != NULL && MSXqual_isSame(seg->c, MSX.C1))
|
|
347
|
+
{
|
|
348
|
+
for (m = 1; m <= MSX.Nobjects[SPECIES]; m++)
|
|
349
|
+
seg->c[m] = (seg->c[m] * seg->v + MSX.C1[m] * vnet) / (seg->v + vnet);
|
|
350
|
+
seg->v += vnet;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// --- otherwise add a new last segment to tank
|
|
354
|
+
|
|
355
|
+
else
|
|
356
|
+
{
|
|
357
|
+
seg = MSXqual_getFreeSeg(vnet, MSX.C1);
|
|
358
|
+
MSXqual_addSeg(k, seg);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// --- quality of tank is that of inflow
|
|
362
|
+
|
|
363
|
+
for (m = 1; m <= MSX.Nobjects[SPECIES]; m++)
|
|
364
|
+
MSX.Tank[i].c[m] = MSX.LastSeg[k]->c[m];
|
|
365
|
+
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// --- if tank emptying then remove last segments until vNet consumed
|
|
369
|
+
|
|
370
|
+
else if (vnet < 0.0)
|
|
371
|
+
{
|
|
372
|
+
for (m = 1; m <= MSX.Nobjects[SPECIES]; m++)
|
|
373
|
+
MSX.C1[m] = 0;
|
|
374
|
+
// --- keep removing volume from last segments until vNet is removed
|
|
375
|
+
vsum = 0;
|
|
376
|
+
vnet = -vnet;
|
|
377
|
+
MSXqual_reversesegs(k);
|
|
378
|
+
while (vnet > 0.0)
|
|
379
|
+
{
|
|
380
|
+
|
|
381
|
+
// --- get volume of current last segment
|
|
382
|
+
seg = MSX.FirstSeg[k];
|
|
383
|
+
if ( seg == NULL ) break;
|
|
384
|
+
vseg = seg->v;
|
|
385
|
+
vseg = MIN(vseg, vnet);
|
|
386
|
+
if ( seg == MSX.LastSeg[k] ) vseg = vnet;
|
|
387
|
+
|
|
388
|
+
// --- update mass & volume removed
|
|
389
|
+
vsum += vseg;
|
|
390
|
+
for (m=1; m<=MSX.Nobjects[SPECIES]; m++)
|
|
391
|
+
MSX.C1[m] += (seg->c[m])*vseg*LperFT3;
|
|
392
|
+
|
|
393
|
+
// --- reduce vNet by volume of last segment
|
|
394
|
+
vnet -= vseg;
|
|
395
|
+
|
|
396
|
+
// --- remove segment if all its volume is used up
|
|
397
|
+
if (vnet >= 0.0 && vseg >= seg->v)
|
|
398
|
+
{
|
|
399
|
+
if (seg->prev)
|
|
400
|
+
{
|
|
401
|
+
MSX.FirstSeg[k] = seg->prev;
|
|
402
|
+
MSXqual_removeSeg(seg);
|
|
403
|
+
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
// --- otherwise just reduce volume of last segment
|
|
407
|
+
else
|
|
408
|
+
{
|
|
409
|
+
seg->v -= vseg;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
MSXqual_reversesegs(k);
|
|
413
|
+
// --- tank quality is mixture of flow released and any inflow
|
|
414
|
+
|
|
415
|
+
vsum = vsum + vin;
|
|
416
|
+
for (m=1; m<=MSX.Nobjects[SPECIES]; m++)
|
|
417
|
+
{
|
|
418
|
+
if (vsum > 0.0)
|
|
419
|
+
MSX.Tank[i].c[m] = (MSX.C1[m] + massin[m]) / (vsum*LperFT3);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|