epyt-flow 0.14.1__py3-none-any.whl → 0.15.0b1__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 +367 -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-0.14.1.dist-info → epyt_flow-0.15.0b1.dist-info}/METADATA +12 -18
- epyt_flow-0.15.0b1.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.0b1.dist-info}/WHEEL +0 -0
- {epyt_flow-0.14.1.dist-info → epyt_flow-0.15.0b1.dist-info}/licenses/LICENSE +0 -0
- {epyt_flow-0.14.1.dist-info → epyt_flow-0.15.0b1.dist-info}/top_level.txt +0 -0
|
@@ -1,1172 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
******************************************************************************
|
|
3
|
-
Project: OWA EPANET
|
|
4
|
-
Version: 2.3
|
|
5
|
-
Module: hydraul.c
|
|
6
|
-
Description: implements EPANET's hydraulic engine
|
|
7
|
-
Authors: see AUTHORS
|
|
8
|
-
Copyright: see AUTHORS
|
|
9
|
-
License: see LICENSE
|
|
10
|
-
Last Updated: 04/19/2025
|
|
11
|
-
******************************************************************************
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
#include <stdlib.h>
|
|
15
|
-
#include <stdio.h>
|
|
16
|
-
#include <string.h>
|
|
17
|
-
#include <math.h>
|
|
18
|
-
|
|
19
|
-
#include "types.h"
|
|
20
|
-
#include "funcs.h"
|
|
21
|
-
#include "text.h"
|
|
22
|
-
|
|
23
|
-
const double QZERO = 1.e-6; // Equivalent to zero flow in cfs
|
|
24
|
-
|
|
25
|
-
// Imported functions
|
|
26
|
-
extern int validateproject(Project *);
|
|
27
|
-
extern int createsparse(Project *);
|
|
28
|
-
extern void freesparse(Project *);
|
|
29
|
-
extern int hydsolve(Project *, int *, double *);
|
|
30
|
-
|
|
31
|
-
// Local functions
|
|
32
|
-
int allocmatrix(Project *);
|
|
33
|
-
void freematrix(Project *);
|
|
34
|
-
void initlinkflow(Project *, int, char, double);
|
|
35
|
-
void demands(Project *);
|
|
36
|
-
int controls(Project *);
|
|
37
|
-
long timestep(Project *);
|
|
38
|
-
void ruletimestep(Project *, long *);
|
|
39
|
-
void addenergy(Project *, long);
|
|
40
|
-
void tanklevels(Project *, long);
|
|
41
|
-
void resetpumpflow(Project *, int);
|
|
42
|
-
void getallpumpsenergy(Project *);
|
|
43
|
-
|
|
44
|
-
int openhyd(Project *pr)
|
|
45
|
-
/*
|
|
46
|
-
*--------------------------------------------------------------
|
|
47
|
-
* Input: none
|
|
48
|
-
* Output: returns error code
|
|
49
|
-
* Purpose: opens hydraulics solver system
|
|
50
|
-
*--------------------------------------------------------------
|
|
51
|
-
*/
|
|
52
|
-
{
|
|
53
|
-
int i;
|
|
54
|
-
int errcode = 0;
|
|
55
|
-
Slink *link;
|
|
56
|
-
|
|
57
|
-
// Check for valid project data (see VALIDATE.C)
|
|
58
|
-
errcode = validateproject(pr);
|
|
59
|
-
if (errcode > 0) return errcode;
|
|
60
|
-
|
|
61
|
-
// Allocate memory for sparse matrix structures (see SMATRIX.C)
|
|
62
|
-
ERRCODE(createsparse(pr));
|
|
63
|
-
|
|
64
|
-
// Allocate memory for hydraulic variables
|
|
65
|
-
ERRCODE(allocmatrix(pr));
|
|
66
|
-
|
|
67
|
-
// Check for unconnected nodes
|
|
68
|
-
ERRCODE(unlinked(pr));
|
|
69
|
-
|
|
70
|
-
// Initialize link flows
|
|
71
|
-
if (!errcode) for (i = 1; i <= pr->network.Nlinks; i++)
|
|
72
|
-
{
|
|
73
|
-
link = &pr->network.Link[i];
|
|
74
|
-
initlinkflow(pr, i, link->InitStatus, link->Kc);
|
|
75
|
-
}
|
|
76
|
-
else closehyd(pr);
|
|
77
|
-
return errcode;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
void inithyd(Project *pr, int initflag)
|
|
81
|
-
/*
|
|
82
|
-
**--------------------------------------------------------------
|
|
83
|
-
** Input: initflag > 0 if link flows should be re-initialized
|
|
84
|
-
** = 0 if not
|
|
85
|
-
** Output: none
|
|
86
|
-
** Purpose: initializes hydraulics solver system
|
|
87
|
-
**--------------------------------------------------------------
|
|
88
|
-
*/
|
|
89
|
-
{
|
|
90
|
-
Network *net = &pr->network;
|
|
91
|
-
Hydraul *hyd = &pr->hydraul;
|
|
92
|
-
Outfile *out = &pr->outfile;
|
|
93
|
-
Times *time = &pr->times;
|
|
94
|
-
|
|
95
|
-
int i;
|
|
96
|
-
Stank *tank;
|
|
97
|
-
Slink *link;
|
|
98
|
-
Spump *pump;
|
|
99
|
-
|
|
100
|
-
// Initialize tanks
|
|
101
|
-
for (i = 1; i <= net->Ntanks; i++)
|
|
102
|
-
{
|
|
103
|
-
tank = &net->Tank[i];
|
|
104
|
-
tank->V = tank->V0;
|
|
105
|
-
hyd->NodeHead[tank->Node] = tank->H0;
|
|
106
|
-
hyd->NodeDemand[tank->Node] = 0.0;
|
|
107
|
-
hyd->OldStatus[net->Nlinks+i] = TEMPCLOSED;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// Initialize node outflows
|
|
111
|
-
memset(hyd->DemandFlow,0,(net->Nnodes+1)*sizeof(double));
|
|
112
|
-
memset(hyd->EmitterFlow,0,(net->Nnodes+1)*sizeof(double));
|
|
113
|
-
memset(hyd->LeakageFlow,0,(net->Nnodes+1)*sizeof(double));
|
|
114
|
-
for (i = 1; i <= net->Nnodes; i++)
|
|
115
|
-
{
|
|
116
|
-
net->Node[i].ResultIndex = i;
|
|
117
|
-
if (net->Node[i].Ke > 0.0) hyd->EmitterFlow[i] = 1.0;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Initialize links
|
|
121
|
-
for (i = 1; i <= net->Nlinks; i++)
|
|
122
|
-
{
|
|
123
|
-
link = &net->Link[i];
|
|
124
|
-
link->ResultIndex = i;
|
|
125
|
-
|
|
126
|
-
// Initialize status and setting
|
|
127
|
-
hyd->LinkStatus[i] = link->InitStatus;
|
|
128
|
-
hyd->LinkSetting[i] = link->InitSetting;
|
|
129
|
-
|
|
130
|
-
// Setting of non-ACTIVE FCV, PRV, PSV valves is "MISSING"
|
|
131
|
-
switch (link->Type)
|
|
132
|
-
{
|
|
133
|
-
case FCV:
|
|
134
|
-
case PRV:
|
|
135
|
-
case PSV:
|
|
136
|
-
if (link->InitStatus != ACTIVE)
|
|
137
|
-
{
|
|
138
|
-
link->Kc = MISSING;
|
|
139
|
-
hyd->LinkSetting[i] = MISSING;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// Compute flow resistance
|
|
144
|
-
resistcoeff(pr, i);
|
|
145
|
-
|
|
146
|
-
// Start active control valves in ACTIVE position
|
|
147
|
-
if (
|
|
148
|
-
(link->Type == PRV || link->Type == PSV
|
|
149
|
-
|| link->Type == FCV) && (link->Kc != MISSING)
|
|
150
|
-
) hyd->LinkStatus[i] = ACTIVE;
|
|
151
|
-
|
|
152
|
-
// Initialize flows if necessary
|
|
153
|
-
if (hyd->LinkStatus[i] <= CLOSED)
|
|
154
|
-
{
|
|
155
|
-
hyd->LinkFlow[i] = QZERO;
|
|
156
|
-
}
|
|
157
|
-
else if (ABS(hyd->LinkFlow[i]) <= QZERO || initflag > 0)
|
|
158
|
-
{
|
|
159
|
-
initlinkflow(pr, i, hyd->LinkStatus[i], hyd->LinkSetting[i]);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// Save initial status
|
|
163
|
-
hyd->OldStatus[i] = hyd->LinkStatus[i];
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// Initialize pump energy usage
|
|
167
|
-
for (i = 1; i <= net->Npumps; i++)
|
|
168
|
-
{
|
|
169
|
-
pump = &net->Pump[i];
|
|
170
|
-
pump->Energy.Efficiency = 0.0;
|
|
171
|
-
pump->Energy.TimeOnLine = 0.0;
|
|
172
|
-
pump->Energy.KwHrs = 0.0;
|
|
173
|
-
pump->Energy.KwHrsPerFlow = 0.0;
|
|
174
|
-
pump->Energy.MaxKwatts = 0.0;
|
|
175
|
-
pump->Energy.TotalCost = 0.0;
|
|
176
|
-
pump->Energy.CurrentPower = 0.0;
|
|
177
|
-
pump->Energy.CurrentEffic = 0.0;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// Initialize flow balance
|
|
181
|
-
startflowbalance(pr);
|
|
182
|
-
|
|
183
|
-
// Re-position hydraulics file
|
|
184
|
-
if (pr->outfile.Saveflag)
|
|
185
|
-
{
|
|
186
|
-
fseek(out->HydFile,out->HydOffset,SEEK_SET);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// Initialize current time
|
|
190
|
-
hyd->Haltflag = 0;
|
|
191
|
-
time->Htime = 0;
|
|
192
|
-
time->Hydstep = 0;
|
|
193
|
-
time->Rtime = time->Rstep;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
int runhyd(Project *pr, long *t)
|
|
198
|
-
/*
|
|
199
|
-
**--------------------------------------------------------------
|
|
200
|
-
** Input: none
|
|
201
|
-
** Output: t = pointer to current time (in seconds)
|
|
202
|
-
** Returns: error code
|
|
203
|
-
** Purpose: solves network hydraulics in a single time period
|
|
204
|
-
**--------------------------------------------------------------
|
|
205
|
-
*/
|
|
206
|
-
{
|
|
207
|
-
Hydraul *hyd = &pr->hydraul;
|
|
208
|
-
Times *time = &pr->times;
|
|
209
|
-
Report *rpt = &pr->report;
|
|
210
|
-
|
|
211
|
-
int iter; // Iteration count
|
|
212
|
-
int errcode; // Error code
|
|
213
|
-
double relerr; // Solution accuracy
|
|
214
|
-
|
|
215
|
-
// Find new demands & control actions
|
|
216
|
-
*t = time->Htime;
|
|
217
|
-
demands(pr);
|
|
218
|
-
controls(pr);
|
|
219
|
-
|
|
220
|
-
// Solve network hydraulic equations
|
|
221
|
-
errcode = hydsolve(pr,&iter,&relerr);
|
|
222
|
-
if (!errcode)
|
|
223
|
-
{
|
|
224
|
-
// Report new status & save results
|
|
225
|
-
if (rpt->Statflag) writehydstat(pr,iter,relerr);
|
|
226
|
-
|
|
227
|
-
// If system unbalanced and no extra trials
|
|
228
|
-
// allowed, then activate the Haltflag
|
|
229
|
-
if (relerr > hyd->Hacc && hyd->ExtraIter == -1)
|
|
230
|
-
{
|
|
231
|
-
hyd->Haltflag = 1;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// Report any warning conditions
|
|
235
|
-
if (!errcode) errcode = writehydwarn(pr,iter,relerr);
|
|
236
|
-
}
|
|
237
|
-
return errcode;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
int nexthyd(Project *pr, long *tstep)
|
|
241
|
-
/*
|
|
242
|
-
**--------------------------------------------------------------
|
|
243
|
-
** Input: none
|
|
244
|
-
** Output: tstep = pointer to time step (in seconds)
|
|
245
|
-
** Returns: error code
|
|
246
|
-
** Purpose: finds length of next time step & updates tank
|
|
247
|
-
** levels and rule-based contol actions
|
|
248
|
-
**--------------------------------------------------------------
|
|
249
|
-
*/
|
|
250
|
-
{
|
|
251
|
-
Hydraul *hyd = &pr->hydraul;
|
|
252
|
-
Times *time = &pr->times;
|
|
253
|
-
|
|
254
|
-
long hydstep; // Actual time step
|
|
255
|
-
int errcode = 0; // Error code
|
|
256
|
-
|
|
257
|
-
// Compute current power and efficiency of all pumps
|
|
258
|
-
getallpumpsenergy(pr);
|
|
259
|
-
|
|
260
|
-
// Save current results to hydraulics file and
|
|
261
|
-
// force end of simulation if Haltflag is active
|
|
262
|
-
if (pr->outfile.Saveflag) errcode = savehyd(pr, &time->Htime);
|
|
263
|
-
if (hyd->Haltflag) time->Htime = time->Dur;
|
|
264
|
-
|
|
265
|
-
// Compute next time step & update tank levels
|
|
266
|
-
*tstep = 0;
|
|
267
|
-
hydstep = 0;
|
|
268
|
-
if (time->Htime < time->Dur) hydstep = timestep(pr);
|
|
269
|
-
if (pr->outfile.Saveflag) errcode = savehydstep(pr,&hydstep);
|
|
270
|
-
|
|
271
|
-
// Accumulate pumping energy
|
|
272
|
-
if (time->Dur == 0) addenergy(pr,0);
|
|
273
|
-
else if (time->Htime < time->Dur) addenergy(pr,hydstep);
|
|
274
|
-
|
|
275
|
-
// Update flow balance
|
|
276
|
-
updateflowbalance(pr, hydstep);
|
|
277
|
-
|
|
278
|
-
// More time remains - update current time
|
|
279
|
-
if (time->Htime < time->Dur)
|
|
280
|
-
{
|
|
281
|
-
time->Htime += hydstep;
|
|
282
|
-
if (!pr->quality.OpenQflag)
|
|
283
|
-
{
|
|
284
|
-
if (time->Htime >= time->Rtime) time->Rtime += time->Rstep;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
// No more time remains - force completion of analysis
|
|
289
|
-
else
|
|
290
|
-
{
|
|
291
|
-
endflowbalance(pr);
|
|
292
|
-
if (pr->report.Statflag) writeflowbalance(pr);
|
|
293
|
-
time->Htime++;
|
|
294
|
-
if (pr->quality.OpenQflag) time->Qtime++;
|
|
295
|
-
}
|
|
296
|
-
*tstep = hydstep;
|
|
297
|
-
return errcode;
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
void closehyd(Project *pr)
|
|
302
|
-
/*
|
|
303
|
-
**--------------------------------------------------------------
|
|
304
|
-
** Input: none
|
|
305
|
-
** Output: returns error code
|
|
306
|
-
** Purpose: closes hydraulics solver system
|
|
307
|
-
**--------------------------------------------------------------
|
|
308
|
-
*/
|
|
309
|
-
{
|
|
310
|
-
freesparse(pr);
|
|
311
|
-
freematrix(pr);
|
|
312
|
-
freeadjlists(&pr->network);
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
int allocmatrix(Project *pr)
|
|
317
|
-
/*
|
|
318
|
-
**--------------------------------------------------------------
|
|
319
|
-
** Input: none
|
|
320
|
-
** Output: returns error code
|
|
321
|
-
** Purpose: allocates memory used for solution matrix coeffs.
|
|
322
|
-
**--------------------------------------------------------------
|
|
323
|
-
*/
|
|
324
|
-
{
|
|
325
|
-
Network *net = &pr->network;
|
|
326
|
-
Hydraul *hyd = &pr->hydraul;
|
|
327
|
-
|
|
328
|
-
int errcode = 0;
|
|
329
|
-
|
|
330
|
-
hyd->P = (double *) calloc(net->Nlinks+1,sizeof(double));
|
|
331
|
-
hyd->Y = (double *) calloc(net->Nlinks+1,sizeof(double));
|
|
332
|
-
hyd->Xflow = (double *) calloc(MAX((net->Nnodes+1), (net->Nlinks+1)),
|
|
333
|
-
sizeof(double));
|
|
334
|
-
hyd->OldStatus = (StatusType *) calloc(net->Nlinks+net->Ntanks+1,
|
|
335
|
-
sizeof(StatusType));
|
|
336
|
-
ERRCODE(MEMCHECK(hyd->P));
|
|
337
|
-
ERRCODE(MEMCHECK(hyd->Y));
|
|
338
|
-
ERRCODE(MEMCHECK(hyd->Xflow));
|
|
339
|
-
ERRCODE(MEMCHECK(hyd->OldStatus));
|
|
340
|
-
return errcode;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
void freematrix(Project *pr)
|
|
345
|
-
/*
|
|
346
|
-
**--------------------------------------------------------------
|
|
347
|
-
** Input: none
|
|
348
|
-
** Output: none
|
|
349
|
-
** Purpose: frees memory used for solution matrix coeffs.
|
|
350
|
-
**--------------------------------------------------------------
|
|
351
|
-
*/
|
|
352
|
-
{
|
|
353
|
-
Hydraul *hyd = &pr->hydraul;
|
|
354
|
-
|
|
355
|
-
free(hyd->P);
|
|
356
|
-
free(hyd->Y);
|
|
357
|
-
free(hyd->Xflow);
|
|
358
|
-
free(hyd->OldStatus);
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
void initlinkflow(Project *pr, int i, char s, double k)
|
|
363
|
-
/*
|
|
364
|
-
**--------------------------------------------------------------------
|
|
365
|
-
** Input: i = link index
|
|
366
|
-
** s = link status
|
|
367
|
-
** k = link setting (i.e., pump speed)
|
|
368
|
-
** Output: none
|
|
369
|
-
** Purpose: sets initial flow in link to QZERO if link is closed,
|
|
370
|
-
** to design flow for a pump, or to flow at velocity of
|
|
371
|
-
** 1 fps for other links.
|
|
372
|
-
**--------------------------------------------------------------------
|
|
373
|
-
*/
|
|
374
|
-
{
|
|
375
|
-
Hydraul *hyd = &pr->hydraul;
|
|
376
|
-
Network *n = &pr->network;
|
|
377
|
-
|
|
378
|
-
Slink *link = &n->Link[i];
|
|
379
|
-
|
|
380
|
-
if (s == CLOSED)
|
|
381
|
-
{
|
|
382
|
-
hyd->LinkFlow[i] = QZERO;
|
|
383
|
-
}
|
|
384
|
-
else if (link->Type == PUMP)
|
|
385
|
-
{
|
|
386
|
-
hyd->LinkFlow[i] = k * n->Pump[findpump(n,i)].Q0;
|
|
387
|
-
}
|
|
388
|
-
else
|
|
389
|
-
{
|
|
390
|
-
hyd->LinkFlow[i] = PI * SQR(link->Diam)/4.0;
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
void setlinkstatus(Project *pr, int index, char value, StatusType *s, double *k)
|
|
396
|
-
/*----------------------------------------------------------------
|
|
397
|
-
** Input: index = link index
|
|
398
|
-
** value = 0 (CLOSED) or 1 (OPEN)
|
|
399
|
-
** s = pointer to link status
|
|
400
|
-
** k = pointer to link setting
|
|
401
|
-
** Output: none
|
|
402
|
-
** Purpose: sets link status to OPEN or CLOSED
|
|
403
|
-
**----------------------------------------------------------------
|
|
404
|
-
*/
|
|
405
|
-
{
|
|
406
|
-
Network *net = &pr->network;
|
|
407
|
-
|
|
408
|
-
Slink *link = &net->Link[index];
|
|
409
|
-
LinkType t = link->Type;
|
|
410
|
-
|
|
411
|
-
// Status set to open
|
|
412
|
-
if (value == 1)
|
|
413
|
-
{
|
|
414
|
-
// Adjust link setting for pumps & valves
|
|
415
|
-
if (t == PUMP)
|
|
416
|
-
{
|
|
417
|
-
*k = 1.0;
|
|
418
|
-
// Check if a re-opened pump needs its flow reset
|
|
419
|
-
if (*s == CLOSED) resetpumpflow(pr, index);
|
|
420
|
-
}
|
|
421
|
-
if (t > PUMP && t != GPV) *k = MISSING;
|
|
422
|
-
*s = OPEN;
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
// Status set to closed
|
|
426
|
-
else if (value == 0)
|
|
427
|
-
{
|
|
428
|
-
// Adjust link setting for pumps & valves
|
|
429
|
-
if (t == PUMP) *k = 0.0;
|
|
430
|
-
if (t > PUMP && t != GPV) *k = MISSING;
|
|
431
|
-
*s = CLOSED;
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
void setlinksetting(Project *pr, int index, double value, StatusType *s,
|
|
437
|
-
double *k)
|
|
438
|
-
/*----------------------------------------------------------------
|
|
439
|
-
** Input: index = link index
|
|
440
|
-
** value = pump speed or valve setting
|
|
441
|
-
** s = pointer to link status
|
|
442
|
-
** k = pointer to link setting
|
|
443
|
-
** Output: none
|
|
444
|
-
** Purpose: sets pump speed or valve setting, adjusting link
|
|
445
|
-
** status and flow when necessary
|
|
446
|
-
**----------------------------------------------------------------
|
|
447
|
-
*/
|
|
448
|
-
{
|
|
449
|
-
Network *net = &pr->network;
|
|
450
|
-
|
|
451
|
-
Slink *link = &net->Link[index];
|
|
452
|
-
LinkType t = link->Type;
|
|
453
|
-
|
|
454
|
-
// For a pump, status is OPEN if speed > 0, CLOSED otherwise
|
|
455
|
-
if (t == PUMP)
|
|
456
|
-
{
|
|
457
|
-
*k = value;
|
|
458
|
-
if (value > 0 && *s <= CLOSED)
|
|
459
|
-
{
|
|
460
|
-
// Check if a re-opened pump needs its flow reset
|
|
461
|
-
resetpumpflow(pr, index);
|
|
462
|
-
*s = OPEN;
|
|
463
|
-
}
|
|
464
|
-
if (value == 0 && *s > CLOSED) *s = CLOSED;
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
// For FCV, activate it
|
|
468
|
-
else if (t == FCV)
|
|
469
|
-
{
|
|
470
|
-
*k = value;
|
|
471
|
-
*s = ACTIVE;
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
// Open closed control valve with fixed status (setting = MISSING)
|
|
475
|
-
else
|
|
476
|
-
{
|
|
477
|
-
if (*k == MISSING && *s <= CLOSED) *s = OPEN;
|
|
478
|
-
if (t == PCV) link->R = pcvlosscoeff(pr, index, link->Kc);
|
|
479
|
-
*k = value;
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
void demands(Project *pr)
|
|
485
|
-
/*
|
|
486
|
-
**--------------------------------------------------------------------
|
|
487
|
-
** Input: none
|
|
488
|
-
** Output: none
|
|
489
|
-
** Purpose: computes demands at nodes during current time period
|
|
490
|
-
**--------------------------------------------------------------------
|
|
491
|
-
*/
|
|
492
|
-
{
|
|
493
|
-
Network *net = &pr->network;
|
|
494
|
-
Hydraul *hyd = &pr->hydraul;
|
|
495
|
-
Times *time = &pr->times;
|
|
496
|
-
|
|
497
|
-
int i ,j, n;
|
|
498
|
-
long k, p;
|
|
499
|
-
double djunc, sum;
|
|
500
|
-
Pdemand demand;
|
|
501
|
-
|
|
502
|
-
// Determine total elapsed number of pattern periods
|
|
503
|
-
p = (time->Htime + time->Pstart) / time->Pstep;
|
|
504
|
-
|
|
505
|
-
// Update demand at each node according to its assigned pattern
|
|
506
|
-
hyd->Dsystem = 0.0; // System-wide demand
|
|
507
|
-
for (i = 1; i <= net->Njuncs; i++)
|
|
508
|
-
{
|
|
509
|
-
sum = 0.0;
|
|
510
|
-
for (demand = net->Node[i].D; demand != NULL; demand = demand->next)
|
|
511
|
-
{
|
|
512
|
-
// pattern period (k) = (elapsed periods) modulus (periods per pattern)
|
|
513
|
-
j = demand->Pat;
|
|
514
|
-
if (j == 0)
|
|
515
|
-
j = hyd->DefPat;
|
|
516
|
-
k = p % (long)net->Pattern[j].Length;
|
|
517
|
-
djunc = (demand->Base) * net->Pattern[j].F[k] * hyd->Dmult;
|
|
518
|
-
if (djunc > 0.0) hyd->Dsystem += djunc;
|
|
519
|
-
sum += djunc;
|
|
520
|
-
}
|
|
521
|
-
hyd->FullDemand[i] = sum;
|
|
522
|
-
|
|
523
|
-
// Initialize pressure dependent demand
|
|
524
|
-
hyd->DemandFlow[i] = sum;
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
// Update head at fixed grade nodes with time patterns
|
|
528
|
-
for (n = 1; n <= net->Ntanks; n++)
|
|
529
|
-
{
|
|
530
|
-
Stank *tank = &net->Tank[n];
|
|
531
|
-
if (tank->A == 0.0)
|
|
532
|
-
{
|
|
533
|
-
j = tank->Pat;
|
|
534
|
-
if (j > 0)
|
|
535
|
-
{
|
|
536
|
-
k = p % (long) net->Pattern[j].Length;
|
|
537
|
-
i = tank->Node;
|
|
538
|
-
hyd->NodeHead[i] = net->Node[i].El * net->Pattern[j].F[k];
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
// Update status of pumps with utilization patterns
|
|
544
|
-
for (n = 1; n <= net->Npumps; n++)
|
|
545
|
-
{
|
|
546
|
-
Spump *pump = &net->Pump[n];
|
|
547
|
-
j = pump->Upat;
|
|
548
|
-
if (j > 0)
|
|
549
|
-
{
|
|
550
|
-
i = pump->Link;
|
|
551
|
-
k = p % (long) net->Pattern[j].Length;
|
|
552
|
-
setlinksetting(pr, i, net->Pattern[j].F[k], &hyd->LinkStatus[i],
|
|
553
|
-
&hyd->LinkSetting[i]);
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
int controls(Project *pr)
|
|
560
|
-
/*
|
|
561
|
-
**---------------------------------------------------------------------
|
|
562
|
-
** Input: none
|
|
563
|
-
** Output: number of links whose setting changes
|
|
564
|
-
** Purpose: implements simple controls based on time or tank levels
|
|
565
|
-
**---------------------------------------------------------------------
|
|
566
|
-
*/
|
|
567
|
-
{
|
|
568
|
-
Network *net = &pr->network;
|
|
569
|
-
Hydraul *hyd = &pr->hydraul;
|
|
570
|
-
Times *time = &pr->times;
|
|
571
|
-
|
|
572
|
-
int i, k, n, reset, setsum;
|
|
573
|
-
double h, vplus;
|
|
574
|
-
double v1, v2;
|
|
575
|
-
double k1, k2;
|
|
576
|
-
char s1, s2;
|
|
577
|
-
Slink *link;
|
|
578
|
-
Scontrol *control;
|
|
579
|
-
|
|
580
|
-
// Examine each control statement
|
|
581
|
-
setsum = 0;
|
|
582
|
-
for (i=1; i <= net->Ncontrols; i++)
|
|
583
|
-
{
|
|
584
|
-
// Make sure that link is defined
|
|
585
|
-
control = &net->Control[i];
|
|
586
|
-
if (!control->isEnabled)
|
|
587
|
-
{
|
|
588
|
-
continue;
|
|
589
|
-
}
|
|
590
|
-
reset = 0;
|
|
591
|
-
if ( (k = control->Link) <= 0) continue;
|
|
592
|
-
link = &net->Link[k];
|
|
593
|
-
|
|
594
|
-
// Link is controlled by tank level
|
|
595
|
-
if ((n = control->Node) > 0 && n > net->Njuncs)
|
|
596
|
-
{
|
|
597
|
-
h = hyd->NodeHead[n];
|
|
598
|
-
vplus = ABS(hyd->NodeDemand[n]);
|
|
599
|
-
v1 = tankvolume(pr,n - net->Njuncs,h);
|
|
600
|
-
v2 = tankvolume(pr,n - net->Njuncs, control->Grade);
|
|
601
|
-
if (control->Type == LOWLEVEL && v1 <= v2 + vplus) reset = 1;
|
|
602
|
-
if (control->Type == HILEVEL && v1 >= v2 - vplus) reset = 1;
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
// Link is time-controlled
|
|
606
|
-
if (control->Type == TIMER)
|
|
607
|
-
{
|
|
608
|
-
if (control->Time == time->Htime) reset = 1;
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
//* Link is time-of-day controlled
|
|
612
|
-
if (control->Type == TIMEOFDAY)
|
|
613
|
-
{
|
|
614
|
-
if ((time->Htime + time->Tstart) % SECperDAY == control->Time)
|
|
615
|
-
{
|
|
616
|
-
reset = 1;
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
// Update link status & pump speed or valve setting
|
|
621
|
-
if (reset == 1)
|
|
622
|
-
{
|
|
623
|
-
if (hyd->LinkStatus[k] <= CLOSED) s1 = CLOSED;
|
|
624
|
-
else s1 = OPEN;
|
|
625
|
-
s2 = control->Status;
|
|
626
|
-
k1 = hyd->LinkSetting[k];
|
|
627
|
-
k2 = k1;
|
|
628
|
-
if (link->Type > PIPE) k2 = control->Setting;
|
|
629
|
-
|
|
630
|
-
// Check if a re-opened pump needs its flow reset
|
|
631
|
-
if (link->Type == PUMP && s1 == CLOSED && s2 == OPEN)
|
|
632
|
-
resetpumpflow(pr, k);
|
|
633
|
-
|
|
634
|
-
if (s1 != s2 || k1 != k2)
|
|
635
|
-
{
|
|
636
|
-
hyd->LinkStatus[k] = s2;
|
|
637
|
-
hyd->LinkSetting[k] = k2;
|
|
638
|
-
if (link->Type == PCV) link->R = pcvlosscoeff(pr, k, k2);
|
|
639
|
-
if (pr->report.Statflag) writecontrolaction(pr,k,i);
|
|
640
|
-
setsum++;
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
return setsum;
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
long timestep(Project *pr)
|
|
649
|
-
/*
|
|
650
|
-
**----------------------------------------------------------------
|
|
651
|
-
** Input: none
|
|
652
|
-
** Output: returns time step until next change in hydraulics
|
|
653
|
-
** Purpose: computes time step to advance hydraulic simulation
|
|
654
|
-
**----------------------------------------------------------------
|
|
655
|
-
*/
|
|
656
|
-
{
|
|
657
|
-
Network *net = &pr->network;
|
|
658
|
-
Times *time = &pr->times;
|
|
659
|
-
|
|
660
|
-
long n, t, tstep;
|
|
661
|
-
|
|
662
|
-
// Normal time step is hydraulic time step
|
|
663
|
-
tstep = time->Hstep;
|
|
664
|
-
|
|
665
|
-
// Revise time step based on time until next demand period
|
|
666
|
-
// (n = next pattern period, t = time till next period)
|
|
667
|
-
n = ((time->Htime + time->Pstart) / time->Pstep) + 1;
|
|
668
|
-
t = n * time->Pstep - time->Htime;
|
|
669
|
-
if (t > 0 && t < tstep) tstep = t;
|
|
670
|
-
|
|
671
|
-
// Revise time step based on time until next reporting period
|
|
672
|
-
t = time->Rtime - time->Htime;
|
|
673
|
-
if (t > 0 && t < tstep) tstep = t;
|
|
674
|
-
|
|
675
|
-
// Revise time step based on smallest time to fill or drain a tank
|
|
676
|
-
tanktimestep(pr, &tstep);
|
|
677
|
-
|
|
678
|
-
// Revise time step based on smallest time to activate a control
|
|
679
|
-
controltimestep(pr, &tstep);
|
|
680
|
-
|
|
681
|
-
// Evaluate rule-based controls (which will also update tank levels)
|
|
682
|
-
if (net->Nrules > 0) ruletimestep(pr, &tstep);
|
|
683
|
-
else tanklevels(pr, tstep);
|
|
684
|
-
return tstep;
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
int tanktimestep(Project *pr, long *tstep)
|
|
689
|
-
/*
|
|
690
|
-
**-----------------------------------------------------------------
|
|
691
|
-
** Input: *tstep = current time step
|
|
692
|
-
** Output: *tstep = modified current time step
|
|
693
|
-
** Purpose: revises time step based on shortest time to fill or
|
|
694
|
-
** drain a tank
|
|
695
|
-
**-----------------------------------------------------------------
|
|
696
|
-
*/
|
|
697
|
-
{
|
|
698
|
-
Network *net = &pr->network;
|
|
699
|
-
Hydraul *hyd = &pr->hydraul;
|
|
700
|
-
|
|
701
|
-
int i, n, tankIdx = 0;
|
|
702
|
-
double h, q, v, xt;
|
|
703
|
-
long t;
|
|
704
|
-
Stank *tank;
|
|
705
|
-
|
|
706
|
-
// Examine each tank
|
|
707
|
-
for (i = 1; i <= net->Ntanks; i++)
|
|
708
|
-
{
|
|
709
|
-
// Skip reservoirs
|
|
710
|
-
tank = &net->Tank[i];
|
|
711
|
-
if (tank->A == 0.0) continue;
|
|
712
|
-
|
|
713
|
-
// Get current tank grade (h) & inflow (q)
|
|
714
|
-
n = tank->Node;
|
|
715
|
-
h = hyd->NodeHead[n];
|
|
716
|
-
q = hyd->NodeDemand[n];
|
|
717
|
-
if (ABS(q) <= QZERO) continue;
|
|
718
|
-
|
|
719
|
-
// Find volume to fill/drain tank
|
|
720
|
-
if (q > 0.0 && h < tank->Hmax) v = tank->Vmax - tank->V;
|
|
721
|
-
else if (q < 0.0 && h > tank->Hmin) v = tank->Vmin - tank->V;
|
|
722
|
-
else continue;
|
|
723
|
-
|
|
724
|
-
// Find time to fill/drain tank
|
|
725
|
-
xt = v / q;
|
|
726
|
-
if (ABS(xt) > *tstep + 1) continue;
|
|
727
|
-
t = (long)ROUND(xt);
|
|
728
|
-
if (t > 0 && t < *tstep)
|
|
729
|
-
{
|
|
730
|
-
*tstep = t;
|
|
731
|
-
tankIdx = n;
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
return tankIdx;
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
int controltimestep(Project *pr, long *tstep)
|
|
739
|
-
/*
|
|
740
|
-
**------------------------------------------------------------------
|
|
741
|
-
** Input: *tstep = current time step
|
|
742
|
-
** Output: *tstep = modified current time step
|
|
743
|
-
** Purpose: revises time step based on shortest time to activate
|
|
744
|
-
** a simple control
|
|
745
|
-
**------------------------------------------------------------------
|
|
746
|
-
*/
|
|
747
|
-
{
|
|
748
|
-
Network *net = &pr->network;
|
|
749
|
-
Hydraul *hyd = &pr->hydraul;
|
|
750
|
-
|
|
751
|
-
int i, j, k, n, controlIndex = 0;
|
|
752
|
-
double h, q, v;
|
|
753
|
-
long t, t1, t2;
|
|
754
|
-
Slink *link;
|
|
755
|
-
Scontrol *control;
|
|
756
|
-
|
|
757
|
-
// Examine each control
|
|
758
|
-
for (i = 1; i <= net->Ncontrols; i++)
|
|
759
|
-
{
|
|
760
|
-
t = 0;
|
|
761
|
-
control = &net->Control[i];
|
|
762
|
-
if (!control->isEnabled)
|
|
763
|
-
{
|
|
764
|
-
continue;
|
|
765
|
-
}
|
|
766
|
-
// Control depends on a tank level
|
|
767
|
-
if ( (n = control->Node) > 0)
|
|
768
|
-
{
|
|
769
|
-
// Skip node if not a tank or reservoir
|
|
770
|
-
if ((j = n - net->Njuncs) <= 0) continue;
|
|
771
|
-
|
|
772
|
-
// Find current head and flow into tank
|
|
773
|
-
h = hyd->NodeHead[n];
|
|
774
|
-
q = hyd->NodeDemand[n];
|
|
775
|
-
if (ABS(q) <= QZERO) continue;
|
|
776
|
-
|
|
777
|
-
// Find time to reach upper or lower control level
|
|
778
|
-
if ( (h < control->Grade && control->Type == HILEVEL && q > 0.0)
|
|
779
|
-
|| (h > control->Grade && control->Type == LOWLEVEL && q < 0.0) )
|
|
780
|
-
{
|
|
781
|
-
v = tankvolume(pr, j, control->Grade) - net->Tank[j].V;
|
|
782
|
-
t = (long)ROUND(v/q);
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
// Control is based on elapsed time
|
|
787
|
-
if (control->Type == TIMER)
|
|
788
|
-
{
|
|
789
|
-
if (control->Time > pr->times.Htime)
|
|
790
|
-
{
|
|
791
|
-
t = control->Time - pr->times.Htime;
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
|
|
795
|
-
// Control is based on time of day
|
|
796
|
-
if (control->Type == TIMEOFDAY)
|
|
797
|
-
{
|
|
798
|
-
t1 = (pr->times.Htime + pr->times.Tstart) % SECperDAY;
|
|
799
|
-
t2 = control->Time;
|
|
800
|
-
if (t2 >= t1) t = t2 - t1;
|
|
801
|
-
else t = SECperDAY - t1 + t2;
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
// Revise the current estimated next time step
|
|
805
|
-
if (t > 0 && t < *tstep)
|
|
806
|
-
{
|
|
807
|
-
// Check if rule actually changes link status or setting
|
|
808
|
-
k = control->Link;
|
|
809
|
-
link = &net->Link[k];
|
|
810
|
-
if ( (link->Type > PIPE && hyd->LinkSetting[k] != control->Setting)
|
|
811
|
-
|| (hyd->LinkStatus[k] != control->Status) )
|
|
812
|
-
{
|
|
813
|
-
*tstep = t;
|
|
814
|
-
controlIndex = i;
|
|
815
|
-
}
|
|
816
|
-
}
|
|
817
|
-
}
|
|
818
|
-
return controlIndex;
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
void ruletimestep(Project *pr, long *tstep)
|
|
823
|
-
/*
|
|
824
|
-
**--------------------------------------------------------------
|
|
825
|
-
** Input: *tstep = current time step (sec)
|
|
826
|
-
** Output: *tstep = modified time step
|
|
827
|
-
** Purpose: updates next time step by checking if any rules
|
|
828
|
-
** will fire before then; also updates tank levels.
|
|
829
|
-
**--------------------------------------------------------------
|
|
830
|
-
*/
|
|
831
|
-
{
|
|
832
|
-
Network *net = &pr->network;
|
|
833
|
-
Times *time = &pr->times;
|
|
834
|
-
|
|
835
|
-
long tnow, // Start of time interval for rule evaluation
|
|
836
|
-
tmax, // End of time interval for rule evaluation
|
|
837
|
-
dt, // Normal time increment for rule evaluation
|
|
838
|
-
dt1; // Actual time increment for rule evaluation
|
|
839
|
-
|
|
840
|
-
// Find interval of time for rule evaluation
|
|
841
|
-
tnow = time->Htime;
|
|
842
|
-
tmax = tnow + *tstep;
|
|
843
|
-
|
|
844
|
-
// If no rules, then time increment equals current time step
|
|
845
|
-
if (net->Nrules == 0)
|
|
846
|
-
{
|
|
847
|
-
dt = *tstep;
|
|
848
|
-
dt1 = dt;
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
// Otherwise, time increment equals rule evaluation time step and
|
|
852
|
-
// first actual increment equals time until next even multiple of
|
|
853
|
-
// Rulestep occurs.
|
|
854
|
-
else
|
|
855
|
-
{
|
|
856
|
-
dt = time->Rulestep;
|
|
857
|
-
dt1 = time->Rulestep - (tnow % time->Rulestep);
|
|
858
|
-
}
|
|
859
|
-
|
|
860
|
-
// Make sure time increment is no larger than current time step
|
|
861
|
-
dt = MIN(dt, *tstep);
|
|
862
|
-
dt1 = MIN(dt1, *tstep);
|
|
863
|
-
if (dt1 == 0) dt1 = dt;
|
|
864
|
-
|
|
865
|
-
// Step through time, updating tank levels, until either
|
|
866
|
-
// a rule fires or we reach the end of evaluation period.
|
|
867
|
-
//
|
|
868
|
-
// Note: we are updating the global simulation time (Htime)
|
|
869
|
-
// here because it is used by functions in RULES.C
|
|
870
|
-
// to evaluate rules when checkrules() is called.
|
|
871
|
-
// It is restored to its original value after the
|
|
872
|
-
// rule evaluation process is completed (see below).
|
|
873
|
-
// Also note that dt1 will equal dt after the first
|
|
874
|
-
// time increment is taken.
|
|
875
|
-
//
|
|
876
|
-
do
|
|
877
|
-
{
|
|
878
|
-
time->Htime += dt1; // Update simulation clock
|
|
879
|
-
tanklevels(pr, dt1); // Find new tank levels
|
|
880
|
-
if (checkrules(pr, dt1)) break; // Stop if any rule fires
|
|
881
|
-
dt = MIN(dt, tmax - time->Htime); // Update time increment
|
|
882
|
-
dt1 = dt; // Update actual increment
|
|
883
|
-
} while (dt > 0); // Stop if no time left
|
|
884
|
-
|
|
885
|
-
// Compute an updated simulation time step (*tstep)
|
|
886
|
-
// and return simulation time to its original value
|
|
887
|
-
*tstep = time->Htime - tnow;
|
|
888
|
-
time->Htime = tnow;
|
|
889
|
-
}
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
void addenergy(Project *pr, long hstep)
|
|
893
|
-
/*
|
|
894
|
-
**-------------------------------------------------------------
|
|
895
|
-
** Input: hstep = time step (sec)
|
|
896
|
-
** Output: none
|
|
897
|
-
** Purpose: accumulates pump energy usage
|
|
898
|
-
**-------------------------------------------------------------
|
|
899
|
-
*/
|
|
900
|
-
{
|
|
901
|
-
Network *net = &pr->network;
|
|
902
|
-
Hydraul *hyd = &pr->hydraul;
|
|
903
|
-
Times *time = &pr->times;
|
|
904
|
-
|
|
905
|
-
int i, j, k;
|
|
906
|
-
long m, n;
|
|
907
|
-
double c0, c, // Energy cost (cost/kwh)
|
|
908
|
-
f0, // Energy cost factor
|
|
909
|
-
dt, // Time interval (hr)
|
|
910
|
-
e, // Pump efficiency (fraction)
|
|
911
|
-
q, // Pump flow (cfs)
|
|
912
|
-
p, // Pump energy (kw)
|
|
913
|
-
psum = 0.0; // Total energy (kw)
|
|
914
|
-
Spump *pump;
|
|
915
|
-
|
|
916
|
-
// Determine current time interval in hours
|
|
917
|
-
if (time->Dur == 0) dt = 1.0;
|
|
918
|
-
else if (time->Htime < time->Dur)
|
|
919
|
-
{
|
|
920
|
-
dt = (double) hstep / 3600.0;
|
|
921
|
-
}
|
|
922
|
-
else dt = 0.0;
|
|
923
|
-
if (dt == 0.0) return;
|
|
924
|
-
n = (time->Htime + time->Pstart) / time->Pstep;
|
|
925
|
-
|
|
926
|
-
// Compute default energy cost at current time
|
|
927
|
-
c0 = hyd->Ecost;
|
|
928
|
-
f0 = 1.0;
|
|
929
|
-
if (hyd->Epat > 0)
|
|
930
|
-
{
|
|
931
|
-
m = n % (long)net->Pattern[hyd->Epat].Length;
|
|
932
|
-
f0 = net->Pattern[hyd->Epat].F[m];
|
|
933
|
-
}
|
|
934
|
-
|
|
935
|
-
// Examine each pump
|
|
936
|
-
for (j = 1; j <= net->Npumps; j++)
|
|
937
|
-
{
|
|
938
|
-
// Skip closed pumps
|
|
939
|
-
pump = &net->Pump[j];
|
|
940
|
-
k = pump->Link;
|
|
941
|
-
if (pump->Energy.CurrentEffic == 0.0) continue;
|
|
942
|
-
q = MAX(QZERO, ABS(hyd->LinkFlow[k]));
|
|
943
|
-
|
|
944
|
-
// Find pump-specific energy cost
|
|
945
|
-
if (pump->Ecost > 0.0) c = pump->Ecost;
|
|
946
|
-
else c = c0;
|
|
947
|
-
if ( (i = pump->Epat) > 0)
|
|
948
|
-
{
|
|
949
|
-
m = n % (long)net->Pattern[i].Length;
|
|
950
|
-
c *= net->Pattern[i].F[m];
|
|
951
|
-
}
|
|
952
|
-
else c *= f0;
|
|
953
|
-
|
|
954
|
-
// Update pump's cumulative statistics
|
|
955
|
-
p = pump->Energy.CurrentPower;
|
|
956
|
-
e = pump->Energy.CurrentEffic;
|
|
957
|
-
psum += p;
|
|
958
|
-
pump->Energy.TimeOnLine += dt;
|
|
959
|
-
pump->Energy.Efficiency += e * dt;
|
|
960
|
-
pump->Energy.KwHrsPerFlow += p / q * dt;
|
|
961
|
-
pump->Energy.KwHrs += p * dt;
|
|
962
|
-
pump->Energy.MaxKwatts = MAX(pump->Energy.MaxKwatts, p);
|
|
963
|
-
pump->Energy.TotalCost += c * p * dt;
|
|
964
|
-
}
|
|
965
|
-
|
|
966
|
-
// Update maximum kw value
|
|
967
|
-
hyd->Emax = MAX(hyd->Emax, psum);
|
|
968
|
-
}
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
void getenergy(Project *pr, int k, double *kw, double *eff)
|
|
972
|
-
/*
|
|
973
|
-
**----------------------------------------------------------------
|
|
974
|
-
** Input: k = link index
|
|
975
|
-
** Output: *kw = kwatt energy used
|
|
976
|
-
** *eff = efficiency (pumps only)
|
|
977
|
-
** Purpose: computes flow energy associated with link k
|
|
978
|
-
**----------------------------------------------------------------
|
|
979
|
-
*/
|
|
980
|
-
{
|
|
981
|
-
Network *net = &pr->network;
|
|
982
|
-
Hydraul *hyd = &pr->hydraul;
|
|
983
|
-
|
|
984
|
-
int i, // efficiency curve index
|
|
985
|
-
j; // pump index
|
|
986
|
-
double dh, // head across pump (ft)
|
|
987
|
-
q, // flow through pump (cfs)
|
|
988
|
-
e; // pump efficiency
|
|
989
|
-
double q4eff; // flow at nominal pump speed of 1.0
|
|
990
|
-
double speed; // current speed setting
|
|
991
|
-
Scurve *curve;
|
|
992
|
-
Slink *link = &net->Link[k];
|
|
993
|
-
|
|
994
|
-
// No energy if link is closed
|
|
995
|
-
if (hyd->LinkStatus[k] <= CLOSED)
|
|
996
|
-
{
|
|
997
|
-
*kw = 0.0;
|
|
998
|
-
*eff = 0.0;
|
|
999
|
-
return;
|
|
1000
|
-
}
|
|
1001
|
-
|
|
1002
|
-
// Determine flow and head difference
|
|
1003
|
-
q = ABS(hyd->LinkFlow[k]);
|
|
1004
|
-
dh = ABS(hyd->NodeHead[link->N1] - hyd->NodeHead[link->N2]);
|
|
1005
|
-
|
|
1006
|
-
// For pumps, find effic. at current flow
|
|
1007
|
-
if (link->Type == PUMP)
|
|
1008
|
-
{
|
|
1009
|
-
j = findpump(net, k);
|
|
1010
|
-
e = hyd->Epump;
|
|
1011
|
-
speed = hyd->LinkSetting[k];
|
|
1012
|
-
if ((i = net->Pump[j].Ecurve) > 0)
|
|
1013
|
-
{
|
|
1014
|
-
q4eff = q / speed * pr->Ucf[FLOW];
|
|
1015
|
-
curve = &net->Curve[i];
|
|
1016
|
-
e = interp(curve->Npts,curve->X, curve->Y, q4eff);
|
|
1017
|
-
|
|
1018
|
-
// Sarbu and Borza pump speed adjustment
|
|
1019
|
-
e = 100.0 - ((100.0-e) * pow(1.0/speed, 0.1));
|
|
1020
|
-
}
|
|
1021
|
-
e = MIN(e, 100.0);
|
|
1022
|
-
e = MAX(e, 1.0);
|
|
1023
|
-
e /= 100.0;
|
|
1024
|
-
}
|
|
1025
|
-
else e = 1.0;
|
|
1026
|
-
|
|
1027
|
-
// Compute energy
|
|
1028
|
-
*kw = dh * q * hyd->SpGrav / 8.814 / e * KWperHP;
|
|
1029
|
-
*eff = e;
|
|
1030
|
-
}
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
void getallpumpsenergy(Project *pr)
|
|
1034
|
-
/*
|
|
1035
|
-
**-------------------------------------------------------------
|
|
1036
|
-
** Input: none
|
|
1037
|
-
** Output: none
|
|
1038
|
-
** Purpose: finds the current power and efficiency for each pump.
|
|
1039
|
-
**-------------------------------------------------------------
|
|
1040
|
-
*/
|
|
1041
|
-
{
|
|
1042
|
-
int j;
|
|
1043
|
-
Spump *pump;
|
|
1044
|
-
|
|
1045
|
-
for (j = 1; j <= pr->network.Npumps; j++)
|
|
1046
|
-
{
|
|
1047
|
-
pump = &(pr->network.Pump[j]);
|
|
1048
|
-
getenergy(pr, pump->Link, &(pump->Energy.CurrentPower),
|
|
1049
|
-
&(pump->Energy.CurrentEffic));
|
|
1050
|
-
}
|
|
1051
|
-
}
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
void tanklevels(Project *pr, long tstep)
|
|
1055
|
-
/*
|
|
1056
|
-
**----------------------------------------------------------------
|
|
1057
|
-
** Input: tstep = current time step
|
|
1058
|
-
** Output: none
|
|
1059
|
-
** Purpose: computes new water levels in tanks after current
|
|
1060
|
-
** time step
|
|
1061
|
-
**----------------------------------------------------------------
|
|
1062
|
-
*/
|
|
1063
|
-
{
|
|
1064
|
-
Network *net = &pr->network;
|
|
1065
|
-
Hydraul *hyd = &pr->hydraul;
|
|
1066
|
-
|
|
1067
|
-
int i, n;
|
|
1068
|
-
double dv;
|
|
1069
|
-
|
|
1070
|
-
for (i = 1; i <= net->Ntanks; i++)
|
|
1071
|
-
{
|
|
1072
|
-
Stank *tank = &net->Tank[i];
|
|
1073
|
-
if (tank->A == 0.0) continue; // Skip reservoirs
|
|
1074
|
-
|
|
1075
|
-
// Update the tank's volume & water elevation
|
|
1076
|
-
n = tank->Node;
|
|
1077
|
-
dv = hyd->NodeDemand[n] * tstep;
|
|
1078
|
-
tank->V += dv;
|
|
1079
|
-
|
|
1080
|
-
// Check if tank full/empty within next second
|
|
1081
|
-
if (tank->V + hyd->NodeDemand[n] >= tank->Vmax)
|
|
1082
|
-
{
|
|
1083
|
-
tank->V = tank->Vmax;
|
|
1084
|
-
}
|
|
1085
|
-
else if (tank->V - hyd->NodeDemand[n] <= tank->Vmin)
|
|
1086
|
-
{
|
|
1087
|
-
tank->V = tank->Vmin;
|
|
1088
|
-
}
|
|
1089
|
-
hyd->NodeHead[n] = tankgrade(pr, i, tank->V);
|
|
1090
|
-
}
|
|
1091
|
-
}
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
double tankvolume(Project *pr, int i, double h)
|
|
1095
|
-
/*
|
|
1096
|
-
**--------------------------------------------------------------------
|
|
1097
|
-
** Input: i = tank index
|
|
1098
|
-
** h = water elevation in tank
|
|
1099
|
-
** Output: returns water volume in tank
|
|
1100
|
-
** Purpose: finds water volume in tank i corresponding to elev. h.
|
|
1101
|
-
**--------------------------------------------------------------------
|
|
1102
|
-
*/
|
|
1103
|
-
{
|
|
1104
|
-
Network *net = &pr->network;
|
|
1105
|
-
|
|
1106
|
-
int j;
|
|
1107
|
-
double y, v;
|
|
1108
|
-
Stank *tank = &net->Tank[i];
|
|
1109
|
-
Scurve *curve;
|
|
1110
|
-
|
|
1111
|
-
// Use level*area if no volume curve
|
|
1112
|
-
j = tank->Vcurve;
|
|
1113
|
-
if (j == 0) return(tank->Vmin + (h - tank->Hmin) * tank->A);
|
|
1114
|
-
|
|
1115
|
-
// If curve exists, interpolate on h to find volume v
|
|
1116
|
-
// remembering that volume curve is in original units.
|
|
1117
|
-
else
|
|
1118
|
-
{
|
|
1119
|
-
curve = &net->Curve[j];
|
|
1120
|
-
y = (h - net->Node[tank->Node].El) * pr->Ucf[HEAD];
|
|
1121
|
-
v = interp(curve->Npts, curve->X, curve->Y, y) / pr->Ucf[VOLUME];
|
|
1122
|
-
return v;
|
|
1123
|
-
}
|
|
1124
|
-
}
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
double tankgrade(Project *pr, int i, double v)
|
|
1128
|
-
/*
|
|
1129
|
-
**-------------------------------------------------------------------
|
|
1130
|
-
** Input: i = tank index
|
|
1131
|
-
** v = volume in tank
|
|
1132
|
-
** Output: returns water level in tank
|
|
1133
|
-
** Purpose: finds water level in tank i corresponding to volume v.
|
|
1134
|
-
**-------------------------------------------------------------------
|
|
1135
|
-
*/
|
|
1136
|
-
{
|
|
1137
|
-
Network *net = &pr->network;
|
|
1138
|
-
|
|
1139
|
-
int j;
|
|
1140
|
-
double y, h;
|
|
1141
|
-
Stank *tank = &net->Tank[i];
|
|
1142
|
-
|
|
1143
|
-
// Use area if no volume curve
|
|
1144
|
-
j = tank->Vcurve;
|
|
1145
|
-
if (j == 0) return(tank->Hmin + (v - tank->Vmin) / tank->A);
|
|
1146
|
-
|
|
1147
|
-
// If curve exists, interpolate on volume (originally the Y-variable
|
|
1148
|
-
// but used here as the X-variable) to find new level above bottom.
|
|
1149
|
-
// Remember that volume curve is stored in original units.
|
|
1150
|
-
else
|
|
1151
|
-
{
|
|
1152
|
-
Scurve *curve = &net->Curve[j];
|
|
1153
|
-
y = interp(curve->Npts, curve->Y, curve->X, v * pr->Ucf[VOLUME]);
|
|
1154
|
-
h = net->Node[tank->Node].El + y / pr->Ucf[HEAD];
|
|
1155
|
-
return h;
|
|
1156
|
-
}
|
|
1157
|
-
}
|
|
1158
|
-
|
|
1159
|
-
void resetpumpflow(Project *pr, int i)
|
|
1160
|
-
/*
|
|
1161
|
-
**-------------------------------------------------------------------
|
|
1162
|
-
** Input: i = link index
|
|
1163
|
-
** Output: none
|
|
1164
|
-
** Purpose: resets flow in a constant HP pump to its initial value.
|
|
1165
|
-
**-------------------------------------------------------------------
|
|
1166
|
-
*/
|
|
1167
|
-
{
|
|
1168
|
-
Network *net = &pr->network;
|
|
1169
|
-
Spump *pump = &net->Pump[findpump(net, i)];
|
|
1170
|
-
if (pump->Ptype == CONST_HP)
|
|
1171
|
-
pr->hydraul.LinkFlow[i] = pump->Q0;
|
|
1172
|
-
}
|