epanet-plus 0.1.0__cp314-cp314t-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-314t-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 +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 +5 -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/msxinp.c
ADDED
|
@@ -0,0 +1,1504 @@
|
|
|
1
|
+
/*******************************************************************************
|
|
2
|
+
** MODULE: MSXINP.C
|
|
3
|
+
** PROJECT: EPANET-MSX
|
|
4
|
+
** DESCRIPTION: Input data processor for the EPANET Multi-Species Extension
|
|
5
|
+
** toolkit.
|
|
6
|
+
** AUTHORS: see AUTHORS
|
|
7
|
+
** Copyright: see AUTHORS
|
|
8
|
+
** License: see LICENSE
|
|
9
|
+
** VERSION: 2.0.00
|
|
10
|
+
** LAST UPDATE: 08/20/2022
|
|
11
|
+
*******************************************************************************/
|
|
12
|
+
|
|
13
|
+
#include <stdio.h>
|
|
14
|
+
#include <stdlib.h>
|
|
15
|
+
#include <string.h>
|
|
16
|
+
#include <math.h>
|
|
17
|
+
|
|
18
|
+
#include "msxtypes.h"
|
|
19
|
+
#include "msxutils.h"
|
|
20
|
+
#include "msxdict.h"
|
|
21
|
+
#include "epanet2.h"
|
|
22
|
+
|
|
23
|
+
// Constants
|
|
24
|
+
//-----------
|
|
25
|
+
#define MAXERRS 100 // Max. input errors reported
|
|
26
|
+
#define MAXTOKS 40 // Max. items per line of input
|
|
27
|
+
#define SEPSTR " \t\n\r" // Token separator characters
|
|
28
|
+
|
|
29
|
+
// External variables
|
|
30
|
+
//--------------------
|
|
31
|
+
extern MSXproject MSX; // MSX project data
|
|
32
|
+
|
|
33
|
+
// Local variables
|
|
34
|
+
//-----------------
|
|
35
|
+
static char *Tok[MAXTOKS]; // String tokens from line of input
|
|
36
|
+
static int Ntokens; // Number of tokens in line of input
|
|
37
|
+
static double **TermArray; // Incidence array used to check Terms
|
|
38
|
+
|
|
39
|
+
enum InpErrorCodes { // Error codes (401 - 409)
|
|
40
|
+
INP_ERR_FIRST = 400,
|
|
41
|
+
ERR_LINE_LENGTH,
|
|
42
|
+
ERR_ITEMS,
|
|
43
|
+
ERR_KEYWORD,
|
|
44
|
+
ERR_NUMBER,
|
|
45
|
+
ERR_NAME,
|
|
46
|
+
ERR_RESERVED_NAME,
|
|
47
|
+
ERR_DUP_NAME,
|
|
48
|
+
ERR_DUP_EXPR,
|
|
49
|
+
ERR_MATH_EXPR,
|
|
50
|
+
ERR_UNSUPPORTED_OPTION,
|
|
51
|
+
INP_ERR_LAST};
|
|
52
|
+
|
|
53
|
+
static char *InpErrorTxt[INP_ERR_LAST-INP_ERR_FIRST] = {
|
|
54
|
+
"",
|
|
55
|
+
"Error 401 (too many characters)",
|
|
56
|
+
"Error 402 (too few input items)",
|
|
57
|
+
"Error 403 (invalid keyword)",
|
|
58
|
+
"Error 404 (invalid numeric value)",
|
|
59
|
+
"Error 405 (reference to undefined object)",
|
|
60
|
+
"Error 406 (illegal use of a reserved name)",
|
|
61
|
+
"Error 407 (name already used by another object)",
|
|
62
|
+
"Error 408 (species already assigned an expression)",
|
|
63
|
+
"Error 409 (illegal math expression)",
|
|
64
|
+
"Error 410 (option no longer supported)"};
|
|
65
|
+
|
|
66
|
+
// Imported functions
|
|
67
|
+
//--------------------
|
|
68
|
+
int MSXproj_addObject(int type, char *id, int n);
|
|
69
|
+
int MSXproj_findObject(int type, char *id);
|
|
70
|
+
char * MSXproj_findID(int type, char *id);
|
|
71
|
+
|
|
72
|
+
// Exported functions
|
|
73
|
+
//--------------------
|
|
74
|
+
int MSXinp_countMsxObjects(void);
|
|
75
|
+
int MSXinp_countNetObjects(void);
|
|
76
|
+
int MSXinp_readNetData(void);
|
|
77
|
+
int MSXinp_readMsxData(void);
|
|
78
|
+
void MSXinp_getSpeciesUnits(int m, char *units);
|
|
79
|
+
|
|
80
|
+
// Local functions
|
|
81
|
+
//-----------------
|
|
82
|
+
static int getLineLength(char *line);
|
|
83
|
+
static int getNewSection(char *tok, char *sectWords[], int *sect);
|
|
84
|
+
static int addSpecies(char *line);
|
|
85
|
+
static int addCoeff(char *line);
|
|
86
|
+
static int addTerm(char *id);
|
|
87
|
+
static int addPattern(char *id);
|
|
88
|
+
static int checkID(char *id);
|
|
89
|
+
static int parseLine(int sect, char *line);
|
|
90
|
+
static int parseOption(void);
|
|
91
|
+
static int parseSpecies(void);
|
|
92
|
+
static int parseCoeff(void);
|
|
93
|
+
static int parseTerm(void);
|
|
94
|
+
static int parseExpression(int classType);
|
|
95
|
+
static int parseTankData(void);
|
|
96
|
+
static int parseQuality(void);
|
|
97
|
+
static int parseParameter(void);
|
|
98
|
+
static int parseSource(void);
|
|
99
|
+
static int parsePattern(void);
|
|
100
|
+
static int parseReport(void);
|
|
101
|
+
static int parseDiffu(void);
|
|
102
|
+
static int getVariableCode(char *id);
|
|
103
|
+
static int getTokens(char *s);
|
|
104
|
+
static void writeInpErrMsg(int errcode, char *sect, char *line, int lineCount);
|
|
105
|
+
|
|
106
|
+
static int checkCyclicTerms(void);
|
|
107
|
+
static int traceTermPath(int i, int istar, int n);
|
|
108
|
+
|
|
109
|
+
//=============================================================================
|
|
110
|
+
|
|
111
|
+
int MSXinp_countMsxObjects()
|
|
112
|
+
/*
|
|
113
|
+
** Purpose:
|
|
114
|
+
** reads multi-species input file to determine number of system objects.
|
|
115
|
+
**
|
|
116
|
+
** Input:
|
|
117
|
+
** none
|
|
118
|
+
**
|
|
119
|
+
** Returns:
|
|
120
|
+
** an error code (0 if no error)
|
|
121
|
+
*/
|
|
122
|
+
{
|
|
123
|
+
char line[MAXLINE+1]; // line from input data file
|
|
124
|
+
char wLine[MAXLINE+1]; // working copy of input line
|
|
125
|
+
char *tok; // first string token of line
|
|
126
|
+
int sect = -1; // input data sections
|
|
127
|
+
int errcode = 0; // error code
|
|
128
|
+
int errsum = 0; // number of errors found
|
|
129
|
+
long lineCount = 0;
|
|
130
|
+
|
|
131
|
+
// --- write name of input file to EPANET report file
|
|
132
|
+
|
|
133
|
+
strcpy(MSX.Msg, "Processing MSX input file ");
|
|
134
|
+
strcpy(line, MSX.MsxFile.name);
|
|
135
|
+
strcat(MSX.Msg, line);
|
|
136
|
+
ENwriteline(MSX.Msg);
|
|
137
|
+
ENwriteline("");
|
|
138
|
+
|
|
139
|
+
// --- make pass through EPANET-MSX data file counting number of each object
|
|
140
|
+
|
|
141
|
+
while ( fgets(line, MAXLINE, MSX.MsxFile.file) != NULL )
|
|
142
|
+
{
|
|
143
|
+
|
|
144
|
+
// --- skip blank lines & those beginning with a comment
|
|
145
|
+
|
|
146
|
+
errcode = 0;
|
|
147
|
+
lineCount++;
|
|
148
|
+
strcpy(wLine, line); // make working copy of line
|
|
149
|
+
tok = strtok(wLine, SEPSTR); // get first text token on line
|
|
150
|
+
if ( tok == NULL || *tok == ';' ) continue;
|
|
151
|
+
if ( getNewSection(tok, MsxSectWords, §) ) continue;
|
|
152
|
+
|
|
153
|
+
// --- read id names from SPECIES, COEFFS, TERMS, & PATTERNS sections
|
|
154
|
+
|
|
155
|
+
if ( sect == s_SPECIES ) errcode = addSpecies(line);
|
|
156
|
+
if ( sect == s_COEFF ) errcode = addCoeff(line);
|
|
157
|
+
if ( sect == s_TERM ) errcode = addTerm(tok);
|
|
158
|
+
if ( sect == s_PATTERN ) errcode = addPattern(tok);
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
// --- report any error found
|
|
162
|
+
|
|
163
|
+
if ( errcode )
|
|
164
|
+
{
|
|
165
|
+
writeInpErrMsg(errcode, MsxSectWords[sect], line, lineCount);
|
|
166
|
+
errsum++;
|
|
167
|
+
if (errsum >= MAXERRS ) break;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// --- return error code
|
|
172
|
+
|
|
173
|
+
if ( errsum > 0 ) return ERR_MSX_INPUT;
|
|
174
|
+
return errcode;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
//=============================================================================
|
|
178
|
+
|
|
179
|
+
int MSXinp_countNetObjects()
|
|
180
|
+
/*
|
|
181
|
+
** Purpose:
|
|
182
|
+
** queries EPANET data base to determine number of network objects.
|
|
183
|
+
**
|
|
184
|
+
** Input:
|
|
185
|
+
** none
|
|
186
|
+
**
|
|
187
|
+
** Returns:
|
|
188
|
+
** an error code (0 if no error)
|
|
189
|
+
*/
|
|
190
|
+
{
|
|
191
|
+
int errcode = 0;
|
|
192
|
+
|
|
193
|
+
// --- retrieve number of network elements
|
|
194
|
+
|
|
195
|
+
CALL(errcode, ENgetcount(EN_NODECOUNT, &MSX.Nobjects[NODE]));
|
|
196
|
+
CALL(errcode, ENgetcount(EN_TANKCOUNT, &MSX.Nobjects[TANK]));
|
|
197
|
+
CALL(errcode, ENgetcount(EN_LINKCOUNT, &MSX.Nobjects[LINK]));
|
|
198
|
+
return errcode;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
//=============================================================================
|
|
202
|
+
|
|
203
|
+
int MSXinp_readNetData()
|
|
204
|
+
/*
|
|
205
|
+
** Purpose:
|
|
206
|
+
** retrieves required input data from the EPANET project data.
|
|
207
|
+
**
|
|
208
|
+
** Input:
|
|
209
|
+
** none
|
|
210
|
+
**
|
|
211
|
+
** Returns:
|
|
212
|
+
** an error code (0 if no error)
|
|
213
|
+
*/
|
|
214
|
+
{
|
|
215
|
+
int errcode = 0;
|
|
216
|
+
int i, k, n, t = 0;
|
|
217
|
+
int n1 = 0, n2 = 0;
|
|
218
|
+
long qstep;
|
|
219
|
+
float diam = 0.0, len = 0.0, v0 = 0.0, xmix = 0.0, vmix = 0.0;
|
|
220
|
+
|
|
221
|
+
float roughness = 0.0;
|
|
222
|
+
|
|
223
|
+
// --- get flow units & time parameters
|
|
224
|
+
|
|
225
|
+
CALL(errcode, ENgetflowunits(&MSX.Flowflag));
|
|
226
|
+
if ( MSX.Flowflag >= EN_LPS ) MSX.Unitsflag = SI;
|
|
227
|
+
else MSX.Unitsflag = US;
|
|
228
|
+
CALL(errcode, ENgettimeparam(EN_QUALSTEP, &qstep));
|
|
229
|
+
MSX.Qstep = qstep * 1000;
|
|
230
|
+
CALL(errcode, ENgettimeparam(EN_REPORTSTEP, &MSX.Rstep));
|
|
231
|
+
CALL(errcode, ENgettimeparam(EN_REPORTSTART, &MSX.Rstart));
|
|
232
|
+
CALL(errcode, ENgettimeparam(EN_PATTERNSTEP, &MSX.Pstep));
|
|
233
|
+
CALL(errcode, ENgettimeparam(EN_PATTERNSTART, &MSX.Pstart));
|
|
234
|
+
CALL(errcode, ENgettimeparam(EN_STATISTIC, &MSX.Statflag));
|
|
235
|
+
|
|
236
|
+
// --- read tank/reservoir data
|
|
237
|
+
|
|
238
|
+
n = MSX.Nobjects[NODE] - MSX.Nobjects[TANK];
|
|
239
|
+
for (i=1; i<=MSX.Nobjects[NODE]; i++)
|
|
240
|
+
{
|
|
241
|
+
k = i - n;
|
|
242
|
+
if ( k > 0 )
|
|
243
|
+
{
|
|
244
|
+
CALL(errcode, ENgetnodetype(i, &t));
|
|
245
|
+
CALL(errcode, ENgetnodevalue(i, EN_INITVOLUME, &v0));
|
|
246
|
+
CALL(errcode, ENgetnodevalue(i, EN_MIXMODEL, &xmix));
|
|
247
|
+
CALL(errcode, ENgetnodevalue(i, EN_MIXZONEVOL, &vmix));
|
|
248
|
+
if ( !errcode )
|
|
249
|
+
{
|
|
250
|
+
MSX.Node[i].tank = k;
|
|
251
|
+
MSX.Tank[k].node = i;
|
|
252
|
+
if ( t == EN_RESERVOIR ) MSX.Tank[k].a = 0.0;
|
|
253
|
+
else MSX.Tank[k].a = 1.0;
|
|
254
|
+
MSX.Tank[k].v0 = v0;
|
|
255
|
+
MSX.Tank[k].mixModel = (int)xmix;
|
|
256
|
+
MSX.Tank[k].vMix = vmix;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// --- read link data
|
|
262
|
+
|
|
263
|
+
for (i=1; i<=MSX.Nobjects[LINK]; i++)
|
|
264
|
+
{
|
|
265
|
+
CALL(errcode, ENgetlinknodes(i, &n1, &n2));
|
|
266
|
+
CALL(errcode, ENgetlinkvalue(i, EN_DIAMETER, &diam));
|
|
267
|
+
CALL(errcode, ENgetlinkvalue(i, EN_LENGTH, &len));
|
|
268
|
+
CALL(errcode, ENgetlinkvalue(i, EN_ROUGHNESS, &roughness));
|
|
269
|
+
if ( !errcode )
|
|
270
|
+
{
|
|
271
|
+
MSX.Link[i].n1 = n1;
|
|
272
|
+
MSX.Link[i].n2 = n2;
|
|
273
|
+
MSX.Link[i].diam = diam;
|
|
274
|
+
MSX.Link[i].len = len;
|
|
275
|
+
MSX.Link[i].roughness = roughness;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return errcode;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
//=============================================================================
|
|
282
|
+
|
|
283
|
+
int MSXinp_readMsxData()
|
|
284
|
+
/*
|
|
285
|
+
** Purpose:
|
|
286
|
+
** reads multi-species data from the EPANET-MSX input file.
|
|
287
|
+
**
|
|
288
|
+
** Input:
|
|
289
|
+
** none
|
|
290
|
+
**
|
|
291
|
+
** Returns:
|
|
292
|
+
** an error code (0 if no error)
|
|
293
|
+
*/
|
|
294
|
+
{
|
|
295
|
+
char line[MAXLINE+1]; // line from input data file
|
|
296
|
+
char wLine[MAXLINE+1]; // working copy of input line
|
|
297
|
+
int sect = -1; // input data sections
|
|
298
|
+
int errsum = 0; // number of errors found
|
|
299
|
+
int inperr = 0; // input error code
|
|
300
|
+
long lineCount = 0; // line count
|
|
301
|
+
|
|
302
|
+
// --- create the TermArray for checking circular references in Terms
|
|
303
|
+
|
|
304
|
+
TermArray = createMatrix(MSX.Nobjects[TERM]+1, MSX.Nobjects[TERM]+1);
|
|
305
|
+
if ( TermArray == NULL ) return ERR_MEMORY;
|
|
306
|
+
|
|
307
|
+
// --- read each line from MSX input file
|
|
308
|
+
|
|
309
|
+
rewind(MSX.MsxFile.file);
|
|
310
|
+
while ( fgets(line, MAXLINE, MSX.MsxFile.file) != NULL )
|
|
311
|
+
{
|
|
312
|
+
// --- make copy of line and scan for tokens
|
|
313
|
+
|
|
314
|
+
lineCount++;
|
|
315
|
+
strcpy(wLine, line);
|
|
316
|
+
Ntokens = getTokens(wLine);
|
|
317
|
+
|
|
318
|
+
// --- skip blank lines and comments
|
|
319
|
+
|
|
320
|
+
if ( Ntokens == 0 || *Tok[0] == ';' ) continue;
|
|
321
|
+
|
|
322
|
+
// --- check if max. line length exceeded
|
|
323
|
+
|
|
324
|
+
if ( getLineLength(line) >= MAXLINE )
|
|
325
|
+
{
|
|
326
|
+
inperr = ERR_LINE_LENGTH;
|
|
327
|
+
writeInpErrMsg(inperr, MsxSectWords[sect], line, lineCount);
|
|
328
|
+
errsum++;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// --- check if at start of a new input section
|
|
332
|
+
|
|
333
|
+
if ( getNewSection(Tok[0], MsxSectWords, §) ) continue;
|
|
334
|
+
|
|
335
|
+
// --- parse tokens from input line
|
|
336
|
+
|
|
337
|
+
inperr = parseLine(sect, line);
|
|
338
|
+
if ( inperr > 0 )
|
|
339
|
+
{
|
|
340
|
+
errsum++;
|
|
341
|
+
writeInpErrMsg(inperr, MsxSectWords[sect], line, lineCount);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// --- stop if reach end of file or max. error count
|
|
345
|
+
|
|
346
|
+
if (errsum >= MAXERRS) break;
|
|
347
|
+
} // End of while
|
|
348
|
+
|
|
349
|
+
// --- check for errors
|
|
350
|
+
|
|
351
|
+
if ( checkCyclicTerms() ) errsum++;
|
|
352
|
+
freeMatrix(TermArray);
|
|
353
|
+
if (errsum > 0) return ERR_MSX_INPUT;
|
|
354
|
+
return 0;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
//=============================================================================
|
|
358
|
+
|
|
359
|
+
void MSXinp_getSpeciesUnits(int m, char *units)
|
|
360
|
+
/*
|
|
361
|
+
** Purpose:
|
|
362
|
+
** constructs the character string for a species concentration units.
|
|
363
|
+
**
|
|
364
|
+
** Input:
|
|
365
|
+
** m = species index
|
|
366
|
+
**
|
|
367
|
+
** Output:
|
|
368
|
+
** units = character string with species concentration units
|
|
369
|
+
*/
|
|
370
|
+
{
|
|
371
|
+
strcpy(units, MSX.Species[m].units);
|
|
372
|
+
strcat(units, "/");
|
|
373
|
+
if ( MSX.Species[m].type == BULK ) strcat(units, "L");
|
|
374
|
+
else strcat(units, AreaUnitsWords[MSX.AreaUnits]);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
//=============================================================================
|
|
378
|
+
|
|
379
|
+
int getLineLength(char *line)
|
|
380
|
+
/*
|
|
381
|
+
** Purpose:
|
|
382
|
+
** determines number of characters of data in a line of input.
|
|
383
|
+
**
|
|
384
|
+
** Input:
|
|
385
|
+
** line = line of text from an input file
|
|
386
|
+
**
|
|
387
|
+
** Returns:
|
|
388
|
+
** number of characters in the line (with comment ignored).
|
|
389
|
+
*/
|
|
390
|
+
{
|
|
391
|
+
char *comment;
|
|
392
|
+
int lineLength = (int)strlen(line);
|
|
393
|
+
if ( lineLength >= MAXLINE )
|
|
394
|
+
{
|
|
395
|
+
// --- don't count comment if present
|
|
396
|
+
comment = strchr(line, ';');
|
|
397
|
+
if ( comment ) lineLength = (int)(comment - line); // Pointer math here
|
|
398
|
+
}
|
|
399
|
+
return lineLength;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
//=============================================================================
|
|
403
|
+
|
|
404
|
+
int getNewSection(char *tok, char *sectWords[], int *sect)
|
|
405
|
+
/*
|
|
406
|
+
** Purpose:
|
|
407
|
+
** checks if a line begins a new section in the input file.
|
|
408
|
+
**
|
|
409
|
+
** Input:
|
|
410
|
+
** tok = a string token
|
|
411
|
+
** sectWords = array of input file section keywords
|
|
412
|
+
**
|
|
413
|
+
** Output:
|
|
414
|
+
** sect = index code of section matching tok (or -1 if no match)
|
|
415
|
+
**
|
|
416
|
+
** Returns:
|
|
417
|
+
** 1 if a section is found, 0 if not
|
|
418
|
+
*/
|
|
419
|
+
{
|
|
420
|
+
int newsect;
|
|
421
|
+
|
|
422
|
+
// --- check if line begins with a new section heading
|
|
423
|
+
|
|
424
|
+
if ( *tok == '[' )
|
|
425
|
+
{
|
|
426
|
+
// --- look for section heading in list of section keywords
|
|
427
|
+
|
|
428
|
+
newsect = MSXutils_findmatch(tok, sectWords);
|
|
429
|
+
if ( newsect >= 0 ) *sect = newsect;
|
|
430
|
+
else *sect = -1;
|
|
431
|
+
return 1;
|
|
432
|
+
}
|
|
433
|
+
return 0;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
//=============================================================================
|
|
437
|
+
|
|
438
|
+
int addSpecies(char *line)
|
|
439
|
+
/*
|
|
440
|
+
** Purpose:
|
|
441
|
+
** adds a species ID name to the project.
|
|
442
|
+
**
|
|
443
|
+
** Input:
|
|
444
|
+
** line = line of input data
|
|
445
|
+
**
|
|
446
|
+
** Returns:
|
|
447
|
+
** an error code (0 if no error)
|
|
448
|
+
*/
|
|
449
|
+
{
|
|
450
|
+
int errcode = 0;
|
|
451
|
+
Ntokens = getTokens(line);
|
|
452
|
+
if ( Ntokens < 2 ) return ERR_ITEMS;
|
|
453
|
+
errcode = checkID(Tok[1]);
|
|
454
|
+
if ( errcode ) return errcode;
|
|
455
|
+
if ( MSXproj_addObject(SPECIES, Tok[1], MSX.Nobjects[SPECIES]+1) < 0 )
|
|
456
|
+
errcode = 101;
|
|
457
|
+
else MSX.Nobjects[SPECIES]++;
|
|
458
|
+
return errcode;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
//=============================================================================
|
|
462
|
+
|
|
463
|
+
int addCoeff(char *line)
|
|
464
|
+
/*
|
|
465
|
+
** Purpose:
|
|
466
|
+
** adds a coefficient ID name to the project.
|
|
467
|
+
**
|
|
468
|
+
** Input:
|
|
469
|
+
** line = line of input data
|
|
470
|
+
**
|
|
471
|
+
** Returns:
|
|
472
|
+
** an error code (0 if no error)
|
|
473
|
+
*/
|
|
474
|
+
{
|
|
475
|
+
int k;
|
|
476
|
+
int errcode = 0;
|
|
477
|
+
|
|
478
|
+
// --- determine the type of coeff.
|
|
479
|
+
|
|
480
|
+
Ntokens = getTokens(line);
|
|
481
|
+
if ( Ntokens < 2 ) return ERR_ITEMS;
|
|
482
|
+
if (MSXutils_match(Tok[0], "PARAM")) k = PARAMETER;
|
|
483
|
+
else if (MSXutils_match(Tok[0], "CONST")) k = CONSTANT;
|
|
484
|
+
else return ERR_KEYWORD;
|
|
485
|
+
|
|
486
|
+
// --- check for valid id name
|
|
487
|
+
|
|
488
|
+
errcode = checkID(Tok[1]);
|
|
489
|
+
if ( errcode ) return errcode;
|
|
490
|
+
if ( MSXproj_addObject(k, Tok[1], MSX.Nobjects[k]+1) < 0 )
|
|
491
|
+
errcode = 101;
|
|
492
|
+
else MSX.Nobjects[k]++;
|
|
493
|
+
return errcode;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
//=============================================================================
|
|
497
|
+
|
|
498
|
+
int addTerm(char *id)
|
|
499
|
+
/*
|
|
500
|
+
** Purpose:
|
|
501
|
+
** adds an intermediate expression term ID name to the project.
|
|
502
|
+
**
|
|
503
|
+
** Input:
|
|
504
|
+
** id = name of an intermediate expression term
|
|
505
|
+
**
|
|
506
|
+
** Returns:
|
|
507
|
+
** an error code (0 if no error)
|
|
508
|
+
*/
|
|
509
|
+
{
|
|
510
|
+
int errcode = checkID(id);
|
|
511
|
+
if ( !errcode )
|
|
512
|
+
{
|
|
513
|
+
if ( MSXproj_addObject(TERM, id, MSX.Nobjects[TERM]+1) < 0 )
|
|
514
|
+
errcode = 101;
|
|
515
|
+
else MSX.Nobjects[TERM]++;
|
|
516
|
+
}
|
|
517
|
+
return errcode;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
//=============================================================================
|
|
521
|
+
|
|
522
|
+
int addPattern(char *id)
|
|
523
|
+
/*
|
|
524
|
+
** Purpose:
|
|
525
|
+
** adds a time pattern ID name to the project.
|
|
526
|
+
**
|
|
527
|
+
** Input:
|
|
528
|
+
** id = name of a time pattern
|
|
529
|
+
**
|
|
530
|
+
** Returns:
|
|
531
|
+
** an error code (0 if no error)
|
|
532
|
+
*/
|
|
533
|
+
{
|
|
534
|
+
int errcode = 0;
|
|
535
|
+
|
|
536
|
+
// --- a time pattern can span several lines
|
|
537
|
+
|
|
538
|
+
if ( MSXproj_findObject(PATTERN, id) <= 0 )
|
|
539
|
+
{
|
|
540
|
+
if ( MSXproj_addObject(PATTERN, id, MSX.Nobjects[PATTERN]+1) < 0 )
|
|
541
|
+
errcode = 101;
|
|
542
|
+
else MSX.Nobjects[PATTERN]++;
|
|
543
|
+
}
|
|
544
|
+
return errcode;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
//=============================================================================
|
|
548
|
+
|
|
549
|
+
int checkID(char *id)
|
|
550
|
+
/*
|
|
551
|
+
** Purpose:
|
|
552
|
+
** checks that an object's name is unique
|
|
553
|
+
**
|
|
554
|
+
** Input:
|
|
555
|
+
** id = name of an object
|
|
556
|
+
**
|
|
557
|
+
** Returns:
|
|
558
|
+
** an error code (0 if successful)
|
|
559
|
+
*/
|
|
560
|
+
{
|
|
561
|
+
// --- check that id name is not a reserved word
|
|
562
|
+
int i = 1;
|
|
563
|
+
while (HydVarWords[i] != NULL)
|
|
564
|
+
{
|
|
565
|
+
if (MSXutils_strcomp(id, HydVarWords[i])) return ERR_RESERVED_NAME;
|
|
566
|
+
i++;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
// --- check that id name not used before
|
|
570
|
+
|
|
571
|
+
if ( MSXproj_findObject(SPECIES, id) > 0 ||
|
|
572
|
+
MSXproj_findObject(TERM, id) > 0 ||
|
|
573
|
+
MSXproj_findObject(PARAMETER, id) > 0 ||
|
|
574
|
+
MSXproj_findObject(CONSTANT, id) > 0
|
|
575
|
+
) return ERR_DUP_NAME;
|
|
576
|
+
return 0;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
//=============================================================================
|
|
580
|
+
|
|
581
|
+
int parseLine(int sect, char *line)
|
|
582
|
+
/*
|
|
583
|
+
** Purpose:
|
|
584
|
+
** parses the contents of a line of input data.
|
|
585
|
+
**
|
|
586
|
+
** Input:
|
|
587
|
+
** sect = index of current input data section
|
|
588
|
+
** line = contents of current line of input data
|
|
589
|
+
**
|
|
590
|
+
** Returns:
|
|
591
|
+
** an error code (0 if no error)
|
|
592
|
+
*/
|
|
593
|
+
{
|
|
594
|
+
switch(sect)
|
|
595
|
+
{
|
|
596
|
+
case s_TITLE:
|
|
597
|
+
strcpy(MSX.Title, line);
|
|
598
|
+
break;
|
|
599
|
+
|
|
600
|
+
case s_OPTION:
|
|
601
|
+
return parseOption();
|
|
602
|
+
|
|
603
|
+
case s_SPECIES:
|
|
604
|
+
return parseSpecies();
|
|
605
|
+
|
|
606
|
+
case s_COEFF:
|
|
607
|
+
return parseCoeff();
|
|
608
|
+
|
|
609
|
+
case s_TERM:
|
|
610
|
+
return parseTerm();
|
|
611
|
+
|
|
612
|
+
case s_PIPE:
|
|
613
|
+
return parseExpression(LINK);
|
|
614
|
+
|
|
615
|
+
case s_TANK:
|
|
616
|
+
return parseExpression(TANK);
|
|
617
|
+
|
|
618
|
+
case s_SOURCE:
|
|
619
|
+
return parseSource();
|
|
620
|
+
|
|
621
|
+
case s_QUALITY:
|
|
622
|
+
return parseQuality();
|
|
623
|
+
|
|
624
|
+
case s_PARAMETER:
|
|
625
|
+
return parseParameter();
|
|
626
|
+
|
|
627
|
+
case s_PATTERN:
|
|
628
|
+
return parsePattern();
|
|
629
|
+
|
|
630
|
+
case s_REPORT:
|
|
631
|
+
return parseReport();
|
|
632
|
+
|
|
633
|
+
case s_Diffu:
|
|
634
|
+
return parseDiffu();
|
|
635
|
+
}
|
|
636
|
+
return 0;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
//=============================================================================
|
|
640
|
+
|
|
641
|
+
int parseOption()
|
|
642
|
+
/*
|
|
643
|
+
** Purpose:
|
|
644
|
+
** parses an input line containing a project option.
|
|
645
|
+
**
|
|
646
|
+
** Input:
|
|
647
|
+
** none
|
|
648
|
+
**
|
|
649
|
+
** Returns:
|
|
650
|
+
** an error code (0 if no error)
|
|
651
|
+
*/
|
|
652
|
+
{
|
|
653
|
+
int k;
|
|
654
|
+
double v;
|
|
655
|
+
|
|
656
|
+
// --- determine which option is being read
|
|
657
|
+
|
|
658
|
+
if ( Ntokens < 2 ) return 0;
|
|
659
|
+
k = MSXutils_findmatch(Tok[0], OptionTypeWords);
|
|
660
|
+
if ( k < 0 ) return ERR_KEYWORD;
|
|
661
|
+
|
|
662
|
+
// --- parse the value for the given option
|
|
663
|
+
|
|
664
|
+
switch ( k )
|
|
665
|
+
{
|
|
666
|
+
case AREA_UNITS_OPTION:
|
|
667
|
+
k = MSXutils_findmatch(Tok[1], AreaUnitsWords);
|
|
668
|
+
if ( k < 0 ) return ERR_KEYWORD;
|
|
669
|
+
MSX.AreaUnits = k;
|
|
670
|
+
break;
|
|
671
|
+
|
|
672
|
+
case RATE_UNITS_OPTION:
|
|
673
|
+
k = MSXutils_findmatch(Tok[1], TimeUnitsWords);
|
|
674
|
+
if ( k < 0 ) return ERR_KEYWORD;
|
|
675
|
+
MSX.RateUnits = k;
|
|
676
|
+
break;
|
|
677
|
+
|
|
678
|
+
case SOLVER_OPTION:
|
|
679
|
+
k = MSXutils_findmatch(Tok[1], SolverTypeWords);
|
|
680
|
+
if ( k < 0 ) return ERR_KEYWORD;
|
|
681
|
+
MSX.Solver = k;
|
|
682
|
+
break;
|
|
683
|
+
|
|
684
|
+
case COUPLING_OPTION:
|
|
685
|
+
k = MSXutils_findmatch(Tok[1], CouplingWords);
|
|
686
|
+
if ( k < 0 ) return ERR_KEYWORD;
|
|
687
|
+
MSX.Coupling = k;
|
|
688
|
+
break;
|
|
689
|
+
|
|
690
|
+
case TIMESTEP_OPTION:
|
|
691
|
+
|
|
692
|
+
// Read time step as a floating point value in seconds
|
|
693
|
+
if ( !MSXutils_getDouble(Tok[1], &v) ) return ERR_NUMBER;
|
|
694
|
+
if ( v < 0.001 ) return ERR_NUMBER;
|
|
695
|
+
|
|
696
|
+
// Convert time step to integer milliseconds
|
|
697
|
+
v = round(v * 1000.);
|
|
698
|
+
MSX.Qstep = (int64_t)v;
|
|
699
|
+
break;
|
|
700
|
+
|
|
701
|
+
case RTOL_OPTION:
|
|
702
|
+
if ( !MSXutils_getDouble(Tok[1], &MSX.DefRtol) ) return ERR_NUMBER;
|
|
703
|
+
break;
|
|
704
|
+
|
|
705
|
+
case ATOL_OPTION:
|
|
706
|
+
if ( !MSXutils_getDouble(Tok[1], &MSX.DefAtol) ) return ERR_NUMBER;
|
|
707
|
+
break;
|
|
708
|
+
|
|
709
|
+
case COMPILER_OPTION:
|
|
710
|
+
k = MSXutils_findmatch(Tok[1], CompilerWords);
|
|
711
|
+
if ( k < 0 ) return ERR_KEYWORD;
|
|
712
|
+
MSX.Compiler = k;
|
|
713
|
+
break;
|
|
714
|
+
|
|
715
|
+
case PECLETNUMER_OPTION:
|
|
716
|
+
v = atof(Tok[1]);
|
|
717
|
+
if (v <= 0.0)return ERR_NUMBER;
|
|
718
|
+
MSX.Dispersion.PecletLimit = MAX(v, 1.0);
|
|
719
|
+
break;
|
|
720
|
+
|
|
721
|
+
case MAXSEGMENT_OPTION:
|
|
722
|
+
k = atoi(Tok[1]);
|
|
723
|
+
if (k <= 0) return ERR_NUMBER;
|
|
724
|
+
MSX.MaxSegments = MAX(k, 50); //at least 50 segments
|
|
725
|
+
|
|
726
|
+
}
|
|
727
|
+
return 0;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
//=============================================================================
|
|
731
|
+
|
|
732
|
+
int parseSpecies()
|
|
733
|
+
/*
|
|
734
|
+
** Purpose:
|
|
735
|
+
** parses an input line containing a species variable.
|
|
736
|
+
**
|
|
737
|
+
** Input:
|
|
738
|
+
** none
|
|
739
|
+
**
|
|
740
|
+
** Returns:
|
|
741
|
+
** an error code (0 if no error)
|
|
742
|
+
*/
|
|
743
|
+
{
|
|
744
|
+
int i;
|
|
745
|
+
|
|
746
|
+
// --- get Species index
|
|
747
|
+
|
|
748
|
+
if ( Ntokens < 3 ) return ERR_ITEMS;
|
|
749
|
+
i = MSXproj_findObject(SPECIES, Tok[1]);
|
|
750
|
+
if ( i <= 0 ) return ERR_NAME;
|
|
751
|
+
|
|
752
|
+
// --- get pointer to Species name
|
|
753
|
+
|
|
754
|
+
MSX.Species[i].id = MSXproj_findID(SPECIES, Tok[1]);
|
|
755
|
+
|
|
756
|
+
// --- get Species type
|
|
757
|
+
|
|
758
|
+
if ( MSXutils_match(Tok[0], "BULK") ) MSX.Species[i].type = BULK;
|
|
759
|
+
else if ( MSXutils_match(Tok[0], "WALL") ) MSX.Species[i].type = WALL;
|
|
760
|
+
else return ERR_KEYWORD;
|
|
761
|
+
|
|
762
|
+
// --- get Species units
|
|
763
|
+
|
|
764
|
+
strncpy(MSX.Species[i].units, Tok[2], MAXUNITS);
|
|
765
|
+
|
|
766
|
+
// --- get Species error tolerance
|
|
767
|
+
|
|
768
|
+
MSX.Species[i].aTol = 0.0;
|
|
769
|
+
MSX.Species[i].rTol = 0.0;
|
|
770
|
+
if ( Ntokens >= 4)
|
|
771
|
+
{
|
|
772
|
+
if ( !MSXutils_getDouble(Tok[3], &MSX.Species[i].aTol) )
|
|
773
|
+
return ERR_NUMBER;
|
|
774
|
+
}
|
|
775
|
+
if ( Ntokens >= 5)
|
|
776
|
+
{
|
|
777
|
+
if ( !MSXutils_getDouble(Tok[4], &MSX.Species[i].rTol) )
|
|
778
|
+
return ERR_NUMBER;
|
|
779
|
+
}
|
|
780
|
+
return 0;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
//=============================================================================
|
|
784
|
+
|
|
785
|
+
int parseCoeff()
|
|
786
|
+
/*
|
|
787
|
+
** Purpose:
|
|
788
|
+
** parses an input line containing a coefficient definition.
|
|
789
|
+
**
|
|
790
|
+
** Input:
|
|
791
|
+
** none
|
|
792
|
+
**
|
|
793
|
+
** Returns:
|
|
794
|
+
** an error code (0 if no error)
|
|
795
|
+
*/
|
|
796
|
+
{
|
|
797
|
+
int i, j;
|
|
798
|
+
double x;
|
|
799
|
+
|
|
800
|
+
// --- check if variable is a Parameter
|
|
801
|
+
|
|
802
|
+
if ( Ntokens < 2 ) return 0;
|
|
803
|
+
if ( MSXutils_match(Tok[0], "PARAM") )
|
|
804
|
+
{
|
|
805
|
+
// --- get Parameter's index
|
|
806
|
+
|
|
807
|
+
i = MSXproj_findObject(PARAMETER, Tok[1]);
|
|
808
|
+
if ( i <= 0 ) return ERR_NAME;
|
|
809
|
+
|
|
810
|
+
// --- get Parameter's value
|
|
811
|
+
|
|
812
|
+
MSX.Param[i].id = MSXproj_findID(PARAMETER, Tok[1]);
|
|
813
|
+
if ( Ntokens >= 3 )
|
|
814
|
+
{
|
|
815
|
+
if ( !MSXutils_getDouble(Tok[2], &x) ) return ERR_NUMBER;
|
|
816
|
+
MSX.Param[i].value = x;
|
|
817
|
+
for (j=1; j<=MSX.Nobjects[LINK]; j++) MSX.Link[j].param[i] = x;
|
|
818
|
+
for (j=1; j<=MSX.Nobjects[TANK]; j++) MSX.Tank[j].param[i] = x;
|
|
819
|
+
}
|
|
820
|
+
return 0;
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
// --- check if variable is a Constant
|
|
824
|
+
|
|
825
|
+
else if ( MSXutils_match(Tok[0], "CONST") )
|
|
826
|
+
{
|
|
827
|
+
// --- get Constant's index
|
|
828
|
+
|
|
829
|
+
i = MSXproj_findObject(CONSTANT, Tok[1]);
|
|
830
|
+
if ( i <= 0 ) return ERR_NAME;
|
|
831
|
+
|
|
832
|
+
// --- get Constant's value
|
|
833
|
+
|
|
834
|
+
MSX.Const[i].id = MSXproj_findID(CONSTANT, Tok[1]);
|
|
835
|
+
MSX.Const[i].value = 0.0;
|
|
836
|
+
if ( Ntokens >= 3 )
|
|
837
|
+
{
|
|
838
|
+
if ( !MSXutils_getDouble(Tok[2], &MSX.Const[i].value) )
|
|
839
|
+
return ERR_NUMBER;
|
|
840
|
+
}
|
|
841
|
+
return 0;
|
|
842
|
+
}
|
|
843
|
+
else return ERR_KEYWORD;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
//=============================================================================
|
|
847
|
+
|
|
848
|
+
int parseTerm()
|
|
849
|
+
/*
|
|
850
|
+
** Purpose:
|
|
851
|
+
** parses an input line containing an intermediate expression term .
|
|
852
|
+
**
|
|
853
|
+
** Input:
|
|
854
|
+
** none
|
|
855
|
+
**
|
|
856
|
+
** Returns:
|
|
857
|
+
** an error code (0 if no error)
|
|
858
|
+
*/
|
|
859
|
+
{
|
|
860
|
+
int i, j;
|
|
861
|
+
int k;
|
|
862
|
+
char s[MAXLINE+1] = "";
|
|
863
|
+
MathExpr *expr;
|
|
864
|
+
|
|
865
|
+
// --- get term's name
|
|
866
|
+
|
|
867
|
+
if ( Ntokens < 2 ) return 0;
|
|
868
|
+
i = MSXproj_findObject(TERM, Tok[0]);
|
|
869
|
+
MSX.Term[i].id = MSXproj_findID(TERM, Tok[0]);
|
|
870
|
+
|
|
871
|
+
// --- reconstruct the expression string from its tokens
|
|
872
|
+
|
|
873
|
+
for (j=1; j<Ntokens; j++)
|
|
874
|
+
{
|
|
875
|
+
strcat(s, Tok[j]);
|
|
876
|
+
k = MSXproj_findObject(TERM, Tok[j]);
|
|
877
|
+
if ( k > 0 ) TermArray[i][k] = 1.0;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
// --- convert expression into a postfix stack of op codes
|
|
881
|
+
|
|
882
|
+
expr = mathexpr_create(s, getVariableCode);
|
|
883
|
+
if ( expr == NULL ) return ERR_MATH_EXPR;
|
|
884
|
+
|
|
885
|
+
// --- assign the expression to a Term object
|
|
886
|
+
|
|
887
|
+
MSX.Term[i].expr = expr;
|
|
888
|
+
return 0;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
//=============================================================================
|
|
892
|
+
|
|
893
|
+
int parseExpression(int classType)
|
|
894
|
+
/*
|
|
895
|
+
** Purpose:
|
|
896
|
+
** parses an input line containing a math expression.
|
|
897
|
+
**
|
|
898
|
+
** Input:
|
|
899
|
+
** classType = either LINK or TANK
|
|
900
|
+
**
|
|
901
|
+
** Returns:
|
|
902
|
+
** an error code (0 if no error)
|
|
903
|
+
*/
|
|
904
|
+
{
|
|
905
|
+
int i, j, k;
|
|
906
|
+
char s[MAXLINE+1] = "";
|
|
907
|
+
MathExpr *expr;
|
|
908
|
+
|
|
909
|
+
// --- determine expression type
|
|
910
|
+
|
|
911
|
+
if ( Ntokens < 3 ) return ERR_ITEMS;
|
|
912
|
+
k = MSXutils_findmatch(Tok[0], ExprTypeWords);
|
|
913
|
+
if ( k < 0 ) return ERR_KEYWORD;
|
|
914
|
+
|
|
915
|
+
// --- determine species associated with expression
|
|
916
|
+
|
|
917
|
+
i = MSXproj_findObject(SPECIES, Tok[1]);
|
|
918
|
+
if ( i < 1 ) return ERR_NAME;
|
|
919
|
+
|
|
920
|
+
// --- check that species does not already have an expression
|
|
921
|
+
|
|
922
|
+
if ( classType == LINK )
|
|
923
|
+
{
|
|
924
|
+
if ( MSX.Species[i].pipeExprType != NO_EXPR ) return ERR_DUP_EXPR;
|
|
925
|
+
}
|
|
926
|
+
if ( classType == TANK )
|
|
927
|
+
{
|
|
928
|
+
if ( MSX.Species[i].tankExprType != NO_EXPR ) return ERR_DUP_EXPR;
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
// --- reconstruct the expression string from its tokens
|
|
932
|
+
|
|
933
|
+
for (j=2; j<Ntokens; j++) strcat(s, Tok[j]);
|
|
934
|
+
|
|
935
|
+
// --- convert expression into a postfix stack of op codes
|
|
936
|
+
|
|
937
|
+
expr = mathexpr_create(s, getVariableCode);
|
|
938
|
+
if ( expr == NULL ) return ERR_MATH_EXPR;
|
|
939
|
+
|
|
940
|
+
// --- assign the expression to the species
|
|
941
|
+
|
|
942
|
+
switch (classType)
|
|
943
|
+
{
|
|
944
|
+
case LINK:
|
|
945
|
+
MSX.Species[i].pipeExpr = expr;
|
|
946
|
+
MSX.Species[i].pipeExprType = k;
|
|
947
|
+
break;
|
|
948
|
+
case TANK:
|
|
949
|
+
MSX.Species[i].tankExpr = expr;
|
|
950
|
+
MSX.Species[i].tankExprType = k;
|
|
951
|
+
break;
|
|
952
|
+
}
|
|
953
|
+
return 0;
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
//=============================================================================
|
|
957
|
+
|
|
958
|
+
int parseQuality()
|
|
959
|
+
/*
|
|
960
|
+
** Purpose:
|
|
961
|
+
** parses an input line containing initial species concentrations.
|
|
962
|
+
**
|
|
963
|
+
** Input:
|
|
964
|
+
** none
|
|
965
|
+
**
|
|
966
|
+
** Returns:
|
|
967
|
+
** an error code (0 if no error)
|
|
968
|
+
*/
|
|
969
|
+
{
|
|
970
|
+
int err, i, j, k, m;
|
|
971
|
+
double x;
|
|
972
|
+
|
|
973
|
+
// --- determine if quality value is global or object-specific
|
|
974
|
+
|
|
975
|
+
if ( Ntokens < 3 ) return ERR_ITEMS;
|
|
976
|
+
if ( MSXutils_match(Tok[0], "GLOBAL") ) i = 1;
|
|
977
|
+
else if ( MSXutils_match(Tok[0], "NODE") ) i = 2;
|
|
978
|
+
else if ( MSXutils_match(Tok[0], "LINK") ) i = 3;
|
|
979
|
+
else return ERR_KEYWORD;
|
|
980
|
+
|
|
981
|
+
// --- find species index
|
|
982
|
+
|
|
983
|
+
k = 1;
|
|
984
|
+
if ( i >= 2 ) k = 2;
|
|
985
|
+
m = MSXproj_findObject(SPECIES, Tok[k]);
|
|
986
|
+
if ( m <= 0 ) return ERR_NAME;
|
|
987
|
+
|
|
988
|
+
// --- get quality value
|
|
989
|
+
|
|
990
|
+
if ( i >= 2 && Ntokens < 4 ) return ERR_ITEMS;
|
|
991
|
+
k = 2;
|
|
992
|
+
if ( i >= 2 ) k = 3;
|
|
993
|
+
if ( !MSXutils_getDouble(Tok[k], &x) ) return ERR_NUMBER;
|
|
994
|
+
|
|
995
|
+
// --- for global specification, set initial quality either for
|
|
996
|
+
// all nodes or links depending on type of species
|
|
997
|
+
|
|
998
|
+
if ( i == 1)
|
|
999
|
+
{
|
|
1000
|
+
MSX.C0[m] = x;
|
|
1001
|
+
if ( MSX.Species[m].type == BULK )
|
|
1002
|
+
{
|
|
1003
|
+
for (j=1; j<=MSX.Nobjects[NODE]; j++) MSX.Node[j].c0[m] = x;
|
|
1004
|
+
}
|
|
1005
|
+
for (j=1; j<=MSX.Nobjects[LINK]; j++) MSX.Link[j].c0[m] = x;
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
// --- for a specific node, get its index & set its initial quality
|
|
1009
|
+
|
|
1010
|
+
else if ( i == 2 )
|
|
1011
|
+
{
|
|
1012
|
+
err = ENgetnodeindex(Tok[1], &j);
|
|
1013
|
+
if ( err ) return ERR_NAME;
|
|
1014
|
+
if ( MSX.Species[m].type == BULK ) MSX.Node[j].c0[m] = x;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
// --- for a specific link, get its index & set its initial quality
|
|
1018
|
+
|
|
1019
|
+
else if ( i == 3 )
|
|
1020
|
+
{
|
|
1021
|
+
err = ENgetlinkindex(Tok[1], &j);
|
|
1022
|
+
if ( err ) return ERR_NAME;
|
|
1023
|
+
MSX.Link[j].c0[m] = x;
|
|
1024
|
+
}
|
|
1025
|
+
return 0;
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
//=============================================================================
|
|
1029
|
+
|
|
1030
|
+
int parseParameter()
|
|
1031
|
+
/*
|
|
1032
|
+
** Purpose:
|
|
1033
|
+
** parses an input line containing a parameter data.
|
|
1034
|
+
**
|
|
1035
|
+
** Input:
|
|
1036
|
+
** none
|
|
1037
|
+
**
|
|
1038
|
+
** Returns:
|
|
1039
|
+
** an error code (0 if no error)
|
|
1040
|
+
*/
|
|
1041
|
+
{
|
|
1042
|
+
int err, i, j;
|
|
1043
|
+
double x;
|
|
1044
|
+
|
|
1045
|
+
// --- get parameter name
|
|
1046
|
+
|
|
1047
|
+
if ( Ntokens < 4 ) return 0;
|
|
1048
|
+
i = MSXproj_findObject(PARAMETER, Tok[2]);
|
|
1049
|
+
|
|
1050
|
+
// --- get parameter value
|
|
1051
|
+
|
|
1052
|
+
if ( !MSXutils_getDouble(Tok[3], &x) ) return ERR_NUMBER;
|
|
1053
|
+
|
|
1054
|
+
// --- for pipe parameter, get pipe index and update parameter's value
|
|
1055
|
+
|
|
1056
|
+
if ( MSXutils_match(Tok[0], "PIPE") )
|
|
1057
|
+
{
|
|
1058
|
+
err = ENgetlinkindex(Tok[1], &j);
|
|
1059
|
+
if ( err ) return ERR_NAME;
|
|
1060
|
+
MSX.Link[j].param[i] = x;
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
// --- for tank parameter, get tank index and update parameter's value
|
|
1064
|
+
|
|
1065
|
+
else if ( MSXutils_match(Tok[0], "TANK") )
|
|
1066
|
+
{
|
|
1067
|
+
err = ENgetnodeindex(Tok[1], &j);
|
|
1068
|
+
if ( err ) return ERR_NAME;
|
|
1069
|
+
j = MSX.Node[j].tank;
|
|
1070
|
+
if ( j > 0 ) MSX.Tank[j].param[i] = x;
|
|
1071
|
+
}
|
|
1072
|
+
else return ERR_KEYWORD;
|
|
1073
|
+
return 0;
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
//=============================================================================
|
|
1077
|
+
|
|
1078
|
+
int parseSource()
|
|
1079
|
+
/*
|
|
1080
|
+
** Purpose:
|
|
1081
|
+
** parses an input line containing a source input data.
|
|
1082
|
+
**
|
|
1083
|
+
** Input:
|
|
1084
|
+
** none
|
|
1085
|
+
**
|
|
1086
|
+
** Returns:
|
|
1087
|
+
** an error code (0 if no error)
|
|
1088
|
+
*/
|
|
1089
|
+
{
|
|
1090
|
+
int err, i, j, k, m;
|
|
1091
|
+
double x;
|
|
1092
|
+
Psource source;
|
|
1093
|
+
|
|
1094
|
+
// --- get source type
|
|
1095
|
+
|
|
1096
|
+
if ( Ntokens < 4 ) return ERR_ITEMS;
|
|
1097
|
+
k = MSXutils_findmatch(Tok[0], SourceTypeWords);
|
|
1098
|
+
if ( k < 0 ) return ERR_KEYWORD;
|
|
1099
|
+
|
|
1100
|
+
// --- get node index
|
|
1101
|
+
|
|
1102
|
+
err = ENgetnodeindex(Tok[1], &j);
|
|
1103
|
+
if ( err ) return ERR_NAME;
|
|
1104
|
+
|
|
1105
|
+
// --- get species index
|
|
1106
|
+
|
|
1107
|
+
m = MSXproj_findObject(SPECIES, Tok[2]);
|
|
1108
|
+
if ( m <= 0 ) return ERR_NAME;
|
|
1109
|
+
|
|
1110
|
+
// --- check that species is a BULK species
|
|
1111
|
+
|
|
1112
|
+
if ( MSX.Species[m].type != BULK ) return 0;
|
|
1113
|
+
|
|
1114
|
+
// --- get base strength
|
|
1115
|
+
|
|
1116
|
+
if ( !MSXutils_getDouble(Tok[3], &x) ) return ERR_NUMBER;
|
|
1117
|
+
|
|
1118
|
+
// --- get time pattern if present
|
|
1119
|
+
|
|
1120
|
+
i = 0;
|
|
1121
|
+
if ( Ntokens >= 5 )
|
|
1122
|
+
{
|
|
1123
|
+
i = MSXproj_findObject(PATTERN, Tok[4]);
|
|
1124
|
+
if ( i <= 0 ) return ERR_NAME;
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
// --- check if a source for this species already exists
|
|
1128
|
+
|
|
1129
|
+
source = MSX.Node[j].sources;
|
|
1130
|
+
while ( source )
|
|
1131
|
+
{
|
|
1132
|
+
if ( source->species == m ) break;
|
|
1133
|
+
source = source->next;
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
// --- otherwise create a new source object
|
|
1137
|
+
|
|
1138
|
+
if ( source == NULL )
|
|
1139
|
+
{
|
|
1140
|
+
source = (struct Ssource *) malloc(sizeof(struct Ssource));
|
|
1141
|
+
if ( source == NULL ) return 101;
|
|
1142
|
+
source->next = MSX.Node[j].sources;
|
|
1143
|
+
MSX.Node[j].sources = source;
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
// --- save source's properties
|
|
1147
|
+
|
|
1148
|
+
source->type = (char)k;
|
|
1149
|
+
source->species = m;
|
|
1150
|
+
source->c0 = x;
|
|
1151
|
+
source->pat = i;
|
|
1152
|
+
return 0;
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
//=============================================================================
|
|
1156
|
+
|
|
1157
|
+
int parsePattern()
|
|
1158
|
+
/*
|
|
1159
|
+
** Purpose:
|
|
1160
|
+
** parses an input line containing a time pattern data.
|
|
1161
|
+
**
|
|
1162
|
+
** Input:
|
|
1163
|
+
** none
|
|
1164
|
+
**
|
|
1165
|
+
** Returns:
|
|
1166
|
+
** an error code (0 if no error)
|
|
1167
|
+
*/
|
|
1168
|
+
{
|
|
1169
|
+
int i, k;
|
|
1170
|
+
double x;
|
|
1171
|
+
SnumList *listItem;
|
|
1172
|
+
|
|
1173
|
+
// --- get time pattern index
|
|
1174
|
+
|
|
1175
|
+
if ( Ntokens < 2 ) return ERR_ITEMS;
|
|
1176
|
+
i = MSXproj_findObject(PATTERN, Tok[0]);
|
|
1177
|
+
if ( i <= 0 ) return ERR_NAME;
|
|
1178
|
+
MSX.Pattern[i].id = MSXproj_findID(PATTERN, Tok[0]);
|
|
1179
|
+
|
|
1180
|
+
// --- begin reading pattern multipliers
|
|
1181
|
+
|
|
1182
|
+
k = 1;
|
|
1183
|
+
while ( k < Ntokens )
|
|
1184
|
+
{
|
|
1185
|
+
if ( !MSXutils_getDouble(Tok[k], &x) ) return ERR_NUMBER;
|
|
1186
|
+
listItem = (SnumList *) malloc(sizeof(SnumList));
|
|
1187
|
+
if ( listItem == NULL ) return 101;
|
|
1188
|
+
listItem->value = x;
|
|
1189
|
+
listItem->next = NULL;
|
|
1190
|
+
if ( MSX.Pattern[i].first == NULL )
|
|
1191
|
+
{
|
|
1192
|
+
MSX.Pattern[i].current = listItem;
|
|
1193
|
+
MSX.Pattern[i].first = listItem;
|
|
1194
|
+
}
|
|
1195
|
+
else
|
|
1196
|
+
{
|
|
1197
|
+
MSX.Pattern[i].current->next = listItem;
|
|
1198
|
+
MSX.Pattern[i].current = listItem;
|
|
1199
|
+
}
|
|
1200
|
+
MSX.Pattern[i].length++;
|
|
1201
|
+
k++;
|
|
1202
|
+
}
|
|
1203
|
+
return 0;
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
//=============================================================================
|
|
1207
|
+
|
|
1208
|
+
int parseReport()
|
|
1209
|
+
{
|
|
1210
|
+
int i, j, k, err;
|
|
1211
|
+
|
|
1212
|
+
// --- get keyword
|
|
1213
|
+
|
|
1214
|
+
if ( Ntokens < 2 ) return 0;
|
|
1215
|
+
k = MSXutils_findmatch(Tok[0], ReportWords);
|
|
1216
|
+
if ( k < 0 ) return ERR_KEYWORD;
|
|
1217
|
+
switch(k)
|
|
1218
|
+
{
|
|
1219
|
+
|
|
1220
|
+
// --- keyword is NODE; parse ID names of reported nodes
|
|
1221
|
+
|
|
1222
|
+
case 0:
|
|
1223
|
+
if ( MSXutils_strcomp(Tok[1], ALL) )
|
|
1224
|
+
{
|
|
1225
|
+
for (j=1; j<=MSX.Nobjects[NODE]; j++) MSX.Node[j].rpt = 1;
|
|
1226
|
+
}
|
|
1227
|
+
else if ( MSXutils_strcomp(Tok[1], NONE) )
|
|
1228
|
+
{
|
|
1229
|
+
for (j=1; j<=MSX.Nobjects[NODE]; j++) MSX.Node[j].rpt = 0;
|
|
1230
|
+
}
|
|
1231
|
+
else for (i=1; i<Ntokens; i++)
|
|
1232
|
+
{
|
|
1233
|
+
err = ENgetnodeindex(Tok[i], &j);
|
|
1234
|
+
if ( err ) return ERR_NAME;
|
|
1235
|
+
MSX.Node[j].rpt = 1;
|
|
1236
|
+
}
|
|
1237
|
+
break;
|
|
1238
|
+
|
|
1239
|
+
// --- keyword is LINK: parse ID names of reported links
|
|
1240
|
+
case 1:
|
|
1241
|
+
if ( MSXutils_strcomp(Tok[1], ALL) )
|
|
1242
|
+
{
|
|
1243
|
+
for (j=1; j<=MSX.Nobjects[LINK]; j++) MSX.Link[j].rpt = 1;
|
|
1244
|
+
}
|
|
1245
|
+
else if ( MSXutils_strcomp(Tok[1], NONE) )
|
|
1246
|
+
{
|
|
1247
|
+
for (j=1; j<=MSX.Nobjects[LINK]; j++) MSX.Link[j].rpt = 0;
|
|
1248
|
+
}
|
|
1249
|
+
else for (i=1; i<Ntokens; i++)
|
|
1250
|
+
{
|
|
1251
|
+
err = ENgetlinkindex(Tok[i], &j);
|
|
1252
|
+
if ( err ) return ERR_NAME;
|
|
1253
|
+
MSX.Link[j].rpt = 1;
|
|
1254
|
+
}
|
|
1255
|
+
break;
|
|
1256
|
+
|
|
1257
|
+
// --- keyword is SPECIES; get YES/NO & precision
|
|
1258
|
+
|
|
1259
|
+
case 2:
|
|
1260
|
+
j = MSXproj_findObject(SPECIES, Tok[1]);
|
|
1261
|
+
if ( j <= 0 ) return ERR_NAME;
|
|
1262
|
+
if ( Ntokens >= 3 )
|
|
1263
|
+
{
|
|
1264
|
+
if ( MSXutils_strcomp(Tok[2], YES) ) MSX.Species[j].rpt = 1;
|
|
1265
|
+
else if ( MSXutils_strcomp(Tok[2], NO) ) MSX.Species[j].rpt = 0;
|
|
1266
|
+
else return ERR_KEYWORD;
|
|
1267
|
+
}
|
|
1268
|
+
if ( Ntokens >= 4 )
|
|
1269
|
+
{
|
|
1270
|
+
if ( !MSXutils_getInt(Tok[3], &MSX.Species[j].precision) )
|
|
1271
|
+
return ERR_NUMBER;
|
|
1272
|
+
}
|
|
1273
|
+
break;
|
|
1274
|
+
|
|
1275
|
+
// --- keyword is FILE: get name of report file
|
|
1276
|
+
|
|
1277
|
+
case 3:
|
|
1278
|
+
strcpy(MSX.RptFile.name, Tok[1]);
|
|
1279
|
+
break;
|
|
1280
|
+
|
|
1281
|
+
// --- keyword is PAGESIZE;
|
|
1282
|
+
|
|
1283
|
+
case 4:
|
|
1284
|
+
if ( !MSXutils_getInt(Tok[1], &MSX.PageSize) ) return ERR_NUMBER;
|
|
1285
|
+
break;
|
|
1286
|
+
}
|
|
1287
|
+
return 0;
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
int parseDiffu()
|
|
1291
|
+
/*
|
|
1292
|
+
** Purpose:
|
|
1293
|
+
** parses an input line containing molecular diffusivity data.
|
|
1294
|
+
**
|
|
1295
|
+
** Input:
|
|
1296
|
+
** none
|
|
1297
|
+
**
|
|
1298
|
+
** Returns:
|
|
1299
|
+
** an error code (0 if no error)
|
|
1300
|
+
*/
|
|
1301
|
+
{
|
|
1302
|
+
int m;
|
|
1303
|
+
double x;
|
|
1304
|
+
|
|
1305
|
+
// --- get source type
|
|
1306
|
+
if (Ntokens < 2) return ERR_ITEMS;
|
|
1307
|
+
|
|
1308
|
+
// --- get species index
|
|
1309
|
+
m = MSXproj_findObject(SPECIES, Tok[0]);
|
|
1310
|
+
if (m <= 0) return ERR_NAME;
|
|
1311
|
+
|
|
1312
|
+
// --- check that species is a BULK species
|
|
1313
|
+
if (MSX.Species[m].type != BULK) return 0;
|
|
1314
|
+
|
|
1315
|
+
// --- get base strength
|
|
1316
|
+
if (!MSXutils_getDouble(Tok[1], &x)) return ERR_NUMBER;
|
|
1317
|
+
if (x < 0) return ERR_NUMBER;
|
|
1318
|
+
|
|
1319
|
+
if (Ntokens > 2 && MSXutils_match(Tok[2], "FIXED"))
|
|
1320
|
+
{
|
|
1321
|
+
x = x * MSX.Dispersion.DIFFUS;
|
|
1322
|
+
MSX.Dispersion.ld[m] = x;
|
|
1323
|
+
}
|
|
1324
|
+
else
|
|
1325
|
+
{
|
|
1326
|
+
x = x * MSX.Dispersion.DIFFUS;
|
|
1327
|
+
MSX.Dispersion.md[m] = x;
|
|
1328
|
+
}
|
|
1329
|
+
MSX.DispersionFlag = 1;
|
|
1330
|
+
return 0;
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
//=============================================================================
|
|
1334
|
+
|
|
1335
|
+
int getVariableCode(char *id)
|
|
1336
|
+
/*
|
|
1337
|
+
** Purpose:
|
|
1338
|
+
** finds the index assigned to a species, intermediate term,
|
|
1339
|
+
** parameter, or constant that appears in a math expression.
|
|
1340
|
+
**
|
|
1341
|
+
** Input:
|
|
1342
|
+
** id = ID name being sought
|
|
1343
|
+
**
|
|
1344
|
+
** Returns:
|
|
1345
|
+
** index of the symbolic variable or term named id.
|
|
1346
|
+
**
|
|
1347
|
+
** Note:
|
|
1348
|
+
** Variables are assigned consecutive code numbers starting from 1
|
|
1349
|
+
** and proceeding through each Species, Term, Parameter and Constant.
|
|
1350
|
+
*/
|
|
1351
|
+
{
|
|
1352
|
+
int j = MSXproj_findObject(SPECIES, id);
|
|
1353
|
+
if ( j >= 1 ) return j;
|
|
1354
|
+
j = MSXproj_findObject(TERM, id);
|
|
1355
|
+
if ( j >= 1 ) return MSX.Nobjects[SPECIES] + j;
|
|
1356
|
+
j = MSXproj_findObject(PARAMETER, id);
|
|
1357
|
+
if ( j >= 1 ) return MSX.Nobjects[SPECIES] + MSX.Nobjects[TERM] + j;
|
|
1358
|
+
j = MSXproj_findObject(CONSTANT, id);
|
|
1359
|
+
if ( j >= 1 ) return MSX.Nobjects[SPECIES] + MSX.Nobjects[TERM] +
|
|
1360
|
+
MSX.Nobjects[PARAMETER] + j;
|
|
1361
|
+
j = MSXutils_findmatch(id, HydVarWords);
|
|
1362
|
+
if ( j >= 1 ) return MSX.Nobjects[SPECIES] + MSX.Nobjects[TERM] +
|
|
1363
|
+
MSX.Nobjects[PARAMETER] + MSX.Nobjects[CONSTANT] + j;
|
|
1364
|
+
return -1;
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
//=============================================================================
|
|
1368
|
+
|
|
1369
|
+
int getTokens(char *s)
|
|
1370
|
+
/*
|
|
1371
|
+
** Purpose:
|
|
1372
|
+
** scans a string for tokens, saving pointers to them
|
|
1373
|
+
** in shared variable Tok[].
|
|
1374
|
+
**
|
|
1375
|
+
** Input:
|
|
1376
|
+
** s = a character string
|
|
1377
|
+
**
|
|
1378
|
+
** Returns:
|
|
1379
|
+
** number of tokens found in s
|
|
1380
|
+
**
|
|
1381
|
+
** Notes:
|
|
1382
|
+
** Tokens can be separated by the characters listed in SEPSTR
|
|
1383
|
+
** (spaces, tabs, newline, carriage return) which is defined in
|
|
1384
|
+
** MSXGLOBALS.H. Text between quotes is treated as a single token.
|
|
1385
|
+
*/
|
|
1386
|
+
{
|
|
1387
|
+
int len, m, n;
|
|
1388
|
+
char *c;
|
|
1389
|
+
|
|
1390
|
+
// --- begin with no tokens
|
|
1391
|
+
|
|
1392
|
+
for (n = 0; n < MAXTOKS; n++) Tok[n] = NULL;
|
|
1393
|
+
n = 0;
|
|
1394
|
+
|
|
1395
|
+
// --- truncate s at start of comment
|
|
1396
|
+
|
|
1397
|
+
c = strchr(s,';');
|
|
1398
|
+
if (c) *c = '\0';
|
|
1399
|
+
len = (int)strlen(s);
|
|
1400
|
+
|
|
1401
|
+
// --- scan s for tokens until nothing left
|
|
1402
|
+
|
|
1403
|
+
while (len > 0 && n < MAXTOKS)
|
|
1404
|
+
{
|
|
1405
|
+
m = (int)strcspn(s,SEPSTR); // find token length
|
|
1406
|
+
if (m == 0) s++; // no token found
|
|
1407
|
+
else
|
|
1408
|
+
{
|
|
1409
|
+
if (*s == '"') // token begins with quote
|
|
1410
|
+
{
|
|
1411
|
+
s++; // start token after quote
|
|
1412
|
+
len--; // reduce length of s
|
|
1413
|
+
m = (int)strcspn(s,"\"\n"); // find end quote or new line
|
|
1414
|
+
}
|
|
1415
|
+
s[m] = '\0'; // null-terminate the token
|
|
1416
|
+
Tok[n] = s; // save pointer to token
|
|
1417
|
+
n++; // update token count
|
|
1418
|
+
s += m+1; // begin next token
|
|
1419
|
+
}
|
|
1420
|
+
len -= m+1; // update length of s
|
|
1421
|
+
}
|
|
1422
|
+
return(n);
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
//=============================================================================
|
|
1426
|
+
|
|
1427
|
+
void writeInpErrMsg(int errcode, char *sect, char *line, int lineCount)
|
|
1428
|
+
{
|
|
1429
|
+
char msg[MAXMSG+1];
|
|
1430
|
+
if ( errcode >= INP_ERR_LAST || errcode <= INP_ERR_FIRST )
|
|
1431
|
+
{
|
|
1432
|
+
sprintf(msg, "Error Code = %d", errcode);
|
|
1433
|
+
}
|
|
1434
|
+
else
|
|
1435
|
+
{
|
|
1436
|
+
sprintf(msg, "%s at line %d of %s] section:",
|
|
1437
|
+
InpErrorTxt[errcode-INP_ERR_FIRST], lineCount, sect);
|
|
1438
|
+
}
|
|
1439
|
+
ENwriteline("");
|
|
1440
|
+
ENwriteline(msg);
|
|
1441
|
+
ENwriteline(line);
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
//=============================================================================
|
|
1445
|
+
|
|
1446
|
+
int checkCyclicTerms()
|
|
1447
|
+
/*
|
|
1448
|
+
** Purpose:
|
|
1449
|
+
** checks for cyclic references in Term expressions (e.g., T1 = T2 + T3
|
|
1450
|
+
** and T3 = T2/T1)
|
|
1451
|
+
**
|
|
1452
|
+
** Input:
|
|
1453
|
+
** none
|
|
1454
|
+
**
|
|
1455
|
+
** Returns:
|
|
1456
|
+
** 1 if cyclic reference found or 0 if none found.
|
|
1457
|
+
*/
|
|
1458
|
+
{
|
|
1459
|
+
int i, j, n;
|
|
1460
|
+
char msg[MAXMSG+1];
|
|
1461
|
+
|
|
1462
|
+
n = MSX.Nobjects[TERM];
|
|
1463
|
+
for (i=1; i<n; i++)
|
|
1464
|
+
{
|
|
1465
|
+
for (j=1; j<=n; j++) TermArray[0][j] = 0.0;
|
|
1466
|
+
if ( traceTermPath(i, i, n) )
|
|
1467
|
+
{
|
|
1468
|
+
sprintf(msg, "Error 410 - term %s contains a cyclic reference.",
|
|
1469
|
+
MSX.Term[i].id);
|
|
1470
|
+
ENwriteline(msg);
|
|
1471
|
+
return 1;
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
return 0;
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
//=============================================================================
|
|
1478
|
+
|
|
1479
|
+
int traceTermPath(int i, int istar, int n)
|
|
1480
|
+
/*
|
|
1481
|
+
** Purpose:
|
|
1482
|
+
** checks if Term[istar] is in the path of terms that appear when evaluating
|
|
1483
|
+
** Term[i]
|
|
1484
|
+
**
|
|
1485
|
+
** Input:
|
|
1486
|
+
** i = index of term whose expressions are to be traced
|
|
1487
|
+
** istar = index of term being searched for
|
|
1488
|
+
** n = total number of terms
|
|
1489
|
+
**
|
|
1490
|
+
** Returns:
|
|
1491
|
+
** 1 if term istar found; 0 if not found.
|
|
1492
|
+
*/
|
|
1493
|
+
{
|
|
1494
|
+
int j;
|
|
1495
|
+
if ( TermArray[0][i] == 1.0 ) return 0;
|
|
1496
|
+
TermArray[0][i] = 1.0;
|
|
1497
|
+
for (j=1; j<=n; j++)
|
|
1498
|
+
{
|
|
1499
|
+
if ( TermArray[i][j] == 0.0 ) continue;
|
|
1500
|
+
if ( j == istar ) return 1;
|
|
1501
|
+
else if ( traceTermPath(j, istar, n) ) return 1;
|
|
1502
|
+
}
|
|
1503
|
+
return 0;
|
|
1504
|
+
}
|