epanet-plus 0.0.1__cp310-cp310-musllinux_1_2_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (105) hide show
  1. docs/conf.py +67 -0
  2. epanet-msx-src/dispersion.h +27 -0
  3. epanet-msx-src/hash.c +107 -0
  4. epanet-msx-src/hash.h +28 -0
  5. epanet-msx-src/include/epanetmsx.h +104 -0
  6. epanet-msx-src/include/epanetmsx_export.h +42 -0
  7. epanet-msx-src/mathexpr.c +937 -0
  8. epanet-msx-src/mathexpr.h +39 -0
  9. epanet-msx-src/mempool.c +204 -0
  10. epanet-msx-src/mempool.h +24 -0
  11. epanet-msx-src/msxchem.c +1285 -0
  12. epanet-msx-src/msxcompiler.c +368 -0
  13. epanet-msx-src/msxdict.h +42 -0
  14. epanet-msx-src/msxdispersion.c +586 -0
  15. epanet-msx-src/msxerr.c +116 -0
  16. epanet-msx-src/msxfile.c +260 -0
  17. epanet-msx-src/msxfuncs.c +175 -0
  18. epanet-msx-src/msxfuncs.h +35 -0
  19. epanet-msx-src/msxinp.c +1504 -0
  20. epanet-msx-src/msxout.c +398 -0
  21. epanet-msx-src/msxproj.c +791 -0
  22. epanet-msx-src/msxqual.c +2011 -0
  23. epanet-msx-src/msxrpt.c +400 -0
  24. epanet-msx-src/msxtank.c +422 -0
  25. epanet-msx-src/msxtoolkit.c +1164 -0
  26. epanet-msx-src/msxtypes.h +551 -0
  27. epanet-msx-src/msxutils.c +524 -0
  28. epanet-msx-src/msxutils.h +56 -0
  29. epanet-msx-src/newton.c +158 -0
  30. epanet-msx-src/newton.h +34 -0
  31. epanet-msx-src/rk5.c +287 -0
  32. epanet-msx-src/rk5.h +39 -0
  33. epanet-msx-src/ros2.c +293 -0
  34. epanet-msx-src/ros2.h +35 -0
  35. epanet-msx-src/smatrix.c +816 -0
  36. epanet-msx-src/smatrix.h +29 -0
  37. epanet-src/AUTHORS +60 -0
  38. epanet-src/LICENSE +21 -0
  39. epanet-src/enumstxt.h +151 -0
  40. epanet-src/epanet.c +5937 -0
  41. epanet-src/epanet2.c +961 -0
  42. epanet-src/epanet2.def +131 -0
  43. epanet-src/errors.dat +79 -0
  44. epanet-src/flowbalance.c +186 -0
  45. epanet-src/funcs.h +219 -0
  46. epanet-src/genmmd.c +1000 -0
  47. epanet-src/hash.c +177 -0
  48. epanet-src/hash.h +28 -0
  49. epanet-src/hydcoeffs.c +1303 -0
  50. epanet-src/hydraul.c +1164 -0
  51. epanet-src/hydsolver.c +781 -0
  52. epanet-src/hydstatus.c +442 -0
  53. epanet-src/include/epanet2.h +466 -0
  54. epanet-src/include/epanet2_2.h +1962 -0
  55. epanet-src/include/epanet2_enums.h +518 -0
  56. epanet-src/inpfile.c +884 -0
  57. epanet-src/input1.c +672 -0
  58. epanet-src/input2.c +970 -0
  59. epanet-src/input3.c +2265 -0
  60. epanet-src/leakage.c +527 -0
  61. epanet-src/mempool.c +146 -0
  62. epanet-src/mempool.h +24 -0
  63. epanet-src/output.c +853 -0
  64. epanet-src/project.c +1691 -0
  65. epanet-src/quality.c +695 -0
  66. epanet-src/qualreact.c +800 -0
  67. epanet-src/qualroute.c +696 -0
  68. epanet-src/report.c +1559 -0
  69. epanet-src/rules.c +1500 -0
  70. epanet-src/smatrix.c +871 -0
  71. epanet-src/text.h +508 -0
  72. epanet-src/types.h +928 -0
  73. epanet-src/util/cstr_helper.c +59 -0
  74. epanet-src/util/cstr_helper.h +38 -0
  75. epanet-src/util/errormanager.c +92 -0
  76. epanet-src/util/errormanager.h +39 -0
  77. epanet-src/util/filemanager.c +212 -0
  78. epanet-src/util/filemanager.h +81 -0
  79. epanet-src/validate.c +408 -0
  80. epanet.cpython-310-x86_64-linux-gnu.so +0 -0
  81. epanet_plus/VERSION +1 -0
  82. epanet_plus/__init__.py +8 -0
  83. epanet_plus/epanet_plus.c +118 -0
  84. epanet_plus/epanet_toolkit.py +2730 -0
  85. epanet_plus/epanet_wrapper.py +2414 -0
  86. epanet_plus/include/epanet_plus.h +9 -0
  87. epanet_plus-0.0.1.dist-info/METADATA +152 -0
  88. epanet_plus-0.0.1.dist-info/RECORD +105 -0
  89. epanet_plus-0.0.1.dist-info/WHEEL +5 -0
  90. epanet_plus-0.0.1.dist-info/licenses/LICENSE +21 -0
  91. epanet_plus-0.0.1.dist-info/top_level.txt +11 -0
  92. examples/basic_usage.py +35 -0
  93. python-extension/ext.c +344 -0
  94. python-extension/pyepanet.c +2133 -0
  95. python-extension/pyepanet.h +143 -0
  96. python-extension/pyepanet2.c +1823 -0
  97. python-extension/pyepanet2.h +141 -0
  98. python-extension/pyepanet_plus.c +37 -0
  99. python-extension/pyepanet_plus.h +4 -0
  100. python-extension/pyepanetmsx.c +388 -0
  101. python-extension/pyepanetmsx.h +35 -0
  102. tests/test_epanet.py +16 -0
  103. tests/test_epanetmsx.py +36 -0
  104. tests/test_epyt.py +114 -0
  105. tests/test_load_inp_from_buffer.py +18 -0
@@ -0,0 +1,1285 @@
1
+ /*******************************************************************************
2
+ ** MODULE: MSXCHEM.C
3
+ ** PROJECT: EPANET-MSX
4
+ ** DESCRIPTION: Water quality chemistry functions.
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
+ #include <math.h>
15
+ #include <stdlib.h>
16
+
17
+ #include "msxtypes.h"
18
+ #include "rk5.h"
19
+ #include "ros2.h"
20
+ #include "newton.h"
21
+ #include "msxfuncs.h"
22
+
23
+ // External variables
24
+ //--------------------
25
+ extern MSXproject MSX; // MSX project data
26
+
27
+
28
+ // Constants
29
+ //-----------
30
+ int MAXIT = 20; // Max. number of iterations used
31
+ // in nonlinear equation solver
32
+ int NUMSIG = 3; // Number of significant digits in
33
+ // nonlinear equation solver error
34
+
35
+ // Local variables
36
+ //-----------------
37
+ static Pseg TheSeg; // Current water quality segment
38
+ static int TheLink; // Index of current link
39
+ static int TheNode; // Index of current node
40
+ static int TheTank; // Index of current tank
41
+ static int NumSpecies; // Total number of species
42
+ static int NumPipeRateSpecies; // Number of species with pipe rates
43
+ static int NumTankRateSpecies; // Number of species with tank rates
44
+ static int NumPipeFormulaSpecies; // Number of species with pipe formulas
45
+ static int NumTankFormulaSpecies; // Number of species with tank formulas
46
+ static int NumPipeEquilSpecies; // Number of species with pipe equilibria
47
+ static int NumTankEquilSpecies; // Number of species with tank equilibria
48
+ static int *PipeRateSpecies; // Species governed by pipe reactions
49
+ static int *TankRateSpecies; // Species governed by tank reactions
50
+ static int *PipeEquilSpecies; // Species governed by pipe equilibria
51
+ static int *TankEquilSpecies; // Species governed by tank equilibria
52
+ static int LastIndex[MAX_OBJECTS]; // Last index of given type of variable
53
+ static double *Atol; // Absolute concentration tolerances
54
+ static double *Rtol; // Relative concentration tolerances
55
+ static double *Yrate; // Rate species concentrations
56
+ static double *Yequil; // Equilibrium species concentrations
57
+ static double HydVar[MAX_HYD_VARS]; // Values of hydraulic variables
58
+ static double *F; // Function values
59
+ static double *ChemC1;
60
+
61
+ #pragma omp threadprivate(TheSeg, TheLink, TheNode, TheTank, Yrate, Yequil, HydVar, F, ChemC1)
62
+
63
+ // Exported functions
64
+ //--------------------
65
+ int MSXchem_open(void);
66
+ int MSXchem_react(double dt);
67
+ int MSXchem_equil(int zone, int k, double *c);
68
+ char* MSXchem_getVariableStr(int i, char *s);
69
+ void MSXchem_close(void);
70
+
71
+ // Imported functions
72
+ //-------------------
73
+ int MSXcompiler_open(void);
74
+ void MSXcompiler_close(void);
75
+ double MSXerr_validate(double x, int index, int element, int exprType);
76
+
77
+ // Local functions
78
+ //-----------------
79
+ static void setSpeciesChemistry(void);
80
+ static void setTankChemistry(void);
81
+ //static void evalHydVariables(int k);
82
+ static int evalPipeReactions(int k, double dt);
83
+ static int evalTankReactions(int k, double dt);
84
+ static int evalPipeEquil(double *c);
85
+ static int evalTankEquil(double *c);
86
+ static void evalPipeFormulas(double *c);
87
+ static void evalTankFormulas(double *c);
88
+ static double getPipeVariableValue(int i);
89
+ static double getTankVariableValue(int i);
90
+ static void getPipeDcDt(double t, double y[], int n, double deriv[]);
91
+ static void getTankDcDt(double t, double y[], int n, double deriv[]);
92
+ static void getPipeEquil(double t, double y[], int n, double f[]);
93
+ static void getTankEquil(double t, double y[], int n, double f[]);
94
+ static int isValidNumber(double x); //(L.Rossman - 11/03/10)
95
+
96
+
97
+ //=============================================================================
98
+
99
+ int MSXchem_open()
100
+ /*
101
+ ** Purpose:
102
+ ** opens the multi-species chemistry system.
103
+ **
104
+ ** Input:
105
+ ** none.
106
+ **
107
+ ** Returns:
108
+ ** an error code (0 if no error).
109
+ */
110
+ {
111
+ int m;
112
+ int numWallSpecies;
113
+ int numBulkSpecies;
114
+ int numTankExpr;
115
+ int numPipeExpr;
116
+ int errcode = 0;
117
+
118
+ // --- allocate memory
119
+
120
+ PipeRateSpecies = NULL;
121
+ TankRateSpecies = NULL;
122
+ PipeEquilSpecies = NULL;
123
+ TankEquilSpecies = NULL;
124
+ Atol = NULL;
125
+ Rtol = NULL;
126
+ Yrate = NULL;
127
+ Yequil = NULL;
128
+ NumSpecies = MSX.Nobjects[SPECIES];
129
+ m = NumSpecies + 1;
130
+ PipeRateSpecies = (int*)calloc(m, sizeof(int));
131
+ TankRateSpecies = (int*)calloc(m, sizeof(int));
132
+ PipeEquilSpecies = (int*)calloc(m, sizeof(int));
133
+ TankEquilSpecies = (int*)calloc(m, sizeof(int));
134
+ Atol = (double*)calloc(m, sizeof(double));
135
+ Rtol = (double*)calloc(m, sizeof(double));
136
+ CALL(errcode, MEMCHECK(PipeRateSpecies));
137
+ CALL(errcode, MEMCHECK(TankRateSpecies));
138
+ CALL(errcode, MEMCHECK(PipeEquilSpecies));
139
+ CALL(errcode, MEMCHECK(TankEquilSpecies));
140
+ CALL(errcode, MEMCHECK(Atol));
141
+ CALL(errcode, MEMCHECK(Rtol));
142
+
143
+ #pragma omp parallel
144
+ {
145
+ Yrate = (double*)calloc(m, sizeof(double));
146
+ Yequil = (double*)calloc(m, sizeof(double));
147
+ F = (double*)calloc(m, sizeof(double));
148
+ ChemC1 = (double*)calloc(m, sizeof(double));
149
+ #pragma omp critical
150
+ {
151
+ CALL(errcode, MEMCHECK(Yrate));
152
+ CALL(errcode, MEMCHECK(Yequil));
153
+ CALL(errcode, MEMCHECK(F));
154
+ CALL(errcode, MEMCHECK(ChemC1));
155
+ }
156
+ }
157
+ if ( errcode ) return errcode;
158
+
159
+ // --- assign species to each type of chemical expression
160
+
161
+ setSpeciesChemistry();
162
+ numPipeExpr = NumPipeRateSpecies + NumPipeFormulaSpecies + NumPipeEquilSpecies;
163
+ numTankExpr = NumTankRateSpecies + NumTankFormulaSpecies + NumTankEquilSpecies;
164
+
165
+ // --- use pipe chemistry for tanks if latter was not supplied
166
+
167
+ if ( numTankExpr == 0 )
168
+ {
169
+ setTankChemistry();
170
+ numTankExpr = numPipeExpr;
171
+ }
172
+
173
+ // --- check if enough equations were specified
174
+
175
+ numWallSpecies = 0;
176
+ numBulkSpecies = 0;
177
+ for (m=1; m<=NumSpecies; m++)
178
+ {
179
+ if ( MSX.Species[m].type == WALL ) numWallSpecies++;
180
+ if ( MSX.Species[m].type == BULK ) numBulkSpecies++;
181
+ }
182
+ if ( numPipeExpr != NumSpecies ) return ERR_NUM_PIPE_EXPR;
183
+ if ( numTankExpr != numBulkSpecies ) return ERR_NUM_TANK_EXPR;
184
+
185
+ // --- open the ODE solver;
186
+ // arguments are max. number of ODE's,
187
+ // max. number of steps to be taken,
188
+ // 1 if automatic step sizing used (or 0 if not used)
189
+
190
+ if ( MSX.Solver == RK5 )
191
+ {
192
+ if ( rk5_open(NumSpecies, 1000, 1) == FALSE )
193
+ return ERR_INTEGRATOR_OPEN;
194
+ }
195
+ if ( MSX.Solver == ROS2 )
196
+ {
197
+ if ( ros2_open(NumSpecies, 1) == FALSE )
198
+ return ERR_INTEGRATOR_OPEN;
199
+ }
200
+
201
+ // --- open the algebraic eqn. solver
202
+
203
+ m = MAX(NumPipeEquilSpecies, NumTankEquilSpecies);
204
+ if ( newton_open(m) == FALSE ) return ERR_NEWTON_OPEN;
205
+
206
+ // --- assign entries to LastIndex array
207
+
208
+ LastIndex[SPECIES] = MSX.Nobjects[SPECIES];
209
+ LastIndex[TERM] = LastIndex[SPECIES] + MSX.Nobjects[TERM];
210
+ LastIndex[PARAMETER] = LastIndex[TERM] + MSX.Nobjects[PARAMETER];
211
+ LastIndex[CONSTANT] = LastIndex[PARAMETER] + MSX.Nobjects[CONSTANT];
212
+
213
+ // --- compile chemistry function dynamic library if specified
214
+
215
+ if ( MSX.Compiler )
216
+ {
217
+ errcode = MSXcompiler_open();
218
+ if ( errcode ) return errcode;
219
+ }
220
+ return 0;
221
+ }
222
+
223
+ //=============================================================================
224
+
225
+ void MSXchem_close()
226
+ /*
227
+ ** Purpose:
228
+ ** closes the multi-species chemistry system.
229
+ **
230
+ ** Input:
231
+ ** none.
232
+ */
233
+ {
234
+ if (MSX.Compiler) MSXcompiler_close();
235
+ if (MSX.Solver == RK5) rk5_close();
236
+ if (MSX.Solver == ROS2) ros2_close();
237
+ newton_close();
238
+ FREE(PipeRateSpecies);
239
+ FREE(TankRateSpecies);
240
+ FREE(PipeEquilSpecies);
241
+ FREE(TankEquilSpecies);
242
+ FREE(Atol);
243
+ FREE(Rtol);
244
+
245
+ #pragma omp parallel
246
+ {
247
+ FREE(ChemC1);
248
+ FREE(Yrate);
249
+ FREE(Yequil);
250
+ FREE(F);
251
+ }
252
+
253
+ }
254
+
255
+ //=============================================================================
256
+
257
+ int MSXchem_react(double dt)
258
+ /*
259
+ ** Purpose:
260
+ ** computes reactions in all pipes and tanks.
261
+ **
262
+ ** Input:
263
+ ** dt = current WQ time step (sec).
264
+ **
265
+ ** Returns:
266
+ ** an error code or 0 if no error.
267
+ */
268
+ {
269
+ int k, m;
270
+ int errcode = 0;
271
+
272
+ // --- save tolerances of pipe rate species
273
+
274
+ for (k=1; k<=NumPipeRateSpecies; k++)
275
+ {
276
+ m = PipeRateSpecies[k];
277
+ Atol[k] = MSX.Species[m].aTol;
278
+ Rtol[k] = MSX.Species[m].rTol;
279
+ }
280
+
281
+ // --- examine each link
282
+ #pragma omp parallel
283
+ {
284
+ #pragma omp for private(k)
285
+ for (k = 1; k <= MSX.Nobjects[LINK]; k++)
286
+ {
287
+ // --- skip non-pipe links
288
+
289
+ if (MSX.Link[k].len == 0.0) continue;
290
+
291
+ // --- evaluate hydraulic variables
292
+
293
+ //evalHydVariables(k);
294
+ for (int hi = 1; hi < MAX_HYD_VARS; hi++)
295
+ HydVar[hi] = MSX.Link[k].HydVar[hi];
296
+ // --- compute pipe reactions
297
+
298
+ errcode = evalPipeReactions(k, dt);
299
+ //if (errcode) return errcode;
300
+ }
301
+ }
302
+ if (errcode) return errcode;
303
+
304
+ // --- save tolerances of tank rate species
305
+
306
+ for (k=1; k<=NumTankRateSpecies; k++)
307
+ {
308
+ m = TankRateSpecies[k];
309
+ Atol[k] = MSX.Species[m].aTol;
310
+ Rtol[k] = MSX.Species[m].rTol;
311
+ }
312
+
313
+ // --- examine each tank
314
+
315
+ for (k=1; k<=MSX.Nobjects[TANK]; k++)
316
+ {
317
+ // --- skip reservoirs
318
+
319
+ if (MSX.Tank[k].a == 0.0) continue;
320
+
321
+ // --- compute tank reactions
322
+
323
+ errcode = evalTankReactions(k, dt);
324
+ if ( errcode ) return errcode;
325
+ }
326
+ return errcode;
327
+ }
328
+
329
+ //=============================================================================
330
+
331
+ int MSXchem_equil(int zone, int k, double *c)
332
+ /*
333
+ ** Purpose:
334
+ ** computes equilibrium concentrations for a set of chemical species.
335
+ **
336
+ ** Input:
337
+ ** zone = reaction zone (NODE or LINK)
338
+ ** k = pipe or tank index
339
+ ** c[] = array of species concentrations
340
+ **
341
+ ** Output:
342
+ ** updated value of c[].
343
+ **
344
+ ** Returns:
345
+ ** an error code or 0 if no errors.
346
+ */
347
+ {
348
+ int errcode = 0;
349
+ if ( zone == LINK )
350
+ {
351
+ TheLink = k;
352
+ for (int vi = 1; vi < MAX_HYD_VARS; vi++)
353
+ HydVar[vi] = MSX.Link[k].HydVar[vi];
354
+ if ( NumPipeEquilSpecies > 0 ) errcode = evalPipeEquil(c);
355
+ evalPipeFormulas(c);
356
+ }
357
+ if ( zone == NODE )
358
+ {
359
+ TheTank = k;
360
+ TheNode = MSX.Tank[k].node;
361
+ if ( NumTankEquilSpecies > 0 ) errcode = evalTankEquil(c);
362
+ evalTankFormulas(c);
363
+ }
364
+ return errcode;
365
+ }
366
+
367
+ //=============================================================================
368
+
369
+ char* MSXchem_getVariableStr(int i, char *s)
370
+ /*
371
+ ** Purpose:
372
+ ** returns a string representation of a variable used in the chemistry
373
+ ** functions appearing in the C source code file used to compile
374
+ ** these functions
375
+ **
376
+ ** Input:
377
+ ** i = variable's index in the LastIndex array
378
+ ** s = string to hold variable's symbol
379
+ **
380
+ ** Output:
381
+ ** returns a pointer to s
382
+ */
383
+ {
384
+ // --- WQ species have index between 1 & # of species
385
+
386
+ if ( i <= LastIndex[SPECIES] ) sprintf(s, "c[%d]", i);
387
+
388
+ // --- intermediate term expressions come next
389
+
390
+ else if ( i <= LastIndex[TERM] )
391
+ {
392
+ i -= LastIndex[TERM-1];
393
+ sprintf(s, "term(%d, c, k, p, h)", i);
394
+ }
395
+
396
+ // --- reaction parameter indexes come after that
397
+
398
+ else if ( i <= LastIndex[PARAMETER] )
399
+ {
400
+ i -= LastIndex[PARAMETER-1];
401
+ sprintf(s, "p[%d]", i);
402
+ }
403
+
404
+ // --- followed by constants
405
+
406
+ else if ( i <= LastIndex[CONSTANT] )
407
+ {
408
+ i -= LastIndex[CONSTANT-1];
409
+ sprintf(s, "k[%d]", i);
410
+ }
411
+
412
+ // --- and finally by hydraulic variables
413
+
414
+ else
415
+ {
416
+ i -= LastIndex[CONSTANT];
417
+ sprintf(s, "h[%d]", i);
418
+ }
419
+ return s;
420
+ }
421
+
422
+ //=============================================================================
423
+
424
+ void setSpeciesChemistry()
425
+ /*
426
+ ** Purpose:
427
+ ** determines which species are described by reaction rate
428
+ ** expressions, equilibrium expressions, or simple formulas.
429
+ **
430
+ ** Input:
431
+ ** none.
432
+ **
433
+ ** Output:
434
+ ** updates arrays of different chemistry types.
435
+ */
436
+ {
437
+ int m;
438
+ NumPipeRateSpecies = 0;
439
+ NumPipeFormulaSpecies = 0;
440
+ NumPipeEquilSpecies = 0;
441
+ NumTankRateSpecies = 0;
442
+ NumTankFormulaSpecies = 0;
443
+ NumTankEquilSpecies = 0;
444
+ for (m=1; m<=NumSpecies; m++)
445
+ {
446
+ switch ( MSX.Species[m].pipeExprType )
447
+ {
448
+ case RATE:
449
+ NumPipeRateSpecies++;
450
+ PipeRateSpecies[NumPipeRateSpecies] = m;
451
+ break;
452
+
453
+ case FORMULA:
454
+ NumPipeFormulaSpecies++;
455
+ break;
456
+
457
+ case EQUIL:
458
+ NumPipeEquilSpecies++;
459
+ PipeEquilSpecies[NumPipeEquilSpecies] = m;
460
+ break;
461
+ }
462
+ switch ( MSX.Species[m].tankExprType )
463
+ {
464
+ case RATE:
465
+ NumTankRateSpecies++;
466
+ TankRateSpecies[NumTankRateSpecies] = m;
467
+ break;
468
+
469
+ case FORMULA:
470
+ NumTankFormulaSpecies++;
471
+ break;
472
+
473
+ case EQUIL:
474
+ NumTankEquilSpecies++;
475
+ TankEquilSpecies[NumTankEquilSpecies] = m;
476
+ break;
477
+ }
478
+ }
479
+ }
480
+
481
+ //=============================================================================
482
+
483
+ void setTankChemistry()
484
+ /*
485
+ ** Purpose:
486
+ ** assigns pipe chemistry expressions to tank chemistry for
487
+ ** each chemical species.
488
+ **
489
+ ** Input:
490
+ ** none.
491
+ **
492
+ ** Output:
493
+ ** updates arrays of different tank chemistry types.
494
+ */
495
+ {
496
+ int m;
497
+ for (m=1; m<=NumSpecies; m++)
498
+ {
499
+ MSX.Species[m].tankExpr = MSX.Species[m].pipeExpr;
500
+ MSX.Species[m].tankExprType = MSX.Species[m].pipeExprType;
501
+ }
502
+ NumTankRateSpecies = NumPipeRateSpecies;
503
+ for (m=1; m<=NumTankRateSpecies; m++)
504
+ {
505
+ TankRateSpecies[m] = PipeRateSpecies[m];
506
+ }
507
+ NumTankFormulaSpecies = NumPipeFormulaSpecies;
508
+ NumTankEquilSpecies = NumPipeEquilSpecies;
509
+ for (m=1; m<=NumTankEquilSpecies; m++)
510
+ {
511
+ TankEquilSpecies[m] = PipeEquilSpecies[m];
512
+ }
513
+ }
514
+
515
+
516
+
517
+ //=============================================================================
518
+
519
+ int evalPipeReactions(int k, double dt)
520
+ /*
521
+ ** Purpose:
522
+ ** updates species concentrations in each WQ segment of a pipe
523
+ ** after reactions occur over time step dt.
524
+ **
525
+ ** Input:
526
+ ** k = link index
527
+ ** dt = time step (sec).
528
+ **
529
+ ** Output:
530
+ ** updates values in the concentration vector C[] associated
531
+ ** with a pipe's WQ segments.
532
+ **
533
+ ** Returns:
534
+ ** an error code or 0 if no error.
535
+ **
536
+ ** Re-written to accommodate compiled functions (1.1)
537
+ */
538
+ {
539
+ int i, m;
540
+ int errcode = 0, ierr = 0;
541
+ double tstep = (double)dt / MSX.Ucf[RATE_UNITS];
542
+ double c, dh;
543
+
544
+ // --- start with the most downstream pipe segment
545
+
546
+ TheLink = k;
547
+ TheSeg = MSX.FirstSeg[TheLink];
548
+ while ( TheSeg )
549
+ {
550
+ for (m = 1; m <= NumSpecies; m++)
551
+ {
552
+ ChemC1[m] = TheSeg->c[m];
553
+ TheSeg->lastc[m] = TheSeg->c[m];
554
+ }
555
+ ierr = 0;
556
+
557
+ // --- react each reacting species over the time step
558
+
559
+ if ( dt > 0.0 )
560
+ {
561
+
562
+ // --- place current concentrations of species that react in vector Yrate
563
+
564
+ for (i=1; i<=NumPipeRateSpecies; i++)
565
+ {
566
+ m = PipeRateSpecies[i];
567
+ Yrate[i] = TheSeg->c[m];
568
+ }
569
+
570
+ // --- Euler integrator
571
+
572
+ if ( MSX.Solver == EUL )
573
+ {
574
+ getPipeDcDt(0, Yrate, NumPipeRateSpecies, Yrate);
575
+ for (i=1; i<=NumPipeRateSpecies; i++)
576
+ {
577
+ m = PipeRateSpecies[i];
578
+ c = TheSeg->c[m] + Yrate[i]*tstep;
579
+ TheSeg->c[m] = MAX(c, 0.0);
580
+ }
581
+ }
582
+
583
+ // --- other integrators
584
+ else
585
+ {
586
+ dh = TheSeg->hstep;
587
+
588
+ // --- Runge-Kutta integrator
589
+
590
+ if ( MSX.Solver == RK5 )
591
+ ierr = rk5_integrate(Yrate, NumPipeRateSpecies, 0, tstep,
592
+ &dh, Atol, Rtol, getPipeDcDt);
593
+
594
+ // --- Rosenbrock integrator
595
+
596
+ if ( MSX.Solver == ROS2 )
597
+ ierr = ros2_integrate(Yrate, NumPipeRateSpecies, 0, tstep,
598
+ &dh, Atol, Rtol, getPipeDcDt);
599
+
600
+ // --- save new concentration values of the species that reacted
601
+
602
+ for (m=1; m<=NumSpecies; m++) TheSeg->c[m] = ChemC1[m];
603
+ for (i=1; i<=NumPipeRateSpecies; i++)
604
+ {
605
+ m = PipeRateSpecies[i];
606
+ TheSeg->c[m] = MAX(Yrate[i], 0.0);
607
+ }
608
+ TheSeg->hstep = dh;
609
+ }
610
+ if ( ierr < 0 ) return
611
+ ERR_INTEGRATOR;
612
+
613
+ for (m = 1; m <= MSX.Nobjects[SPECIES]; m++)
614
+ {
615
+ if (MSX.Species[m].type == BULK)
616
+ {
617
+ MSX.Link[k].reacted[m] += TheSeg->v * (TheSeg->c[m] - TheSeg->lastc[m]) * LperFT3;
618
+ }
619
+ else if (MSX.Link[k].diam > 0)
620
+ {
621
+ MSX.Link[k].reacted[m] += TheSeg->v * 4.0 / MSX.Link[k].diam * MSX.Ucf[AREA_UNITS] * (TheSeg->c[m] - TheSeg->lastc[m]);
622
+ }
623
+ TheSeg->lastc[m] = TheSeg->c[m];
624
+ }
625
+ }
626
+
627
+ // --- compute new equilibrium concentrations within segment
628
+
629
+ errcode = MSXchem_equil(LINK, k, TheSeg->c);
630
+ if ( errcode ) return errcode;
631
+
632
+ // --- move to the segment upstream of the current one
633
+ TheSeg = TheSeg->prev;
634
+ }
635
+ return errcode;
636
+ }
637
+
638
+ //=============================================================================
639
+
640
+ int evalTankReactions(int k, double dt)
641
+ /*
642
+ ** Purpose:
643
+ ** updates species concentrations in a given storage tank
644
+ ** after reactions occur over time step dt.
645
+ **
646
+ ** Input:
647
+ ** k = tank index
648
+ ** dt = time step (sec).
649
+ **
650
+ ** Output:
651
+ ** updates values in the concentration vector Tank[k].c[]
652
+ ** for tank k.
653
+ **
654
+ ** Returns:
655
+ ** an error code or 0 if no error.
656
+ **
657
+ ** Re-written to accommodate compiled functions (1.1)
658
+ */
659
+ {
660
+ int i, m;
661
+ int errcode = 0, ierr = 0;
662
+ double tstep = (double)dt / MSX.Ucf[RATE_UNITS];
663
+ double c, dh;
664
+
665
+ // --- evaluate each volume segment in the tank
666
+
667
+ TheTank = k;
668
+ TheNode = MSX.Tank[k].node;
669
+ i = MSX.Nobjects[LINK] + k;
670
+ TheSeg = MSX.FirstSeg[i];
671
+ while ( TheSeg )
672
+ {
673
+ for (m = 1; m <= NumSpecies; m++)
674
+ {
675
+ ChemC1[m] = TheSeg->c[m];
676
+ TheSeg->lastc[m] = TheSeg->c[m];
677
+ }
678
+ ierr = 0;
679
+
680
+ // --- react each reacting species over the time step
681
+
682
+ if ( dt > 0.0 )
683
+ {
684
+
685
+ // --- place current concentrations of species that react in vector Yrate
686
+ for (i=1; i<=NumTankRateSpecies; i++)
687
+ {
688
+ m = TankRateSpecies[i];
689
+ // Yrate[i] = MSX.Tank[k].c[m];
690
+ Yrate[i] = TheSeg->c[m];
691
+ }
692
+
693
+ // --- Euler integrator
694
+
695
+ if ( MSX.Solver == EUL )
696
+ {
697
+ getTankDcDt(0, Yrate, NumTankRateSpecies, Yrate);
698
+ for (i=1; i<=NumTankRateSpecies; i++)
699
+ {
700
+ m = TankRateSpecies[i];
701
+ c = TheSeg->c[m] + Yrate[i]*tstep;
702
+ TheSeg->c[m] = MAX(c, 0.0);
703
+ }
704
+ }
705
+
706
+ // --- other integrators
707
+ else
708
+ {
709
+ dh = MSX.Tank[k].hstep;
710
+
711
+ // --- Runge-Kutta integrator
712
+
713
+ if ( MSX.Solver == RK5 )
714
+ ierr = rk5_integrate(Yrate, NumTankRateSpecies, 0, tstep,
715
+ &dh, Atol, Rtol, getTankDcDt);
716
+
717
+ // --- Rosenbrock integrator
718
+
719
+ if ( MSX.Solver == ROS2 )
720
+ ierr = ros2_integrate(Yrate, NumTankRateSpecies, 0, tstep,
721
+ &dh, Atol, Rtol, getTankDcDt);
722
+
723
+ // --- save new concentration values of the species that reacted
724
+
725
+ for (m=1; m<=NumSpecies; m++) TheSeg->c[m] = ChemC1[m];
726
+ for (i=1; i<=NumTankRateSpecies; i++)
727
+ {
728
+ m = TankRateSpecies[i];
729
+ TheSeg->c[m] = MAX(Yrate[i], 0.0);
730
+ }
731
+ TheSeg->hstep = dh;
732
+ }
733
+ if ( ierr < 0 ) return
734
+ ERR_INTEGRATOR;
735
+ }
736
+
737
+ // --- compute new equilibrium concentrations within segment
738
+
739
+ errcode = MSXchem_equil(NODE, k, TheSeg->c);
740
+ if ( errcode ) return errcode;
741
+
742
+ // --- move to the next tank segment
743
+ for (m = 1; m <= MSX.Nobjects[SPECIES]; m++)
744
+ {
745
+ if (MSX.Species[m].type == BULK)
746
+ {
747
+ MSX.Tank[k].reacted[m] += TheSeg->v * (TheSeg->c[m] - TheSeg->lastc[m]) * LperFT3;
748
+ }
749
+ TheSeg->lastc[m] = TheSeg->c[m];
750
+ }
751
+
752
+ TheSeg = TheSeg->prev;
753
+ }
754
+ return errcode;
755
+ }
756
+
757
+ //=============================================================================
758
+
759
+ int evalPipeEquil(double *c)
760
+ /*
761
+ ** Purpose:
762
+ ** computes equilibrium concentrations for water in a pipe segment.
763
+ **
764
+ ** Input:
765
+ ** c[] = array of starting species concentrations
766
+ **
767
+ ** Output:
768
+ ** c[] = array of equilibrium concentrations.
769
+ **
770
+ ** Returns:
771
+ ** an error code or 0 if no error.
772
+ */
773
+ {
774
+ int i, m;
775
+ int errcode;
776
+ for (m=1; m<=NumSpecies; m++) ChemC1[m] = c[m];
777
+ for (i=1; i<=NumPipeEquilSpecies; i++)
778
+ {
779
+ m = PipeEquilSpecies[i];
780
+ Yequil[i] = c[m];
781
+ }
782
+ errcode = newton_solve(Yequil, NumPipeEquilSpecies, MAXIT, NUMSIG,
783
+ getPipeEquil);
784
+ if ( errcode < 0 ) return ERR_NEWTON;
785
+ for (i=1; i<=NumPipeEquilSpecies; i++)
786
+ {
787
+ m = PipeEquilSpecies[i];
788
+ c[m] = Yequil[i];
789
+ ChemC1[m] = c[m];
790
+ }
791
+ return 0;
792
+ }
793
+
794
+
795
+ //=============================================================================
796
+
797
+ int evalTankEquil(double *c)
798
+ /*
799
+ ** Purpose:
800
+ ** computes equilibrium concentrations for water in a tank.
801
+ **
802
+ ** Input:
803
+ ** c[] = array of starting species concentrations
804
+ **
805
+ ** Output:
806
+ ** c[] = array of equilibrium concentrations.
807
+ **
808
+ ** Returns:
809
+ ** an error code or 0 if no error.
810
+ */
811
+ {
812
+ int i, m;
813
+ int errcode;
814
+ for (m=1; m<=NumSpecies; m++) ChemC1[m] = c[m];
815
+ for (i=1; i<=NumTankEquilSpecies; i++)
816
+ {
817
+ m = TankEquilSpecies[i];
818
+ Yequil[i] = c[m];
819
+ }
820
+ errcode = newton_solve(Yequil, NumTankEquilSpecies, MAXIT, NUMSIG,
821
+ getTankEquil);
822
+ if ( errcode < 0 ) return ERR_NEWTON;
823
+ for (i=1; i<=NumTankEquilSpecies; i++)
824
+ {
825
+ m = TankEquilSpecies[i];
826
+ c[m] = Yequil[i];
827
+ ChemC1[m] = c[m];
828
+ }
829
+ return 0;
830
+ }
831
+
832
+ //=============================================================================
833
+
834
+ void evalPipeFormulas(double *c)
835
+ /*
836
+ ** Purpose:
837
+ ** evaluates species concentrations in a pipe segment that are simple
838
+ ** formulas involving other known species concentrations.
839
+ **
840
+ ** Input:
841
+ ** c[] = array of current species concentrations.
842
+ **
843
+ ** Output:
844
+ ** c[] = array of updated concentrations.
845
+ **
846
+ ** Re-written to accommodate compiled functions (1.1)
847
+ */
848
+ {
849
+ int m;
850
+ double x;
851
+
852
+ for (m=1; m<=NumSpecies; m++) ChemC1[m] = c[m];
853
+ // --- use compiled functions if available
854
+
855
+ if ( MSX.Compiler )
856
+ {
857
+ MSXgetPipeFormulas(ChemC1, MSX.K, MSX.Link[TheLink].param, HydVar);
858
+ for (m=1; m<=NumSpecies; m++)
859
+ {
860
+ if (MSX.Species[m].pipeExprType == FORMULA)
861
+ c[m] = MSXerr_validate(ChemC1[m], m, LINK, FORMULA);
862
+ }
863
+ return;
864
+ }
865
+
866
+ for (m=1; m<=NumSpecies; m++)
867
+ {
868
+ if ( MSX.Species[m].pipeExprType == FORMULA )
869
+ {
870
+ x = mathexpr_eval(MSX.Species[m].pipeExpr, getPipeVariableValue);
871
+ c[m] = MSXerr_validate(x, m, LINK, FORMULA);
872
+ }
873
+ }
874
+ }
875
+
876
+ //=============================================================================
877
+
878
+ void evalTankFormulas(double *c)
879
+ /*
880
+ ** Purpose:
881
+ ** evaluates species concentrations in a tank that are simple
882
+ ** formulas involving other known species concentrations.
883
+ **
884
+ ** Input:
885
+ ** c[] = array of current species concentrations.
886
+ **
887
+ ** Output:
888
+ ** c[] = array of updated concentrations.
889
+ **
890
+ ** Re-written to accommodate compiled functions (1.1)
891
+ */
892
+ {
893
+ int m;
894
+ double x;
895
+
896
+ for (m=1; m<=NumSpecies; m++) ChemC1[m] = c[m];
897
+
898
+ // --- use compiled functions if available
899
+
900
+ if ( MSX.Compiler )
901
+ {
902
+ MSXgetTankFormulas(ChemC1, MSX.K, MSX.Link[TheLink].param, HydVar);
903
+ for (m=1; m<=NumSpecies; m++)
904
+ {
905
+ if (MSX.Species[m].tankExprType == FORMULA)
906
+ c[m] = MSXerr_validate(ChemC1[m], m, TANK, FORMULA);
907
+ }
908
+ return;
909
+ }
910
+
911
+ for (m=1; m<=NumSpecies; m++)
912
+ {
913
+ if ( MSX.Species[m].tankExprType == FORMULA )
914
+ {
915
+ x = mathexpr_eval(MSX.Species[m].tankExpr, getTankVariableValue);
916
+ c[m] = MSXerr_validate(x, m, TANK, FORMULA);
917
+ }
918
+ }
919
+ }
920
+
921
+ //=============================================================================
922
+
923
+ double getPipeVariableValue(int i)
924
+ /*
925
+ ** Purpose:
926
+ ** finds the value of a species, a parameter, or a constant for
927
+ ** the pipe link being analyzed.
928
+ **
929
+ ** Input:
930
+ ** i = variable index.
931
+ **
932
+ ** Returns:
933
+ ** the current value of the indexed variable.
934
+ */
935
+ {
936
+ double x;
937
+
938
+ // --- WQ species have index i between 1 & # of species
939
+ // and their current values are stored in vector ChemC1
940
+
941
+ if ( i <= LastIndex[SPECIES] )
942
+ {
943
+ // --- if species represented by a formula then evaluate it
944
+
945
+ if ( MSX.Species[i].pipeExprType == FORMULA )
946
+ {
947
+ x = mathexpr_eval(MSX.Species[i].pipeExpr, getPipeVariableValue);
948
+ return MSXerr_validate(x, i, LINK, FORMULA);
949
+ }
950
+
951
+ // --- otherwise return the current concentration
952
+
953
+ else return ChemC1[i];
954
+ }
955
+
956
+ // --- intermediate term expressions come next
957
+
958
+ else if ( i <= LastIndex[TERM] )
959
+ {
960
+ i -= LastIndex[TERM-1];
961
+ x = mathexpr_eval(MSX.Term[i].expr, getPipeVariableValue);
962
+ return MSXerr_validate(x, i, 0, TERM);
963
+ }
964
+
965
+ // --- reaction parameter indexes come after that
966
+
967
+ else if ( i <= LastIndex[PARAMETER] )
968
+ {
969
+ i -= LastIndex[PARAMETER-1];
970
+ return MSX.Link[TheLink].param[i];
971
+ }
972
+
973
+ // --- followed by constants
974
+
975
+ else if ( i <= LastIndex[CONSTANT] )
976
+ {
977
+ i -= LastIndex[CONSTANT-1];
978
+ return MSX.Const[i].value;
979
+ }
980
+
981
+ // --- and finally by hydraulic variables
982
+ else
983
+ {
984
+ i -= LastIndex[CONSTANT];
985
+ if (i < MAX_HYD_VARS) return HydVar[i];
986
+ else return 0.0;
987
+ }
988
+ }
989
+
990
+ //=============================================================================
991
+
992
+ double getTankVariableValue(int i)
993
+ /*
994
+ ** Purpose:
995
+ ** finds the value of a species, a parameter, or a constant for
996
+ ** the current node being analyzed.
997
+ **
998
+ ** Input:
999
+ ** i = variable index.
1000
+ **
1001
+ ** Returns:
1002
+ ** the current value of the indexed variable.
1003
+ **
1004
+ ** Modified to check for NaN values (L.Rossman - 11/03/10).
1005
+ */
1006
+ {
1007
+ int j;
1008
+ double x;
1009
+
1010
+ // --- WQ species have index i between 1 & # of species
1011
+ // and their current values are stored in vector ChemC1
1012
+
1013
+ if ( i <= LastIndex[SPECIES] )
1014
+ {
1015
+ // --- if species represented by a formula then evaluate it
1016
+
1017
+ if ( MSX.Species[i].tankExprType == FORMULA )
1018
+ {
1019
+ x = mathexpr_eval(MSX.Species[i].tankExpr, getTankVariableValue);
1020
+ return MSXerr_validate(x, i, TANK, FORMULA);
1021
+ }
1022
+
1023
+ // --- otherwise return the current concentration
1024
+
1025
+ else return ChemC1[i];
1026
+ }
1027
+
1028
+ // --- intermediate term expressions come next
1029
+
1030
+ else if ( i <= LastIndex[TERM] )
1031
+ {
1032
+ i -= LastIndex[TERM-1];
1033
+ x = mathexpr_eval(MSX.Term[i].expr, getTankVariableValue);
1034
+ return MSXerr_validate(x, i, 0, TERM);
1035
+ }
1036
+
1037
+ // --- next come reaction parameters associated with Tank nodes
1038
+
1039
+ else if (i <= LastIndex[PARAMETER] )
1040
+ {
1041
+ i -= LastIndex[PARAMETER-1];
1042
+ j = MSX.Node[TheNode].tank;
1043
+ if ( j > 0 )
1044
+ {
1045
+ return MSX.Tank[j].param[i];
1046
+ }
1047
+ else return 0.0;
1048
+ }
1049
+
1050
+ // --- and then come constants
1051
+
1052
+ else if (i <= LastIndex[CONSTANT] )
1053
+ {
1054
+ i -= LastIndex[CONSTANT-1];
1055
+ return MSX.Const[i].value;
1056
+ }
1057
+ else return 0.0;
1058
+ }
1059
+
1060
+ //=============================================================================
1061
+
1062
+ void getPipeDcDt(double t, double y[], int n, double deriv[])
1063
+ /*
1064
+ ** Purpose:
1065
+ ** finds reaction rate (dC/dt) for each reacting species in a pipe.
1066
+ **
1067
+ ** Input:
1068
+ ** t = current time (not used)
1069
+ ** y[] = vector of reacting species concentrations
1070
+ ** n = number of reacting species.
1071
+ **
1072
+ ** Output:
1073
+ ** deriv[] = vector of reaction rates of each reacting species.
1074
+ */
1075
+ {
1076
+ int i, m;
1077
+ double x;
1078
+
1079
+ // --- assign species concentrations to their proper positions in the global
1080
+ // concentration vector ChemC1
1081
+
1082
+ for (i=1; i<=n; i++)
1083
+ {
1084
+ m = PipeRateSpecies[i];
1085
+ ChemC1[m] = y[i];
1086
+ }
1087
+
1088
+ // --- update equilibrium species if full coupling in use
1089
+
1090
+ if ( MSX.Coupling == FULL_COUPLING )
1091
+ {
1092
+ if ( MSXchem_equil(LINK, TheLink, ChemC1) > 0 ) // check for error condition
1093
+ {
1094
+ for (i=1; i<=n; i++) deriv[i] = 0.0;
1095
+ return;
1096
+ }
1097
+ }
1098
+
1099
+ // --- use compiled functions if available
1100
+
1101
+ if ( MSX.Compiler )
1102
+ {
1103
+ MSXgetPipeRates(ChemC1, MSX.K, MSX.Link[TheLink].param, HydVar, F);
1104
+ for (i=1; i<=n; i++)
1105
+ {
1106
+ m = PipeRateSpecies[i];
1107
+ deriv[i] = MSXerr_validate(F[m], m, LINK, RATE);
1108
+ }
1109
+ return;
1110
+ }
1111
+
1112
+ // --- evaluate each pipe reaction expression
1113
+
1114
+ for (i=1; i<=n; i++)
1115
+ {
1116
+ m = PipeRateSpecies[i];
1117
+ x = mathexpr_eval(MSX.Species[m].pipeExpr, getPipeVariableValue);
1118
+ deriv[i] = MSXerr_validate(x, m, LINK, RATE);
1119
+ }
1120
+ }
1121
+
1122
+ //=============================================================================
1123
+
1124
+ void getTankDcDt(double t, double y[], int n, double deriv[])
1125
+ /*
1126
+ ** Purpose:
1127
+ ** finds reaction rate (dC/dt) for each reacting species in a tank.
1128
+ **
1129
+ ** Input:
1130
+ ** t = current time (not used)
1131
+ ** y[] = vector of reacting species concentrations
1132
+ ** n = number of reacting species.
1133
+ **
1134
+ ** Output:
1135
+ ** deriv[] = vector of reaction rates of each reacting species.
1136
+ */
1137
+ {
1138
+ int i, m;
1139
+ double x;
1140
+
1141
+ // --- assign species concentrations to their proper positions in the global
1142
+ // concentration vector ChemC1
1143
+
1144
+ for (i=1; i<=n; i++)
1145
+ {
1146
+ m = TankRateSpecies[i];
1147
+ ChemC1[m] = y[i];
1148
+ }
1149
+
1150
+ // --- update equilibrium species if full coupling in use
1151
+
1152
+ if ( MSX.Coupling == FULL_COUPLING )
1153
+ {
1154
+ if ( MSXchem_equil(NODE, TheTank, ChemC1) > 0 ) // check for error condition
1155
+ {
1156
+ for (i=1; i<=n; i++) deriv[i] = 0.0;
1157
+ return;
1158
+ }
1159
+ }
1160
+
1161
+ // --- use compiled functions if available
1162
+
1163
+ if ( MSX.Compiler )
1164
+ {
1165
+ MSXgetTankRates(ChemC1, MSX.K, MSX.Tank[TheTank].param, HydVar, F);
1166
+ for (i=1; i<=n; i++)
1167
+ {
1168
+ m = TankRateSpecies[i];
1169
+ deriv[i] = MSXerr_validate(F[m], m, TANK, RATE);
1170
+ }
1171
+ return;
1172
+ }
1173
+
1174
+ // --- evaluate each tank reaction expression
1175
+
1176
+ for (i=1; i<=n; i++)
1177
+ {
1178
+ m = TankRateSpecies[i];
1179
+ x = mathexpr_eval(MSX.Species[m].tankExpr, getTankVariableValue);
1180
+ deriv[i] = MSXerr_validate(x, m, TANK, RATE);
1181
+ }
1182
+ }
1183
+
1184
+ //=============================================================================
1185
+
1186
+ void getPipeEquil(double t, double y[], int n, double f[])
1187
+ /*
1188
+ ** Purpose:
1189
+ ** evaluates equilibrium expressions for pipe chemistry.
1190
+ **
1191
+ ** Input:
1192
+ ** t = current time (not used)
1193
+ ** y[] = vector of equilibrium species concentrations
1194
+ ** n = number of equilibrium species.
1195
+ **
1196
+ ** Output:
1197
+ ** f[] = vector of equilibrium function values.
1198
+ */
1199
+ {
1200
+ int i, m;
1201
+ double x;
1202
+
1203
+ // --- assign species concentrations to their proper positions in the global
1204
+ // concentration vector ChemC1
1205
+
1206
+ for (i=1; i<=n; i++)
1207
+ {
1208
+ m = PipeEquilSpecies[i];
1209
+ ChemC1[m] = y[i];
1210
+ }
1211
+
1212
+ // --- use compiled functions if available
1213
+
1214
+ if ( MSX.Compiler )
1215
+ {
1216
+ MSXgetPipeEquil(ChemC1, MSX.K, MSX.Link[TheLink].param, HydVar, F);
1217
+ for (i=1; i<=n; i++)
1218
+ {
1219
+ m = PipeEquilSpecies[i];
1220
+ f[i] = MSXerr_validate(F[m], m, LINK, EQUIL);
1221
+ }
1222
+ return;
1223
+ }
1224
+
1225
+ // --- evaluate each pipe equilibrium expression
1226
+
1227
+ for (i=1; i<=n; i++)
1228
+ {
1229
+ m = PipeEquilSpecies[i];
1230
+ x = mathexpr_eval(MSX.Species[m].pipeExpr, getPipeVariableValue);
1231
+ f[i] = MSXerr_validate(x, m, LINK, EQUIL);
1232
+ }
1233
+ }
1234
+
1235
+ //=============================================================================
1236
+
1237
+ void getTankEquil(double t, double y[], int n, double f[])
1238
+ /*
1239
+ ** Purpose:
1240
+ ** evaluates equilibrium expressions for tank chemistry.
1241
+ **
1242
+ ** Input:
1243
+ ** t = current time (not used)
1244
+ ** y[] = vector of equilibrium species concentrations
1245
+ ** n = number of equilibrium species
1246
+ **
1247
+ ** Output:
1248
+ ** f[] = vector of equilibrium function values.
1249
+ */
1250
+ {
1251
+ int i, m;
1252
+ double x;
1253
+
1254
+ // --- assign species concentrations to their proper positions in the global
1255
+ // concentration vector ChemC1
1256
+
1257
+ for (i=1; i<=n; i++)
1258
+ {
1259
+ m = TankEquilSpecies[i];
1260
+ ChemC1[m] = y[i];
1261
+ }
1262
+
1263
+ // --- use compiled functions if available
1264
+
1265
+ if ( MSX.Compiler )
1266
+ {
1267
+ MSXgetTankEquil(ChemC1, MSX.K, MSX.Tank[TheTank].param, HydVar, F);
1268
+ for (i=1; i<=n; i++)
1269
+ {
1270
+ m = TankEquilSpecies[i];
1271
+ f[i] = MSXerr_validate(F[m], m, TANK, EQUIL);
1272
+ }
1273
+ return;
1274
+ }
1275
+
1276
+ // --- evaluate each tank equilibrium expression
1277
+
1278
+ for (i=1; i<=n; i++)
1279
+ {
1280
+ m = TankEquilSpecies[i];
1281
+ x = mathexpr_eval(MSX.Species[m].tankExpr, getTankVariableValue);
1282
+ f[i] = MSXerr_validate(x, m, TANK, EQUIL);
1283
+ }
1284
+ }
1285
+