epyt-flow 0.14.1__py3-none-any.whl → 0.15.0__py3-none-any.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.
- epyt_flow/VERSION +1 -1
- epyt_flow/__init__.py +0 -37
- epyt_flow/data/benchmarks/battledim.py +2 -2
- epyt_flow/data/benchmarks/leakdb.py +12 -9
- epyt_flow/gym/scenario_control_env.py +32 -33
- epyt_flow/simulation/events/actuator_events.py +24 -18
- epyt_flow/simulation/events/leakages.py +59 -57
- epyt_flow/simulation/events/quality_events.py +21 -30
- epyt_flow/simulation/events/system_event.py +3 -3
- epyt_flow/simulation/scada/complex_control.py +14 -12
- epyt_flow/simulation/scada/custom_control.py +22 -21
- epyt_flow/simulation/scada/scada_data.py +108 -105
- epyt_flow/simulation/scada/simple_control.py +38 -31
- epyt_flow/simulation/scenario_simulator.py +368 -395
- epyt_flow/simulation/sensor_config.py +31 -32
- epyt_flow/topology.py +11 -10
- epyt_flow/uncertainty/model_uncertainty.py +146 -122
- epyt_flow/utils.py +66 -0
- epyt_flow/visualization/visualization_utils.py +4 -2
- {epyt_flow-0.14.1.dist-info → epyt_flow-0.15.0.dist-info}/METADATA +14 -19
- epyt_flow-0.15.0.dist-info/RECORD +65 -0
- epyt_flow/EPANET/EPANET/SRC_engines/AUTHORS +0 -60
- epyt_flow/EPANET/EPANET/SRC_engines/LICENSE +0 -21
- epyt_flow/EPANET/EPANET/SRC_engines/enumstxt.h +0 -151
- epyt_flow/EPANET/EPANET/SRC_engines/epanet.c +0 -5930
- epyt_flow/EPANET/EPANET/SRC_engines/epanet2.c +0 -961
- epyt_flow/EPANET/EPANET/SRC_engines/errors.dat +0 -79
- epyt_flow/EPANET/EPANET/SRC_engines/flowbalance.c +0 -186
- epyt_flow/EPANET/EPANET/SRC_engines/funcs.h +0 -219
- epyt_flow/EPANET/EPANET/SRC_engines/genmmd.c +0 -1000
- epyt_flow/EPANET/EPANET/SRC_engines/hash.c +0 -177
- epyt_flow/EPANET/EPANET/SRC_engines/hash.h +0 -28
- epyt_flow/EPANET/EPANET/SRC_engines/hydcoeffs.c +0 -1303
- epyt_flow/EPANET/EPANET/SRC_engines/hydraul.c +0 -1172
- epyt_flow/EPANET/EPANET/SRC_engines/hydsolver.c +0 -781
- epyt_flow/EPANET/EPANET/SRC_engines/hydstatus.c +0 -442
- epyt_flow/EPANET/EPANET/SRC_engines/include/epanet2.h +0 -464
- epyt_flow/EPANET/EPANET/SRC_engines/include/epanet2_2.h +0 -1960
- epyt_flow/EPANET/EPANET/SRC_engines/include/epanet2_enums.h +0 -518
- epyt_flow/EPANET/EPANET/SRC_engines/inpfile.c +0 -884
- epyt_flow/EPANET/EPANET/SRC_engines/input1.c +0 -672
- epyt_flow/EPANET/EPANET/SRC_engines/input2.c +0 -735
- epyt_flow/EPANET/EPANET/SRC_engines/input3.c +0 -2265
- epyt_flow/EPANET/EPANET/SRC_engines/leakage.c +0 -527
- epyt_flow/EPANET/EPANET/SRC_engines/mempool.c +0 -146
- epyt_flow/EPANET/EPANET/SRC_engines/mempool.h +0 -24
- epyt_flow/EPANET/EPANET/SRC_engines/output.c +0 -853
- epyt_flow/EPANET/EPANET/SRC_engines/project.c +0 -1691
- epyt_flow/EPANET/EPANET/SRC_engines/quality.c +0 -695
- epyt_flow/EPANET/EPANET/SRC_engines/qualreact.c +0 -800
- epyt_flow/EPANET/EPANET/SRC_engines/qualroute.c +0 -696
- epyt_flow/EPANET/EPANET/SRC_engines/report.c +0 -1557
- epyt_flow/EPANET/EPANET/SRC_engines/rules.c +0 -1500
- epyt_flow/EPANET/EPANET/SRC_engines/smatrix.c +0 -871
- epyt_flow/EPANET/EPANET/SRC_engines/text.h +0 -508
- epyt_flow/EPANET/EPANET/SRC_engines/types.h +0 -928
- epyt_flow/EPANET/EPANET/SRC_engines/util/cstr_helper.c +0 -59
- epyt_flow/EPANET/EPANET/SRC_engines/util/cstr_helper.h +0 -38
- epyt_flow/EPANET/EPANET/SRC_engines/util/errormanager.c +0 -92
- epyt_flow/EPANET/EPANET/SRC_engines/util/errormanager.h +0 -39
- epyt_flow/EPANET/EPANET/SRC_engines/util/filemanager.c +0 -212
- epyt_flow/EPANET/EPANET/SRC_engines/util/filemanager.h +0 -81
- epyt_flow/EPANET/EPANET/SRC_engines/validate.c +0 -408
- epyt_flow/EPANET/EPANET-MSX/MSX_Updates.txt +0 -53
- epyt_flow/EPANET/EPANET-MSX/Src/dispersion.h +0 -27
- epyt_flow/EPANET/EPANET-MSX/Src/hash.c +0 -107
- epyt_flow/EPANET/EPANET-MSX/Src/hash.h +0 -28
- epyt_flow/EPANET/EPANET-MSX/Src/include/epanetmsx.h +0 -102
- epyt_flow/EPANET/EPANET-MSX/Src/include/epanetmsx_export.h +0 -42
- epyt_flow/EPANET/EPANET-MSX/Src/mathexpr.c +0 -937
- epyt_flow/EPANET/EPANET-MSX/Src/mathexpr.h +0 -39
- epyt_flow/EPANET/EPANET-MSX/Src/mempool.c +0 -204
- epyt_flow/EPANET/EPANET-MSX/Src/mempool.h +0 -24
- epyt_flow/EPANET/EPANET-MSX/Src/msxchem.c +0 -1285
- epyt_flow/EPANET/EPANET-MSX/Src/msxcompiler.c +0 -368
- epyt_flow/EPANET/EPANET-MSX/Src/msxdict.h +0 -42
- epyt_flow/EPANET/EPANET-MSX/Src/msxdispersion.c +0 -586
- epyt_flow/EPANET/EPANET-MSX/Src/msxerr.c +0 -116
- epyt_flow/EPANET/EPANET-MSX/Src/msxfile.c +0 -260
- epyt_flow/EPANET/EPANET-MSX/Src/msxfuncs.c +0 -175
- epyt_flow/EPANET/EPANET-MSX/Src/msxfuncs.h +0 -35
- epyt_flow/EPANET/EPANET-MSX/Src/msxinp.c +0 -1504
- epyt_flow/EPANET/EPANET-MSX/Src/msxout.c +0 -401
- epyt_flow/EPANET/EPANET-MSX/Src/msxproj.c +0 -791
- epyt_flow/EPANET/EPANET-MSX/Src/msxqual.c +0 -2010
- epyt_flow/EPANET/EPANET-MSX/Src/msxrpt.c +0 -400
- epyt_flow/EPANET/EPANET-MSX/Src/msxtank.c +0 -422
- epyt_flow/EPANET/EPANET-MSX/Src/msxtoolkit.c +0 -1164
- epyt_flow/EPANET/EPANET-MSX/Src/msxtypes.h +0 -551
- epyt_flow/EPANET/EPANET-MSX/Src/msxutils.c +0 -524
- epyt_flow/EPANET/EPANET-MSX/Src/msxutils.h +0 -56
- epyt_flow/EPANET/EPANET-MSX/Src/newton.c +0 -158
- epyt_flow/EPANET/EPANET-MSX/Src/newton.h +0 -34
- epyt_flow/EPANET/EPANET-MSX/Src/rk5.c +0 -287
- epyt_flow/EPANET/EPANET-MSX/Src/rk5.h +0 -39
- epyt_flow/EPANET/EPANET-MSX/Src/ros2.c +0 -293
- epyt_flow/EPANET/EPANET-MSX/Src/ros2.h +0 -35
- epyt_flow/EPANET/EPANET-MSX/Src/smatrix.c +0 -816
- epyt_flow/EPANET/EPANET-MSX/Src/smatrix.h +0 -29
- epyt_flow/EPANET/EPANET-MSX/readme.txt +0 -14
- epyt_flow/EPANET/compile_linux.sh +0 -4
- epyt_flow/EPANET/compile_macos.sh +0 -4
- epyt_flow/simulation/backend/__init__.py +0 -1
- epyt_flow/simulation/backend/my_epyt.py +0 -1101
- epyt_flow-0.14.1.dist-info/RECORD +0 -148
- {epyt_flow-0.14.1.dist-info → epyt_flow-0.15.0.dist-info}/WHEEL +0 -0
- {epyt_flow-0.14.1.dist-info → epyt_flow-0.15.0.dist-info}/licenses/LICENSE +0 -0
- {epyt_flow-0.14.1.dist-info → epyt_flow-0.15.0.dist-info}/top_level.txt +0 -0
|
@@ -1,1500 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
******************************************************************************
|
|
3
|
-
Project: OWA EPANET
|
|
4
|
-
Version: 2.3
|
|
5
|
-
Module: rules.c
|
|
6
|
-
Description: implements rule-based controls
|
|
7
|
-
Authors: see AUTHORS
|
|
8
|
-
Copyright: see AUTHORS
|
|
9
|
-
License: see LICENSE
|
|
10
|
-
Last Updated: 02/11/2025
|
|
11
|
-
******************************************************************************
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
#include <stdlib.h>
|
|
15
|
-
#include <stdio.h>
|
|
16
|
-
#include <string.h>
|
|
17
|
-
|
|
18
|
-
#include "types.h"
|
|
19
|
-
#include "funcs.h"
|
|
20
|
-
#include "hash.h"
|
|
21
|
-
#include "text.h"
|
|
22
|
-
|
|
23
|
-
#ifdef _WIN32
|
|
24
|
-
#define snprintf _snprintf
|
|
25
|
-
#endif
|
|
26
|
-
|
|
27
|
-
enum Rulewords {
|
|
28
|
-
r_RULE,
|
|
29
|
-
r_IF,
|
|
30
|
-
r_AND,
|
|
31
|
-
r_OR,
|
|
32
|
-
r_THEN,
|
|
33
|
-
r_ELSE,
|
|
34
|
-
r_PRIORITY,
|
|
35
|
-
r_DISABLED,
|
|
36
|
-
r_ERROR
|
|
37
|
-
};
|
|
38
|
-
char *Ruleword[] = {w_RULE, w_IF, w_AND, w_OR,
|
|
39
|
-
w_THEN, w_ELSE, w_PRIORITY, w_DISABLED, NULL};
|
|
40
|
-
|
|
41
|
-
enum Varwords {
|
|
42
|
-
r_DEMAND,
|
|
43
|
-
r_HEAD,
|
|
44
|
-
r_GRADE,
|
|
45
|
-
r_LEVEL,
|
|
46
|
-
r_PRESSURE,
|
|
47
|
-
r_FLOW,
|
|
48
|
-
r_STATUS,
|
|
49
|
-
r_SETTING,
|
|
50
|
-
r_POWER,
|
|
51
|
-
r_TIME,
|
|
52
|
-
r_CLOCKTIME,
|
|
53
|
-
r_FILLTIME,
|
|
54
|
-
r_DRAINTIME
|
|
55
|
-
};
|
|
56
|
-
char *Varword[] = {w_DEMAND, w_HEAD, w_GRADE, w_LEVEL, w_PRESSURE,
|
|
57
|
-
w_FLOW, w_STATUS, w_SETTING, w_POWER, w_TIME,
|
|
58
|
-
w_CLOCKTIME, w_FILLTIME, w_DRAINTIME, NULL};
|
|
59
|
-
|
|
60
|
-
enum Objects {
|
|
61
|
-
r_JUNC,
|
|
62
|
-
r_RESERV,
|
|
63
|
-
r_TANK,
|
|
64
|
-
r_PIPE,
|
|
65
|
-
r_PUMP,
|
|
66
|
-
r_VALVE,
|
|
67
|
-
r_NODE,
|
|
68
|
-
r_LINK,
|
|
69
|
-
r_SYSTEM
|
|
70
|
-
};
|
|
71
|
-
char *Object[] = {w_JUNC, w_RESERV, w_TANK, w_PIPE, w_PUMP,
|
|
72
|
-
w_VALVE, w_NODE, w_LINK, w_SYSTEM, NULL};
|
|
73
|
-
|
|
74
|
-
// NOTE: place "<=" & ">=" before "<" & ">" so that findmatch() works correctly.
|
|
75
|
-
enum Operators { EQ, NE, LE, GE, LT, GT, IS, NOT, BELOW, ABOVE };
|
|
76
|
-
char *Operator[] = {"=", "<>", "<=", ">=", "<", ">",
|
|
77
|
-
w_IS, w_NOT, w_BELOW, w_ABOVE, NULL};
|
|
78
|
-
|
|
79
|
-
enum Values { IS_NUMBER, IS_OPEN, IS_CLOSED, IS_ACTIVE };
|
|
80
|
-
char *Value[] = {"XXXX", w_OPEN, w_CLOSED, w_ACTIVE, NULL};
|
|
81
|
-
|
|
82
|
-
// Local functions
|
|
83
|
-
static void newrule(Project *);
|
|
84
|
-
static int newpremise(Project *, int);
|
|
85
|
-
static int newaction(Project *);
|
|
86
|
-
static int newpriority(Project *);
|
|
87
|
-
|
|
88
|
-
static int evalpremises(Project *, int);
|
|
89
|
-
static int checkpremise(Project *, Spremise *);
|
|
90
|
-
static int checktime(Project *, Spremise *);
|
|
91
|
-
static int checkstatus(Project *, Spremise *);
|
|
92
|
-
static int checkvalue(Project *, Spremise *);
|
|
93
|
-
|
|
94
|
-
static int onactionlist(Project *, int, Saction *);
|
|
95
|
-
static void updateactionlist(Project *, int, Saction *);
|
|
96
|
-
static int takeactions(Project *);
|
|
97
|
-
static void clearactionlist(Rules *);
|
|
98
|
-
static void clearrule(Project *, int);
|
|
99
|
-
|
|
100
|
-
static void writepremise(Spremise *, FILE *, Network *);
|
|
101
|
-
static void writeaction(Saction *, FILE *, Network *);
|
|
102
|
-
static void getobjtxt(int, int, char *);
|
|
103
|
-
static void gettimetxt(double, char *);
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
void initrules(Project *pr)
|
|
107
|
-
//--------------------------------------------------------------
|
|
108
|
-
// Initializes rule base.
|
|
109
|
-
//--------------------------------------------------------------
|
|
110
|
-
{
|
|
111
|
-
pr->rules.RuleState = r_PRIORITY;
|
|
112
|
-
pr->rules.LastPremise = NULL;
|
|
113
|
-
pr->rules.LastThenAction = NULL;
|
|
114
|
-
pr->rules.LastElseAction = NULL;
|
|
115
|
-
pr->rules.ActionList = NULL;
|
|
116
|
-
pr->network.Rule = NULL;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
void addrule(Parser *parser, char *tok)
|
|
120
|
-
//--------------------------------------------------------------
|
|
121
|
-
// Updates rule count if RULE keyword found in line of input.
|
|
122
|
-
//--------------------------------------------------------------
|
|
123
|
-
{
|
|
124
|
-
if (match(tok, w_RULE)) parser->MaxRules++;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
void deleterule(Project *pr, int index)
|
|
128
|
-
//-----------------------------------------------------------
|
|
129
|
-
// Deletes a specific rule
|
|
130
|
-
//-----------------------------------------------------------
|
|
131
|
-
{
|
|
132
|
-
Network *net = &pr->network;
|
|
133
|
-
|
|
134
|
-
int i;
|
|
135
|
-
Srule *lastRule;
|
|
136
|
-
|
|
137
|
-
// Free memory allocated to rule's premises & actions
|
|
138
|
-
clearrule(pr, index);
|
|
139
|
-
|
|
140
|
-
// Shift position of higher indexed rules down one
|
|
141
|
-
for (i = index; i <= net->Nrules - 1; i++)
|
|
142
|
-
{
|
|
143
|
-
net->Rule[i] = net->Rule[i + 1];
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Remove premises & actions from last (inactive) entry in Rule array
|
|
147
|
-
lastRule = &net->Rule[net->Nrules];
|
|
148
|
-
lastRule->Premises = NULL;
|
|
149
|
-
lastRule->ThenActions = NULL;
|
|
150
|
-
lastRule->ElseActions = NULL;
|
|
151
|
-
|
|
152
|
-
// Reduce active rule count by one
|
|
153
|
-
net->Nrules--;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
int allocrules(Project *pr)
|
|
157
|
-
//--------------------------------------------------------------
|
|
158
|
-
// Allocates memory for rule-based controls.
|
|
159
|
-
//--------------------------------------------------------------
|
|
160
|
-
{
|
|
161
|
-
Network *net = &pr->network;
|
|
162
|
-
int n = pr->parser.MaxRules + 1;
|
|
163
|
-
|
|
164
|
-
net->Rule = (Srule *)calloc(n, sizeof(Srule));
|
|
165
|
-
if (net->Rule == NULL) return 101;
|
|
166
|
-
return 0;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
void freerules(Project *pr)
|
|
170
|
-
//--------------------------------------------------------------
|
|
171
|
-
// Frees memory used for rule-based controls.
|
|
172
|
-
//--------------------------------------------------------------
|
|
173
|
-
{
|
|
174
|
-
int i;
|
|
175
|
-
|
|
176
|
-
// Already freed
|
|
177
|
-
if (pr->network.Rule == NULL)
|
|
178
|
-
return;
|
|
179
|
-
|
|
180
|
-
for (i = 1; i <= pr->network.Nrules; i++) clearrule(pr, i);
|
|
181
|
-
free(pr->network.Rule);
|
|
182
|
-
pr->network.Rule = NULL;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
int ruledata(Project *pr)
|
|
186
|
-
//--------------------------------------------------------------
|
|
187
|
-
// Parses a line from [RULES] section of input.
|
|
188
|
-
//--------------------------------------------------------------
|
|
189
|
-
{
|
|
190
|
-
Network *net = &pr->network;
|
|
191
|
-
Parser *parser = &pr->parser;
|
|
192
|
-
Rules *rules = &pr->rules;
|
|
193
|
-
|
|
194
|
-
int key, // Keyword code
|
|
195
|
-
err;
|
|
196
|
-
char **Tok = parser->Tok; // Tokenized line of a rule statement
|
|
197
|
-
|
|
198
|
-
// Exit if current rule has an error
|
|
199
|
-
if (rules->RuleState == r_ERROR) return 0;
|
|
200
|
-
|
|
201
|
-
// Find the key word that begins the rule statement
|
|
202
|
-
err = 0;
|
|
203
|
-
key = findmatch(Tok[0], Ruleword);
|
|
204
|
-
switch (key)
|
|
205
|
-
{
|
|
206
|
-
case -1:
|
|
207
|
-
err = 201; // Unrecognized keyword
|
|
208
|
-
break;
|
|
209
|
-
|
|
210
|
-
case r_RULE:
|
|
211
|
-
// Missing the rule label
|
|
212
|
-
if (parser->Ntokens != 2)
|
|
213
|
-
{
|
|
214
|
-
err = 201;
|
|
215
|
-
break;
|
|
216
|
-
}
|
|
217
|
-
net->Nrules++;
|
|
218
|
-
newrule(pr);
|
|
219
|
-
rules->RuleState = r_RULE;
|
|
220
|
-
rules->Errcode = 0;
|
|
221
|
-
break;
|
|
222
|
-
|
|
223
|
-
case r_IF:
|
|
224
|
-
if (rules->RuleState != r_RULE)
|
|
225
|
-
{
|
|
226
|
-
err = 221; // Mis-placed IF clause
|
|
227
|
-
break;
|
|
228
|
-
}
|
|
229
|
-
rules->RuleState = r_IF;
|
|
230
|
-
err = newpremise(pr, r_AND);
|
|
231
|
-
break;
|
|
232
|
-
|
|
233
|
-
case r_AND:
|
|
234
|
-
if (rules->RuleState == r_IF) err = newpremise(pr, r_AND);
|
|
235
|
-
else if (rules->RuleState == r_THEN || rules->RuleState == r_ELSE)
|
|
236
|
-
{
|
|
237
|
-
err = newaction(pr);
|
|
238
|
-
}
|
|
239
|
-
else err = 221;
|
|
240
|
-
break;
|
|
241
|
-
|
|
242
|
-
case r_OR:
|
|
243
|
-
if (rules->RuleState == r_IF) err = newpremise(pr, r_OR);
|
|
244
|
-
else err = 221;
|
|
245
|
-
break;
|
|
246
|
-
|
|
247
|
-
case r_THEN:
|
|
248
|
-
if (rules->RuleState != r_IF)
|
|
249
|
-
{
|
|
250
|
-
err = 221; // Mis-placed THEN clause
|
|
251
|
-
break;
|
|
252
|
-
}
|
|
253
|
-
rules->RuleState = r_THEN;
|
|
254
|
-
err = newaction(pr);
|
|
255
|
-
break;
|
|
256
|
-
|
|
257
|
-
case r_ELSE:
|
|
258
|
-
if (rules->RuleState != r_THEN)
|
|
259
|
-
{
|
|
260
|
-
err = 221; // Mis-placed ELSE clause
|
|
261
|
-
break;
|
|
262
|
-
}
|
|
263
|
-
rules->RuleState = r_ELSE;
|
|
264
|
-
err = newaction(pr);
|
|
265
|
-
break;
|
|
266
|
-
|
|
267
|
-
case r_PRIORITY:
|
|
268
|
-
if (rules->RuleState != r_THEN && rules->RuleState != r_ELSE)
|
|
269
|
-
{
|
|
270
|
-
err = 221;
|
|
271
|
-
break;
|
|
272
|
-
}
|
|
273
|
-
rules->RuleState = r_PRIORITY;
|
|
274
|
-
err = newpriority(pr);
|
|
275
|
-
break;
|
|
276
|
-
|
|
277
|
-
case r_DISABLED:
|
|
278
|
-
if (rules->RuleState != r_THEN && rules->RuleState != r_ELSE &&
|
|
279
|
-
rules->RuleState != r_PRIORITY)
|
|
280
|
-
{
|
|
281
|
-
err = 221;
|
|
282
|
-
break;
|
|
283
|
-
}
|
|
284
|
-
net->Rule[net->Nrules].isEnabled = FALSE;
|
|
285
|
-
break;
|
|
286
|
-
|
|
287
|
-
default:
|
|
288
|
-
err = 201;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
// Set RuleState to r_ERROR if errors found
|
|
292
|
-
if (err)
|
|
293
|
-
{
|
|
294
|
-
rules->RuleState = r_ERROR;
|
|
295
|
-
rules->Errcode = err;
|
|
296
|
-
err = 200;
|
|
297
|
-
}
|
|
298
|
-
return err;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
void ruleerrmsg(Project *pr)
|
|
302
|
-
//-----------------------------------------------------------
|
|
303
|
-
// Report a rule parsing error message
|
|
304
|
-
//-----------------------------------------------------------
|
|
305
|
-
{
|
|
306
|
-
Network *net = &pr->network;
|
|
307
|
-
Parser *parser = &pr->parser;
|
|
308
|
-
Rules *rules = &pr->rules;
|
|
309
|
-
|
|
310
|
-
int i;
|
|
311
|
-
char label[MAXMSG + 1];
|
|
312
|
-
char msg[MAXLINE + 1];
|
|
313
|
-
char **Tok = parser->Tok;
|
|
314
|
-
|
|
315
|
-
// Get text of error message
|
|
316
|
-
switch (rules->Errcode)
|
|
317
|
-
{
|
|
318
|
-
case 201: strcpy(msg, R_ERR201); break;
|
|
319
|
-
case 202: strcpy(msg, R_ERR202); break;
|
|
320
|
-
case 203: strcpy(msg, R_ERR203); break;
|
|
321
|
-
case 204: strcpy(msg, R_ERR204); break;
|
|
322
|
-
case 207: strcpy(msg, R_ERR207); break;
|
|
323
|
-
case 221: strcpy(msg, R_ERR221); break;
|
|
324
|
-
default: return;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// Get label of rule being parsed
|
|
328
|
-
if (net->Nrules > 0)
|
|
329
|
-
{
|
|
330
|
-
strncpy(label, t_RULE, MAXMSG);
|
|
331
|
-
strncat(label, " ", MAXMSG);
|
|
332
|
-
strncat(label, net->Rule[net->Nrules].label, MAXMSG);
|
|
333
|
-
}
|
|
334
|
-
else strncpy(label, t_RULES_SECT, MAXMSG);
|
|
335
|
-
|
|
336
|
-
// Write rule label and error message to status report
|
|
337
|
-
snprintf(pr->Msg, MAXMSG, "%s", msg);
|
|
338
|
-
strncat(pr->Msg, label, MAXMSG);
|
|
339
|
-
strncat(pr->Msg, ":", MAXMSG);
|
|
340
|
-
writeline(pr, pr->Msg);
|
|
341
|
-
|
|
342
|
-
// Write text of rule clause being parsed to status report
|
|
343
|
-
strcpy(msg, Tok[0]);
|
|
344
|
-
for (i = 1; i < parser->Ntokens; i++)
|
|
345
|
-
{
|
|
346
|
-
strncat(msg, " ", MAXLINE);
|
|
347
|
-
strncat(msg, Tok[i], MAXLINE);
|
|
348
|
-
}
|
|
349
|
-
writeline(pr, msg);
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
void adjustrules(Project *pr, int objtype, int index)
|
|
353
|
-
//-----------------------------------------------------------
|
|
354
|
-
// Adjusts rules when a specific node or link is deleted.
|
|
355
|
-
//-----------------------------------------------------------
|
|
356
|
-
{
|
|
357
|
-
Network *net = &pr->network;
|
|
358
|
-
|
|
359
|
-
int i, delete;
|
|
360
|
-
Spremise *p;
|
|
361
|
-
Saction *a;
|
|
362
|
-
|
|
363
|
-
// Delete rules that refer to objtype and index
|
|
364
|
-
for (i = net->Nrules; i >= 1; i--)
|
|
365
|
-
{
|
|
366
|
-
delete = FALSE;
|
|
367
|
-
p = net->Rule[i].Premises;
|
|
368
|
-
while (p != NULL && !delete)
|
|
369
|
-
{
|
|
370
|
-
if (objtype == p->object && p->index == index) delete = TRUE;
|
|
371
|
-
p = p->next;
|
|
372
|
-
}
|
|
373
|
-
if (objtype == r_LINK)
|
|
374
|
-
{
|
|
375
|
-
a = net->Rule[i].ThenActions;
|
|
376
|
-
while (a != NULL && !delete)
|
|
377
|
-
{
|
|
378
|
-
if (a->link == index) delete = TRUE;
|
|
379
|
-
a = a->next;
|
|
380
|
-
}
|
|
381
|
-
a = net->Rule[i].ElseActions;
|
|
382
|
-
while (a != NULL && !delete)
|
|
383
|
-
{
|
|
384
|
-
if (a->link == index) delete = TRUE;
|
|
385
|
-
a = a->next;
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
if (delete) deleterule(pr, i);
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
// Adjust all higher object indices to reflect deletion of object index
|
|
392
|
-
for (i = 1; i <= net->Nrules; i++)
|
|
393
|
-
{
|
|
394
|
-
p = net->Rule[i].Premises;
|
|
395
|
-
while (p != NULL)
|
|
396
|
-
{
|
|
397
|
-
if (objtype == p->object && p->index > index) p->index--;
|
|
398
|
-
p = p->next;
|
|
399
|
-
}
|
|
400
|
-
if (objtype == r_LINK)
|
|
401
|
-
{
|
|
402
|
-
a = net->Rule[i].ThenActions;
|
|
403
|
-
while (a != NULL)
|
|
404
|
-
{
|
|
405
|
-
if (a->link > index) a->link--;
|
|
406
|
-
a = a->next;
|
|
407
|
-
}
|
|
408
|
-
a = net->Rule[i].ElseActions;
|
|
409
|
-
while (a != NULL)
|
|
410
|
-
{
|
|
411
|
-
if (a->link > index) a->link--;
|
|
412
|
-
a = a->next;
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
void adjusttankrules(Project *pr, int ndiff)
|
|
419
|
-
//-----------------------------------------------------------
|
|
420
|
-
// Adjusts tank indices in rule premises.
|
|
421
|
-
//-----------------------------------------------------------
|
|
422
|
-
{
|
|
423
|
-
Network *net = &pr->network;
|
|
424
|
-
|
|
425
|
-
int i, njuncs;
|
|
426
|
-
Spremise *p;
|
|
427
|
-
|
|
428
|
-
njuncs = net->Njuncs;
|
|
429
|
-
for (i = 1; i <= net->Nrules; i++)
|
|
430
|
-
{
|
|
431
|
-
p = net->Rule[i].Premises;
|
|
432
|
-
while (p != NULL)
|
|
433
|
-
{
|
|
434
|
-
if (p->object == r_NODE && p->index > njuncs)
|
|
435
|
-
p->index += ndiff;
|
|
436
|
-
p = p->next;
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
Spremise *getpremise(Spremise *premises, int i)
|
|
442
|
-
//----------------------------------------------------------
|
|
443
|
-
// Return the i-th premise in a rule
|
|
444
|
-
//----------------------------------------------------------
|
|
445
|
-
{
|
|
446
|
-
int count = 0;
|
|
447
|
-
Spremise *p;
|
|
448
|
-
|
|
449
|
-
p = premises;
|
|
450
|
-
while (p != NULL)
|
|
451
|
-
{
|
|
452
|
-
count++;
|
|
453
|
-
if (count == i) break;
|
|
454
|
-
p = p->next;
|
|
455
|
-
}
|
|
456
|
-
return p;
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
Saction *getaction(Saction *actions, int i)
|
|
460
|
-
//----------------------------------------------------------
|
|
461
|
-
// Return the i-th action from a rule's action list
|
|
462
|
-
//----------------------------------------------------------
|
|
463
|
-
{
|
|
464
|
-
int count = 0;
|
|
465
|
-
Saction *a;
|
|
466
|
-
|
|
467
|
-
a = actions;
|
|
468
|
-
while (a != NULL)
|
|
469
|
-
{
|
|
470
|
-
count++;
|
|
471
|
-
if (count == i) break;
|
|
472
|
-
a = a->next;
|
|
473
|
-
}
|
|
474
|
-
return a;
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
int writerule(Project *pr, FILE *f, int ruleIndex)
|
|
478
|
-
//-----------------------------------------------------------------------------
|
|
479
|
-
// Write a rule to an INP file.
|
|
480
|
-
//-----------------------------------------------------------------------------
|
|
481
|
-
{
|
|
482
|
-
Network *net = &pr->network;
|
|
483
|
-
|
|
484
|
-
Srule *rule = &net->Rule[ruleIndex];
|
|
485
|
-
Spremise *p;
|
|
486
|
-
Saction *a;
|
|
487
|
-
|
|
488
|
-
// Write each premise clause to the file
|
|
489
|
-
p = rule->Premises;
|
|
490
|
-
fprintf(f, "\nIF ");
|
|
491
|
-
while (p != NULL)
|
|
492
|
-
{
|
|
493
|
-
writepremise(p, f, net);
|
|
494
|
-
p = p->next;
|
|
495
|
-
if (p) fprintf(f, "\n%-5s", Ruleword[p->logop]);
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
// Write each THEN action clause to the file
|
|
499
|
-
a = rule->ThenActions;
|
|
500
|
-
if (a) fprintf(f, "\nTHEN ");
|
|
501
|
-
while (a != NULL)
|
|
502
|
-
{
|
|
503
|
-
writeaction(a, f, net);
|
|
504
|
-
a = a->next;
|
|
505
|
-
if (a) fprintf(f, "\nAND ");
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
// Write each ELSE action clause to the file
|
|
509
|
-
a = rule->ElseActions;
|
|
510
|
-
if (a) fprintf(f, "\nELSE ");
|
|
511
|
-
while (a != NULL)
|
|
512
|
-
{
|
|
513
|
-
writeaction(a, f, net);
|
|
514
|
-
a = a->next;
|
|
515
|
-
if (a) fprintf(f, "\nAND ");
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
// Write the rule's priority to the file
|
|
519
|
-
if (rule->priority > 0) fprintf(f, "\nPRIORITY %f", rule->priority);
|
|
520
|
-
return 0;
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
int checkrules(Project *pr, long dt)
|
|
524
|
-
//-----------------------------------------------------
|
|
525
|
-
// Checks which rules should fire at current time.
|
|
526
|
-
//-----------------------------------------------------
|
|
527
|
-
{
|
|
528
|
-
Network *net = &pr->network;
|
|
529
|
-
Times *time = &pr->times;
|
|
530
|
-
Rules *rules = &pr->rules;
|
|
531
|
-
|
|
532
|
-
int i;
|
|
533
|
-
int actionCount = 0; // Number of actions actually taken
|
|
534
|
-
|
|
535
|
-
// Start of rule evaluation time interval
|
|
536
|
-
rules->Time1 = time->Htime - dt + 1;
|
|
537
|
-
|
|
538
|
-
// Iterate through each rule
|
|
539
|
-
rules->ActionList = NULL;
|
|
540
|
-
for (i = 1; i <= net->Nrules; i++)
|
|
541
|
-
{
|
|
542
|
-
// skip if the rule is disabled
|
|
543
|
-
if (!net->Rule[i].isEnabled)
|
|
544
|
-
{
|
|
545
|
-
continue;
|
|
546
|
-
}
|
|
547
|
-
// If premises true, add THEN clauses to action list
|
|
548
|
-
if (evalpremises(pr, i) == TRUE)
|
|
549
|
-
{
|
|
550
|
-
updateactionlist(pr, i, net->Rule[i].ThenActions);
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
// If premises false, add ELSE actions to list
|
|
554
|
-
else
|
|
555
|
-
{
|
|
556
|
-
if (net->Rule[i].ElseActions != NULL)
|
|
557
|
-
{
|
|
558
|
-
updateactionlist(pr, i, net->Rule[i].ElseActions);
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
// Execute actions then clear action list
|
|
564
|
-
if (rules->ActionList != NULL) actionCount = takeactions(pr);
|
|
565
|
-
clearactionlist(rules);
|
|
566
|
-
return actionCount;
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
void updateruleunits(Project *pr, double dcf, double pcf, double hcf, double qcf)
|
|
570
|
-
//-----------------------------------------------------------
|
|
571
|
-
// Updates the units of a rule's premises and actions.
|
|
572
|
-
//-----------------------------------------------------------
|
|
573
|
-
{
|
|
574
|
-
Network *net = &pr->network;
|
|
575
|
-
Slink *Link = net->Link;
|
|
576
|
-
|
|
577
|
-
int i, k;
|
|
578
|
-
double x;
|
|
579
|
-
Spremise *p;
|
|
580
|
-
Saction *a;
|
|
581
|
-
|
|
582
|
-
for (i = 1; i <= net->Nrules; i++)
|
|
583
|
-
{
|
|
584
|
-
p = net->Rule[i].Premises;
|
|
585
|
-
while (p != NULL)
|
|
586
|
-
{
|
|
587
|
-
|
|
588
|
-
switch (p->variable)
|
|
589
|
-
{
|
|
590
|
-
case r_DEMAND:
|
|
591
|
-
p->value *= dcf;
|
|
592
|
-
break;
|
|
593
|
-
|
|
594
|
-
case r_HEAD:
|
|
595
|
-
case r_GRADE:
|
|
596
|
-
p->value *= hcf;
|
|
597
|
-
break;
|
|
598
|
-
|
|
599
|
-
case r_PRESSURE:
|
|
600
|
-
p->value *= pcf;
|
|
601
|
-
break;
|
|
602
|
-
|
|
603
|
-
case r_LEVEL:
|
|
604
|
-
p->value *= hcf;
|
|
605
|
-
break;
|
|
606
|
-
|
|
607
|
-
case r_FLOW:
|
|
608
|
-
p->value *= qcf;
|
|
609
|
-
break;
|
|
610
|
-
|
|
611
|
-
case r_SETTING:
|
|
612
|
-
|
|
613
|
-
switch (Link[p->index].Type)
|
|
614
|
-
{
|
|
615
|
-
case PRV:
|
|
616
|
-
case PSV:
|
|
617
|
-
case PBV:
|
|
618
|
-
p->value *= pcf;
|
|
619
|
-
break;
|
|
620
|
-
case FCV:
|
|
621
|
-
p->value *= qcf;
|
|
622
|
-
break;
|
|
623
|
-
default:
|
|
624
|
-
break;
|
|
625
|
-
}
|
|
626
|
-
break;
|
|
627
|
-
|
|
628
|
-
default:
|
|
629
|
-
break;
|
|
630
|
-
|
|
631
|
-
}
|
|
632
|
-
p = p->next;
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
a = net->Rule[i].ThenActions;
|
|
636
|
-
while (a != NULL)
|
|
637
|
-
{
|
|
638
|
-
k = a->link;
|
|
639
|
-
x = a->setting;
|
|
640
|
-
|
|
641
|
-
// Change link's setting
|
|
642
|
-
if (x != MISSING)
|
|
643
|
-
{
|
|
644
|
-
switch (net->Link[k].Type)
|
|
645
|
-
{
|
|
646
|
-
case PRV:
|
|
647
|
-
case PSV:
|
|
648
|
-
case PBV:
|
|
649
|
-
a->setting *= pcf;
|
|
650
|
-
break;
|
|
651
|
-
case FCV:
|
|
652
|
-
a->setting *= qcf;
|
|
653
|
-
break;
|
|
654
|
-
default:
|
|
655
|
-
break;
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
a = a->next;
|
|
659
|
-
}
|
|
660
|
-
a = net->Rule[i].ElseActions;
|
|
661
|
-
while (a != NULL)
|
|
662
|
-
{
|
|
663
|
-
k = a->link;
|
|
664
|
-
x = a->setting;
|
|
665
|
-
|
|
666
|
-
// Change link's setting
|
|
667
|
-
if (x != MISSING)
|
|
668
|
-
{
|
|
669
|
-
switch (net->Link[k].Type)
|
|
670
|
-
{
|
|
671
|
-
case PRV:
|
|
672
|
-
case PSV:
|
|
673
|
-
case PBV:
|
|
674
|
-
a->setting *= pcf;
|
|
675
|
-
break;
|
|
676
|
-
case FCV:
|
|
677
|
-
a->setting *= qcf;
|
|
678
|
-
break;
|
|
679
|
-
default:
|
|
680
|
-
break;
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
a = a->next;
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
void newrule(Project *pr)
|
|
690
|
-
//----------------------------------------------------------
|
|
691
|
-
// Adds a new rule to the project
|
|
692
|
-
//----------------------------------------------------------
|
|
693
|
-
{
|
|
694
|
-
Network *net = &pr->network;
|
|
695
|
-
|
|
696
|
-
char **Tok = pr->parser.Tok;
|
|
697
|
-
Srule *rule = &net->Rule[net->Nrules];
|
|
698
|
-
|
|
699
|
-
strncpy(rule->label, Tok[1], MAXID);
|
|
700
|
-
rule->Premises = NULL;
|
|
701
|
-
rule->ThenActions = NULL;
|
|
702
|
-
rule->ElseActions = NULL;
|
|
703
|
-
rule->priority = 0.0;
|
|
704
|
-
rule->isEnabled = TRUE;
|
|
705
|
-
pr->rules.LastPremise = NULL;
|
|
706
|
-
pr->rules.LastThenAction = NULL;
|
|
707
|
-
pr->rules.LastElseAction = NULL;
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
int newpremise(Project *pr, int logop)
|
|
711
|
-
//--------------------------------------------------------------------
|
|
712
|
-
// Adds new premise to current rule.
|
|
713
|
-
// Formats are:
|
|
714
|
-
// IF/AND/OR <object> <id> <variable> <operator> <value>
|
|
715
|
-
// IF/AND/OR SYSTEM <variable> <operator> <value> (units)
|
|
716
|
-
//---------------------------------------------------------------------
|
|
717
|
-
{
|
|
718
|
-
Network *net = &pr->network;
|
|
719
|
-
Parser *parser = &pr->parser;
|
|
720
|
-
Rules *rules = &pr->rules;
|
|
721
|
-
|
|
722
|
-
int i, j, k, m, r, s, v;
|
|
723
|
-
double x;
|
|
724
|
-
char **Tok = parser->Tok;
|
|
725
|
-
Spremise *p;
|
|
726
|
-
|
|
727
|
-
// Check for correct number of tokens
|
|
728
|
-
if (parser->Ntokens != 5 && parser->Ntokens != 6) return 201;
|
|
729
|
-
|
|
730
|
-
// Find network object & id if present
|
|
731
|
-
i = findmatch(Tok[1], Object);
|
|
732
|
-
if (i == r_SYSTEM)
|
|
733
|
-
{
|
|
734
|
-
j = 0;
|
|
735
|
-
v = findmatch(Tok[2], Varword);
|
|
736
|
-
if (v != r_DEMAND && v != r_TIME && v != r_CLOCKTIME) return 201;
|
|
737
|
-
}
|
|
738
|
-
else
|
|
739
|
-
{
|
|
740
|
-
v = findmatch(Tok[3], Varword);
|
|
741
|
-
if (v < 0) return (201);
|
|
742
|
-
switch (i)
|
|
743
|
-
{
|
|
744
|
-
case r_NODE:
|
|
745
|
-
case r_JUNC:
|
|
746
|
-
case r_RESERV:
|
|
747
|
-
case r_TANK:
|
|
748
|
-
k = r_NODE;
|
|
749
|
-
break;
|
|
750
|
-
case r_LINK:
|
|
751
|
-
case r_PIPE:
|
|
752
|
-
case r_PUMP:
|
|
753
|
-
case r_VALVE:
|
|
754
|
-
k = r_LINK;
|
|
755
|
-
break;
|
|
756
|
-
default:
|
|
757
|
-
return 201;
|
|
758
|
-
}
|
|
759
|
-
i = k;
|
|
760
|
-
if (i == r_NODE)
|
|
761
|
-
{
|
|
762
|
-
j = findnode(net, Tok[2]);
|
|
763
|
-
if (j == 0) return 203;
|
|
764
|
-
switch (v)
|
|
765
|
-
{
|
|
766
|
-
case r_DEMAND:
|
|
767
|
-
case r_HEAD:
|
|
768
|
-
case r_GRADE:
|
|
769
|
-
case r_LEVEL:
|
|
770
|
-
case r_PRESSURE:
|
|
771
|
-
break;
|
|
772
|
-
case r_FILLTIME:
|
|
773
|
-
case r_DRAINTIME:
|
|
774
|
-
if (j <= net->Njuncs) return 201;
|
|
775
|
-
break;
|
|
776
|
-
default:
|
|
777
|
-
return 201;
|
|
778
|
-
}
|
|
779
|
-
}
|
|
780
|
-
else
|
|
781
|
-
{
|
|
782
|
-
j = findlink(net, Tok[2]);
|
|
783
|
-
if (j == 0) return 204;
|
|
784
|
-
switch (v)
|
|
785
|
-
{
|
|
786
|
-
case r_FLOW:
|
|
787
|
-
case r_STATUS:
|
|
788
|
-
case r_SETTING:
|
|
789
|
-
break;
|
|
790
|
-
default:
|
|
791
|
-
return 201;
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
// Parse relational operator (r) and check for synonyms
|
|
797
|
-
if (i == r_SYSTEM) m = 3;
|
|
798
|
-
else m = 4;
|
|
799
|
-
k = findmatch(Tok[m], Operator);
|
|
800
|
-
if (k < 0) return 201;
|
|
801
|
-
switch (k)
|
|
802
|
-
{
|
|
803
|
-
case IS:
|
|
804
|
-
r = EQ;
|
|
805
|
-
break;
|
|
806
|
-
case NOT:
|
|
807
|
-
r = NE;
|
|
808
|
-
break;
|
|
809
|
-
case BELOW:
|
|
810
|
-
r = LT;
|
|
811
|
-
break;
|
|
812
|
-
case ABOVE:
|
|
813
|
-
r = GT;
|
|
814
|
-
break;
|
|
815
|
-
default:
|
|
816
|
-
r = k;
|
|
817
|
-
}
|
|
818
|
-
|
|
819
|
-
// Parse for status (s) or numerical value (x)
|
|
820
|
-
s = 0;
|
|
821
|
-
x = MISSING;
|
|
822
|
-
if (v == r_TIME || v == r_CLOCKTIME)
|
|
823
|
-
{
|
|
824
|
-
if (parser->Ntokens == 6) x = hour(Tok[4], Tok[5]) * 3600.;
|
|
825
|
-
else x = hour(Tok[4], "") * 3600.;
|
|
826
|
-
if (x < 0.0) return 202;
|
|
827
|
-
}
|
|
828
|
-
else if ((k = findmatch(Tok[parser->Ntokens - 1], Value)) > IS_NUMBER) s = k;
|
|
829
|
-
else
|
|
830
|
-
{
|
|
831
|
-
if (!getfloat(Tok[parser->Ntokens - 1], &x))
|
|
832
|
-
return (202);
|
|
833
|
-
if (v == r_FILLTIME || v == r_DRAINTIME) x = x * 3600.0;
|
|
834
|
-
}
|
|
835
|
-
|
|
836
|
-
// Create new premise structure
|
|
837
|
-
p = (Spremise *)malloc(sizeof(Spremise));
|
|
838
|
-
if (p == NULL) return 101;
|
|
839
|
-
p->object = i;
|
|
840
|
-
p->index = j;
|
|
841
|
-
p->variable = v;
|
|
842
|
-
p->relop = r;
|
|
843
|
-
p->logop = logop;
|
|
844
|
-
p->status = s;
|
|
845
|
-
p->value = x;
|
|
846
|
-
|
|
847
|
-
// Add premise to current rule's premise list
|
|
848
|
-
p->next = NULL;
|
|
849
|
-
if (rules->LastPremise == NULL) net->Rule[net->Nrules].Premises = p;
|
|
850
|
-
else rules->LastPremise->next = p;
|
|
851
|
-
rules->LastPremise = p;
|
|
852
|
-
return 0;
|
|
853
|
-
}
|
|
854
|
-
|
|
855
|
-
int newaction(Project *pr)
|
|
856
|
-
//----------------------------------------------------------
|
|
857
|
-
// Adds new action to current rule.
|
|
858
|
-
// Format is:
|
|
859
|
-
// THEN/ELSE/AND LINK <id> <variable> IS <value>
|
|
860
|
-
//----------------------------------------------------------
|
|
861
|
-
{
|
|
862
|
-
Network *net = &pr->network;
|
|
863
|
-
Parser *parser = &pr->parser;
|
|
864
|
-
Rules *rules = &pr->rules;
|
|
865
|
-
|
|
866
|
-
int j, k, s;
|
|
867
|
-
double x;
|
|
868
|
-
Saction *a;
|
|
869
|
-
char **Tok = parser->Tok;
|
|
870
|
-
|
|
871
|
-
// Check for correct number of tokens
|
|
872
|
-
if (parser->Ntokens != 6) return 201;
|
|
873
|
-
|
|
874
|
-
// Check that link exists
|
|
875
|
-
j = findlink(net, Tok[2]);
|
|
876
|
-
if (j == 0) return 204;
|
|
877
|
-
|
|
878
|
-
// Cannot control a CV
|
|
879
|
-
if (net->Link[j].Type == CVPIPE) return 207;
|
|
880
|
-
|
|
881
|
-
// Find value for status or setting
|
|
882
|
-
s = -1;
|
|
883
|
-
x = MISSING;
|
|
884
|
-
if ((k = findmatch(Tok[5], Value)) > IS_NUMBER) s = k;
|
|
885
|
-
else
|
|
886
|
-
{
|
|
887
|
-
if (!getfloat(Tok[5], &x)) return 202;
|
|
888
|
-
if (x < 0.0) return 202;
|
|
889
|
-
}
|
|
890
|
-
|
|
891
|
-
// Cannot change setting for a GPV
|
|
892
|
-
if (x != MISSING && net->Link[j].Type == GPV) return 202;
|
|
893
|
-
|
|
894
|
-
// Set status for pipe in case setting was specified
|
|
895
|
-
if (x != MISSING && net->Link[j].Type == PIPE)
|
|
896
|
-
{
|
|
897
|
-
if (x == 0.0) s = IS_CLOSED;
|
|
898
|
-
else s = IS_OPEN;
|
|
899
|
-
x = MISSING;
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
// Create a new action structure
|
|
903
|
-
a = (Saction *)malloc(sizeof(Saction));
|
|
904
|
-
if (a == NULL) return 101;
|
|
905
|
-
a->link = j;
|
|
906
|
-
a->status = s;
|
|
907
|
-
a->setting = x;
|
|
908
|
-
|
|
909
|
-
// Add action to current rule's action list
|
|
910
|
-
if (rules->RuleState == r_THEN)
|
|
911
|
-
{
|
|
912
|
-
a->next = NULL;
|
|
913
|
-
if (rules->LastThenAction == NULL)
|
|
914
|
-
{
|
|
915
|
-
net->Rule[net->Nrules].ThenActions = a;
|
|
916
|
-
}
|
|
917
|
-
else rules->LastThenAction->next = a;
|
|
918
|
-
rules->LastThenAction = a;
|
|
919
|
-
}
|
|
920
|
-
else
|
|
921
|
-
{
|
|
922
|
-
a->next = NULL;
|
|
923
|
-
if (rules->LastElseAction == NULL)
|
|
924
|
-
{
|
|
925
|
-
net->Rule[net->Nrules].ElseActions = a;
|
|
926
|
-
}
|
|
927
|
-
else rules->LastElseAction->next = a;
|
|
928
|
-
rules->LastElseAction = a;
|
|
929
|
-
}
|
|
930
|
-
return 0;
|
|
931
|
-
}
|
|
932
|
-
|
|
933
|
-
int newpriority(Project *pr)
|
|
934
|
-
//---------------------------------------------------
|
|
935
|
-
// Adds priority rating to current rule
|
|
936
|
-
//---------------------------------------------------
|
|
937
|
-
{
|
|
938
|
-
Network *net = &pr->network;
|
|
939
|
-
|
|
940
|
-
double x;
|
|
941
|
-
char **Tok = pr->parser.Tok;
|
|
942
|
-
|
|
943
|
-
if (!getfloat(Tok[1], &x)) return 202;
|
|
944
|
-
net->Rule[net->Nrules].priority = x;
|
|
945
|
-
return 0;
|
|
946
|
-
}
|
|
947
|
-
|
|
948
|
-
int evalpremises(Project *pr, int i)
|
|
949
|
-
//----------------------------------------------------------
|
|
950
|
-
// Checks if premises to rule i are true
|
|
951
|
-
//----------------------------------------------------------
|
|
952
|
-
{
|
|
953
|
-
Network *net = &pr->network;
|
|
954
|
-
|
|
955
|
-
int result;
|
|
956
|
-
Spremise *p;
|
|
957
|
-
|
|
958
|
-
result = TRUE;
|
|
959
|
-
p = net->Rule[i].Premises;
|
|
960
|
-
while (p != NULL)
|
|
961
|
-
{
|
|
962
|
-
if (p->logop == r_OR)
|
|
963
|
-
{
|
|
964
|
-
if (result == FALSE) result = checkpremise(pr, p);
|
|
965
|
-
}
|
|
966
|
-
else
|
|
967
|
-
{
|
|
968
|
-
if (result == FALSE) return (FALSE);
|
|
969
|
-
result = checkpremise(pr, p);
|
|
970
|
-
}
|
|
971
|
-
p = p->next;
|
|
972
|
-
}
|
|
973
|
-
return result;
|
|
974
|
-
}
|
|
975
|
-
|
|
976
|
-
int checkpremise(Project *pr, Spremise *p)
|
|
977
|
-
//----------------------------------------------------------
|
|
978
|
-
// Checks if a particular premise is true
|
|
979
|
-
//----------------------------------------------------------
|
|
980
|
-
{
|
|
981
|
-
if (p->variable == r_TIME ||
|
|
982
|
-
p->variable == r_CLOCKTIME) return (checktime(pr,p));
|
|
983
|
-
else if (p->status > IS_NUMBER) return (checkstatus(pr,p));
|
|
984
|
-
else return (checkvalue(pr,p));
|
|
985
|
-
}
|
|
986
|
-
|
|
987
|
-
int checktime(Project *pr, Spremise *p)
|
|
988
|
-
//------------------------------------------------------------
|
|
989
|
-
// Checks if condition on system time holds
|
|
990
|
-
//------------------------------------------------------------
|
|
991
|
-
{
|
|
992
|
-
Times *time = &pr->times;
|
|
993
|
-
Rules *rules = &pr->rules;
|
|
994
|
-
|
|
995
|
-
char flag;
|
|
996
|
-
long t1, t2, x;
|
|
997
|
-
|
|
998
|
-
// Get start and end of rule evaluation time interval
|
|
999
|
-
if (p->variable == r_TIME)
|
|
1000
|
-
{
|
|
1001
|
-
t1 = rules->Time1;
|
|
1002
|
-
t2 = time->Htime;
|
|
1003
|
-
}
|
|
1004
|
-
else if (p->variable == r_CLOCKTIME)
|
|
1005
|
-
{
|
|
1006
|
-
t1 = (rules->Time1 + time->Tstart) % SECperDAY;
|
|
1007
|
-
t2 = (time->Htime + time->Tstart) % SECperDAY;
|
|
1008
|
-
}
|
|
1009
|
-
else return (0);
|
|
1010
|
-
|
|
1011
|
-
// Test premise's time
|
|
1012
|
-
x = (long)(p->value);
|
|
1013
|
-
switch (p->relop)
|
|
1014
|
-
{
|
|
1015
|
-
// For inequality, test against current time
|
|
1016
|
-
case LT:
|
|
1017
|
-
if (t2 >= x) return (0);
|
|
1018
|
-
break;
|
|
1019
|
-
case LE:
|
|
1020
|
-
if (t2 > x) return (0);
|
|
1021
|
-
break;
|
|
1022
|
-
case GT:
|
|
1023
|
-
if (t2 <= x) return (0);
|
|
1024
|
-
break;
|
|
1025
|
-
case GE:
|
|
1026
|
-
if (t2 < x) return (0);
|
|
1027
|
-
break;
|
|
1028
|
-
|
|
1029
|
-
// For equality, test if within interval
|
|
1030
|
-
case EQ:
|
|
1031
|
-
case NE:
|
|
1032
|
-
flag = FALSE;
|
|
1033
|
-
if (t2 < t1) // E.g., 11:00 am to 1:00 am
|
|
1034
|
-
{
|
|
1035
|
-
if (x >= t1 || x <= t2)
|
|
1036
|
-
flag = TRUE;
|
|
1037
|
-
}
|
|
1038
|
-
else
|
|
1039
|
-
{
|
|
1040
|
-
if (x >= t1 && x <= t2)
|
|
1041
|
-
flag = TRUE;
|
|
1042
|
-
}
|
|
1043
|
-
if (p->relop == EQ && flag == FALSE) return (0);
|
|
1044
|
-
if (p->relop == NE && flag == TRUE) return (0);
|
|
1045
|
-
break;
|
|
1046
|
-
}
|
|
1047
|
-
|
|
1048
|
-
// If we get to here then premise was satisfied
|
|
1049
|
-
return 1;
|
|
1050
|
-
}
|
|
1051
|
-
|
|
1052
|
-
int checkstatus(Project *pr, Spremise *p)
|
|
1053
|
-
//------------------------------------------------------------
|
|
1054
|
-
// Checks if condition on link status holds
|
|
1055
|
-
//------------------------------------------------------------
|
|
1056
|
-
{
|
|
1057
|
-
Hydraul *hyd = &pr->hydraul;
|
|
1058
|
-
|
|
1059
|
-
char i;
|
|
1060
|
-
int j;
|
|
1061
|
-
|
|
1062
|
-
switch (p->status)
|
|
1063
|
-
{
|
|
1064
|
-
case IS_OPEN:
|
|
1065
|
-
case IS_CLOSED:
|
|
1066
|
-
case IS_ACTIVE:
|
|
1067
|
-
i = hyd->LinkStatus[p->index];
|
|
1068
|
-
if (i <= CLOSED) j = IS_CLOSED;
|
|
1069
|
-
else if (i == ACTIVE) j = IS_ACTIVE;
|
|
1070
|
-
else j = IS_OPEN;
|
|
1071
|
-
if (j == p->status && p->relop == EQ) return 1;
|
|
1072
|
-
if (j != p->status && p->relop == NE) return 1;
|
|
1073
|
-
}
|
|
1074
|
-
return 0;
|
|
1075
|
-
}
|
|
1076
|
-
|
|
1077
|
-
int checkvalue(Project *pr, Spremise *p)
|
|
1078
|
-
//----------------------------------------------------------
|
|
1079
|
-
// Checks if numerical condition on a variable is true.
|
|
1080
|
-
// Uses tolerance of 0.001 when testing conditions.
|
|
1081
|
-
//----------------------------------------------------------
|
|
1082
|
-
{
|
|
1083
|
-
Network *net = &pr->network;
|
|
1084
|
-
Hydraul *hyd = &pr->hydraul;
|
|
1085
|
-
|
|
1086
|
-
int i, j, v;
|
|
1087
|
-
double x, // A variable's value
|
|
1088
|
-
tol = 1.e-3; // Equality tolerance
|
|
1089
|
-
int Njuncs = net->Njuncs;
|
|
1090
|
-
double *Ucf = pr->Ucf;
|
|
1091
|
-
double *NodeDemand = hyd->NodeDemand;
|
|
1092
|
-
double *LinkFlow = hyd->LinkFlow;
|
|
1093
|
-
double *LinkSetting = hyd->LinkSetting;
|
|
1094
|
-
Snode *Node = net->Node;
|
|
1095
|
-
Slink *Link = net->Link;
|
|
1096
|
-
Stank *Tank = net->Tank;
|
|
1097
|
-
|
|
1098
|
-
// Find the value being checked
|
|
1099
|
-
i = p->index;
|
|
1100
|
-
v = p->variable;
|
|
1101
|
-
switch (v)
|
|
1102
|
-
{
|
|
1103
|
-
case r_DEMAND:
|
|
1104
|
-
if (p->object == r_SYSTEM) x = hyd->Dsystem * Ucf[DEMAND];
|
|
1105
|
-
else x = NodeDemand[i] * Ucf[DEMAND];
|
|
1106
|
-
break;
|
|
1107
|
-
|
|
1108
|
-
case r_HEAD:
|
|
1109
|
-
case r_GRADE:
|
|
1110
|
-
x = hyd->NodeHead[i] * Ucf[HEAD];
|
|
1111
|
-
break;
|
|
1112
|
-
|
|
1113
|
-
case r_PRESSURE:
|
|
1114
|
-
x = (hyd->NodeHead[i] - Node[i].El) * Ucf[PRESSURE];
|
|
1115
|
-
break;
|
|
1116
|
-
|
|
1117
|
-
case r_LEVEL:
|
|
1118
|
-
x = (hyd->NodeHead[i] - Node[i].El) * Ucf[HEAD];
|
|
1119
|
-
break;
|
|
1120
|
-
|
|
1121
|
-
case r_FLOW:
|
|
1122
|
-
x = ABS(LinkFlow[i]) * Ucf[FLOW];
|
|
1123
|
-
break;
|
|
1124
|
-
|
|
1125
|
-
case r_SETTING:
|
|
1126
|
-
if (LinkSetting[i] == MISSING) return 0;
|
|
1127
|
-
x = LinkSetting[i];
|
|
1128
|
-
switch (Link[i].Type)
|
|
1129
|
-
{
|
|
1130
|
-
case PRV:
|
|
1131
|
-
case PSV:
|
|
1132
|
-
case PBV:
|
|
1133
|
-
x = x * Ucf[PRESSURE];
|
|
1134
|
-
break;
|
|
1135
|
-
case FCV:
|
|
1136
|
-
x = x * Ucf[FLOW];
|
|
1137
|
-
break;
|
|
1138
|
-
default:
|
|
1139
|
-
break;
|
|
1140
|
-
}
|
|
1141
|
-
break;
|
|
1142
|
-
|
|
1143
|
-
case r_FILLTIME:
|
|
1144
|
-
if (i <= Njuncs) return 0;
|
|
1145
|
-
j = i - Njuncs;
|
|
1146
|
-
if (Tank[j].A == 0.0) return 0;
|
|
1147
|
-
if (NodeDemand[i] <= TINY) return 0;
|
|
1148
|
-
x = (Tank[j].Vmax - Tank[j].V) / NodeDemand[i];
|
|
1149
|
-
break;
|
|
1150
|
-
|
|
1151
|
-
case r_DRAINTIME:
|
|
1152
|
-
if (i <= Njuncs) return 0;
|
|
1153
|
-
j = i - Njuncs;
|
|
1154
|
-
if (Tank[j].A == 0.0) return 0;
|
|
1155
|
-
if (NodeDemand[i] >= -TINY) return 0;
|
|
1156
|
-
x = (Tank[j].Vmin - Tank[j].V) / NodeDemand[i];
|
|
1157
|
-
break;
|
|
1158
|
-
|
|
1159
|
-
default:
|
|
1160
|
-
return 0;
|
|
1161
|
-
}
|
|
1162
|
-
|
|
1163
|
-
// Compare value x against the premise
|
|
1164
|
-
switch (p->relop)
|
|
1165
|
-
{
|
|
1166
|
-
case EQ: if (ABS(x - p->value) > tol) return 0; break;
|
|
1167
|
-
case NE: if (ABS(x - p->value) < tol) return 0; break;
|
|
1168
|
-
case LT: if (x > p->value + tol) return 0; break;
|
|
1169
|
-
case LE: if (x > p->value - tol) return 0; break;
|
|
1170
|
-
case GT: if (x < p->value - tol) return 0; break;
|
|
1171
|
-
case GE: if (x < p->value + tol) return 0; break;
|
|
1172
|
-
}
|
|
1173
|
-
return 1;
|
|
1174
|
-
}
|
|
1175
|
-
|
|
1176
|
-
void updateactionlist(Project *pr, int i, Saction *actions)
|
|
1177
|
-
//---------------------------------------------------
|
|
1178
|
-
// Adds rule's actions to action list
|
|
1179
|
-
//--------------------------------------------------
|
|
1180
|
-
{
|
|
1181
|
-
Rules *rules = &pr->rules;
|
|
1182
|
-
|
|
1183
|
-
SactionList *actionItem;
|
|
1184
|
-
Saction *a;
|
|
1185
|
-
|
|
1186
|
-
// Iterate through each action of Rule i
|
|
1187
|
-
a = actions;
|
|
1188
|
-
while (a != NULL)
|
|
1189
|
-
{
|
|
1190
|
-
// Add action to list if its link not already on it
|
|
1191
|
-
if (!onactionlist(pr, i, a))
|
|
1192
|
-
{
|
|
1193
|
-
actionItem = (SactionList *)malloc(sizeof(SactionList));
|
|
1194
|
-
if (actionItem != NULL)
|
|
1195
|
-
{
|
|
1196
|
-
actionItem->action = a;
|
|
1197
|
-
actionItem->ruleIndex = i;
|
|
1198
|
-
actionItem->next = rules->ActionList;
|
|
1199
|
-
rules->ActionList = actionItem;
|
|
1200
|
-
}
|
|
1201
|
-
}
|
|
1202
|
-
a = a->next;
|
|
1203
|
-
}
|
|
1204
|
-
}
|
|
1205
|
-
|
|
1206
|
-
int onactionlist(Project *pr, int i, Saction *a)
|
|
1207
|
-
//-----------------------------------------------------------------------------
|
|
1208
|
-
// Checks if action a from rule i can be added to the action list
|
|
1209
|
-
//-----------------------------------------------------------------------------
|
|
1210
|
-
{
|
|
1211
|
-
Network *net = &pr->network;
|
|
1212
|
-
|
|
1213
|
-
int link, i1;
|
|
1214
|
-
SactionList *actionItem;
|
|
1215
|
-
Saction *a1;
|
|
1216
|
-
|
|
1217
|
-
// Search action list for link included in action a
|
|
1218
|
-
link = a->link;
|
|
1219
|
-
actionItem = pr->rules.ActionList;
|
|
1220
|
-
while (actionItem != NULL)
|
|
1221
|
-
{
|
|
1222
|
-
a1 = actionItem->action;
|
|
1223
|
-
i1 = actionItem->ruleIndex;
|
|
1224
|
-
|
|
1225
|
-
// Link appears in list
|
|
1226
|
-
if (link == a1->link)
|
|
1227
|
-
{
|
|
1228
|
-
// Replace its action with 'a' if rule i has higher priority
|
|
1229
|
-
if (net->Rule[i].priority > net->Rule[i1].priority)
|
|
1230
|
-
{
|
|
1231
|
-
actionItem->action = a;
|
|
1232
|
-
actionItem->ruleIndex = i;
|
|
1233
|
-
}
|
|
1234
|
-
|
|
1235
|
-
// Return indicating that 'a' should not be added to action list
|
|
1236
|
-
return 1;
|
|
1237
|
-
}
|
|
1238
|
-
actionItem = actionItem->next;
|
|
1239
|
-
}
|
|
1240
|
-
|
|
1241
|
-
// Return indicating that it's ok to add 'a' to the action list
|
|
1242
|
-
return 0;
|
|
1243
|
-
}
|
|
1244
|
-
|
|
1245
|
-
int takeactions(Project *pr)
|
|
1246
|
-
//-----------------------------------------------------------
|
|
1247
|
-
// Implements actions on action list
|
|
1248
|
-
//-----------------------------------------------------------
|
|
1249
|
-
{
|
|
1250
|
-
Network *net = &pr->network;
|
|
1251
|
-
Hydraul *hyd = &pr->hydraul;
|
|
1252
|
-
Report *rpt = &pr->report;
|
|
1253
|
-
Rules *rules = &pr->rules;
|
|
1254
|
-
|
|
1255
|
-
char flag;
|
|
1256
|
-
int k, s, n;
|
|
1257
|
-
double tol = 1.e-3, v, x;
|
|
1258
|
-
Saction *a;
|
|
1259
|
-
SactionList *actionItem;
|
|
1260
|
-
|
|
1261
|
-
n = 0;
|
|
1262
|
-
actionItem = rules->ActionList;
|
|
1263
|
-
while (actionItem != NULL)
|
|
1264
|
-
{
|
|
1265
|
-
flag = FALSE;
|
|
1266
|
-
a = actionItem->action;
|
|
1267
|
-
k = a->link;
|
|
1268
|
-
s = hyd->LinkStatus[k];
|
|
1269
|
-
v = hyd->LinkSetting[k];
|
|
1270
|
-
x = a->setting;
|
|
1271
|
-
|
|
1272
|
-
// Switch link from closed to open
|
|
1273
|
-
if (a->status == IS_OPEN && s <= CLOSED)
|
|
1274
|
-
{
|
|
1275
|
-
setlinkstatus(pr, k, 1, &hyd->LinkStatus[k], &hyd->LinkSetting[k]);
|
|
1276
|
-
flag = TRUE;
|
|
1277
|
-
}
|
|
1278
|
-
|
|
1279
|
-
// Switch link from not closed to closed
|
|
1280
|
-
else if (a->status == IS_CLOSED && s > CLOSED)
|
|
1281
|
-
{
|
|
1282
|
-
setlinkstatus(pr, k, 0, &hyd->LinkStatus[k], &hyd->LinkSetting[k]);
|
|
1283
|
-
flag = TRUE;
|
|
1284
|
-
}
|
|
1285
|
-
|
|
1286
|
-
// Change link's setting
|
|
1287
|
-
else if (x != MISSING)
|
|
1288
|
-
{
|
|
1289
|
-
switch (net->Link[k].Type)
|
|
1290
|
-
{
|
|
1291
|
-
case PRV:
|
|
1292
|
-
case PSV:
|
|
1293
|
-
case PBV:
|
|
1294
|
-
x = x / pr->Ucf[PRESSURE];
|
|
1295
|
-
break;
|
|
1296
|
-
case FCV:
|
|
1297
|
-
x = x / pr->Ucf[FLOW];
|
|
1298
|
-
break;
|
|
1299
|
-
default:
|
|
1300
|
-
break;
|
|
1301
|
-
}
|
|
1302
|
-
if (ABS(x - v) > tol)
|
|
1303
|
-
{
|
|
1304
|
-
setlinksetting(pr, k, x, &hyd->LinkStatus[k],
|
|
1305
|
-
&hyd->LinkSetting[k]);
|
|
1306
|
-
flag = TRUE;
|
|
1307
|
-
}
|
|
1308
|
-
}
|
|
1309
|
-
|
|
1310
|
-
// Report rule action
|
|
1311
|
-
if (flag == TRUE)
|
|
1312
|
-
{
|
|
1313
|
-
n++;
|
|
1314
|
-
if (rpt->Statflag)
|
|
1315
|
-
{
|
|
1316
|
-
writeruleaction(pr, k, net->Rule[actionItem->ruleIndex].label);
|
|
1317
|
-
}
|
|
1318
|
-
}
|
|
1319
|
-
|
|
1320
|
-
// Move to next action on list
|
|
1321
|
-
actionItem = actionItem->next;
|
|
1322
|
-
}
|
|
1323
|
-
return n;
|
|
1324
|
-
}
|
|
1325
|
-
|
|
1326
|
-
void clearactionlist(Rules *rules)
|
|
1327
|
-
//----------------------------------------------------------
|
|
1328
|
-
// Clears memory used for action list
|
|
1329
|
-
//----------------------------------------------------------
|
|
1330
|
-
{
|
|
1331
|
-
SactionList *nextItem;
|
|
1332
|
-
SactionList *actionItem;
|
|
1333
|
-
actionItem = rules->ActionList;
|
|
1334
|
-
while (actionItem != NULL)
|
|
1335
|
-
{
|
|
1336
|
-
nextItem = actionItem->next;
|
|
1337
|
-
free(actionItem);
|
|
1338
|
-
actionItem = nextItem;
|
|
1339
|
-
}
|
|
1340
|
-
}
|
|
1341
|
-
|
|
1342
|
-
void clearrule(Project *pr, int i)
|
|
1343
|
-
//-----------------------------------------------------------
|
|
1344
|
-
// Clears memory used by a rule for premises & actions
|
|
1345
|
-
//-----------------------------------------------------------
|
|
1346
|
-
{
|
|
1347
|
-
Network *net = &pr->network;
|
|
1348
|
-
|
|
1349
|
-
Spremise *p;
|
|
1350
|
-
Spremise *pnext;
|
|
1351
|
-
Saction *a;
|
|
1352
|
-
Saction *anext;
|
|
1353
|
-
|
|
1354
|
-
p = net->Rule[i].Premises;
|
|
1355
|
-
while (p != NULL)
|
|
1356
|
-
{
|
|
1357
|
-
pnext = p->next;
|
|
1358
|
-
free(p);
|
|
1359
|
-
p = pnext;
|
|
1360
|
-
}
|
|
1361
|
-
a = net->Rule[i].ThenActions;
|
|
1362
|
-
while (a != NULL)
|
|
1363
|
-
{
|
|
1364
|
-
anext = a->next;
|
|
1365
|
-
free(a);
|
|
1366
|
-
a = anext;
|
|
1367
|
-
}
|
|
1368
|
-
a = net->Rule[i].ElseActions;
|
|
1369
|
-
while (a != NULL)
|
|
1370
|
-
{
|
|
1371
|
-
anext = a->next;
|
|
1372
|
-
free(a);
|
|
1373
|
-
a = anext;
|
|
1374
|
-
}
|
|
1375
|
-
}
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
void writepremise(Spremise *p, FILE *f, Network *net)
|
|
1379
|
-
//-----------------------------------------------------------------------------
|
|
1380
|
-
// Write a rule's premise clause to an INP file.
|
|
1381
|
-
//-----------------------------------------------------------------------------
|
|
1382
|
-
{
|
|
1383
|
-
char s_obj[20];
|
|
1384
|
-
char s_id[MAXID + 1];
|
|
1385
|
-
char s_value[20];
|
|
1386
|
-
int subtype;
|
|
1387
|
-
|
|
1388
|
-
// Get the type name & ID of object referred to in the premise
|
|
1389
|
-
if (p->object == r_NODE)
|
|
1390
|
-
{
|
|
1391
|
-
subtype = net->Node[p->index].Type;
|
|
1392
|
-
getobjtxt(r_NODE, subtype, s_obj);
|
|
1393
|
-
strcpy(s_id, net->Node[p->index].ID);
|
|
1394
|
-
}
|
|
1395
|
-
else if (p->object == r_LINK)
|
|
1396
|
-
{
|
|
1397
|
-
subtype = net->Link[p->index].Type;
|
|
1398
|
-
getobjtxt(r_LINK, subtype, s_obj);
|
|
1399
|
-
strcpy(s_id, net->Link[p->index].ID);
|
|
1400
|
-
}
|
|
1401
|
-
else
|
|
1402
|
-
{
|
|
1403
|
-
strcpy(s_obj, "SYSTEM");
|
|
1404
|
-
strcpy(s_id, "");
|
|
1405
|
-
}
|
|
1406
|
-
|
|
1407
|
-
// If premise has no value field, use its status field as a value
|
|
1408
|
-
if (p->value == MISSING) strcpy(s_value, Value[p->status]);
|
|
1409
|
-
|
|
1410
|
-
// Otherwise get text of premise's value field
|
|
1411
|
-
else
|
|
1412
|
-
{
|
|
1413
|
-
// For time values convert from seconds to hr:min:sec
|
|
1414
|
-
switch (p->variable)
|
|
1415
|
-
{
|
|
1416
|
-
case r_CLOCKTIME:
|
|
1417
|
-
case r_DRAINTIME:
|
|
1418
|
-
case r_FILLTIME:
|
|
1419
|
-
case r_TIME:
|
|
1420
|
-
gettimetxt(p->value, s_value);
|
|
1421
|
-
break;
|
|
1422
|
-
default: sprintf(s_value, "%.4f", p->value);
|
|
1423
|
-
}
|
|
1424
|
-
}
|
|
1425
|
-
|
|
1426
|
-
// Write the premise clause to the file
|
|
1427
|
-
fprintf(f, "%s %s %s %s %s", s_obj, s_id, Varword[p->variable],
|
|
1428
|
-
Operator[p->relop], s_value);
|
|
1429
|
-
}
|
|
1430
|
-
|
|
1431
|
-
void writeaction(Saction *a, FILE *f, Network *net)
|
|
1432
|
-
//-----------------------------------------------------------------------------
|
|
1433
|
-
// Write a rule's action clause to an INP file.
|
|
1434
|
-
//-----------------------------------------------------------------------------
|
|
1435
|
-
{
|
|
1436
|
-
char s_id[MAXID + 1];
|
|
1437
|
-
char s_obj[20];
|
|
1438
|
-
char s_var[20];
|
|
1439
|
-
char s_value[20];
|
|
1440
|
-
int subtype;
|
|
1441
|
-
|
|
1442
|
-
subtype = net->Link[a->link].Type;
|
|
1443
|
-
getobjtxt(r_LINK, subtype, s_obj);
|
|
1444
|
-
strcpy(s_id, net->Link[a->link].ID);
|
|
1445
|
-
if (a->setting == MISSING)
|
|
1446
|
-
{
|
|
1447
|
-
strcpy(s_var, "STATUS");
|
|
1448
|
-
strcpy(s_value, Value[a->status]);
|
|
1449
|
-
}
|
|
1450
|
-
else
|
|
1451
|
-
{
|
|
1452
|
-
strcpy(s_var, "SETTING");
|
|
1453
|
-
sprintf(s_value, "%.4f", a->setting);
|
|
1454
|
-
}
|
|
1455
|
-
fprintf(f, "%s %s %s = %s", s_obj, s_id, s_var, s_value);
|
|
1456
|
-
}
|
|
1457
|
-
|
|
1458
|
-
void getobjtxt(int objtype, int subtype, char *objtxt)
|
|
1459
|
-
//-----------------------------------------------------------------------------
|
|
1460
|
-
// Retrieve the text label for a specific type of object.
|
|
1461
|
-
//-----------------------------------------------------------------------------
|
|
1462
|
-
{
|
|
1463
|
-
if (objtype == r_NODE)
|
|
1464
|
-
{
|
|
1465
|
-
switch (subtype)
|
|
1466
|
-
{
|
|
1467
|
-
case JUNCTION: strcpy(objtxt, "JUNCTION"); break;
|
|
1468
|
-
case RESERVOIR: strcpy(objtxt, "RESERVOIR"); break;
|
|
1469
|
-
case TANK: strcpy(objtxt, "TANK"); break;
|
|
1470
|
-
default: strcpy(objtxt, "NODE");
|
|
1471
|
-
}
|
|
1472
|
-
}
|
|
1473
|
-
else if (objtype == r_LINK)
|
|
1474
|
-
{
|
|
1475
|
-
switch (subtype)
|
|
1476
|
-
{
|
|
1477
|
-
case CVPIPE:
|
|
1478
|
-
case PIPE: strcpy(objtxt, "PIPE"); break;
|
|
1479
|
-
case PUMP: strcpy(objtxt, "PUMP"); break;
|
|
1480
|
-
default: strcpy(objtxt, "VALVE");
|
|
1481
|
-
}
|
|
1482
|
-
}
|
|
1483
|
-
else strcpy(objtxt, "SYSTEM");
|
|
1484
|
-
}
|
|
1485
|
-
|
|
1486
|
-
void gettimetxt(double secs, char *timetxt)
|
|
1487
|
-
//-----------------------------------------------------------------------------
|
|
1488
|
-
// Convert number of seconds to a text string in hrs:min:sec format.
|
|
1489
|
-
//-----------------------------------------------------------------------------
|
|
1490
|
-
{
|
|
1491
|
-
int hours = 0, minutes = 0, seconds = 0;
|
|
1492
|
-
hours = (int)secs / 3600;
|
|
1493
|
-
if (hours > 24 * 7) sprintf(timetxt, "%.4f", secs / 3600.0);
|
|
1494
|
-
else
|
|
1495
|
-
{
|
|
1496
|
-
minutes = (int)((secs - 3600 * hours) / 60);
|
|
1497
|
-
seconds = (int)(secs - 3600 * hours - minutes * 60);
|
|
1498
|
-
sprintf(timetxt, "%d:%02d:%02d", hours, minutes, seconds);
|
|
1499
|
-
}
|
|
1500
|
-
}
|