Initial commit
This commit is contained in:
76
src/Engine Updates.txt
Normal file
76
src/Engine Updates.txt
Normal file
@@ -0,0 +1,76 @@
|
||||
-----------------------
|
||||
Build 2.00.11 (8/15/07)
|
||||
-----------------------
|
||||
|
||||
Computational Engine Changes (epanet2.dll and epanet2d.exe):
|
||||
===============================================================================
|
||||
CODE MODULES CHANGES
|
||||
===============================================================================
|
||||
All All variables previously declared as floats were re-defined as
|
||||
doubles except for those used to write results to binary output
|
||||
files and those used as arguments in the toolkit functions.
|
||||
-------------------------------------------------------------------------------
|
||||
EPANET.C The symbols CLE (for command line executable) and SOL (for shared
|
||||
object library) were introduced in addition to the existing
|
||||
symbol DLL (for dynamic linked library) to support conditional
|
||||
compliation for shared object libraries on Unix/Linux.
|
||||
-------------------------------------------------------------------------------
|
||||
EPANET.C EN_INITVOLUME, EN_MIXMODEL and EN_MIXZONEVOL were added to the
|
||||
EPANET2.H list of tank parameters that can be retrieved with
|
||||
TOOLKIT.H ENgetnodevalue.
|
||||
-------------------------------------------------------------------------------
|
||||
EPANET.C Missing code was added to the ENgetnodevalue function to return
|
||||
a value for EN_SOURCEPAT when requested.
|
||||
-------------------------------------------------------------------------------
|
||||
EPANET.H The function declarations in these "include" files were modified
|
||||
TOOLKIT.H to support conditional compliation for shared object libraries
|
||||
on Unix/Linux.
|
||||
-------------------------------------------------------------------------------
|
||||
INPUT3.C The keyword "HEADLOSS" is no longer confused with "HEAD" when
|
||||
parsing reporting variable names in the [REPORT] section of the
|
||||
input file.
|
||||
-------------------------------------------------------------------------------
|
||||
RULES.C The input values for a tank's FILLTIME or DRAINTIME in a rule
|
||||
premise are now correctly converted to seconds in the
|
||||
newpremise() function.
|
||||
-------------------------------------------------------------------------------
|
||||
HYDRAUL.C During hydraulic balancing, status checks on control valves are
|
||||
now made only when the convergence error drops to less than a
|
||||
factor of 10 of the accuracy limit and a damping factor of 0.6
|
||||
is applied to flow changes computed at each iteration beyond
|
||||
this point.
|
||||
-------------------------------------------------------------------------------
|
||||
HYDRAUL.C The logic for determining the status of PRVs and PSVs was changed
|
||||
to produce more robust solutions, particularly for the case of
|
||||
multi-stage regulator stations where there are two or more PRVs
|
||||
connected in parallel.
|
||||
-------------------------------------------------------------------------------
|
||||
HYDRAUL.C The matrix coefficients for fully open control valves are now set
|
||||
directly rather than by assuming the valve has a certain length
|
||||
and friction factor.
|
||||
-------------------------------------------------------------------------------
|
||||
HYDRAUL.C Changes were made to how the P-coefficient for FCVs and the Y-
|
||||
coefficient for GPVs are calculated.
|
||||
-------------------------------------------------------------------------------
|
||||
HYDRAUL.C An extraneous "if" statement was removed from the resistance()
|
||||
function; the Y-coefficient value in gpvcoeff() was corrected;
|
||||
the P-coefficient value in fcvcoeff() was corrected.
|
||||
-------------------------------------------------------------------------------
|
||||
QUALITY.C The memory pool used for water quality routing segments was given
|
||||
the name SegPool and declared as a static global variable.
|
||||
-------------------------------------------------------------------------------
|
||||
QUALITY.C In the release() function, the upstream node quality is now mixed
|
||||
together with that of the upstream pipe segment when the quality
|
||||
difference between the two is less than the CTOL tolerance.
|
||||
-------------------------------------------------------------------------------
|
||||
INPFILE.C The ENsaveinpfile toolkit function now writes disabled reporting
|
||||
variables to the [REPORT] section of the generated input file.
|
||||
-------------------------------------------------------------------------------
|
||||
INPFILE.C The appearance of an extraneous character at the end of the .INP
|
||||
file produced by the toolkit function ENsaveinpfile was fixed.
|
||||
-------------------------------------------------------------------------------
|
||||
TYPES.H MAXID was increased to allow ID names to contain up to 31
|
||||
HASH.C characters.
|
||||
-------------------------------------------------------------------------------
|
||||
TYPES.H The code version was changed to 20011.
|
||||
===============================================================================
|
||||
54
src/Readme.txt
Normal file
54
src/Readme.txt
Normal file
@@ -0,0 +1,54 @@
|
||||
Contents of EPANET2.ZIP
|
||||
=======================
|
||||
This archive contains the source code for the EPANET 2
|
||||
network hydraulic and water quality solver. The solver
|
||||
provides functions for simulating the extended period
|
||||
hydraulic and water quality behavior of water distribution
|
||||
system pipe networks. It is written in ANSI-compatible C
|
||||
and can be compiled into either a Windows Dynamic Link
|
||||
Library of functions or into a command-line executable.
|
||||
|
||||
The archived code is set up for compilation as a DLL.
|
||||
To compile it as a command line (or console) application
|
||||
simply comment out the "#define DLL" macro statement at
|
||||
the top of EPANET.C and un-comment the "#define CLE" macro.
|
||||
|
||||
The DLL version of the solver (epanet2.dll) is used with
|
||||
the EPANET 2 user interface executable (epanet2w.exe) to
|
||||
form a complete Windows modeling package. It also serves
|
||||
as the function library for the EPANET Programmer's Toolkit,
|
||||
allowing developers to construct their own customized pipe
|
||||
network analysis applications.
|
||||
|
||||
The following C-code files are included in this archive:
|
||||
EPANET.C -- main module providing supervisory control
|
||||
INPUT1.C -- controls processing of input data
|
||||
INPUT2.C -- reads data from input file
|
||||
INPUT3.C -- parses individual lines of input data
|
||||
INPFILE.C -- saves modified input data to a text file
|
||||
RULES.C -- implements rule-based control of piping system
|
||||
HYDRAUL.C -- computes extended period hydraulic behavior
|
||||
QUALITY.C -- tracks transport & fate of water quality
|
||||
OUTPUT.C -- handles transfer of data to and from binary files
|
||||
REPORT.C -- handles reporting of results to text file
|
||||
SMATRIX.C -- sparse matrix linear equation solver routines
|
||||
MEMPOOL.C -- memory pool management routines
|
||||
HASH.C -- hash table routines
|
||||
|
||||
Also included are the following header files:
|
||||
TOOLKIT.H -- function prototypes of exported DLL functions
|
||||
FUNCS.H -- prototypes of all other functions
|
||||
TYPES.H -- declaration of global constants and data structures
|
||||
VARS.H -- declaration of global variables
|
||||
HASH.H -- header file for hash table routines
|
||||
MEMPOOL.H -- header file for memory pool routines
|
||||
ENUMSTXT.H -- string constants for enumerated types
|
||||
TEXT.H -- declaration of all other string constants
|
||||
|
||||
The comments at the top of each file lists the date when the latest
|
||||
update was made, and these updates can be located in the code by
|
||||
searching for comments with the phrase "/*** Updated" or with the
|
||||
release number (e.g., 2.00.11) in them.
|
||||
|
||||
Other useful documentation that can be consulted includes the EPANET
|
||||
Programmers Toolkit Help file and the EPANET Version 2 Users Manual.
|
||||
135
src/enumstxt.h
Normal file
135
src/enumstxt.h
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
***********************************************************************
|
||||
|
||||
ENUMSTXT.H -- Text strings for enumerated data types in EPANET
|
||||
|
||||
VERSION: 2.00
|
||||
DATE: 5/8/00
|
||||
AUTHOR: L. Rossman
|
||||
US EPA - NRMRL
|
||||
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
char *NodeTxt[] = {t_JUNCTION,
|
||||
t_RESERVOIR,
|
||||
t_TANK};
|
||||
|
||||
char *LinkTxt[] = {w_CV,
|
||||
w_PIPE,
|
||||
w_PUMP,
|
||||
w_PRV,
|
||||
w_PSV,
|
||||
w_PBV,
|
||||
w_FCV,
|
||||
w_TCV,
|
||||
w_GPV};
|
||||
|
||||
char *StatTxt[] = {t_XHEAD,
|
||||
t_TEMPCLOSED,
|
||||
t_CLOSED,
|
||||
t_OPEN,
|
||||
t_ACTIVE,
|
||||
t_XFLOW,
|
||||
t_XFCV,
|
||||
t_XPRESSURE,
|
||||
t_FILLING,
|
||||
t_EMPTYING};
|
||||
|
||||
char *FormTxt[] = {w_HW,
|
||||
w_DW,
|
||||
w_CM};
|
||||
|
||||
char *RptFormTxt[] = {t_HW,
|
||||
t_DW,
|
||||
t_CM};
|
||||
|
||||
char *RptFlowUnitsTxt[] = {u_CFS,
|
||||
u_GPM,
|
||||
u_MGD,
|
||||
u_IMGD,
|
||||
u_AFD,
|
||||
u_LPS,
|
||||
u_LPM,
|
||||
u_MLD,
|
||||
u_CMH,
|
||||
u_CMD};
|
||||
|
||||
char *FlowUnitsTxt[] = {w_CFS,
|
||||
w_GPM,
|
||||
w_MGD,
|
||||
w_IMGD,
|
||||
w_AFD,
|
||||
w_LPS,
|
||||
w_LPM,
|
||||
w_MLD,
|
||||
w_CMH,
|
||||
w_CMD};
|
||||
|
||||
char *PressUnitsTxt[] = {w_PSI,
|
||||
w_KPA,
|
||||
w_METERS};
|
||||
|
||||
char *QualTxt[] = {w_NONE,
|
||||
w_CHEM,
|
||||
w_AGE,
|
||||
w_TRACE};
|
||||
|
||||
|
||||
char *SourceTxt[] = {w_CONCEN,
|
||||
w_MASS,
|
||||
w_SETPOINT,
|
||||
w_FLOWPACED};
|
||||
|
||||
char *ControlTxt[] = {w_BELOW,
|
||||
w_ABOVE,
|
||||
w_TIME,
|
||||
w_CLOCKTIME};
|
||||
|
||||
char *TstatTxt[] = {w_NONE,
|
||||
w_AVG,
|
||||
w_MIN,
|
||||
w_MAX,
|
||||
w_RANGE};
|
||||
|
||||
char *MixTxt[] = {w_MIXED,
|
||||
w_2COMP,
|
||||
w_FIFO,
|
||||
w_LIFO,
|
||||
NULL};
|
||||
|
||||
char *RptFlagTxt[] = {w_NO,
|
||||
w_YES,
|
||||
w_FULL};
|
||||
|
||||
char *SectTxt[] = {s_TITLE, s_JUNCTIONS, s_RESERVOIRS,
|
||||
s_TANKS, s_PIPES, s_PUMPS,
|
||||
s_VALVES, s_CONTROLS, s_RULES,
|
||||
s_DEMANDS, s_SOURCES, s_EMITTERS,
|
||||
s_PATTERNS, s_CURVES, s_QUALITY,
|
||||
s_STATUS, s_ROUGHNESS, s_ENERGY,
|
||||
s_REACTIONS, s_MIXING, s_REPORT,
|
||||
s_TIMES, s_OPTIONS, s_COORDS,
|
||||
s_VERTICES, s_LABELS, s_BACKDROP,
|
||||
s_TAGS, s_END,
|
||||
NULL};
|
||||
|
||||
char *RptSectTxt[] = {NULL, t_JUNCTION, t_RESERVOIR,
|
||||
t_TANK, t_PIPE, t_PUMP,
|
||||
t_VALVE, t_CONTROL, t_RULE,
|
||||
t_DEMANDFOR,t_SOURCE, t_EMITTER,
|
||||
t_PATTERN, t_CURVE, t_QUALITY,
|
||||
t_STATUS, t_ROUGHNESS,t_ENERGY,
|
||||
t_REACTION, t_MIXING, t_REPORT,
|
||||
t_TIME, t_OPTION};
|
||||
|
||||
char *Fldname[] = {t_ELEV, t_DEMAND, t_HEAD,
|
||||
t_PRESSURE, t_QUALITY, t_LENGTH,
|
||||
t_DIAM, t_FLOW, t_VELOCITY,
|
||||
t_HEADLOSS, t_LINKQUAL, t_LINKSTATUS,
|
||||
t_SETTING, t_REACTRATE, t_FRICTION,
|
||||
"", "", "", "", "", "", NULL};
|
||||
|
||||
char *LogoTxt[] = {LOGO1,LOGO2,LOGO3,LOGO4,LOGO5,LOGO6,NULL};
|
||||
|
||||
|
||||
2837
src/epanet.c
Normal file
2837
src/epanet.c
Normal file
File diff suppressed because it is too large
Load Diff
57
src/epanet2.def
Normal file
57
src/epanet2.def
Normal file
@@ -0,0 +1,57 @@
|
||||
LIBRARY EPANET2.DLL
|
||||
|
||||
EXPORTS
|
||||
ENclose @4 ; ENclose
|
||||
ENcloseH @11 ; ENcloseH
|
||||
ENcloseQ @20 ; ENcloseQ
|
||||
ENepanet @1 ; ENepanet
|
||||
ENgetcontrol @26 ; ENgetcontrol
|
||||
ENgetcount @27 ; ENgetcount
|
||||
ENgeterror @36 ; ENgeterror
|
||||
ENgetflowunits @30 ; ENgetflowunits
|
||||
ENgetlinkid @42 ; ENgetlinkid
|
||||
ENgetlinkindex @41 ; ENgetlinkindex
|
||||
ENgetlinknodes @44 ; ENgetlinknodes
|
||||
ENgetlinktype @43 ; ENgetlinktype
|
||||
ENgetlinkvalue @45 ; ENgetlinkvalue
|
||||
ENgetnodeid @38 ; ENgetnodeid
|
||||
ENgetnodeindex @37 ; ENgetnodeindex
|
||||
ENgetnodetype @39 ; ENgetnodetype
|
||||
ENgetnodevalue @40 ; ENgetnodevalue
|
||||
ENgetoption @28 ; ENgetoption
|
||||
ENgetpatternid @32 ; ENgetpatternid
|
||||
ENgetpatternindex @31 ; ENgetpatternindex
|
||||
ENgetpatternlen @33 ; ENgetpatternlen
|
||||
ENgetpatternvalue @34 ; ENgetpatternvalue
|
||||
ENgetqualtype @35 ; ENgetqualtype
|
||||
ENgettimeparam @29 ; ENgettimeparam
|
||||
ENgetversion @25 ; ENgetversion
|
||||
ENinitH @8 ; ENinitH
|
||||
ENinitQ @16 ; ENinitQ
|
||||
ENnextH @10 ; ENnextH
|
||||
ENnextQ @18 ; ENnextQ
|
||||
ENopen @2 ; ENopen
|
||||
ENopenH @7 ; ENopenH
|
||||
ENopenQ @15 ; ENopenQ
|
||||
ENreport @22 ; ENreport
|
||||
ENresetreport @23 ; ENresetreport
|
||||
ENrunH @9 ; ENrunH
|
||||
ENrunQ @17 ; ENrunQ
|
||||
ENsaveH @6 ; ENsaveH
|
||||
ENsavehydfile @12 ; ENsavehydfile
|
||||
ENsaveinpfile @3 ; ENsaveinpfile
|
||||
ENsetcontrol @46 ; ENsetcontrol
|
||||
ENsetlinkvalue @48 ; ENsetlinkvalue
|
||||
ENsetnodevalue @47 ; ENsetnodevalue
|
||||
ENsetoption @52 ; ENsetoption
|
||||
ENsetpattern @49 ; ENsetpattern
|
||||
ENsetpatternvalue @50 ; ENsetpatternvalue
|
||||
ENsetqualtype @54 ; ENsetqualtype
|
||||
ENsetreport @24 ; ENsetreport
|
||||
ENsetstatusreport @53 ; ENsetstatusreport
|
||||
ENsettimeparam @51 ; ENsettimeparam
|
||||
ENsolveH @5 ; ENsolveH
|
||||
ENsolveQ @14 ; ENsolveQ
|
||||
ENstepQ @19 ; ENstepQ
|
||||
ENusehydfile @13 ; ENusehydfile
|
||||
ENwriteline @21 ; ENwriteline
|
||||
215
src/epanet2.h
Normal file
215
src/epanet2.h
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
** EPANET2.H
|
||||
**
|
||||
** C/C++ header file for EPANET Programmers Toolkit
|
||||
**
|
||||
** Last updated on 8/15/07 (2.00.11)
|
||||
*/
|
||||
|
||||
#ifndef EPANET2_H
|
||||
#define EPANET2_H
|
||||
|
||||
// --- Define the EPANET toolkit constants
|
||||
|
||||
#define EN_ELEVATION 0 /* Node parameters */
|
||||
#define EN_BASEDEMAND 1
|
||||
#define EN_PATTERN 2
|
||||
#define EN_EMITTER 3
|
||||
#define EN_INITQUAL 4
|
||||
#define EN_SOURCEQUAL 5
|
||||
#define EN_SOURCEPAT 6
|
||||
#define EN_SOURCETYPE 7
|
||||
#define EN_TANKLEVEL 8
|
||||
#define EN_DEMAND 9
|
||||
#define EN_HEAD 10
|
||||
#define EN_PRESSURE 11
|
||||
#define EN_QUALITY 12
|
||||
#define EN_SOURCEMASS 13
|
||||
#define EN_INITVOLUME 14
|
||||
#define EN_MIXMODEL 15
|
||||
#define EN_MIXZONEVOL 16
|
||||
|
||||
#define EN_DIAMETER 0 /* Link parameters */
|
||||
#define EN_LENGTH 1
|
||||
#define EN_ROUGHNESS 2
|
||||
#define EN_MINORLOSS 3
|
||||
#define EN_INITSTATUS 4
|
||||
#define EN_INITSETTING 5
|
||||
#define EN_KBULK 6
|
||||
#define EN_KWALL 7
|
||||
#define EN_FLOW 8
|
||||
#define EN_VELOCITY 9
|
||||
#define EN_HEADLOSS 10
|
||||
#define EN_STATUS 11
|
||||
#define EN_SETTING 12
|
||||
#define EN_ENERGY 13
|
||||
|
||||
#define EN_DURATION 0 /* Time parameters */
|
||||
#define EN_HYDSTEP 1
|
||||
#define EN_QUALSTEP 2
|
||||
#define EN_PATTERNSTEP 3
|
||||
#define EN_PATTERNSTART 4
|
||||
#define EN_REPORTSTEP 5
|
||||
#define EN_REPORTSTART 6
|
||||
#define EN_RULESTEP 7
|
||||
#define EN_STATISTIC 8
|
||||
#define EN_PERIODS 9
|
||||
|
||||
#define EN_NODECOUNT 0 /* Component counts */
|
||||
#define EN_TANKCOUNT 1
|
||||
#define EN_LINKCOUNT 2
|
||||
#define EN_PATCOUNT 3
|
||||
#define EN_CURVECOUNT 4
|
||||
#define EN_CONTROLCOUNT 5
|
||||
|
||||
#define EN_JUNCTION 0 /* Node types */
|
||||
#define EN_RESERVOIR 1
|
||||
#define EN_TANK 2
|
||||
|
||||
#define EN_CVPIPE 0 /* Link types */
|
||||
#define EN_PIPE 1
|
||||
#define EN_PUMP 2
|
||||
#define EN_PRV 3
|
||||
#define EN_PSV 4
|
||||
#define EN_PBV 5
|
||||
#define EN_FCV 6
|
||||
#define EN_TCV 7
|
||||
#define EN_GPV 8
|
||||
|
||||
#define EN_NONE 0 /* Quality analysis types */
|
||||
#define EN_CHEM 1
|
||||
#define EN_AGE 2
|
||||
#define EN_TRACE 3
|
||||
|
||||
#define EN_CONCEN 0 /* Source quality types */
|
||||
#define EN_MASS 1
|
||||
#define EN_SETPOINT 2
|
||||
#define EN_FLOWPACED 3
|
||||
|
||||
#define EN_CFS 0 /* Flow units types */
|
||||
#define EN_GPM 1
|
||||
#define EN_MGD 2
|
||||
#define EN_IMGD 3
|
||||
#define EN_AFD 4
|
||||
#define EN_LPS 5
|
||||
#define EN_LPM 6
|
||||
#define EN_MLD 7
|
||||
#define EN_CMH 8
|
||||
#define EN_CMD 9
|
||||
|
||||
#define EN_TRIALS 0 /* Misc. options */
|
||||
#define EN_ACCURACY 1
|
||||
#define EN_TOLERANCE 2
|
||||
#define EN_EMITEXPON 3
|
||||
#define EN_DEMANDMULT 4
|
||||
|
||||
#define EN_LOWLEVEL 0 /* Control types */
|
||||
#define EN_HILEVEL 1
|
||||
#define EN_TIMER 2
|
||||
#define EN_TIMEOFDAY 3
|
||||
|
||||
#define EN_AVERAGE 1 /* Time statistic types. */
|
||||
#define EN_MINIMUM 2
|
||||
#define EN_MAXIMUM 3
|
||||
#define EN_RANGE 4
|
||||
|
||||
#define EN_NOSAVE 0 /* Save-results-to-file flag */
|
||||
#define EN_SAVE 1
|
||||
#define EN_INITFLOW 10 /* Re-initialize flow flag */
|
||||
|
||||
|
||||
|
||||
// --- define WINDOWS
|
||||
|
||||
#undef WINDOWS
|
||||
#ifdef _WIN32
|
||||
#define WINDOWS
|
||||
#endif
|
||||
#ifdef __WIN32__
|
||||
#define WINDOWS
|
||||
#endif
|
||||
|
||||
// --- define DLLEXPORT
|
||||
|
||||
#ifdef WINDOWS
|
||||
#ifdef __cplusplus
|
||||
#define DLLEXPORT extern "C" __declspec(dllexport) __stdcall
|
||||
#else
|
||||
#define DLLEXPORT __declspec(dllexport) __stdcall
|
||||
#endif
|
||||
#else
|
||||
#ifdef __cplusplus
|
||||
#define DLLEXPORT extern "C"
|
||||
#else
|
||||
#define DLLEXPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
// --- declare the EPANET toolkit functions
|
||||
|
||||
int DLLEXPORT ENepanet(char *, char *, char *, void (*) (char *));
|
||||
int DLLEXPORT ENopen(char *, char *, char *);
|
||||
int DLLEXPORT ENsaveinpfile(char *);
|
||||
int DLLEXPORT ENclose(void);
|
||||
|
||||
int DLLEXPORT ENsolveH(void);
|
||||
int DLLEXPORT ENsaveH(void);
|
||||
int DLLEXPORT ENopenH(void);
|
||||
int DLLEXPORT ENinitH(int);
|
||||
int DLLEXPORT ENrunH(long *);
|
||||
int DLLEXPORT ENnextH(long *);
|
||||
int DLLEXPORT ENcloseH(void);
|
||||
int DLLEXPORT ENsavehydfile(char *);
|
||||
int DLLEXPORT ENusehydfile(char *);
|
||||
|
||||
int DLLEXPORT ENsolveQ(void);
|
||||
int DLLEXPORT ENopenQ(void);
|
||||
int DLLEXPORT ENinitQ(int);
|
||||
int DLLEXPORT ENrunQ(long *);
|
||||
int DLLEXPORT ENnextQ(long *);
|
||||
int DLLEXPORT ENstepQ(long *);
|
||||
int DLLEXPORT ENcloseQ(void);
|
||||
|
||||
int DLLEXPORT ENwriteline(char *);
|
||||
int DLLEXPORT ENreport(void);
|
||||
int DLLEXPORT ENresetreport(void);
|
||||
int DLLEXPORT ENsetreport(char *);
|
||||
|
||||
int DLLEXPORT ENgetcontrol(int, int *, int *, float *,
|
||||
int *, float *);
|
||||
int DLLEXPORT ENgetcount(int, int *);
|
||||
int DLLEXPORT ENgetoption(int, float *);
|
||||
int DLLEXPORT ENgettimeparam(int, long *);
|
||||
int DLLEXPORT ENgetflowunits(int *);
|
||||
int DLLEXPORT ENgetpatternindex(char *, int *);
|
||||
int DLLEXPORT ENgetpatternid(int, char *);
|
||||
int DLLEXPORT ENgetpatternlen(int, int *);
|
||||
int DLLEXPORT ENgetpatternvalue(int, int, float *);
|
||||
int DLLEXPORT ENgetqualtype(int *, int *);
|
||||
int DLLEXPORT ENgeterror(int, char *, int);
|
||||
|
||||
int DLLEXPORT ENgetnodeindex(char *, int *);
|
||||
int DLLEXPORT ENgetnodeid(int, char *);
|
||||
int DLLEXPORT ENgetnodetype(int, int *);
|
||||
int DLLEXPORT ENgetnodevalue(int, int, float *);
|
||||
|
||||
int DLLEXPORT ENgetlinkindex(char *, int *);
|
||||
int DLLEXPORT ENgetlinkid(int, char *);
|
||||
int DLLEXPORT ENgetlinktype(int, int *);
|
||||
int DLLEXPORT ENgetlinknodes(int, int *, int *);
|
||||
int DLLEXPORT ENgetlinkvalue(int, int, float *);
|
||||
|
||||
int DLLEXPORT ENgetversion(int *);
|
||||
|
||||
int DLLEXPORT ENsetcontrol(int, int, int, float, int, float);
|
||||
int DLLEXPORT ENsetnodevalue(int, int, float);
|
||||
int DLLEXPORT ENsetlinkvalue(int, int, float);
|
||||
int DLLEXPORT ENsetpattern(int, float *, int);
|
||||
int DLLEXPORT ENsetpatternvalue(int, int, float);
|
||||
int DLLEXPORT ENsettimeparam(int, long);
|
||||
int DLLEXPORT ENsetoption(int, float);
|
||||
int DLLEXPORT ENsetstatusreport(int);
|
||||
int DLLEXPORT ENsetqualtype(int, char *, char *, char *);
|
||||
|
||||
#endif
|
||||
279
src/funcs.h
Normal file
279
src/funcs.h
Normal file
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
**************************************************************************
|
||||
|
||||
FUNCS.H -- Function Prototypes for EPANET Program
|
||||
|
||||
VERSION: 2.00
|
||||
DATE: 5/8/00
|
||||
9/25/00
|
||||
10/25/00
|
||||
12/29/00
|
||||
3/1/01
|
||||
AUTHOR: L. Rossman
|
||||
US EPA - NRMRL
|
||||
|
||||
**************************************************************************
|
||||
*/
|
||||
|
||||
/*****************************************************************/
|
||||
/* Most float arguments have been changed to double - 7/3/07 */
|
||||
/*****************************************************************/
|
||||
|
||||
/* ------- EPANET.C --------------------*/
|
||||
/*
|
||||
** NOTE: The exportable functions that can be called
|
||||
** via the DLL are prototyped in TOOLKIT.H.
|
||||
*/
|
||||
void initpointers(void); /* Initializes pointers */
|
||||
int allocdata(void); /* Allocates memory */
|
||||
void freeTmplist(STmplist *); /* Frees items in linked list */
|
||||
void freeFloatlist(SFloatlist *); /* Frees list of floats */
|
||||
void freedata(void); /* Frees allocated memory */
|
||||
int openfiles(char *,char *,char *); /* Opens input & report files */
|
||||
int openhydfile(void); /* Opens hydraulics file */
|
||||
int openoutfile(void); /* Opens binary output file */
|
||||
int strcomp(char *, char *); /* Compares two strings */
|
||||
double interp(int, double *, /* Interpolates a data curve */
|
||||
double *, double);
|
||||
int findnode(char *); /* Finds node's index from ID */
|
||||
int findlink(char *); /* Finds link's index from ID */
|
||||
char* geterrmsg(int); /* Gets text of error message */
|
||||
void errmsg(int); /* Reports program error */
|
||||
void writecon(char *); /* Writes text to console */
|
||||
void writewin(char *); /* Passes text to calling app */
|
||||
|
||||
/* ------- INPUT1.C --------------------*/
|
||||
int getdata(void); /* Gets network data */
|
||||
void setdefaults(void); /* Sets default values */
|
||||
void initreport(void); /* Initializes report options */
|
||||
void adjustdata(void); /* Adjusts input data */
|
||||
int inittanks(void); /* Initializes tank levels */
|
||||
void initunits(void); /* Determines reporting units */
|
||||
void convertunits(void); /* Converts data to std. units*/
|
||||
|
||||
/* -------- INPUT2.C -------------------*/
|
||||
int netsize(void); /* Determines network size */
|
||||
int readdata(void); /* Reads in network data */
|
||||
int newline(int, char *); /* Processes new line of data */
|
||||
int addnodeID(int, char *); /* Adds node ID to data base */
|
||||
int addlinkID(int, char *); /* Adds link ID to data base */
|
||||
int addpattern(char *); /* Adds pattern to data base */
|
||||
int addcurve(char *); /* Adds curve to data base */
|
||||
STmplist *findID(char *, STmplist *); /* Locates ID on linked list */
|
||||
int unlinked(void); /* Checks for unlinked nodes */
|
||||
int getpumpparams(void); /* Computes pump curve coeffs.*/
|
||||
int getpatterns(void); /* Gets pattern data from list*/
|
||||
int getcurves(void); /* Gets curve data from list */
|
||||
int findmatch(char *,char *[]); /* Finds keyword in line */
|
||||
int match(char *, char *); /* Checks for word match */
|
||||
int gettokens(char *); /* Tokenizes input line */
|
||||
int getfloat(char *, double *); /* Converts string to double */
|
||||
double hour(char *, char *); /* Converts time to hours */
|
||||
int setreport(char *); /* Processes reporting command*/
|
||||
void inperrmsg(int,int,char *); /* Input error message */
|
||||
|
||||
/* ---------- INPUT3.C -----------------*/
|
||||
int juncdata(void); /* Processes junction data */
|
||||
int tankdata(void); /* Processes tank data */
|
||||
int pipedata(void); /* Processes pipe data */
|
||||
int pumpdata(void); /* Processes pump data */
|
||||
int valvedata(void); /* Processes valve data */
|
||||
int patterndata(void); /* Processes pattern data */
|
||||
int curvedata(void); /* Processes curve data */
|
||||
int demanddata(void); /* Processes demand data */
|
||||
int controldata(void); /* Processes simple controls */
|
||||
int energydata(void); /* Processes energy data */
|
||||
int sourcedata(void); /* Processes source data */
|
||||
int emitterdata(void); /* Processes emitter data */
|
||||
int qualdata(void); /* Processes quality data */
|
||||
int reactdata(void); /* Processes reaction data */
|
||||
int mixingdata(void); /* Processes tank mixing data */
|
||||
int statusdata(void); /* Processes link status data */
|
||||
int reportdata(void); /* Processes report options */
|
||||
int timedata(void); /* Processes time options */
|
||||
int optiondata(void); /* Processes analysis options */
|
||||
int optionchoice(int); /* Processes option choices */
|
||||
int optionvalue(int); /* Processes option values */
|
||||
int getpumpcurve(int); /* Constructs a pump curve */
|
||||
int powercurve(double, double, double,/* Coeffs. of power pump curve*/
|
||||
double, double, double *,
|
||||
double *, double *);
|
||||
int valvecheck(int, int, int); /* Checks valve placement */
|
||||
void changestatus(int, char, double); /* Changes status of a link */
|
||||
|
||||
/* -------------- RULES.C --------------*/
|
||||
void initrules(void); /* Initializes rule base */
|
||||
void addrule(char *); /* Adds rule to rule base */
|
||||
int allocrules(void); /* Allocates memory for rule */
|
||||
int ruledata(void); /* Processes rule input data */
|
||||
int checkrules(long); /* Checks all rules */
|
||||
void freerules(void); /* Frees rule base memory */
|
||||
|
||||
/* ------------- REPORT.C --------------*/
|
||||
int writereport(void); /* Writes formatted report */
|
||||
void writelogo(void); /* Writes program logo */
|
||||
void writesummary(void); /* Writes network summary */
|
||||
void writehydstat(int,double); /* Writes hydraulic status */
|
||||
void writeenergy(void); /* Writes energy usage */
|
||||
int writeresults(void); /* Writes node/link results */
|
||||
void writeheader(int,int); /* Writes heading on report */
|
||||
void writeline(char *); /* Writes line to report file */
|
||||
void writerelerr(int, double); /* Writes convergence error */
|
||||
void writestatchange(int,char,char); /* Writes link status change */
|
||||
void writecontrolaction(int, int); /* Writes control action taken*/
|
||||
void writeruleaction(int, char *); /* Writes rule action taken */
|
||||
int writehydwarn(int,double); /* Writes hydraulic warnings */
|
||||
void writehyderr(int); /* Writes hydraulic error msg.*/
|
||||
int disconnected(void); /* Checks for disconnections */
|
||||
void marknodes(int, int *, char *); /* Identifies connected nodes */
|
||||
void getclosedlink(int, char *); /* Finds a disconnecting link */
|
||||
void writelimits(int,int); /* Writes reporting limits */
|
||||
int checklimits(double *,int,int); /* Checks variable limits */
|
||||
void writetime(char *); /* Writes current clock time */
|
||||
char *clocktime(char *, long); /* Converts time to hrs:min */
|
||||
char *fillstr(char *, char, int); /* Fills string with character*/
|
||||
int getnodetype(int); /* Determines node type */
|
||||
|
||||
/* --------- HYDRAUL.C -----------------*/
|
||||
int openhyd(void); /* Opens hydraulics solver */
|
||||
|
||||
/*** Updated 3/1/01 ***/
|
||||
void inithyd(int); /* Re-sets initial conditions */
|
||||
|
||||
int runhyd(long *); /* Solves 1-period hydraulics */
|
||||
int nexthyd(long *); /* Moves to next time period */
|
||||
void closehyd(void); /* Closes hydraulics solver */
|
||||
int allocmatrix(void); /* Allocates matrix coeffs. */
|
||||
void freematrix(void); /* Frees matrix coeffs. */
|
||||
void initlinkflow(int, char, double); /* Initializes link flow */
|
||||
void setlinkflow(int, double); /* Sets link flow via headloss*/
|
||||
void setlinkstatus(int, char, char *, /* Sets link status */
|
||||
double *);
|
||||
void setlinksetting(int, double, /* Sets pump/valve setting */
|
||||
char *, double *);
|
||||
void resistance(int); /* Computes resistance coeff. */
|
||||
void demands(void); /* Computes current demands */
|
||||
int controls(void); /* Controls link settings */
|
||||
long timestep(void); /* Computes new time step */
|
||||
void tanktimestep(long *); /* Time till tanks fill/drain */
|
||||
void controltimestep(long *); /* Time till control action */
|
||||
void ruletimestep(long *); /* Time till rule action */
|
||||
void addenergy(long); /* Accumulates energy usage */
|
||||
void getenergy(int, double *, double *); /* Computes link energy use */
|
||||
void tanklevels(long); /* Computes new tank levels */
|
||||
double tankvolume(int,double); /* Finds tank vol. from grade */
|
||||
double tankgrade(int,double); /* Finds tank grade from vol. */
|
||||
int netsolve(int *,double *); /* Solves network equations */
|
||||
int badvalve(int); /* Checks for bad valve */
|
||||
int valvestatus(void); /* Updates valve status */
|
||||
int linkstatus(void); /* Updates link status */
|
||||
char cvstatus(char,double,double); /* Updates CV status */
|
||||
char pumpstatus(int,double); /* Updates pump status */
|
||||
char prvstatus(int,char,double, /* Updates PRV status */
|
||||
double,double);
|
||||
char psvstatus(int,char,double, /* Updates PSV status */
|
||||
double,double);
|
||||
char fcvstatus(int,char,double, /* Updates FCV status */
|
||||
double);
|
||||
void tankstatus(int,int,int); /* Checks if tank full/empty */
|
||||
int pswitch(void); /* Pressure switch controls */
|
||||
double newflows(void); /* Updates link flows */
|
||||
void newcoeffs(void); /* Computes matrix coeffs. */
|
||||
void linkcoeffs(void); /* Computes link coeffs. */
|
||||
void nodecoeffs(void); /* Computes node coeffs. */
|
||||
void valvecoeffs(void); /* Computes valve coeffs. */
|
||||
void pipecoeff(int); /* Computes pipe coeff. */
|
||||
double DWcoeff(int, double *); /* Computes D-W coeff. */
|
||||
void pumpcoeff(int); /* Computes pump coeff. */
|
||||
|
||||
/*** Updated 10/25/00 ***/
|
||||
/*** Updated 12/29/00 ***/
|
||||
void curvecoeff(int,double,double *, /* Computes curve coeffs. */
|
||||
double *);
|
||||
|
||||
void gpvcoeff(int); /* Computes GPV coeff. */
|
||||
void pbvcoeff(int); /* Computes PBV coeff. */
|
||||
void tcvcoeff(int); /* Computes TCV coeff. */
|
||||
void prvcoeff(int,int,int); /* Computes PRV coeff. */
|
||||
void psvcoeff(int,int,int); /* Computes PSV coeff. */
|
||||
void fcvcoeff(int,int,int); /* Computes FCV coeff. */
|
||||
void emittercoeffs(void); /* Computes emitter coeffs. */
|
||||
double emitflowchange(int); /* Computes new emitter flow */
|
||||
|
||||
/* ----------- SMATRIX.C ---------------*/
|
||||
int createsparse(void); /* Creates sparse matrix */
|
||||
int allocsparse(void); /* Allocates matrix memory */
|
||||
void freesparse(void); /* Frees matrix memory */
|
||||
int buildlists(int); /* Builds adjacency lists */
|
||||
int paralink(int, int, int); /* Checks for parallel links */
|
||||
void xparalinks(void); /* Removes parallel links */
|
||||
void freelists(void); /* Frees adjacency lists */
|
||||
void countdegree(void); /* Counts links at each node */
|
||||
int reordernodes(void); /* Finds a node re-ordering */
|
||||
int mindegree(int, int); /* Finds min. degree node */
|
||||
int growlist(int); /* Augments adjacency list */
|
||||
int newlink(Padjlist); /* Adds fill-ins for a node */
|
||||
int linked(int, int); /* Checks if 2 nodes linked */
|
||||
int addlink(int, int, int); /* Creates new fill-in */
|
||||
int storesparse(int); /* Stores sparse matrix */
|
||||
int ordersparse(int); /* Orders matrix storage */
|
||||
void transpose(int,int *,int *, /* Transposes sparse matrix */
|
||||
int *,int *,int *,int *,int *);
|
||||
int linsolve(int, double *, double *, /* Solution of linear eqns. */
|
||||
double *); /* via Cholesky factorization */
|
||||
|
||||
/* ----------- QUALITY.C ---------------*/
|
||||
int openqual(void); /* Opens WQ solver system */
|
||||
void initqual(void); /* Initializes WQ solver */
|
||||
int runqual(long *); /* Gets current WQ results */
|
||||
int nextqual(long *); /* Updates WQ by hyd.timestep */
|
||||
int stepqual(long *); /* Updates WQ by WQ time step */
|
||||
int closequal(void); /* Closes WQ solver system */
|
||||
int gethyd(long *, long *); /* Gets next hyd. results */
|
||||
char setReactflag(void); /* Checks for reactive chem. */
|
||||
void transport(long); /* Transports mass in network */
|
||||
void initsegs(void); /* Initializes WQ segments */
|
||||
void reorientsegs(void); /* Re-orients WQ segments */
|
||||
void updatesegs(long); /* Updates quality in segments*/
|
||||
void removesegs(int); /* Removes a WQ segment */
|
||||
void addseg(int,double,double); /* Adds a WQ segment to pipe */
|
||||
void accumulate(long); /* Sums mass flow into node */
|
||||
void updatenodes(long); /* Updates WQ at nodes */
|
||||
void sourceinput(long); /* Computes source inputs */
|
||||
void release(long); /* Releases mass from nodes */
|
||||
void updatetanks(long); /* Updates WQ in tanks */
|
||||
void updatesourcenodes(long); /* Updates WQ at source nodes */
|
||||
void tankmix1(int, long); /* Complete mix tank model */
|
||||
void tankmix2(int, long); /* 2-compartment tank model */
|
||||
void tankmix3(int, long); /* FIFO tank model */
|
||||
void tankmix4(int, long); /* LIFO tank model */
|
||||
double sourcequal(Psource); /* Finds WQ input from source */
|
||||
double avgqual(int); /* Finds avg. quality in pipe */
|
||||
void ratecoeffs(void); /* Finds wall react. coeffs. */
|
||||
double piperate(int); /* Finds wall react. coeff. */
|
||||
double pipereact(int,double,double,long);/* Reacts water in a pipe */
|
||||
double tankreact(double,double,double,
|
||||
long); /* Reacts water in a tank */
|
||||
double bulkrate(double,double,double); /* Finds bulk reaction rate */
|
||||
double wallrate(double,double,double,double);/* Finds wall reaction rate */
|
||||
|
||||
|
||||
/* ------------ OUTPUT.C ---------------*/
|
||||
int savenetdata(void); /* Saves basic data to file */
|
||||
int savehyd(long *); /* Saves hydraulic solution */
|
||||
int savehydstep(long *); /* Saves hydraulic timestep */
|
||||
int saveenergy(void); /* Saves energy usage */
|
||||
int readhyd(long *); /* Reads hydraulics from file */
|
||||
int readhydstep(long *); /* Reads time step from file */
|
||||
int saveoutput(void); /* Saves results to file */
|
||||
int nodeoutput(int, REAL4 *, double); /* Saves node results to file */
|
||||
int linkoutput(int, REAL4 *, double); /* Saves link results to file */
|
||||
int savefinaloutput(void); /* Finishes saving output */
|
||||
int savetimestat(REAL4 *, char); /* Saves time stats to file */
|
||||
int savenetreacts(double, double,
|
||||
double, double); /* Saves react. rates to file */
|
||||
int saveepilog(void); /* Saves output file epilog */
|
||||
|
||||
|
||||
/* ------------ INPFILE.C --------------*/
|
||||
int saveinpfile(char *); /* Saves network to text file */
|
||||
110
src/hash.c
Normal file
110
src/hash.c
Normal file
@@ -0,0 +1,110 @@
|
||||
/*-----------------------------------------------------------------------------
|
||||
** hash.c
|
||||
**
|
||||
** Implementation of a simple Hash Table for string storage & retrieval
|
||||
**
|
||||
** Written by L. Rossman
|
||||
** Last Updated on 6/19/03
|
||||
**
|
||||
** The hash table data structure (HTable) is defined in "hash.h".
|
||||
** Interface Functions:
|
||||
** HTcreate() - creates a hash table
|
||||
** HTinsert() - inserts a string & its index value into a hash table
|
||||
** HTfind() - retrieves the index value of a string from a table
|
||||
** HTfree() - frees a hash table
|
||||
**
|
||||
*********************************************************************
|
||||
** NOTE: This is a modified version of the original HASH.C module.
|
||||
*********************************************************************
|
||||
*/
|
||||
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include "hash.h"
|
||||
|
||||
/* Use Fletcher's checksum to compute 2-byte hash of string */
|
||||
unsigned int hash(char *str)
|
||||
{
|
||||
unsigned int sum1= 0, check1;
|
||||
unsigned long sum2= 0L;
|
||||
while( '\0' != *str )
|
||||
{
|
||||
sum1 += (*str);
|
||||
str++;
|
||||
if ( 255 <= sum1 ) sum1 -= 255;
|
||||
sum2 += sum1;
|
||||
}
|
||||
check1= sum2;
|
||||
check1 %= 255;
|
||||
check1= 255 - (sum1+check1) % 255;
|
||||
sum1= 255 - (sum1+check1) % 255;
|
||||
return( ( ( check1 << 8 ) | sum1 ) % HTMAXSIZE);
|
||||
}
|
||||
|
||||
HTtable *HTcreate()
|
||||
{
|
||||
int i;
|
||||
HTtable *ht = (HTtable *) calloc(HTMAXSIZE, sizeof(HTtable));
|
||||
if (ht != NULL) for (i=0; i<HTMAXSIZE; i++) ht[i] = NULL;
|
||||
return(ht);
|
||||
}
|
||||
|
||||
int HTinsert(HTtable *ht, char *key, int data)
|
||||
{
|
||||
unsigned int i = hash(key);
|
||||
struct HTentry *entry;
|
||||
if ( i >= HTMAXSIZE ) return(0);
|
||||
entry = (struct HTentry *) malloc(sizeof(struct HTentry));
|
||||
if (entry == NULL) return(0);
|
||||
entry->key = key;
|
||||
entry->data = data;
|
||||
entry->next = ht[i];
|
||||
ht[i] = entry;
|
||||
return(1);
|
||||
}
|
||||
|
||||
int HTfind(HTtable *ht, char *key)
|
||||
{
|
||||
unsigned int i = hash(key);
|
||||
struct HTentry *entry;
|
||||
if ( i >= HTMAXSIZE ) return(NOTFOUND);
|
||||
entry = ht[i];
|
||||
while (entry != NULL)
|
||||
{
|
||||
if ( strcmp(entry->key,key) == 0 ) return(entry->data);
|
||||
entry = entry->next;
|
||||
}
|
||||
return(NOTFOUND);
|
||||
}
|
||||
|
||||
char *HTfindKey(HTtable *ht, char *key)
|
||||
{
|
||||
unsigned int i = hash(key);
|
||||
struct HTentry *entry;
|
||||
if ( i >= HTMAXSIZE ) return(NULL);
|
||||
entry = ht[i];
|
||||
while (entry != NULL)
|
||||
{
|
||||
if ( strcmp(entry->key,key) == 0 ) return(entry->key);
|
||||
entry = entry->next;
|
||||
}
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
void HTfree(HTtable *ht)
|
||||
{
|
||||
struct HTentry *entry,
|
||||
*nextentry;
|
||||
int i;
|
||||
for (i=0; i<HTMAXSIZE; i++)
|
||||
{
|
||||
entry = ht[i];
|
||||
while (entry != NULL)
|
||||
{
|
||||
nextentry = entry->next;
|
||||
free(entry);
|
||||
entry = nextentry;
|
||||
}
|
||||
}
|
||||
free(ht);
|
||||
}
|
||||
24
src/hash.h
Normal file
24
src/hash.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/* HASH.H
|
||||
**
|
||||
** Header file for Hash Table module HASH.C
|
||||
**
|
||||
*/
|
||||
|
||||
#define HTMAXSIZE 1999
|
||||
#define NOTFOUND 0
|
||||
|
||||
struct HTentry
|
||||
{
|
||||
char *key;
|
||||
int data;
|
||||
struct HTentry *next;
|
||||
};
|
||||
|
||||
typedef struct HTentry *HTtable;
|
||||
|
||||
HTtable *HTcreate(void);
|
||||
int HTinsert(HTtable *, char *, int);
|
||||
int HTfind(HTtable *, char *);
|
||||
char *HTfindKey(HTtable *, char *);
|
||||
void HTfree(HTtable *);
|
||||
|
||||
2480
src/hydraul.c
Normal file
2480
src/hydraul.c
Normal file
File diff suppressed because it is too large
Load Diff
655
src/inpfile.c
Normal file
655
src/inpfile.c
Normal file
@@ -0,0 +1,655 @@
|
||||
/*
|
||||
*********************************************************************
|
||||
|
||||
INPFILE.C -- Save Input Function for EPANET Program
|
||||
|
||||
VERSION: 2.00
|
||||
DATE: 5/8/00
|
||||
3/1/01
|
||||
11/19/01
|
||||
6/24/02
|
||||
8/15/07 (2.00.11)
|
||||
AUTHOR: L. Rossman
|
||||
US EPA - NRMRL
|
||||
|
||||
This module contains the function saveinpfile() which saves the
|
||||
data describing a piping network to a file in EPANET's text format.
|
||||
|
||||
********************************************************************
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <math.h>
|
||||
#include "hash.h"
|
||||
#include "text.h"
|
||||
#include "types.h"
|
||||
#include "funcs.h"
|
||||
#define EXTERN extern
|
||||
#include "vars.h"
|
||||
|
||||
/* Defined in enumstxt.h in EPANET.C */
|
||||
extern char *LinkTxt[];
|
||||
extern char *FormTxt[];
|
||||
extern char *StatTxt[];
|
||||
extern char *FlowUnitsTxt[];
|
||||
extern char *PressUnitsTxt[];
|
||||
extern char *ControlTxt[];
|
||||
extern char *SourceTxt[];
|
||||
extern char *MixTxt[];
|
||||
extern char *TstatTxt[];
|
||||
extern char *RptFlagTxt[];
|
||||
extern char *SectTxt[];
|
||||
|
||||
|
||||
/*** Updated 6/24/02 ***/
|
||||
void savemapinfo(FILE *ftmp)
|
||||
{
|
||||
int sect,newsect;
|
||||
char *tok;
|
||||
char line[MAXLINE+1];
|
||||
char s[MAXLINE+1];
|
||||
|
||||
sect = -1;
|
||||
rewind(InFile);
|
||||
while (fgets(line,MAXLINE,InFile) != NULL)
|
||||
{
|
||||
/* Skip blank lines & those beginning with a comment */
|
||||
strcpy(s,line);
|
||||
tok = strtok(line,SEPSTR);
|
||||
if (tok == NULL) continue;
|
||||
if (*tok == ';') continue;
|
||||
|
||||
/* Check if line begins with a new section heading */
|
||||
if (*tok == '[')
|
||||
{
|
||||
newsect = findmatch(tok,SectTxt);
|
||||
if (newsect >= 0)
|
||||
{
|
||||
sect = newsect;
|
||||
if (sect == _END) break;
|
||||
switch(sect)
|
||||
{
|
||||
case _RULES:
|
||||
case _COORDS:
|
||||
case _VERTICES:
|
||||
case _LABELS:
|
||||
case _BACKDROP:
|
||||
case _TAGS: fwrite(s, sizeof(char), strlen(s), ftmp);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else continue;
|
||||
}
|
||||
|
||||
/* Write lines appearing in the section to file */
|
||||
switch(sect)
|
||||
{
|
||||
case _RULES:
|
||||
case _COORDS:
|
||||
case _VERTICES:
|
||||
case _LABELS:
|
||||
case _BACKDROP:
|
||||
case _TAGS: fwrite(s, sizeof(char), strlen(s), ftmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*** End of update ***/
|
||||
|
||||
|
||||
int saveinpfile(char *fname)
|
||||
/*
|
||||
-------------------------------------------------
|
||||
Writes network data to text file.
|
||||
-------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i,j,n;
|
||||
double d,kc,ke,km,ucf;
|
||||
|
||||
/*** Updated 6/24/02 ***/
|
||||
char s[MAXLINE+1], s1[MAXLINE+1], s2[MAXLINE+1];
|
||||
|
||||
Pdemand demand;
|
||||
Psource source;
|
||||
FILE *f;
|
||||
|
||||
/*** Updated 6/24/02 ***/
|
||||
FILE *ftmp;
|
||||
|
||||
/* Copy [RULES], [COORDS], [VERTICES], [LABELS], [BACKDROP] & [TAGS] */
|
||||
/* sections from original input file to new input file */
|
||||
|
||||
ftmp = NULL;
|
||||
if (InFile)
|
||||
{
|
||||
ftmp = tmpfile();
|
||||
if (ftmp) savemapinfo(ftmp);
|
||||
}
|
||||
|
||||
/* Open text file */
|
||||
|
||||
if ((f = fopen(fname,"wt")) == NULL)
|
||||
{
|
||||
if (ftmp) fclose(ftmp);
|
||||
return(102);
|
||||
}
|
||||
|
||||
/*** End of update ***/
|
||||
|
||||
/* Write [TITLE] section */
|
||||
|
||||
fprintf(f,"[TITLE]");
|
||||
for (i=0; i<3; i++)
|
||||
{
|
||||
if (strlen(Title[i]) > 0) fprintf(f,"\n%s",Title[i]);
|
||||
}
|
||||
|
||||
/* Write [JUNCTIONS] section */
|
||||
/* (Leave demands for [DEMANDS] section) */
|
||||
|
||||
fprintf(f,"\n\n[JUNCTIONS]");
|
||||
for (i=1; i<=Njuncs; i++)
|
||||
fprintf(f,"\n %-15s %12.2f", Node[i].ID, Node[i].El*Ucf[ELEV]);
|
||||
|
||||
/* Write [RESERVOIRS] section */
|
||||
|
||||
fprintf(f,"\n\n[RESERVOIRS]");
|
||||
for (i=1; i<=Ntanks; i++)
|
||||
{
|
||||
if (Tank[i].A == 0.0)
|
||||
{
|
||||
n = Tank[i].Node;
|
||||
sprintf(s," %-15s %12.2f",Node[n].ID, Node[n].El*Ucf[ELEV]);
|
||||
if ((j = Tank[i].Pat) > 0)
|
||||
sprintf(s1," %-15s",Pattern[j].ID);
|
||||
else
|
||||
strcpy(s1,"");
|
||||
fprintf(f, "\n%s %s", s,s1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Write [TANKS] section */
|
||||
|
||||
fprintf(f,"\n\n[TANKS]");
|
||||
for (i=1; i<=Ntanks; i++)
|
||||
{
|
||||
if (Tank[i].A > 0.0)
|
||||
{
|
||||
n = Tank[i].Node;
|
||||
sprintf(s," %-15s %12.2f %12.2f %12.2f %12.2f %12.2f %12.2f",
|
||||
Node[n].ID,
|
||||
Node[n].El*Ucf[ELEV],
|
||||
(Tank[i].H0 - Node[n].El)*Ucf[ELEV],
|
||||
(Tank[i].Hmin - Node[n].El)*Ucf[ELEV],
|
||||
(Tank[i].Hmax - Node[n].El)*Ucf[ELEV],
|
||||
sqrt(4.0*Tank[i].A/PI)*Ucf[ELEV],
|
||||
Tank[i].Vmin*SQR(Ucf[ELEV])*Ucf[ELEV]);
|
||||
if ((j = Tank[i].Vcurve) > 0)
|
||||
sprintf(s1,"%-15s",Curve[j].ID);
|
||||
else
|
||||
strcpy(s1,"");
|
||||
fprintf(f, "\n%s %s", s,s1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Write [PIPES] section */
|
||||
|
||||
fprintf(f,"\n\n[PIPES]");
|
||||
for (i=1; i<=Nlinks; i++)
|
||||
{
|
||||
if (Link[i].Type <= PIPE)
|
||||
{
|
||||
d = Link[i].Diam;
|
||||
kc = Link[i].Kc;
|
||||
if (Formflag == DW) kc = kc*Ucf[ELEV]*1000.0;
|
||||
km = Link[i].Km*SQR(d)*SQR(d)/0.02517;
|
||||
|
||||
/*** Updated 6/24/02 ***/
|
||||
sprintf(s," %-15s %-15s %-15s %12.2f %12.2f",
|
||||
Link[i].ID,
|
||||
Node[Link[i].N1].ID,
|
||||
Node[Link[i].N2].ID,
|
||||
Link[i].Len*Ucf[LENGTH],
|
||||
d*Ucf[DIAM]);
|
||||
if (Formflag == DW) sprintf(s1, "%12.4f %12.4f", kc, km);
|
||||
else sprintf(s1, "%12.2f %12.4f", kc, km);
|
||||
if (Link[i].Type == CV) sprintf(s2,"CV");
|
||||
else if (Link[i].Stat == CLOSED) sprintf(s2,"CLOSED");
|
||||
else strcpy(s2,"");
|
||||
fprintf(f,"\n%s %s %s",s,s1,s2);
|
||||
/*** End of update ***/
|
||||
}
|
||||
}
|
||||
|
||||
/* Write [PUMPS] section */
|
||||
|
||||
fprintf(f, "\n\n[PUMPS]");
|
||||
for (i=1; i<=Npumps; i++)
|
||||
{
|
||||
n = Pump[i].Link;
|
||||
sprintf(s," %-15s %-15s %-15s",
|
||||
Link[n].ID,
|
||||
Node[Link[n].N1].ID,
|
||||
Node[Link[n].N2].ID);
|
||||
|
||||
/* Pump has constant power */
|
||||
if (Pump[i].Ptype == CONST_HP)
|
||||
sprintf(s1, " POWER %.2f", Link[n].Km);
|
||||
|
||||
/* Pump has a head curve */
|
||||
else if ((j = Pump[i].Hcurve) > 0)
|
||||
sprintf(s1, " HEAD %s", Curve[j].ID);
|
||||
|
||||
/* Old format used for pump curve */
|
||||
else
|
||||
{
|
||||
fprintf(f, "\n%s %12.2f %12.2f %12.2f 0.0 %12.2f",s,
|
||||
-Pump[i].H0*Ucf[HEAD],
|
||||
(-Pump[i].H0 - Pump[i].R*pow(Pump[i].Q0,Pump[i].N))*Ucf[HEAD],
|
||||
Pump[i].Q0*Ucf[FLOW],
|
||||
Pump[i].Qmax*Ucf[FLOW]);
|
||||
continue;
|
||||
}
|
||||
strcat(s,s1);
|
||||
|
||||
if ((j = Pump[i].Upat) > 0)
|
||||
sprintf(s1," PATTERN %s",Pattern[j].ID);
|
||||
else strcpy(s1,"");
|
||||
strcat(s,s1);
|
||||
|
||||
if (Link[n].Kc != 1.0)
|
||||
sprintf(s1, " SPEED %.2f", Link[n].Kc);
|
||||
else strcpy(s1,"");
|
||||
strcat(s,s1);
|
||||
|
||||
fprintf(f,"\n%s",s);
|
||||
}
|
||||
|
||||
/* Write [VALVES] section */
|
||||
|
||||
fprintf(f, "\n\n[VALVES]");
|
||||
for (i=1; i<=Nvalves; i++)
|
||||
{
|
||||
n = Valve[i].Link;
|
||||
d = Link[n].Diam;
|
||||
kc = Link[n].Kc;
|
||||
if (kc == MISSING) kc = 0.0;
|
||||
switch (Link[n].Type)
|
||||
{
|
||||
case FCV: kc *= Ucf[FLOW]; break;
|
||||
case PRV:
|
||||
case PSV:
|
||||
case PBV: kc *= Ucf[PRESSURE]; break;
|
||||
}
|
||||
km = Link[n].Km*SQR(d)*SQR(d)/0.02517;
|
||||
|
||||
sprintf(s," %-15s %-15s %-15s %12.2f %5s",
|
||||
Link[n].ID,
|
||||
Node[Link[n].N1].ID,
|
||||
Node[Link[n].N2].ID,
|
||||
d*Ucf[DIAM],
|
||||
LinkTxt[Link[n].Type]);
|
||||
|
||||
if (Link[n].Type == GPV && (j = ROUND(Link[n].Kc)) > 0)
|
||||
sprintf(s1,"%-15s %12.2f", Curve[j].ID, km);
|
||||
else sprintf(s1,"%12.2f %12.2f",kc,km);
|
||||
|
||||
fprintf(f, "\n%s %s", s,s1);
|
||||
}
|
||||
|
||||
/* Write [DEMANDS] section */
|
||||
|
||||
fprintf(f, "\n\n[DEMANDS]");
|
||||
|
||||
/*** Updated 11/19/01 ***/
|
||||
ucf = Ucf[DEMAND];
|
||||
|
||||
for (i=1; i<=Njuncs; i++)
|
||||
{
|
||||
for (demand = Node[i].D; demand != NULL; demand = demand->next)
|
||||
{
|
||||
sprintf(s," %-15s %12.2f",Node[i].ID,ucf*demand->Base);
|
||||
if ((j = demand->Pat) > 0) sprintf(s1," %s",Pattern[j].ID);
|
||||
else strcpy(s1,"");
|
||||
fprintf(f,"\n%s %s",s,s1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Write [EMITTERS] section */
|
||||
|
||||
fprintf(f, "\n\n[EMITTERS]");
|
||||
for (i=1; i<=Njuncs; i++)
|
||||
{
|
||||
if (Node[i].Ke == 0.0) continue;
|
||||
ke = Ucf[FLOW]/pow(Ucf[PRESSURE]*Node[i].Ke,(1.0/Qexp));
|
||||
fprintf(f,"\n %-15s %12.2f",Node[i].ID,ke);
|
||||
}
|
||||
|
||||
/* Write [STATUS] section */
|
||||
|
||||
fprintf(f, "\n\n[STATUS]");
|
||||
for (i=1; i<=Nlinks; i++)
|
||||
{
|
||||
if (Link[i].Type <= PUMP)
|
||||
{
|
||||
if (Link[i].Stat == CLOSED)
|
||||
fprintf(f, "\n %-15s %s",Link[i].ID,StatTxt[CLOSED]);
|
||||
|
||||
/* Write pump speed here for pumps with old-style pump curve input */
|
||||
else if (Link[i].Type == PUMP)
|
||||
{
|
||||
n = PUMPINDEX(i);
|
||||
if (
|
||||
Pump[n].Hcurve == 0 &&
|
||||
Pump[n].Ptype != CONST_HP &&
|
||||
Link[i].Kc != 1.0
|
||||
)
|
||||
fprintf(f, "\n %-15s %-.2f",Link[i].ID, Link[i].Kc);
|
||||
}
|
||||
}
|
||||
|
||||
/* Write fixed-status PRVs & PSVs (setting = MISSING) */
|
||||
else if (Link[i].Kc == MISSING)
|
||||
{
|
||||
if (Link[i].Stat == OPEN)
|
||||
fprintf(f, "\n %-15s %s",Link[i].ID,StatTxt[OPEN]);
|
||||
if (Link[i].Stat == CLOSED)
|
||||
fprintf(f, "\n%-15s %s",Link[i].ID,StatTxt[CLOSED]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Write [PATTERNS] section */
|
||||
/* (Use 6 pattern factors per line) */
|
||||
|
||||
fprintf(f, "\n\n[PATTERNS]");
|
||||
for (i=1; i<=Npats; i++)
|
||||
{
|
||||
for (j=0; j<Pattern[i].Length; j++)
|
||||
{
|
||||
if (j % 6 == 0) fprintf(f,"\n %-15s",Pattern[i].ID);
|
||||
fprintf(f," %12.4f",Pattern[i].F[j]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Write [CURVES] section */
|
||||
|
||||
fprintf(f, "\n\n[CURVES]");
|
||||
for (i=1; i<=Ncurves; i++)
|
||||
{
|
||||
for (j=0; j<Curve[i].Npts; j++)
|
||||
fprintf(f,"\n %-15s %12.4f %12.4f",
|
||||
Curve[i].ID,Curve[i].X[j],Curve[i].Y[j]);
|
||||
}
|
||||
|
||||
/* Write [CONTROLS] section */
|
||||
|
||||
fprintf(f, "\n\n[CONTROLS]");
|
||||
for (i=1; i<=Ncontrols; i++)
|
||||
{
|
||||
/* Check that controlled link exists */
|
||||
if ( (j = Control[i].Link) <= 0) continue;
|
||||
|
||||
/* Get text of control's link status/setting */
|
||||
if (Control[i].Setting == MISSING)
|
||||
sprintf(s, " LINK %s %s ", Link[j].ID, StatTxt[Control[i].Status]);
|
||||
else
|
||||
{
|
||||
kc = Control[i].Setting;
|
||||
switch(Link[j].Type)
|
||||
{
|
||||
case PRV:
|
||||
case PSV:
|
||||
case PBV: kc *= Ucf[PRESSURE]; break;
|
||||
case FCV: kc *= Ucf[FLOW]; break;
|
||||
}
|
||||
sprintf(s, " LINK %s %.4f",Link[j].ID, kc);
|
||||
}
|
||||
|
||||
switch (Control[i].Type)
|
||||
{
|
||||
/* Print level control */
|
||||
case LOWLEVEL:
|
||||
case HILEVEL:
|
||||
n = Control[i].Node;
|
||||
kc = Control[i].Grade - Node[n].El;
|
||||
if (n > Njuncs) kc *= Ucf[HEAD];
|
||||
else kc *= Ucf[PRESSURE];
|
||||
fprintf(f, "\n%s IF NODE %s %s %.4f", s,
|
||||
Node[n].ID, ControlTxt[Control[i].Type], kc);
|
||||
break;
|
||||
|
||||
/* Print timer control */
|
||||
case TIMER:
|
||||
fprintf(f, "\n%s AT %s %.2f HOURS",
|
||||
s, ControlTxt[TIMER], Control[i].Time/3600.);
|
||||
break;
|
||||
|
||||
/* Print time-of-day control */
|
||||
case TIMEOFDAY:
|
||||
fprintf(f, "\n%s AT %s %s",
|
||||
s, ControlTxt[TIMEOFDAY], clocktime(Atime, Control[i].Time));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write [QUALITY] section */
|
||||
/* (Skip nodes with default quality of 0) */
|
||||
|
||||
fprintf(f, "\n\n[QUALITY]");
|
||||
for (i=1; i<=Nnodes; i++)
|
||||
{
|
||||
if (Node[i].C0 == 0.0) continue;
|
||||
fprintf(f, "\n %-15s %12.3f",Node[i].ID,Node[i].C0*Ucf[QUALITY]);
|
||||
}
|
||||
|
||||
/* Write [SOURCES] section */
|
||||
|
||||
fprintf(f, "\n\n[SOURCES]");
|
||||
for (i=1; i<=Nnodes; i++)
|
||||
{
|
||||
source = Node[i].S;
|
||||
if (source == NULL) continue;
|
||||
sprintf(s," %-15s %-8s %12.2f",
|
||||
Node[i].ID,
|
||||
SourceTxt[source->Type],
|
||||
source->C0);
|
||||
if ((j = source->Pat) > 0)
|
||||
sprintf(s1,"%s",Pattern[j].ID);
|
||||
else strcpy(s1,"");
|
||||
fprintf(f,"\n%s %s",s,s1);
|
||||
}
|
||||
|
||||
/* Write [MIXING] section */
|
||||
|
||||
fprintf(f, "\n\n[MIXING]");
|
||||
for (i=1; i<=Ntanks; i++)
|
||||
{
|
||||
if (Tank[i].A == 0.0) continue;
|
||||
fprintf(f, "\n %-15s %-8s %12.4f",
|
||||
Node[Tank[i].Node].ID,
|
||||
MixTxt[Tank[i].MixModel],
|
||||
(Tank[i].V1max/Tank[i].Vmax));
|
||||
}
|
||||
|
||||
/* Write [REACTIONS] section */
|
||||
|
||||
fprintf(f, "\n\n[REACTIONS]");
|
||||
fprintf(f, "\n ORDER BULK %-.2f", BulkOrder);
|
||||
fprintf(f, "\n ORDER WALL %-.0f", WallOrder);
|
||||
fprintf(f, "\n ORDER TANK %-.2f", TankOrder);
|
||||
fprintf(f, "\n GLOBAL BULK %-.4f", Kbulk*SECperDAY);
|
||||
fprintf(f, "\n GLOBAL WALL %-.4f", Kwall*SECperDAY);
|
||||
if (Climit > 0.0)
|
||||
fprintf(f, "\n LIMITING POTENTIAL %-.4f", Climit);
|
||||
if (Rfactor != MISSING && Rfactor != 0.0)
|
||||
fprintf(f, "\n ROUGHNESS CORRELATION %-.4f",Rfactor);
|
||||
for (i=1; i<=Nlinks; i++)
|
||||
{
|
||||
if (Link[i].Type > PIPE) continue;
|
||||
if (Link[i].Kb != Kbulk)
|
||||
fprintf(f, "\n BULK %-15s %-.4f",Link[i].ID,Link[i].Kb*SECperDAY);
|
||||
if (Link[i].Kw != Kwall)
|
||||
fprintf(f, "\n WALL %-15s %-.4f",Link[i].ID,Link[i].Kw*SECperDAY);
|
||||
}
|
||||
for (i=1; i<=Ntanks; i++)
|
||||
{
|
||||
if (Tank[i].A == 0.0) continue;
|
||||
if (Tank[i].Kb != Kbulk)
|
||||
fprintf(f, "\n TANK %-15s %-.4f",Node[Tank[i].Node].ID,
|
||||
Tank[i].Kb*SECperDAY);
|
||||
}
|
||||
|
||||
/* Write [ENERGY] section */
|
||||
|
||||
fprintf(f, "\n\n[ENERGY]");
|
||||
if (Ecost != 0.0)
|
||||
fprintf(f, "\n GLOBAL PRICE %-.4f", Ecost);
|
||||
if (Epat != 0)
|
||||
fprintf(f, "\n GLOBAL PATTERN %s", Pattern[Epat].ID);
|
||||
fprintf(f, "\n GLOBAL EFFIC %-.2f", Epump);
|
||||
fprintf(f, "\n DEMAND CHARGE %-.4f", Dcost);
|
||||
for (i=1; i<=Npumps; i++)
|
||||
{
|
||||
if (Pump[i].Ecost > 0.0)
|
||||
fprintf(f, "\n PUMP %-15s PRICE %-.4f",
|
||||
Link[Pump[i].Link].ID,Pump[i].Ecost);
|
||||
if (Pump[i].Epat > 0.0)
|
||||
fprintf(f, "\n PUMP %-15s PATTERN %s",
|
||||
Link[Pump[i].Link].ID,Pattern[Pump[i].Epat].ID);
|
||||
|
||||
/*** Updated 3/1/01 ***/
|
||||
if (Pump[i].Ecurve > 0.0)
|
||||
fprintf(f, "\n PUMP %-15s EFFIC %s",
|
||||
Link[Pump[i].Link].ID,Curve[Pump[i].Ecurve].ID);
|
||||
}
|
||||
|
||||
/* Write [TIMES] section */
|
||||
|
||||
fprintf(f, "\n\n[TIMES]");
|
||||
fprintf(f, "\n DURATION %s",clocktime(Atime,Dur));
|
||||
fprintf(f, "\n HYDRAULIC TIMESTEP %s",clocktime(Atime,Hstep));
|
||||
fprintf(f, "\n QUALITY TIMESTEP %s",clocktime(Atime,Qstep));
|
||||
fprintf(f, "\n REPORT TIMESTEP %s",clocktime(Atime,Rstep));
|
||||
fprintf(f, "\n REPORT START %s",clocktime(Atime,Rstart));
|
||||
fprintf(f, "\n PATTERN TIMESTEP %s",clocktime(Atime,Pstep));
|
||||
fprintf(f, "\n PATTERN START %s",clocktime(Atime,Pstart));
|
||||
fprintf(f, "\n RULE TIMESTEP %s",clocktime(Atime,Rulestep));
|
||||
fprintf(f, "\n START CLOCKTIME %s",clocktime(Atime,Tstart));
|
||||
fprintf(f, "\n STATISTIC %s",TstatTxt[Tstatflag]);
|
||||
|
||||
/* Write [OPTIONS] section */
|
||||
|
||||
fprintf(f, "\n\n[OPTIONS]");
|
||||
fprintf(f, "\n UNITS %s", FlowUnitsTxt[Flowflag]);
|
||||
fprintf(f, "\n PRESSURE %s", PressUnitsTxt[Pressflag]);
|
||||
fprintf(f, "\n HEADLOSS %s", FormTxt[Formflag]);
|
||||
if (DefPat >= 1 && DefPat <= Npats)
|
||||
fprintf(f, "\n PATTERN %s", Pattern[DefPat].ID);
|
||||
if (Hydflag == USE)
|
||||
fprintf(f, "\n HYDRAULICS USE %s", HydFname);
|
||||
if (Hydflag == SAVE)
|
||||
fprintf(f, "\n HYDRAULICS SAVE %s", HydFname);
|
||||
if (ExtraIter == -1)
|
||||
fprintf(f, "\n UNBALANCED STOP");
|
||||
if (ExtraIter >= 0)
|
||||
fprintf(f, "\n UNBALANCED CONTINUE %d", ExtraIter);
|
||||
if (Qualflag == CHEM)
|
||||
fprintf(f, "\n QUALITY %s %s", ChemName, ChemUnits);
|
||||
if (Qualflag == TRACE)
|
||||
fprintf(f, "\n QUALITY TRACE %-15s", Node[TraceNode].ID);
|
||||
if (Qualflag == AGE)
|
||||
fprintf(f, "\n QUALITY AGE");
|
||||
if (Qualflag == NONE)
|
||||
fprintf(f, "\n QUALITY NONE");
|
||||
fprintf(f, "\n DEMAND MULTIPLIER %-.2f", Dmult);
|
||||
|
||||
/*** Updated 11/19/01 ***/
|
||||
fprintf(f, "\n EMITTER EXPONENT %-.2f", 1.0/Qexp);
|
||||
|
||||
fprintf(f, "\n VISCOSITY %-.4f", Viscos/VISCOS);
|
||||
fprintf(f, "\n DIFFUSIVITY %-.4f", Diffus/DIFFUS);
|
||||
fprintf(f, "\n SPECIFIC GRAVITY %-.4f", SpGrav);
|
||||
fprintf(f, "\n TRIALS %-d", MaxIter);
|
||||
fprintf(f, "\n ACCURACY %-.8f", Hacc);
|
||||
fprintf(f, "\n TOLERANCE %-.8f", Ctol*Ucf[QUALITY]);
|
||||
|
||||
/* Write [REPORT] section */
|
||||
|
||||
fprintf(f, "\n\n[REPORT]");
|
||||
fprintf(f, "\n PAGESIZE %d", PageSize);
|
||||
fprintf(f, "\n STATUS %s", RptFlagTxt[Statflag]);
|
||||
fprintf(f, "\n SUMMARY %s", RptFlagTxt[Summaryflag]);
|
||||
fprintf(f, "\n ENERGY %s", RptFlagTxt[Energyflag]);
|
||||
switch (Nodeflag)
|
||||
{
|
||||
case 0:
|
||||
fprintf(f, "\n NODES NONE");
|
||||
break;
|
||||
case 1:
|
||||
fprintf(f, "\n NODES ALL");
|
||||
break;
|
||||
default:
|
||||
j = 0;
|
||||
for (i=1; i<=Nnodes; i++)
|
||||
{
|
||||
if (Node[i].Rpt == 1)
|
||||
{
|
||||
if (j % 5 == 0) fprintf(f, "\n NODES ");
|
||||
fprintf(f, "%s ", Node[i].ID);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (Linkflag)
|
||||
{
|
||||
case 0:
|
||||
fprintf(f, "\n LINKS NONE");
|
||||
break;
|
||||
case 1:
|
||||
fprintf(f, "\n LINKS ALL");
|
||||
break;
|
||||
default:
|
||||
j = 0;
|
||||
for (i=1; i<=Nlinks; i++)
|
||||
{
|
||||
if (Link[i].Rpt == 1)
|
||||
{
|
||||
if (j % 5 == 0) fprintf(f, "\n LINKS ");
|
||||
fprintf(f, "%s ", Link[i].ID);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i=0; i<MAXVAR; i++)
|
||||
{
|
||||
/*** Updated ********************************************************/ //(2.00.11 - LR)
|
||||
if (Field[i].Enabled == TRUE)
|
||||
{
|
||||
fprintf(f, "\n %-20sPRECISION %d", Field[i].Name, Field[i].Precision);
|
||||
if (Field[i].RptLim[LOW] < BIG)
|
||||
fprintf(f, "\n %-20sBELOW %.4f", Field[i].Name, Field[i].RptLim[LOW]);
|
||||
if (Field[i].RptLim[HI] > -BIG)
|
||||
fprintf(f, "\n %-20sABOVE %.4f", Field[i].Name, Field[i].RptLim[HI]);
|
||||
}
|
||||
else fprintf(f, "\n %-20sNO", Field[i].Name);
|
||||
/********************************************************************/
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
|
||||
/*** Updated *****************************************/ //(2.00.11 - LR)
|
||||
/* Copy data from scratch file to new input file */
|
||||
if (ftmp != NULL)
|
||||
{
|
||||
fseek(ftmp, 0, SEEK_SET);
|
||||
while ( (j = fgetc(ftmp)) != EOF ) fputc(j, f);
|
||||
fclose(ftmp);
|
||||
}
|
||||
/*****************************************************/
|
||||
|
||||
fprintf(f, "\n\n[END]");
|
||||
fclose(f);
|
||||
return(0);
|
||||
}
|
||||
|
||||
634
src/input1.c
Normal file
634
src/input1.c
Normal file
@@ -0,0 +1,634 @@
|
||||
/*
|
||||
*********************************************************************
|
||||
|
||||
INPUT1.C -- Input Functions for EPANET Program
|
||||
|
||||
VERSION: 2.00
|
||||
DATE: 5/30/00
|
||||
9/7/00
|
||||
11/19/01
|
||||
6/24/02
|
||||
AUTHOR: L. Rossman
|
||||
US EPA - NRMRL
|
||||
|
||||
This module initializes, retrieves, and adjusts the input
|
||||
data for a network simulation.
|
||||
|
||||
The entry point for this module is:
|
||||
getdata() -- called from ENopen() in EPANET.C.
|
||||
|
||||
*********************************************************************
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <math.h>
|
||||
#include "hash.h"
|
||||
#include "text.h"
|
||||
#include "types.h"
|
||||
#include "funcs.h"
|
||||
#define EXTERN extern
|
||||
#include "vars.h"
|
||||
|
||||
/*
|
||||
--------------------- Module Global Variables ----------------------
|
||||
*/
|
||||
|
||||
#define MAXITER 40 /* Default max. # hydraulic iterations */
|
||||
#define HACC 0.001 /* Default hydraulics convergence ratio */
|
||||
#define HTOL 0.0005 /* Default hydraulic head tolerance (ft) */
|
||||
|
||||
/*** Updated 11/19/01 ***/
|
||||
#define QTOL 0.0001 /* Default flow rate tolerance (cfs) */
|
||||
|
||||
#define AGETOL 0.01 /* Default water age tolerance (hrs) */
|
||||
#define CHEMTOL 0.01 /* Default concentration tolerance */
|
||||
#define PAGESIZE 0 /* Default uses no page breaks */
|
||||
#define SPGRAV 1.0 /* Default specific gravity */
|
||||
#define EPUMP 75 /* Default pump efficiency */
|
||||
#define DEFPATID "1" /* Default demand pattern ID */
|
||||
|
||||
/*
|
||||
These next three parameters are used in the hydraulics solver:
|
||||
*/
|
||||
|
||||
#define RQTOL 1E-7 /* Default low flow resistance tolerance */
|
||||
#define CHECKFREQ 2 /* Default status check frequency */
|
||||
#define MAXCHECK 10 /* Default # iterations for status checks */
|
||||
|
||||
extern char *Fldname[]; /* Defined in enumstxt.h in EPANET.C */
|
||||
extern char *RptFlowUnitsTxt[];
|
||||
|
||||
|
||||
int getdata()
|
||||
/*
|
||||
**----------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: returns error code
|
||||
** Purpose: reads in network data from disk file
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int errcode = 0;
|
||||
setdefaults(); /* Assign default data values */
|
||||
initreport(); /* Initialize reporting options */
|
||||
rewind(InFile); /* Rewind input file */
|
||||
ERRCODE(readdata()); /* Read in network data */
|
||||
if (!errcode) adjustdata(); /* Adjust data for default values */
|
||||
if (!errcode) initunits(); /* Initialize units on input data */
|
||||
ERRCODE(inittanks()); /* Initialize tank volumes */
|
||||
if (!errcode) convertunits(); /* Convert units on input data */
|
||||
return(errcode);
|
||||
} /* End of getdata */
|
||||
|
||||
|
||||
void setdefaults()
|
||||
/*
|
||||
**----------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: none
|
||||
** Purpose: assigns default values to global variables
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
strncpy(Title[0],"",MAXMSG);
|
||||
strncpy(Title[1],"",MAXMSG);
|
||||
strncpy(Title[2],"",MAXMSG);
|
||||
strncpy(HydFname,"",MAXFNAME);
|
||||
strncpy(MapFname,"",MAXFNAME);
|
||||
strncpy(ChemName,t_CHEMICAL,MAXID);
|
||||
strncpy(ChemUnits,u_MGperL,MAXID);
|
||||
strncpy(DefPatID,DEFPATID,MAXID);
|
||||
Hydflag = SCRATCH; /* No external hydraulics file */
|
||||
Qualflag = NONE; /* No quality simulation */
|
||||
Formflag = HW; /* Use Hazen-Williams formula */
|
||||
Unitsflag = US; /* US unit system */
|
||||
Flowflag = GPM; /* Flow units are gpm */
|
||||
Pressflag = PSI; /* Pressure units are psi */
|
||||
Tstatflag = SERIES; /* Generate time series output */
|
||||
Warnflag = FALSE; /* Warning flag is off */
|
||||
Htol = HTOL; /* Default head tolerance */
|
||||
Qtol = QTOL; /* Default flow tolerance */
|
||||
Hacc = HACC; /* Default hydraulic accuracy */
|
||||
Ctol = MISSING; /* No pre-set quality tolerance */
|
||||
MaxIter = MAXITER; /* Default max. hydraulic trials */
|
||||
ExtraIter = -1; /* Stop if network unbalanced */
|
||||
Dur = 0; /* 0 sec duration (steady state) */
|
||||
Tstart = 0; /* Starting time of day */
|
||||
Pstart = 0; /* Starting pattern period */
|
||||
Hstep = 3600; /* 1 hr hydraulic time step */
|
||||
Qstep = 0; /* No pre-set quality time step */
|
||||
Pstep = 3600; /* 1 hr time pattern period */
|
||||
Rstep = 3600; /* 1 hr reporting period */
|
||||
Rulestep = 0; /* No pre-set rule time step */
|
||||
Rstart = 0; /* Start reporting at time 0 */
|
||||
TraceNode = 0; /* No source tracing */
|
||||
BulkOrder = 1.0; /* 1st-order bulk reaction rate */
|
||||
WallOrder = 1.0; /* 1st-order wall reaction rate */
|
||||
TankOrder = 1.0; /* 1st-order tank reaction rate */
|
||||
Kbulk = 0.0; /* No global bulk reaction */
|
||||
Kwall = 0.0; /* No global wall reaction */
|
||||
Climit = 0.0; /* No limiting potential quality */
|
||||
Diffus = MISSING; /* Temporary diffusivity */
|
||||
Rfactor = 0.0; /* No roughness-reaction factor */
|
||||
Viscos = MISSING; /* Temporary viscosity */
|
||||
SpGrav = SPGRAV; /* Default specific gravity */
|
||||
DefPat = 0; /* Default demand pattern index */
|
||||
Epat = 0; /* No energy price pattern */
|
||||
Ecost = 0.0; /* Zero unit energy cost */
|
||||
Dcost = 0.0; /* Zero energy demand charge */
|
||||
Epump = EPUMP; /* Default pump efficiency */
|
||||
Emax = 0.0; /* Zero peak energy usage */
|
||||
Qexp = 2.0; /* Flow exponent for emitters */
|
||||
Dmult = 1.0; /* Demand multiplier */
|
||||
RQtol = RQTOL; /* Default hydraulics parameters */
|
||||
CheckFreq = CHECKFREQ;
|
||||
MaxCheck = MAXCHECK;
|
||||
} /* End of setdefaults */
|
||||
|
||||
|
||||
void initreport()
|
||||
/*
|
||||
**----------------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: none
|
||||
** Purpose: initializes reporting options
|
||||
**----------------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i;
|
||||
strncpy(Rpt2Fname,"",MAXFNAME);
|
||||
PageSize = PAGESIZE; /* Default page size for report */
|
||||
Summaryflag = TRUE; /* Write summary report */
|
||||
Messageflag = TRUE; /* Report error/warning messages */
|
||||
Statflag = FALSE; /* No hydraulic status reports */
|
||||
Energyflag = FALSE; /* No energy usage report */
|
||||
Nodeflag = 0; /* No reporting on nodes */
|
||||
Linkflag = 0; /* No reporting on links */
|
||||
for (i=0; i<MAXVAR; i++) /* For each reporting variable: */
|
||||
{
|
||||
strncpy(Field[i].Name,Fldname[i],MAXID);
|
||||
Field[i].Enabled = FALSE; /* Not included in report */
|
||||
Field[i].Precision = 2; /* 2 decimal precision */
|
||||
|
||||
/*** Updated 6/24/02 ***/
|
||||
Field[i].RptLim[LOW] = SQR(BIG); /* No reporting limits */
|
||||
Field[i].RptLim[HI] = -SQR(BIG);
|
||||
}
|
||||
Field[FRICTION].Precision = 3;
|
||||
for (i=DEMAND; i<=QUALITY; i++) Field[i].Enabled = TRUE;
|
||||
for (i=FLOW; i<=HEADLOSS; i++) Field[i].Enabled = TRUE;
|
||||
}
|
||||
|
||||
|
||||
void adjustdata()
|
||||
/*
|
||||
**----------------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: none
|
||||
** Purpose: adjusts data after input file has been processed
|
||||
**----------------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i;
|
||||
double ucf; /* Unit conversion factor */
|
||||
Pdemand demand; /* Pointer to demand record */
|
||||
|
||||
/* Use 1 hr pattern & report time step if none specified */
|
||||
if (Pstep <= 0) Pstep = 3600;
|
||||
if (Rstep == 0) Rstep = Pstep;
|
||||
|
||||
/* Hydraulic time step cannot be greater than pattern or report time step */
|
||||
if (Hstep <= 0) Hstep = 3600;
|
||||
if (Hstep > Pstep) Hstep = Pstep;
|
||||
if (Hstep > Rstep) Hstep = Rstep;
|
||||
|
||||
/* Report start time cannot be greater than simulation duration */
|
||||
if (Rstart > Dur) Rstart = 0;
|
||||
|
||||
/* No water quality analysis for steady state run */
|
||||
if (Dur == 0) Qualflag = NONE;
|
||||
|
||||
/* If no quality timestep, then make it 1/10 of hydraulic timestep */
|
||||
if (Qstep == 0) Qstep = Hstep/10;
|
||||
|
||||
/* If no rule time step then make it 1/10 of hydraulic time step; */
|
||||
/* Rule time step cannot be greater than hydraulic time step */
|
||||
if (Rulestep == 0) Rulestep = Hstep/10;
|
||||
Rulestep = MIN(Rulestep, Hstep);
|
||||
|
||||
/* Quality timestep cannot exceed hydraulic timestep */
|
||||
Qstep = MIN(Qstep, Hstep);
|
||||
|
||||
/* If no quality tolerance, then use default values */
|
||||
if (Ctol == MISSING)
|
||||
{
|
||||
if (Qualflag == AGE) Ctol = AGETOL;
|
||||
else Ctol = CHEMTOL;
|
||||
}
|
||||
|
||||
/* Determine unit system based on flow units */
|
||||
switch (Flowflag)
|
||||
{
|
||||
case LPS: /* Liters/sec */
|
||||
case LPM: /* Liters/min */
|
||||
case MLD: /* megaliters/day */
|
||||
case CMH: /* cubic meters/hr */
|
||||
case CMD: /* cubic meters/day */
|
||||
Unitsflag = SI;
|
||||
break;
|
||||
default:
|
||||
Unitsflag = US;
|
||||
}
|
||||
|
||||
/* Revise pressure units depending on flow units */
|
||||
if (Unitsflag != SI) Pressflag = PSI;
|
||||
else if (Pressflag == PSI) Pressflag = METERS;
|
||||
|
||||
/* Store value of viscosity & diffusivity */
|
||||
ucf = 1.0;
|
||||
if (Unitsflag == SI) ucf = SQR(MperFT);
|
||||
|
||||
if (Viscos == MISSING) /* No value supplied */
|
||||
Viscos = VISCOS;
|
||||
else if (Viscos > 1.e-3) /* Multiplier supplied */
|
||||
Viscos = Viscos*VISCOS;
|
||||
else /* Actual value supplied */
|
||||
Viscos = Viscos/ucf;
|
||||
|
||||
if (Diffus == MISSING)
|
||||
Diffus = DIFFUS;
|
||||
else if (Diffus > 1.e-4)
|
||||
Diffus = Diffus*DIFFUS;
|
||||
else
|
||||
Diffus = Diffus/ucf;
|
||||
|
||||
/*
|
||||
Set exponent in head loss equation and adjust flow-resistance tolerance.
|
||||
*/
|
||||
if (Formflag == HW) Hexp = 1.852;
|
||||
else Hexp = 2.0;
|
||||
|
||||
/*** Updated 9/7/00 ***/
|
||||
/*** No adjustment made to flow-resistance tolerance ***/
|
||||
/*RQtol = RQtol/Hexp;*/
|
||||
|
||||
/* See if default reaction coeffs. apply */
|
||||
for (i=1; i<=Nlinks; i++)
|
||||
{
|
||||
if (Link[i].Type > PIPE) continue;
|
||||
if (Link[i].Kb == MISSING) Link[i].Kb = Kbulk; /* Bulk coeff. */
|
||||
if (Link[i].Kw == MISSING) /* Wall coeff. */
|
||||
{
|
||||
/* Rfactor is the pipe roughness correlation factor */
|
||||
if (Rfactor == 0.0) Link[i].Kw = Kwall;
|
||||
else if ((Link[i].Kc > 0.0) && (Link[i].Diam > 0.0))
|
||||
{
|
||||
if (Formflag == HW) Link[i].Kw = Rfactor/Link[i].Kc;
|
||||
if (Formflag == DW) Link[i].Kw = Rfactor/ABS(log(Link[i].Kc/Link[i].Diam));
|
||||
if (Formflag == CM) Link[i].Kw = Rfactor*Link[i].Kc;
|
||||
}
|
||||
else Link[i].Kw = 0.0;
|
||||
}
|
||||
}
|
||||
for (i=1; i<=Ntanks; i++)
|
||||
if (Tank[i].Kb == MISSING) Tank[i].Kb = Kbulk;
|
||||
|
||||
/* Use default pattern if none assigned to a demand */
|
||||
for (i=1; i<=Nnodes; i++)
|
||||
{
|
||||
for (demand = Node[i].D; demand != NULL; demand = demand->next)
|
||||
if (demand->Pat == 0) demand->Pat = DefPat;
|
||||
}
|
||||
|
||||
/* Remove QUALITY as a reporting variable if no WQ analysis */
|
||||
if (Qualflag == NONE) Field[QUALITY].Enabled = FALSE;
|
||||
|
||||
} /* End of adjustdata */
|
||||
|
||||
|
||||
int inittanks()
|
||||
/*
|
||||
**---------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: returns error code
|
||||
** Purpose: initializes volumes in non-cylindrical tanks
|
||||
**---------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i,j,n = 0;
|
||||
double a;
|
||||
int errcode = 0,
|
||||
levelerr;
|
||||
|
||||
for (j=1; j<=Ntanks; j++)
|
||||
{
|
||||
|
||||
/* Skip reservoirs */
|
||||
if (Tank[j].A == 0.0) continue;
|
||||
|
||||
/* Check for valid lower/upper tank levels */
|
||||
levelerr = 0;
|
||||
if (Tank[j].H0 > Tank[j].Hmax ||
|
||||
Tank[j].Hmin > Tank[j].Hmax ||
|
||||
Tank[j].H0 < Tank[j].Hmin
|
||||
) levelerr = 1;
|
||||
|
||||
/* Check that tank heights are within volume curve */
|
||||
i = Tank[j].Vcurve;
|
||||
if (i > 0)
|
||||
{
|
||||
n = Curve[i].Npts - 1;
|
||||
if (Tank[j].Hmin < Curve[i].X[0] ||
|
||||
Tank[j].Hmax > Curve[i].X[n]
|
||||
) levelerr = 1;
|
||||
}
|
||||
|
||||
/* Report error in levels if found */
|
||||
if (levelerr)
|
||||
{
|
||||
sprintf(Msg,ERR225,Node[Tank[j].Node].ID);
|
||||
writeline(Msg);
|
||||
errcode = 200;
|
||||
}
|
||||
|
||||
/* Else if tank has a volume curve, */
|
||||
else if (i > 0)
|
||||
{
|
||||
/* Find min., max., and initial volumes from curve */
|
||||
Tank[j].Vmin = interp(Curve[i].Npts,Curve[i].X,
|
||||
Curve[i].Y,Tank[j].Hmin);
|
||||
Tank[j].Vmax = interp(Curve[i].Npts,Curve[i].X,
|
||||
Curve[i].Y,Tank[j].Hmax);
|
||||
Tank[j].V0 = interp(Curve[i].Npts,Curve[i].X,
|
||||
Curve[i].Y,Tank[j].H0);
|
||||
|
||||
/* Find a "nominal" diameter for tank */
|
||||
a = (Curve[i].Y[n] - Curve[i].Y[0])/
|
||||
(Curve[i].X[n] - Curve[i].X[0]);
|
||||
Tank[j].A = sqrt(4.0*a/PI);
|
||||
}
|
||||
}
|
||||
return(errcode);
|
||||
} /* End of inittanks */
|
||||
|
||||
|
||||
void initunits()
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: none
|
||||
** Purpose: determines unit conversion factors
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
double dcf, /* distance conversion factor */
|
||||
ccf, /* concentration conversion factor */
|
||||
qcf, /* flow conversion factor */
|
||||
hcf, /* head conversion factor */
|
||||
pcf, /* pressure conversion factor */
|
||||
wcf; /* energy conversion factor */
|
||||
|
||||
if (Unitsflag == SI) /* SI units */
|
||||
{
|
||||
strcpy(Field[DEMAND].Units,RptFlowUnitsTxt[Flowflag]);
|
||||
strcpy(Field[ELEV].Units,u_METERS);
|
||||
strcpy(Field[HEAD].Units,u_METERS);
|
||||
if (Pressflag == METERS) strcpy(Field[PRESSURE].Units,u_METERS);
|
||||
else strcpy(Field[PRESSURE].Units,u_KPA);
|
||||
strcpy(Field[LENGTH].Units,u_METERS);
|
||||
strcpy(Field[DIAM].Units,u_MMETERS);
|
||||
strcpy(Field[FLOW].Units,RptFlowUnitsTxt[Flowflag]);
|
||||
strcpy(Field[VELOCITY].Units,u_MperSEC);
|
||||
strcpy(Field[HEADLOSS].Units,u_per1000M);
|
||||
strcpy(Field[FRICTION].Units,"");
|
||||
strcpy(Field[POWER].Units,u_KW);
|
||||
dcf = 1000.0*MperFT;
|
||||
qcf = LPSperCFS;
|
||||
if (Flowflag == LPM) qcf = LPMperCFS;
|
||||
if (Flowflag == MLD) qcf = MLDperCFS;
|
||||
if (Flowflag == CMH) qcf = CMHperCFS;
|
||||
if (Flowflag == CMD) qcf = CMDperCFS;
|
||||
hcf = MperFT;
|
||||
if (Pressflag == METERS) pcf = MperFT*SpGrav;
|
||||
else pcf = KPAperPSI*PSIperFT*SpGrav;
|
||||
wcf = KWperHP;
|
||||
}
|
||||
else /* US units */
|
||||
{
|
||||
strcpy(Field[DEMAND].Units,RptFlowUnitsTxt[Flowflag]);
|
||||
strcpy(Field[ELEV].Units,u_FEET);
|
||||
strcpy(Field[HEAD].Units,u_FEET);
|
||||
strcpy(Field[PRESSURE].Units,u_PSI);
|
||||
strcpy(Field[LENGTH].Units,u_FEET);
|
||||
strcpy(Field[DIAM].Units,u_INCHES);
|
||||
strcpy(Field[FLOW].Units,RptFlowUnitsTxt[Flowflag]);
|
||||
strcpy(Field[VELOCITY].Units,u_FTperSEC);
|
||||
strcpy(Field[HEADLOSS].Units,u_per1000FT);
|
||||
strcpy(Field[FRICTION].Units,"");
|
||||
strcpy(Field[POWER].Units,u_HP);
|
||||
dcf = 12.0;
|
||||
qcf = 1.0;
|
||||
if (Flowflag == GPM) qcf = GPMperCFS;
|
||||
if (Flowflag == MGD) qcf = MGDperCFS;
|
||||
if (Flowflag == IMGD)qcf = IMGDperCFS;
|
||||
if (Flowflag == AFD) qcf = AFDperCFS;
|
||||
hcf = 1.0;
|
||||
pcf = PSIperFT*SpGrav;
|
||||
wcf = 1.0;
|
||||
}
|
||||
strcpy(Field[QUALITY].Units,"");
|
||||
ccf = 1.0;
|
||||
if (Qualflag == CHEM)
|
||||
{
|
||||
ccf = 1.0/LperFT3;
|
||||
strncpy(Field[QUALITY].Units,ChemUnits,MAXID);
|
||||
strncpy(Field[REACTRATE].Units,ChemUnits,MAXID);
|
||||
strcat(Field[REACTRATE].Units,t_PERDAY);
|
||||
}
|
||||
else if (Qualflag == AGE) strcpy(Field[QUALITY].Units,u_HOURS);
|
||||
else if (Qualflag == TRACE) strcpy(Field[QUALITY].Units,u_PERCENT);
|
||||
Ucf[DEMAND] = qcf;
|
||||
Ucf[ELEV] = hcf;
|
||||
Ucf[HEAD] = hcf;
|
||||
Ucf[PRESSURE] = pcf;
|
||||
Ucf[QUALITY] = ccf;
|
||||
Ucf[LENGTH] = hcf;
|
||||
Ucf[DIAM] = dcf;
|
||||
Ucf[FLOW] = qcf;
|
||||
Ucf[VELOCITY] = hcf;
|
||||
Ucf[HEADLOSS] = hcf;
|
||||
Ucf[LINKQUAL] = ccf;
|
||||
Ucf[REACTRATE] = ccf;
|
||||
Ucf[FRICTION] = 1.0;
|
||||
Ucf[POWER] = wcf;
|
||||
Ucf[VOLUME] = hcf*hcf*hcf;
|
||||
if (Hstep < 1800) /* Report time in mins. */
|
||||
{ /* if hydraulic time step */
|
||||
Ucf[TIME] = 1.0/60.0; /* is less than 1/2 hour. */
|
||||
strcpy(Field[TIME].Units,u_MINUTES);
|
||||
}
|
||||
else
|
||||
{
|
||||
Ucf[TIME] = 1.0/3600.0;
|
||||
strcpy(Field[TIME].Units,u_HOURS);
|
||||
}
|
||||
|
||||
} /* End of initunits */
|
||||
|
||||
|
||||
void convertunits()
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: none
|
||||
** Purpose: converts units of input data
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i,j,k;
|
||||
double ucf; /* Unit conversion factor */
|
||||
Pdemand demand; /* Pointer to demand record */
|
||||
|
||||
/* Convert nodal elevations & initial WQ */
|
||||
/* (WQ source units are converted in QUALITY.C */
|
||||
for (i=1; i<=Nnodes; i++)
|
||||
{
|
||||
Node[i].El /= Ucf[ELEV];
|
||||
Node[i].C0 /= Ucf[QUALITY];
|
||||
}
|
||||
|
||||
/* Convert demands */
|
||||
for (i=1; i<=Njuncs; i++)
|
||||
{
|
||||
for (demand = Node[i].D; demand != NULL; demand = demand->next)
|
||||
demand->Base /= Ucf[DEMAND];
|
||||
}
|
||||
|
||||
/* Convert emitter discharge coeffs. to head loss coeff. */
|
||||
ucf = pow(Ucf[FLOW],Qexp)/Ucf[PRESSURE];
|
||||
for (i=1; i<=Njuncs; i++)
|
||||
if (Node[i].Ke > 0.0) Node[i].Ke = ucf/pow(Node[i].Ke,Qexp);
|
||||
|
||||
/* Initialize tank variables (convert tank levels to elevations) */
|
||||
for (j=1; j<=Ntanks; j++)
|
||||
{
|
||||
i = Tank[j].Node;
|
||||
Tank[j].H0 = Node[i].El + Tank[j].H0/Ucf[ELEV];
|
||||
Tank[j].Hmin = Node[i].El + Tank[j].Hmin/Ucf[ELEV];
|
||||
Tank[j].Hmax = Node[i].El + Tank[j].Hmax/Ucf[ELEV];
|
||||
Tank[j].A = PI*SQR(Tank[j].A/Ucf[ELEV])/4.0;
|
||||
Tank[j].V0 /= Ucf[VOLUME];
|
||||
Tank[j].Vmin /= Ucf[VOLUME];
|
||||
Tank[j].Vmax /= Ucf[VOLUME];
|
||||
Tank[j].Kb /= SECperDAY;
|
||||
Tank[j].V = Tank[j].V0;
|
||||
Tank[j].C = Node[i].C0;
|
||||
Tank[j].V1max *= Tank[j].Vmax;
|
||||
}
|
||||
|
||||
/* Convert WQ option concentration units */
|
||||
Climit /= Ucf[QUALITY];
|
||||
Ctol /= Ucf[QUALITY];
|
||||
|
||||
/* Convert global reaction coeffs. */
|
||||
Kbulk /= SECperDAY;
|
||||
Kwall /= SECperDAY;
|
||||
|
||||
/* Convert units of link parameters */
|
||||
for (k=1; k<=Nlinks; k++)
|
||||
{
|
||||
if (Link[k].Type <= PIPE)
|
||||
{
|
||||
/* Convert pipe parameter units: */
|
||||
/* - for Darcy-Weisbach formula, convert roughness */
|
||||
/* from millifeet (or mm) to ft (or m) */
|
||||
/* - for US units, convert diameter from inches to ft */
|
||||
if (Formflag == DW) Link[k].Kc /= (1000.0*Ucf[ELEV]);
|
||||
Link[k].Diam /= Ucf[DIAM];
|
||||
Link[k].Len /= Ucf[LENGTH];
|
||||
|
||||
/* Convert minor loss coeff. from V^2/2g basis to Q^2 basis */
|
||||
Link[k].Km = 0.02517*Link[k].Km/SQR(Link[k].Diam)/SQR(Link[k].Diam);
|
||||
|
||||
/* Convert units on reaction coeffs. */
|
||||
Link[k].Kb /= SECperDAY;
|
||||
Link[k].Kw /= SECperDAY;
|
||||
}
|
||||
|
||||
else if (Link[k].Type == PUMP )
|
||||
{
|
||||
/* Convert units for pump curve parameters */
|
||||
i = PUMPINDEX(k);
|
||||
if (Pump[i].Ptype == CONST_HP)
|
||||
{
|
||||
/* For constant hp pump, convert kw to hp */
|
||||
if (Unitsflag == SI) Pump[i].R /= Ucf[POWER];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* For power curve pumps, convert */
|
||||
/* shutoff head and flow coefficient */
|
||||
if (Pump[i].Ptype == POWER_FUNC)
|
||||
{
|
||||
Pump[i].H0 /= Ucf[HEAD];
|
||||
Pump[i].R *= (pow(Ucf[FLOW],Pump[i].N)/Ucf[HEAD]);
|
||||
}
|
||||
/* Convert flow range & max. head units */
|
||||
Pump[i].Q0 /= Ucf[FLOW];
|
||||
Pump[i].Qmax /= Ucf[FLOW];
|
||||
Pump[i].Hmax /= Ucf[HEAD];
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
/* For flow control valves, convert flow setting */
|
||||
/* while for other valves convert pressure setting */
|
||||
Link[k].Diam /= Ucf[DIAM];
|
||||
Link[k].Km = 0.02517*Link[k].Km/SQR(Link[k].Diam)/SQR(Link[k].Diam);
|
||||
if (Link[k].Kc != MISSING) switch (Link[k].Type)
|
||||
{
|
||||
case FCV: Link[k].Kc /= Ucf[FLOW]; break;
|
||||
case PRV:
|
||||
case PSV:
|
||||
case PBV: Link[k].Kc /= Ucf[PRESSURE]; break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute flow resistances */
|
||||
resistance(k);
|
||||
}
|
||||
|
||||
/* Convert units on control settings */
|
||||
for (i=1; i<=Ncontrols; i++)
|
||||
{
|
||||
if ( (k = Control[i].Link) == 0) continue;
|
||||
if ( (j = Control[i].Node) > 0)
|
||||
{
|
||||
/* j = index of controlling node, and if */
|
||||
/* j > Njuncs, then control is based on tank level */
|
||||
/* otherwise control is based on nodal pressure */
|
||||
if (j > Njuncs)
|
||||
Control[i].Grade = Node[j].El + Control[i].Grade/Ucf[ELEV];
|
||||
else Control[i].Grade = Node[j].El + Control[i].Grade/Ucf[PRESSURE];
|
||||
}
|
||||
|
||||
/* Convert units on valve settings */
|
||||
if (Control[i].Setting != MISSING) switch (Link[k].Type)
|
||||
{
|
||||
case PRV:
|
||||
case PSV:
|
||||
case PBV:
|
||||
Control[i].Setting /= Ucf[PRESSURE];
|
||||
break;
|
||||
case FCV:
|
||||
Control[i].Setting /= Ucf[FLOW];
|
||||
}
|
||||
}
|
||||
} /* End of convertunits */
|
||||
|
||||
/************************ END OF INPUT1.C ************************/
|
||||
|
||||
966
src/input2.c
Normal file
966
src/input2.c
Normal file
@@ -0,0 +1,966 @@
|
||||
/*
|
||||
**********************************************************************
|
||||
|
||||
INPUT2.C -- Input data file interpreter for EPANET
|
||||
|
||||
VERSION: 2.00
|
||||
DATE: 5/30/00
|
||||
9/7/00
|
||||
10/25/00
|
||||
AUTHOR: L. Rossman
|
||||
US EPA - NRMRL
|
||||
|
||||
This module reads and interprets the input data from file InFile.
|
||||
|
||||
The entry points for this module are:
|
||||
netsize() -- called from ENopen() in EPANET.C
|
||||
readdata() -- called from getdata() in INPUT1.C
|
||||
|
||||
The following utility functions are all called from INPUT3.C
|
||||
addnodeID()
|
||||
addlinkID()
|
||||
findID()
|
||||
getfloat()
|
||||
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <math.h>
|
||||
#include "hash.h"
|
||||
#include "text.h"
|
||||
#include "types.h"
|
||||
#include "funcs.h"
|
||||
#define EXTERN extern
|
||||
#include "vars.h"
|
||||
|
||||
#define MAXERRS 10 /* Max. input errors reported */
|
||||
|
||||
int Ntokens, /* Number of tokens in input line */
|
||||
Ntitle; /* Number of title lines */
|
||||
char *Tok[MAXTOKS]; /* Array of token strings */
|
||||
|
||||
/* Used in INPUT3.C: */
|
||||
STmplist *PrevPat; /* Pointer to pattern list element */
|
||||
STmplist *PrevCurve; /* Pointer to curve list element */
|
||||
|
||||
/* Defined in enumstxt.h in EPANET.C */
|
||||
extern char *SectTxt[]; /* Input section keywords */
|
||||
extern char *RptSectTxt[];
|
||||
|
||||
|
||||
int netsize()
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: returns error code
|
||||
** Purpose: determines number of system components
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
char line[MAXLINE+1]; /* Line from input data file */
|
||||
char *tok; /* First token of line */
|
||||
int sect,newsect; /* Input data sections */
|
||||
int errcode = 0; /* Error code */
|
||||
|
||||
/* Initialize network component counts */
|
||||
MaxJuncs = 0;
|
||||
MaxTanks = 0;
|
||||
MaxPipes = 0;
|
||||
MaxPumps = 0;
|
||||
MaxValves = 0;
|
||||
MaxControls = 0;
|
||||
MaxRules = 0;
|
||||
MaxCurves = 0;
|
||||
sect = -1;
|
||||
|
||||
/* Add a default pattern 0 */
|
||||
MaxPats = -1;
|
||||
addpattern("");
|
||||
|
||||
/* Make pass through data file counting number of each component */
|
||||
while (fgets(line,MAXLINE,InFile) != NULL)
|
||||
{
|
||||
/* Skip blank lines & those beginning with a comment */
|
||||
tok = strtok(line,SEPSTR);
|
||||
if (tok == NULL) continue;
|
||||
if (*tok == ';') continue;
|
||||
|
||||
/* Check if line begins with a new section heading */
|
||||
if (*tok == '[')
|
||||
{
|
||||
newsect = findmatch(tok,SectTxt);
|
||||
if (newsect >= 0)
|
||||
{
|
||||
sect = newsect;
|
||||
if (sect == _END) break;
|
||||
continue;
|
||||
}
|
||||
else continue;
|
||||
}
|
||||
|
||||
/* Add to count of current component */
|
||||
switch(sect)
|
||||
{
|
||||
case _JUNCTIONS: MaxJuncs++; break;
|
||||
case _RESERVOIRS:
|
||||
case _TANKS: MaxTanks++; break;
|
||||
case _PIPES: MaxPipes++; break;
|
||||
case _PUMPS: MaxPumps++; break;
|
||||
case _VALVES: MaxValves++; break;
|
||||
case _CONTROLS: MaxControls++; break;
|
||||
case _RULES: addrule(tok); break; /* See RULES.C */
|
||||
case _PATTERNS: errcode = addpattern(tok);
|
||||
break;
|
||||
case _CURVES: errcode = addcurve(tok);
|
||||
break;
|
||||
}
|
||||
if (errcode) break;
|
||||
}
|
||||
|
||||
MaxNodes = MaxJuncs + MaxTanks;
|
||||
MaxLinks = MaxPipes + MaxPumps + MaxValves;
|
||||
if (MaxPats < 1) MaxPats = 1;
|
||||
if (!errcode)
|
||||
{
|
||||
if (MaxJuncs < 1) errcode = 223; /* Not enough nodes */
|
||||
else if (MaxTanks == 0) errcode = 224; /* No tanks */
|
||||
}
|
||||
return(errcode);
|
||||
} /* End of netsize */
|
||||
|
||||
|
||||
int readdata()
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: returns error code
|
||||
** Purpose: reads contents of input data file
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
char line[MAXLINE+1], /* Line from input data file */
|
||||
wline[MAXLINE+1]; /* Working copy of input line */
|
||||
int sect,newsect, /* Data sections */
|
||||
errcode = 0, /* Error code */
|
||||
inperr,errsum; /* Error code & total error count */
|
||||
|
||||
/* Allocate input buffer */
|
||||
X = (double *) calloc(MAXTOKS, sizeof(double));
|
||||
ERRCODE(MEMCHECK(X));
|
||||
|
||||
if (!errcode)
|
||||
{
|
||||
|
||||
/* Initialize number of network components */
|
||||
Ntitle = 0;
|
||||
Nnodes = 0;
|
||||
Njuncs = 0;
|
||||
Ntanks = 0;
|
||||
Nlinks = 0;
|
||||
Npipes = 0;
|
||||
Npumps = 0;
|
||||
Nvalves = 0;
|
||||
Ncontrols = 0;
|
||||
Nrules = 0;
|
||||
Ncurves = MaxCurves;
|
||||
Npats = MaxPats;
|
||||
PrevPat = NULL;
|
||||
PrevCurve = NULL;
|
||||
sect = -1;
|
||||
errsum = 0;
|
||||
|
||||
/* Read each line from input file. */
|
||||
while (fgets(line,MAXLINE,InFile) != NULL)
|
||||
{
|
||||
|
||||
/* Make copy of line and scan for tokens */
|
||||
strcpy(wline,line);
|
||||
Ntokens = gettokens(wline);
|
||||
|
||||
/* Skip blank lines and comments */
|
||||
if (Ntokens == 0) continue;
|
||||
if (*Tok[0] == ';') continue;
|
||||
|
||||
/* Check if max. length exceeded */
|
||||
if (strlen(line) >= MAXLINE)
|
||||
{
|
||||
sprintf(Msg,ERR214);
|
||||
writeline(Msg);
|
||||
writeline(line);
|
||||
errsum++;
|
||||
}
|
||||
|
||||
/* Check if at start of a new input section */
|
||||
if (*Tok[0] == '[')
|
||||
{
|
||||
newsect = findmatch(Tok[0],SectTxt);
|
||||
if (newsect >= 0)
|
||||
{
|
||||
sect = newsect;
|
||||
if (sect == _END) break;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
inperrmsg(201,sect,line);
|
||||
errsum++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise process next line of input in current section */
|
||||
else
|
||||
{
|
||||
inperr = newline(sect,line);
|
||||
if (inperr > 0)
|
||||
{
|
||||
inperrmsg(inperr,sect,line);
|
||||
errsum++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Stop if reach end of file or max. error count */
|
||||
if (errsum == MAXERRS) break;
|
||||
} /* End of while */
|
||||
|
||||
/* Check for errors */
|
||||
if (errsum > 0) errcode = 200;
|
||||
}
|
||||
|
||||
/* Check for unlinked nodes */
|
||||
if (!errcode) errcode = unlinked();
|
||||
|
||||
/* Get pattern & curve data from temp. lists */
|
||||
if (!errcode) errcode = getpatterns();
|
||||
if (!errcode) errcode = getcurves();
|
||||
if (!errcode) errcode = getpumpparams();
|
||||
|
||||
/* Free input buffer */
|
||||
free(X);
|
||||
return(errcode);
|
||||
|
||||
} /* End of readdata */
|
||||
|
||||
|
||||
int newline(int sect, char *line)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: sect = current section of input file
|
||||
** *line = line read from input file
|
||||
** Output: returns error code or 0 if no error found
|
||||
** Purpose: processes a new line of data from input file
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int n;
|
||||
switch (sect)
|
||||
{
|
||||
case _TITLE: if (Ntitle < 3)
|
||||
{
|
||||
n = strlen(line);
|
||||
if (line[n-1] == 10) line[n-1] = ' ';
|
||||
strncpy(Title[Ntitle],line,MAXMSG);
|
||||
Ntitle++;
|
||||
}
|
||||
return(0);
|
||||
case _JUNCTIONS: return(juncdata());
|
||||
case _RESERVOIRS:
|
||||
case _TANKS: return(tankdata());
|
||||
case _PIPES: return(pipedata());
|
||||
case _PUMPS: return(pumpdata());
|
||||
case _VALVES: return(valvedata());
|
||||
case _PATTERNS: return(patterndata());
|
||||
case _CURVES: return(curvedata());
|
||||
case _DEMANDS: return(demanddata());
|
||||
case _CONTROLS: return(controldata());
|
||||
case _RULES: return(ruledata()); /* See RULES.C */
|
||||
case _SOURCES: return(sourcedata());
|
||||
case _EMITTERS: return(emitterdata());
|
||||
case _QUALITY: return(qualdata());
|
||||
case _STATUS: return(statusdata());
|
||||
case _ROUGHNESS: return(0);
|
||||
case _ENERGY: return(energydata());
|
||||
case _REACTIONS: return(reactdata());
|
||||
case _MIXING: return(mixingdata());
|
||||
case _REPORT: return(reportdata());
|
||||
case _TIMES: return(timedata());
|
||||
case _OPTIONS: return(optiondata());
|
||||
|
||||
/* Data in these sections are not used for any computations */
|
||||
case _COORDS: return(0);
|
||||
case _LABELS: return(0);
|
||||
case _TAGS: return(0);
|
||||
case _VERTICES: return(0);
|
||||
case _BACKDROP: return(0);
|
||||
}
|
||||
return(201);
|
||||
} /* end of newline */
|
||||
|
||||
|
||||
int getpumpparams(void)
|
||||
/*
|
||||
**-------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: returns error code
|
||||
** Purpose: computes & checks pump curve parameters
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i, j = 0, k, m, n = 0;
|
||||
double a,b,c,
|
||||
h0 = 0.0, h1 = 0.0, h2 = 0.0, q1 = 0.0, q2 = 0.0;
|
||||
|
||||
for (i=1; i<=Npumps; i++)
|
||||
{
|
||||
k = Pump[i].Link;
|
||||
if (Pump[i].Ptype == CONST_HP) /* Constant Hp pump */
|
||||
{
|
||||
Pump[i].H0 = 0.0;
|
||||
Pump[i].R = -8.814*Link[k].Km;
|
||||
Pump[i].N = -1.0;
|
||||
Pump[i].Hmax = BIG; /* No head limit */
|
||||
Pump[i].Qmax = BIG; /* No flow limit */
|
||||
Pump[i].Q0 = 1.0; /* Init. flow = 1 cfs */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Set parameters for pump curves */
|
||||
else if (Pump[i].Ptype == NOCURVE) /* Pump curve specified */
|
||||
{
|
||||
j = Pump[i].Hcurve; /* Get index of head curve */
|
||||
if (j == 0)
|
||||
{ /* Error: No head curve */
|
||||
sprintf(Msg,ERR226,Link[k].ID);
|
||||
writeline(Msg);
|
||||
return(200);
|
||||
}
|
||||
n = Curve[j].Npts;
|
||||
if (n == 1) /* Only a single h-q point */
|
||||
{ /* supplied so use generic */
|
||||
Pump[i].Ptype = POWER_FUNC; /* power function curve. */
|
||||
q1 = Curve[j].X[0];
|
||||
h1 = Curve[j].Y[0];
|
||||
h0 = 1.33334*h1;
|
||||
q2 = 2.0*q1;
|
||||
h2 = 0.0;
|
||||
}
|
||||
else if (n == 3
|
||||
&& Curve[j].X[0] == 0.0) /* 3 h-q points supplied with */
|
||||
{ /* shutoff head so use fitted */
|
||||
Pump[i].Ptype = POWER_FUNC; /* power function curve. */
|
||||
h0 = Curve[j].Y[0];
|
||||
q1 = Curve[j].X[1];
|
||||
h1 = Curve[j].Y[1];
|
||||
q2 = Curve[j].X[2];
|
||||
h2 = Curve[j].Y[2];
|
||||
}
|
||||
else Pump[i].Ptype = CUSTOM; /* Else use custom pump curve.*/
|
||||
|
||||
/* Compute shape factors & limits of power function pump curves */
|
||||
if (Pump[i].Ptype == POWER_FUNC)
|
||||
{
|
||||
if (!powercurve(h0,h1,h2,q1,q2,&a,&b,&c))
|
||||
{ /* Error: Invalid curve */
|
||||
sprintf(Msg,ERR227,Link[k].ID);
|
||||
writeline(Msg);
|
||||
return(200);
|
||||
}
|
||||
else
|
||||
{
|
||||
Pump[i].H0 = -a;
|
||||
Pump[i].R = -b;
|
||||
Pump[i].N = c;
|
||||
Pump[i].Q0 = q1;
|
||||
Pump[i].Qmax = pow((-a/b),(1.0/c));
|
||||
Pump[i].Hmax = h0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Assign limits to custom pump curves */
|
||||
if (Pump[i].Ptype == CUSTOM)
|
||||
{
|
||||
for (m=1; m<n; m++)
|
||||
{
|
||||
if (Curve[j].Y[m] >= Curve[j].Y[m-1])
|
||||
{ /* Error: Invalid curve */
|
||||
sprintf(Msg,ERR227,Link[k].ID);
|
||||
writeline(Msg);
|
||||
return(200);
|
||||
}
|
||||
}
|
||||
Pump[i].Qmax = Curve[j].X[n-1];
|
||||
Pump[i].Q0 = (Curve[j].X[0] + Pump[i].Qmax)/2.0;
|
||||
Pump[i].Hmax = Curve[j].Y[0];
|
||||
}
|
||||
} /* Next pump */
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
int addnodeID(int n, char *id)
|
||||
/*
|
||||
**-------------------------------------------------------------
|
||||
** Input: n = node index
|
||||
** id = ID label
|
||||
** Output: returns 0 if ID already in use, 1 if not
|
||||
** Purpose: adds a node ID to the Node Hash Table
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
if (findnode(id)) return(0); /* see EPANET.C */
|
||||
strncpy(Node[n].ID, id, MAXID);
|
||||
HTinsert(Nht, Node[n].ID, n); /* see HASH.C */
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int addlinkID(int n, char *id)
|
||||
/*
|
||||
**-------------------------------------------------------------
|
||||
** Input: n = link index
|
||||
** id = ID label
|
||||
** Output: returns 0 if ID already in use, 1 if not
|
||||
** Purpose: adds a link ID to the Link Hash Table
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
if (findlink(id)) return(0); /* see EPANET.C */
|
||||
strncpy(Link[n].ID, id, MAXID);
|
||||
HTinsert(Lht, Link[n].ID, n); /* see HASH.C */
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int addpattern(char *id)
|
||||
/*
|
||||
**-------------------------------------------------------------
|
||||
** Input: id = pattern ID label
|
||||
** Output: returns error code
|
||||
** Purpose: adds a new pattern to the database
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
STmplist *p;
|
||||
|
||||
/* Check if ID is same as last one processed */
|
||||
if (Patlist != NULL && strcmp(id,Patlist->ID) == 0) return(0);
|
||||
|
||||
/* Check that pattern was not already created */
|
||||
if (findID(id,Patlist) == NULL)
|
||||
{
|
||||
|
||||
/* Update pattern count & create new list element */
|
||||
(MaxPats)++;
|
||||
p = (STmplist *) malloc(sizeof(STmplist));
|
||||
if (p == NULL) return(101);
|
||||
|
||||
/* Initialize list element properties */
|
||||
else
|
||||
{
|
||||
p->i = MaxPats;
|
||||
strncpy(p->ID,id,MAXID);
|
||||
p->x = NULL;
|
||||
p->y = NULL;
|
||||
p->next = Patlist;
|
||||
Patlist = p;
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
int addcurve(char *id)
|
||||
/*
|
||||
**-------------------------------------------------------------
|
||||
** Input: id = curve ID label
|
||||
** Output: returns error code
|
||||
** Purpose: adds a new curve to the database
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
STmplist *c;
|
||||
|
||||
/* Check if ID is same as last one processed */
|
||||
if (Curvelist != NULL && strcmp(id,Curvelist->ID) == 0) return(0);
|
||||
|
||||
/* Check that curve was not already created */
|
||||
if (findID(id,Curvelist) == NULL)
|
||||
{
|
||||
|
||||
/* Update curve count & create new list element */
|
||||
(MaxCurves)++;
|
||||
c = (STmplist *) malloc(sizeof(STmplist));
|
||||
if (c == NULL) return(101);
|
||||
|
||||
/* Initialize list element properties */
|
||||
else
|
||||
{
|
||||
c->i = MaxCurves;
|
||||
strncpy(c->ID,id,MAXID);
|
||||
c->x = NULL;
|
||||
c->y = NULL;
|
||||
c->next = Curvelist;
|
||||
Curvelist = c;
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
STmplist *findID(char *id, STmplist *list)
|
||||
/*
|
||||
**-------------------------------------------------------------
|
||||
** Input: id = ID label
|
||||
** list = pointer to head of a temporary list
|
||||
** Output: returns list item with requested ID label
|
||||
** Purpose: searches for item in temporary list
|
||||
**-------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
STmplist *item;
|
||||
for (item = list; item != NULL; item = item->next)
|
||||
{
|
||||
if (strcmp(item->ID,id) == 0)
|
||||
{
|
||||
return(item);
|
||||
}
|
||||
}
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
|
||||
int unlinked()
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: returns error code if any unlinked junctions found
|
||||
** Purpose: checks for unlinked junctions in network
|
||||
**
|
||||
** NOTE: unlinked tanks have no effect on computations.
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
char *marked;
|
||||
int i,err, errcode;
|
||||
errcode = 0;
|
||||
err = 0;
|
||||
marked = (char *) calloc(Nnodes+1,sizeof(char));
|
||||
ERRCODE(MEMCHECK(marked));
|
||||
if (!errcode)
|
||||
{
|
||||
memset(marked,0,(Nnodes+1)*sizeof(char));
|
||||
for (i=1; i<=Nlinks; i++) /* Mark end nodes of each link */
|
||||
{
|
||||
marked[Link[i].N1]++;
|
||||
marked[Link[i].N2]++;
|
||||
}
|
||||
for (i=1; i<=Njuncs; i++) /* Check each junction */
|
||||
{
|
||||
if (marked[i] == 0) /* If not marked then error */
|
||||
{
|
||||
err++;
|
||||
sprintf(Msg,ERR233,Node[i].ID);
|
||||
writeline(Msg);
|
||||
}
|
||||
if (err >= MAXERRS) break;
|
||||
}
|
||||
if (err > 0) errcode = 200;
|
||||
}
|
||||
free(marked);
|
||||
return(errcode);
|
||||
} /* End of unlinked */
|
||||
|
||||
|
||||
int getpatterns(void)
|
||||
/*
|
||||
**-----------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: returns error code
|
||||
** Purpose: retrieves pattern data from temporary linked list
|
||||
**-------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i,j;
|
||||
SFloatlist *f;
|
||||
STmplist *pat;
|
||||
|
||||
/* Start at head of list */
|
||||
pat = Patlist;
|
||||
|
||||
/* Traverse list of patterns */
|
||||
while (pat != NULL)
|
||||
{
|
||||
|
||||
/* Get index of current pattern in Pattern array */
|
||||
i = pat->i;
|
||||
|
||||
/* Check if this is the default pattern */
|
||||
if (strcmp(pat->ID, DefPatID) == 0) DefPat = i;
|
||||
if (i >= 0 && i <= MaxPats)
|
||||
{
|
||||
/* Save pattern ID */
|
||||
strcpy(Pattern[i].ID, pat->ID);
|
||||
|
||||
/* Give pattern a length of at least 1 */
|
||||
if (Pattern[i].Length == 0) Pattern[i].Length = 1;
|
||||
Pattern[i].F = (double *) calloc(Pattern[i].Length, sizeof(double));
|
||||
if (Pattern[i].F == NULL) return(101);
|
||||
|
||||
/* Start at head of pattern multiplier list */
|
||||
/* (which holds multipliers in reverse order)*/
|
||||
f = pat->x;
|
||||
j = Pattern[i].Length - 1;
|
||||
|
||||
/* Use at least one multiplier equal to 1.0 */
|
||||
if (f == NULL) Pattern[i].F[0] = 1.0;
|
||||
|
||||
/* Traverse list, storing multipliers in Pattern array */
|
||||
else while (f != NULL && j >= 0)
|
||||
{
|
||||
Pattern[i].F[j] = f->value;
|
||||
f = f->next;
|
||||
j--;
|
||||
}
|
||||
}
|
||||
pat = pat->next;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
int getcurves(void)
|
||||
/*
|
||||
**-----------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: returns error code
|
||||
** Purpose: retrieves curve data from temporary linked list
|
||||
**-----------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i,j;
|
||||
double x;
|
||||
SFloatlist *fx, *fy;
|
||||
STmplist *c;
|
||||
|
||||
/* Start at head of curve list */
|
||||
c = Curvelist;
|
||||
|
||||
/* Traverse list of curves */
|
||||
while (c != NULL)
|
||||
{
|
||||
i = c->i;
|
||||
if (i >= 1 && i <= MaxCurves)
|
||||
{
|
||||
|
||||
/* Save curve ID */
|
||||
strcpy(Curve[i].ID, c->ID);
|
||||
|
||||
/* Check that curve has data points */
|
||||
if (Curve[i].Npts <= 0)
|
||||
{
|
||||
sprintf(Msg,ERR230,c->ID);
|
||||
writeline(Msg);
|
||||
return(200);
|
||||
}
|
||||
|
||||
/* Allocate memory for curve data */
|
||||
Curve[i].X = (double *) calloc(Curve[i].Npts, sizeof(double));
|
||||
Curve[i].Y = (double *) calloc(Curve[i].Npts, sizeof(double));
|
||||
if (Curve[i].X == NULL || Curve[i].Y == NULL) return(101);
|
||||
|
||||
/* Traverse list of x,y data */
|
||||
x = BIG;
|
||||
fx = c->x;
|
||||
fy = c->y;
|
||||
j = Curve[i].Npts - 1;
|
||||
while (fx != NULL && fy != NULL && j >= 0)
|
||||
{
|
||||
|
||||
/* Check that x data is in ascending order */
|
||||
if (fx->value >= x)
|
||||
{
|
||||
sprintf(Msg,ERR230,c->ID);
|
||||
writeline(Msg);
|
||||
return(200);
|
||||
}
|
||||
x = fx->value;
|
||||
|
||||
/* Save x,y data in Curve structure */
|
||||
Curve[i].X[j] = fx->value;
|
||||
fx = fx->next;
|
||||
Curve[i].Y[j] = fy->value;
|
||||
fy = fy->next;
|
||||
j--;
|
||||
}
|
||||
}
|
||||
c = c->next;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
int findmatch(char *line, char *keyword[])
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: *line = line from input file
|
||||
** *keyword[] = list of NULL terminated keywords
|
||||
** Output: returns index of matching keyword or
|
||||
** -1 if no match found
|
||||
** Purpose: determines which keyword appears on input line
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i = 0;
|
||||
while (keyword[i] != NULL)
|
||||
{
|
||||
if (match(line,keyword[i])) return(i);
|
||||
i++;
|
||||
}
|
||||
return(-1);
|
||||
} /* end of findmatch */
|
||||
|
||||
|
||||
|
||||
int match(char *str, char *substr)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: *str = string being searched
|
||||
** *substr = substring being searched for
|
||||
** Output: returns 1 if substr found in str, 0 if not
|
||||
** Purpose: sees if substr matches any part of str
|
||||
**
|
||||
** (Not case sensitive)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i,j;
|
||||
|
||||
/*** Updated 9/7/00 ***/
|
||||
/* Fail if substring is empty */
|
||||
if (!substr[0]) return(0);
|
||||
|
||||
/* Skip leading blanks of str. */
|
||||
for (i=0; str[i]; i++)
|
||||
if (str[i] != ' ') break;
|
||||
|
||||
/* Check if substr matches remainder of str. */
|
||||
for (i=i,j=0; substr[j]; i++,j++)
|
||||
if (!str[i] || UCHAR(str[i]) != UCHAR(substr[j]))
|
||||
return(0);
|
||||
return(1);
|
||||
} /* end of match */
|
||||
|
||||
|
||||
/*** Updated 10/25/00 ***/
|
||||
/* The gettokens function has been totally re-written. */
|
||||
|
||||
int gettokens(char *s)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: *s = string to be tokenized
|
||||
** Output: returns number of tokens in s
|
||||
** Purpose: scans string for tokens, saving pointers to them
|
||||
** in module global variable Tok[]
|
||||
**
|
||||
** Tokens can be separated by the characters listed in SEPSTR
|
||||
** (spaces, tabs, newline, carriage return) which is defined
|
||||
** in TYPES.H. Text between quotes is treated as a single token.
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int len, m, n;
|
||||
char *c;
|
||||
|
||||
/* Begin with no tokens */
|
||||
for (n=0; n<MAXTOKS; n++) Tok[n] = NULL;
|
||||
n = 0;
|
||||
|
||||
/* Truncate s at start of comment */
|
||||
c = strchr(s,';');
|
||||
if (c) *c = '\0';
|
||||
len = strlen(s);
|
||||
|
||||
/* Scan s for tokens until nothing left */
|
||||
while (len > 0 && n < MAXTOKS)
|
||||
{
|
||||
m = strcspn(s,SEPSTR); /* Find token length */
|
||||
len -= m+1; /* Update length of s */
|
||||
if (m == 0) s++; /* No token found */
|
||||
else
|
||||
{
|
||||
if (*s == '"') /* Token begins with quote */
|
||||
{
|
||||
s++; /* Start token after quote */
|
||||
m = strcspn(s,"\"\n\r"); /* Find end quote (or EOL) */
|
||||
}
|
||||
s[m] = '\0'; /* Null-terminate the token */
|
||||
Tok[n] = s; /* Save pointer to token */
|
||||
n++; /* Update token count */
|
||||
s += m+1; /* Begin next token */
|
||||
}
|
||||
}
|
||||
return(n);
|
||||
} /* End of gettokens */
|
||||
|
||||
|
||||
double hour(char *time, char *units)
|
||||
/*
|
||||
**---------------------------------------------------------
|
||||
** Input: *time = string containing a time value
|
||||
** *units = string containing time units
|
||||
** Output: returns numerical value of time in hours,
|
||||
** or -1 if an error occurs
|
||||
** Purpose: converts time from units to hours
|
||||
**---------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int n;
|
||||
double y[3];
|
||||
char *s;
|
||||
|
||||
/* Separate clock time into hrs, min, sec. */
|
||||
for (n=0; n<3; n++) y[n] = 0.0;
|
||||
n = 0;
|
||||
s = strtok(time,":");
|
||||
while (s != NULL && n <= 3)
|
||||
{
|
||||
if (!getfloat(s,&y[n])) return(-1.0);
|
||||
s = strtok(NULL,":");
|
||||
n++;
|
||||
}
|
||||
|
||||
/* If decimal time with units attached then convert to hours. */
|
||||
if (n == 1)
|
||||
{
|
||||
/*if (units[0] == '\0') return(y[0]);*/
|
||||
if (strlen(units) == 0) return(y[0]);
|
||||
if (match(units,w_SECONDS)) return(y[0]/3600.0);
|
||||
if (match(units,w_MINUTES)) return(y[0]/60.0);
|
||||
if (match(units,w_HOURS)) return(y[0]);
|
||||
if (match(units,w_DAYS)) return(y[0]*24.0);
|
||||
}
|
||||
|
||||
/* Convert hh:mm:ss format to decimal hours */
|
||||
if (n > 1) y[0] = y[0] + y[1]/60.0 + y[2]/3600.0;
|
||||
|
||||
/* If am/pm attached then adjust hour accordingly */
|
||||
/* (12 am is midnight, 12 pm is noon) */
|
||||
if (units[0] == '\0') return(y[0]);
|
||||
if (match(units,w_AM))
|
||||
{
|
||||
if (y[0] >= 13.0) return(-1.0);
|
||||
if (y[0] >= 12.0) return(y[0]-12.0);
|
||||
else return(y[0]);
|
||||
}
|
||||
if (match(units,w_PM))
|
||||
{
|
||||
if (y[0] >= 13.0) return(-1.0);
|
||||
if (y[0] >= 12.0) return(y[0]);
|
||||
else return(y[0]+12.0);
|
||||
}
|
||||
return(-1.0);
|
||||
} /* end of hour */
|
||||
|
||||
|
||||
int getfloat(char *s, double *y)
|
||||
/*
|
||||
**-----------------------------------------------------------
|
||||
** Input: *s = character string
|
||||
** Output: *y = floating point number
|
||||
** returns 1 if conversion successful, 0 if not
|
||||
** Purpose: converts string to floating point number
|
||||
**-----------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
char *endptr;
|
||||
*y = (double) strtod(s,&endptr);
|
||||
if (*endptr > 0) return(0);
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int setreport(char *s)
|
||||
/*
|
||||
**-----------------------------------------------------------
|
||||
** Input: *s = report format command
|
||||
** Output: none
|
||||
** Returns: error code
|
||||
** Purpose: processes a report formatting command
|
||||
** issued by the ENsetreport function
|
||||
**-----------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Ntokens = gettokens(s);
|
||||
return(reportdata());
|
||||
}
|
||||
|
||||
|
||||
void inperrmsg(int err, int sect, char *line)
|
||||
/*
|
||||
**-------------------------------------------------------------
|
||||
** Input: err = error code
|
||||
** sect = input data section
|
||||
** *line = line from input file
|
||||
** Output: none
|
||||
** Purpose: displays input error message
|
||||
**-------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
char fmt[MAXMSG+1];
|
||||
char id[MAXMSG+1];
|
||||
|
||||
/* Retrieve ID label of object with input error */
|
||||
/* (No ID used for CONTROLS or REPORT sections).*/
|
||||
if (sect == _CONTROLS || sect == _REPORT) strcpy(id,"");
|
||||
else if (sect == _ENERGY) strcpy(id,Tok[1]);
|
||||
else strcpy(id,Tok[0]);
|
||||
|
||||
/* Copy error messge to string variable fmt */
|
||||
switch (err)
|
||||
{
|
||||
case 201: strcpy(fmt,ERR201); break;
|
||||
case 202: strcpy(fmt,ERR202); break;
|
||||
case 203: strcpy(fmt,ERR203); break;
|
||||
case 204: strcpy(fmt,ERR204); break;
|
||||
case 205: strcpy(fmt,ERR205); break;
|
||||
case 206: strcpy(fmt,ERR206); break;
|
||||
case 207: strcpy(fmt,ERR207); break;
|
||||
case 208: strcpy(fmt,ERR208); break;
|
||||
case 209: strcpy(fmt,ERR209); break;
|
||||
case 210: strcpy(fmt,ERR210); break;
|
||||
case 211: strcpy(fmt,ERR211); break;
|
||||
case 212: strcpy(fmt,ERR212); break;
|
||||
case 213: strcpy(id,"");
|
||||
strcpy(fmt,ERR213); break;
|
||||
case 214: strcpy(id,"");
|
||||
strcpy(fmt,ERR214); break;
|
||||
case 215: strcpy(fmt,ERR215); break;
|
||||
case 216: strcpy(fmt,ERR216); break;
|
||||
case 217: strcpy(fmt,ERR217); break;
|
||||
case 219: strcpy(fmt,ERR219); break;
|
||||
case 220: strcpy(fmt,ERR220); break;
|
||||
|
||||
/*** Updated 10/25/00 ***/
|
||||
case 222: strcpy(fmt,ERR222); break;
|
||||
|
||||
default: return;
|
||||
}
|
||||
|
||||
/* Write error message to Report file */
|
||||
sprintf(Msg,fmt,RptSectTxt[sect],id);
|
||||
writeline(Msg);
|
||||
|
||||
/* Echo input line for syntax errors, and */
|
||||
/* errors in CONTROLS and OPTIONS sections. */
|
||||
if (sect == _CONTROLS || err == 201 || err == 213) writeline(line);
|
||||
else writeline("");
|
||||
}
|
||||
|
||||
/********************** END OF INPUT2.C ************************/
|
||||
|
||||
|
||||
1854
src/input3.c
Normal file
1854
src/input3.c
Normal file
File diff suppressed because it is too large
Load Diff
204
src/mempool.c
Normal file
204
src/mempool.c
Normal file
@@ -0,0 +1,204 @@
|
||||
/* mempool.c
|
||||
**
|
||||
** A simple fast memory allocation package.
|
||||
**
|
||||
** By Steve Hill in Graphics Gems III, David Kirk (ed.),
|
||||
** Academic Press, Boston, MA, 1992
|
||||
**
|
||||
** Modified by Lew Rossman, 8/13/94.
|
||||
**
|
||||
** AllocInit() - create an alloc pool, returns the old pool handle
|
||||
** Alloc() - allocate memory
|
||||
** AllocReset() - reset the current pool
|
||||
** AllocSetPool() - set the current pool
|
||||
** AllocFree() - free the memory used by the current pool.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
#include "mempool.h"
|
||||
|
||||
/*
|
||||
** ALLOC_BLOCK_SIZE - adjust this size to suit your installation - it
|
||||
** should be reasonably large otherwise you will be mallocing a lot.
|
||||
*/
|
||||
|
||||
#define ALLOC_BLOCK_SIZE 64000 /*(62*1024)*/
|
||||
|
||||
/*
|
||||
** alloc_hdr_t - Header for each block of memory.
|
||||
*/
|
||||
|
||||
typedef struct alloc_hdr_s
|
||||
{
|
||||
struct alloc_hdr_s *next; /* Next Block */
|
||||
char *block, /* Start of block */
|
||||
*free, /* Next free in block */
|
||||
*end; /* block + block size */
|
||||
} alloc_hdr_t;
|
||||
|
||||
/*
|
||||
** alloc_root_t - Header for the whole pool.
|
||||
*/
|
||||
|
||||
typedef struct alloc_root_s
|
||||
{
|
||||
alloc_hdr_t *first, /* First header in pool */
|
||||
*current; /* Current header */
|
||||
} alloc_root_t;
|
||||
|
||||
/*
|
||||
** root - Pointer to the current pool.
|
||||
*/
|
||||
|
||||
static alloc_root_t *root;
|
||||
|
||||
|
||||
/*
|
||||
** AllocHdr()
|
||||
**
|
||||
** Private routine to allocate a header and memory block.
|
||||
*/
|
||||
|
||||
static alloc_hdr_t *AllocHdr(void);
|
||||
|
||||
static alloc_hdr_t * AllocHdr()
|
||||
{
|
||||
alloc_hdr_t *hdr;
|
||||
char *block;
|
||||
|
||||
block = (char *) malloc(ALLOC_BLOCK_SIZE);
|
||||
hdr = (alloc_hdr_t *) malloc(sizeof(alloc_hdr_t));
|
||||
|
||||
if (hdr == NULL || block == NULL) return(NULL);
|
||||
hdr->block = block;
|
||||
hdr->free = block;
|
||||
hdr->next = NULL;
|
||||
hdr->end = block + ALLOC_BLOCK_SIZE;
|
||||
|
||||
return(hdr);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** AllocInit()
|
||||
**
|
||||
** Create a new memory pool with one block.
|
||||
** Returns pointer to the new pool.
|
||||
*/
|
||||
|
||||
alloc_handle_t * AllocInit()
|
||||
{
|
||||
alloc_handle_t *newpool;
|
||||
|
||||
root = (alloc_root_t *) malloc(sizeof(alloc_root_t));
|
||||
if (root == NULL) return(NULL);
|
||||
if ( (root->first = AllocHdr()) == NULL) return(NULL);
|
||||
root->current = root->first;
|
||||
newpool = (alloc_handle_t *) root;
|
||||
return(newpool);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Alloc()
|
||||
**
|
||||
** Use as a direct replacement for malloc(). Allocates
|
||||
** memory from the current pool.
|
||||
*/
|
||||
|
||||
char * Alloc(long size)
|
||||
{
|
||||
alloc_hdr_t *hdr = root->current;
|
||||
char *ptr;
|
||||
|
||||
/*
|
||||
** Align to 4 byte boundary - should be ok for most machines.
|
||||
** Change this if your machine has weird alignment requirements.
|
||||
*/
|
||||
size = (size + 3) & 0xfffffffc;
|
||||
|
||||
ptr = hdr->free;
|
||||
hdr->free += size;
|
||||
|
||||
/* Check if the current block is exhausted. */
|
||||
|
||||
if (hdr->free >= hdr->end)
|
||||
{
|
||||
/* Is the next block already allocated? */
|
||||
|
||||
if (hdr->next != NULL)
|
||||
{
|
||||
/* re-use block */
|
||||
hdr->next->free = hdr->next->block;
|
||||
root->current = hdr->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* extend the pool with a new block */
|
||||
if ( (hdr->next = AllocHdr()) == NULL) return(NULL);
|
||||
root->current = hdr->next;
|
||||
}
|
||||
|
||||
/* set ptr to the first location in the next block */
|
||||
ptr = root->current->free;
|
||||
root->current->free += size;
|
||||
}
|
||||
|
||||
/* Return pointer to allocated memory. */
|
||||
|
||||
return(ptr);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** AllocSetPool()
|
||||
**
|
||||
** Change the current pool. Return the old pool.
|
||||
*/
|
||||
|
||||
alloc_handle_t * AllocSetPool(alloc_handle_t *newpool)
|
||||
{
|
||||
alloc_handle_t *old = (alloc_handle_t *) root;
|
||||
root = (alloc_root_t *) newpool;
|
||||
return(old);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** AllocReset()
|
||||
**
|
||||
** Reset the current pool for re-use. No memory is freed,
|
||||
** so this is very fast.
|
||||
*/
|
||||
|
||||
void AllocReset()
|
||||
{
|
||||
root->current = root->first;
|
||||
root->current->free = root->current->block;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** AllocFreePool()
|
||||
**
|
||||
** Free the memory used by the current pool.
|
||||
** Don't use where AllocReset() could be used.
|
||||
*/
|
||||
|
||||
void AllocFreePool()
|
||||
{
|
||||
alloc_hdr_t *tmp,
|
||||
*hdr = root->first;
|
||||
|
||||
while (hdr != NULL)
|
||||
{
|
||||
tmp = hdr->next;
|
||||
free((char *) hdr->block);
|
||||
free((char *) hdr);
|
||||
hdr = tmp;
|
||||
}
|
||||
free((char *) root);
|
||||
root = NULL;
|
||||
}
|
||||
19
src/mempool.h
Normal file
19
src/mempool.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
** mempool.h
|
||||
**
|
||||
** Header for mempool.c
|
||||
**
|
||||
** The type alloc_handle_t provides an opaque reference to the
|
||||
** alloc pool - only the alloc routines know its structure.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
long dummy;
|
||||
} alloc_handle_t;
|
||||
|
||||
alloc_handle_t *AllocInit(void);
|
||||
char *Alloc(long);
|
||||
alloc_handle_t *AllocSetPool(alloc_handle_t *);
|
||||
void AllocReset(void);
|
||||
void AllocFreePool(void);
|
||||
697
src/output.c
Normal file
697
src/output.c
Normal file
@@ -0,0 +1,697 @@
|
||||
/*
|
||||
*********************************************************************
|
||||
|
||||
OUTPUT.C -- Binary File Transfer Routines for EPANET Program
|
||||
|
||||
VERSION: 2.00
|
||||
DATE: 5/8/00
|
||||
8/15/07 (2.00.11)
|
||||
AUTHOR: L. Rossman
|
||||
US EPA - NRMRL
|
||||
|
||||
********************************************************************
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <math.h>
|
||||
#include "text.h"
|
||||
#include "types.h"
|
||||
#include "funcs.h"
|
||||
#define EXTERN extern
|
||||
#include "hash.h"
|
||||
#include "vars.h"
|
||||
|
||||
/* Macro to write x[1] to x[n] to file OutFile: */
|
||||
#define FSAVE(n) (fwrite(x+1,sizeof(REAL4),(n),OutFile))
|
||||
|
||||
int savenetdata()
|
||||
/*
|
||||
**---------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: returns error code
|
||||
** Purpose: saves input data in original units to binary
|
||||
** output file using fixed-sized (4-byte) records
|
||||
**---------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i,nmax;
|
||||
INT4 *ibuf;
|
||||
REAL4 *x;
|
||||
int errcode = 0;
|
||||
|
||||
/* Allocate buffer arrays */
|
||||
nmax = MAX(Nnodes,Nlinks) + 1;
|
||||
nmax = MAX(nmax,15);
|
||||
ibuf = (INT4 *) calloc(nmax, sizeof(INT4));
|
||||
x = (REAL4 *) calloc(nmax, sizeof(REAL4));
|
||||
ERRCODE(MEMCHECK(ibuf));
|
||||
ERRCODE(MEMCHECK(x));
|
||||
|
||||
if (!errcode)
|
||||
{
|
||||
/* Write integer variables to OutFile */
|
||||
ibuf[0] = MAGICNUMBER;
|
||||
|
||||
/*** CODEVERSION replaces VERSION ***/ //(2.00.11 - LR)
|
||||
ibuf[1] = CODEVERSION; //(2.00.11 - LR)
|
||||
|
||||
ibuf[2] = Nnodes;
|
||||
ibuf[3] = Ntanks;
|
||||
ibuf[4] = Nlinks;
|
||||
ibuf[5] = Npumps;
|
||||
ibuf[6] = Nvalves;
|
||||
ibuf[7] = Qualflag;
|
||||
ibuf[8] = TraceNode;
|
||||
ibuf[9] = Flowflag;
|
||||
ibuf[10] = Pressflag;
|
||||
ibuf[11] = Tstatflag;
|
||||
ibuf[12] = Rstart;
|
||||
ibuf[13] = Rstep;
|
||||
ibuf[14] = Dur;
|
||||
fwrite(ibuf,sizeof(INT4),15,OutFile);
|
||||
|
||||
/* Write string variables to OutFile */
|
||||
fwrite(Title[0],sizeof(char),MAXMSG+1,OutFile);
|
||||
fwrite(Title[1],sizeof(char),MAXMSG+1,OutFile);
|
||||
fwrite(Title[2],sizeof(char),MAXMSG+1,OutFile);
|
||||
fwrite(InpFname,sizeof(char),MAXFNAME+1,OutFile);
|
||||
fwrite(Rpt2Fname,sizeof(char),MAXFNAME+1,OutFile);
|
||||
fwrite(ChemName,sizeof(char),MAXID+1,OutFile);
|
||||
fwrite(Field[QUALITY].Units,sizeof(char),MAXID+1,OutFile);
|
||||
|
||||
/* Write node ID information to OutFile */
|
||||
for (i=1; i<=Nnodes; i++)
|
||||
fwrite(Node[i].ID, MAXID+1, 1, OutFile);
|
||||
|
||||
/* Write link information to OutFile */
|
||||
/* (Note: first transfer values to buffer array,*/
|
||||
/* then fwrite buffer array at offset of 1 ) */
|
||||
for (i=1; i<=Nlinks; i++)
|
||||
fwrite(Link[i].ID, MAXID+1, 1, OutFile);
|
||||
for (i=1; i<=Nlinks; i++) ibuf[i] = Link[i].N1;
|
||||
fwrite(ibuf+1,sizeof(INT4),Nlinks,OutFile);
|
||||
for (i=1; i<=Nlinks; i++) ibuf[i] = Link[i].N2;
|
||||
fwrite(ibuf+1,sizeof(INT4),Nlinks,OutFile);
|
||||
for (i=1; i<=Nlinks; i++) ibuf[i] = Link[i].Type;
|
||||
fwrite(ibuf+1,sizeof(INT4),Nlinks,OutFile);
|
||||
|
||||
/* Write tank information to OutFile.*/
|
||||
for (i=1; i<=Ntanks; i++) ibuf[i] = Tank[i].Node;
|
||||
fwrite(ibuf+1,sizeof(INT4),Ntanks,OutFile);
|
||||
for (i=1; i<=Ntanks; i++) x[i] = (REAL4)Tank[i].A;
|
||||
FSAVE(Ntanks);
|
||||
|
||||
/* Save node elevations to OutFile.*/
|
||||
for (i=1; i<=Nnodes; i++) x[i] = (REAL4)(Node[i].El*Ucf[ELEV]);
|
||||
FSAVE(Nnodes);
|
||||
|
||||
/* Save link lengths & diameters to OutFile.*/
|
||||
for (i=1; i<=Nlinks; i++) x[i] = (REAL4)(Link[i].Len*Ucf[ELEV]);
|
||||
FSAVE(Nlinks);
|
||||
for (i=1; i<=Nlinks; i++)
|
||||
{
|
||||
if (Link[i].Type != PUMP)
|
||||
x[i] = (REAL4)(Link[i].Diam*Ucf[DIAM]);
|
||||
else
|
||||
x[i] = 0.0f;
|
||||
}
|
||||
if (FSAVE(Nlinks) < (unsigned)Nlinks) errcode = 308;
|
||||
}
|
||||
|
||||
/* Free memory used for buffer arrays */
|
||||
free(ibuf);
|
||||
free(x);
|
||||
return(errcode);
|
||||
}
|
||||
|
||||
|
||||
int savehyd(long *htime)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: *htime = current time
|
||||
** Output: returns error code
|
||||
** Purpose: saves current hydraulic solution to file HydFile
|
||||
** in binary format
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i;
|
||||
INT4 t;
|
||||
int errcode = 0;
|
||||
REAL4 *x = (REAL4 *) calloc(MAX(Nnodes,Nlinks) + 1, sizeof(REAL4));
|
||||
if ( x == NULL ) return 101;
|
||||
|
||||
/* Save current time (htime) */
|
||||
t = *htime;
|
||||
fwrite(&t,sizeof(INT4),1,HydFile);
|
||||
|
||||
/* Save current nodal demands (D) */
|
||||
for (i=1; i<=Nnodes; i++) x[i] = (REAL4)D[i];
|
||||
fwrite(x+1,sizeof(REAL4),Nnodes,HydFile);
|
||||
|
||||
/* Copy heads (H) to buffer of floats (x) and save buffer */
|
||||
for (i=1; i<=Nnodes; i++) x[i] = (REAL4)H[i];
|
||||
fwrite(x+1,sizeof(REAL4),Nnodes,HydFile);
|
||||
|
||||
/* Force flow in closed links to be zero then save flows */
|
||||
for (i=1; i<=Nlinks; i++)
|
||||
{
|
||||
if (S[i] <= CLOSED) x[i] = 0.0f;
|
||||
else x[i] = (REAL4)Q[i];
|
||||
}
|
||||
fwrite(x+1,sizeof(REAL4),Nlinks,HydFile);
|
||||
|
||||
/* Copy link status to buffer of floats (x) & write buffer */
|
||||
for (i=1; i<=Nlinks; i++) x[i] = (REAL4)S[i];
|
||||
fwrite(x+1,sizeof(REAL4),Nlinks,HydFile);
|
||||
|
||||
/* Save link settings & check for successful write-to-disk */
|
||||
/* (We assume that if any of the previous fwrites failed, */
|
||||
/* then this one will also fail.) */
|
||||
for (i=1; i<=Nlinks; i++) x[i] = (REAL4)K[i];
|
||||
if (fwrite(x+1,sizeof(REAL4),Nlinks,HydFile) < (unsigned)Nlinks)
|
||||
errcode = 308;
|
||||
free(x);
|
||||
return(errcode);
|
||||
} /* End of savehyd */
|
||||
|
||||
|
||||
int savehydstep(long *hydstep)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: *hydstep = next time step
|
||||
** Output: returns error code
|
||||
** Purpose: saves next hydraulic timestep to file HydFile
|
||||
** in binary format
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
INT4 t;
|
||||
int errcode = 0;
|
||||
t = *hydstep;
|
||||
if (fwrite(&t,sizeof(INT4),1,HydFile) < 1) errcode = 308;
|
||||
if (t == 0) fputc(EOFMARK, HydFile);
|
||||
return(errcode);
|
||||
}
|
||||
|
||||
|
||||
int saveenergy()
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: returns error code
|
||||
** Purpose: saves energy usage by each pump to OutFile
|
||||
** in binary format
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i,j;
|
||||
INT4 index;
|
||||
REAL4 x[6]; /* work array */
|
||||
double hdur, /* total duration in hours */
|
||||
t; /* pumping duration */
|
||||
|
||||
hdur = Dur / 3600.0;
|
||||
for (i=1; i<=Npumps; i++)
|
||||
{
|
||||
if (hdur == 0.0)
|
||||
{
|
||||
for (j=0; j<5; j++) x[j] = (REAL4)Pump[i].Energy[j];
|
||||
x[5] = (REAL4)(Pump[i].Energy[5]*24.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
t = Pump[i].Energy[0];
|
||||
x[0] = (REAL4)(t/hdur);
|
||||
x[1] = 0.0f;
|
||||
x[2] = 0.0f;
|
||||
x[3] = 0.0f;
|
||||
x[4] = 0.0f;
|
||||
if (t > 0.0)
|
||||
{
|
||||
x[1] = (REAL4)(Pump[i].Energy[1]/t);
|
||||
x[2] = (REAL4)(Pump[i].Energy[2]/t);
|
||||
x[3] = (REAL4)(Pump[i].Energy[3]/t);
|
||||
}
|
||||
x[4] = (REAL4)Pump[i].Energy[4];
|
||||
x[5] = (REAL4)(Pump[i].Energy[5]*24.0/hdur);
|
||||
}
|
||||
x[0] *= 100.0f;
|
||||
x[1] *= 100.0f;
|
||||
/* Compute Kw-hr per MilGal (or per cubic meter) */
|
||||
if (Unitsflag == SI) x[2] *= (REAL4)(1000.0/LPSperCFS/3600.0);
|
||||
else x[2] *= (REAL4)(1.0e6/GPMperCFS/60.0);
|
||||
for (j=0; j<6; j++) Pump[i].Energy[j] = x[j];
|
||||
index = Pump[i].Link;
|
||||
if (fwrite(&index,sizeof(INT4),1,OutFile) < 1) return(308);
|
||||
if (fwrite(x, sizeof(REAL4), 6, OutFile) < 6) return(308);
|
||||
}
|
||||
Emax = Emax*Dcost;
|
||||
x[0] = (REAL4)Emax;
|
||||
if (fwrite(&x[0], sizeof(REAL4), 1, OutFile) < 1) return(308);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
int readhyd(long *hydtime)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: *hydtime = time of hydraulic solution
|
||||
** Returns: 1 if successful, 0 if not
|
||||
** Purpose: reads hydraulic solution from file HydFile
|
||||
**
|
||||
** NOTE: A hydraulic solution consists of the current time
|
||||
** (hydtime), nodal demands (D) and heads (H), link
|
||||
** flows (Q), link status (S), and link settings (K).
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i;
|
||||
INT4 t;
|
||||
int result = 1;
|
||||
REAL4 *x = (REAL4 *) calloc(MAX(Nnodes,Nlinks) + 1, sizeof(REAL4));
|
||||
if ( x == NULL ) return 0;
|
||||
|
||||
if (fread(&t,sizeof(INT4),1,HydFile) < 1) result = 0;
|
||||
*hydtime = t;
|
||||
|
||||
if (fread(x+1,sizeof(REAL4),Nnodes,HydFile) < (unsigned)Nnodes) result = 0;
|
||||
else for (i=1; i<=Nnodes; i++) D[i] = x[i];
|
||||
|
||||
if (fread(x+1,sizeof(REAL4),Nnodes,HydFile) < (unsigned)Nnodes) result = 0;
|
||||
else for (i=1; i<=Nnodes; i++) H[i] = x[i];
|
||||
|
||||
if (fread(x+1,sizeof(REAL4),Nlinks,HydFile) < (unsigned)Nlinks) result = 0;
|
||||
else for (i=1; i<=Nlinks; i++) Q[i] = x[i];
|
||||
|
||||
if (fread(x+1,sizeof(REAL4),Nlinks,HydFile) < (unsigned)Nlinks) result = 0;
|
||||
else for (i=1; i<=Nlinks; i++) S[i] = (char) x[i];
|
||||
|
||||
if (fread(x+1,sizeof(REAL4),Nlinks,HydFile) < (unsigned)Nlinks) result = 0;
|
||||
else for (i=1; i<=Nlinks; i++) K[i] = x[i];
|
||||
|
||||
free(x);
|
||||
return result;
|
||||
} /* End of readhyd */
|
||||
|
||||
|
||||
int readhydstep(long *hydstep)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: *hydstep = next hydraulic time step (sec)
|
||||
** Returns: 1 if successful, 0 if not
|
||||
** Purpose: reads hydraulic time step from file HydFile
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
INT4 t;
|
||||
if (fread(&t,sizeof(INT4),1,HydFile) < 1) return(0);
|
||||
*hydstep = t;
|
||||
return(1);
|
||||
} /* End of readhydstep */
|
||||
|
||||
|
||||
int saveoutput()
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: returns error code
|
||||
** Purpose: writes simulation results to output file
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int j;
|
||||
int errcode = 0;
|
||||
REAL4 *x = (REAL4 *) calloc(MAX(Nnodes,Nlinks) + 1, sizeof(REAL4));
|
||||
if ( x == NULL ) return 101;
|
||||
|
||||
/* Write out node results, then link results */
|
||||
for (j=DEMAND; j<=QUALITY; j++) ERRCODE(nodeoutput(j,x,Ucf[j]));
|
||||
for (j=FLOW; j<=FRICTION; j++) ERRCODE(linkoutput(j,x,Ucf[j]));
|
||||
return(errcode);
|
||||
} /* End of saveoutput */
|
||||
|
||||
|
||||
int nodeoutput(int j, REAL4 *x, double ucf)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: j = type of node variable
|
||||
** *x = buffer for node values
|
||||
** ucf = units conversion factor
|
||||
** Output: returns error code
|
||||
** Purpose: writes results for node variable j to output file
|
||||
**-----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Load computed results (in proper units) into buffer x */
|
||||
switch(j)
|
||||
{
|
||||
case DEMAND: for (i=1; i<=Nnodes; i++)
|
||||
x[i] = (REAL4)(D[i]*ucf);
|
||||
break;
|
||||
case HEAD: for (i=1; i<=Nnodes; i++)
|
||||
x[i] = (REAL4)(H[i]*ucf);
|
||||
break;
|
||||
case PRESSURE: for (i=1; i<=Nnodes; i++)
|
||||
x[i] = (REAL4)((H[i] - Node[i].El)*ucf);
|
||||
break;
|
||||
case QUALITY: for (i=1; i<=Nnodes; i++)
|
||||
x[i] = (REAL4)(C[i]*ucf);
|
||||
}
|
||||
|
||||
/* Write x[1] to x[Nnodes] to output file */
|
||||
if (fwrite(x+1,sizeof(REAL4),Nnodes,TmpOutFile) < (unsigned)Nnodes)
|
||||
return(308);
|
||||
return(0);
|
||||
} /* End of nodeoutput */
|
||||
|
||||
|
||||
int linkoutput(int j, float *x, double ucf)
|
||||
/*
|
||||
**----------------------------------------------------------------
|
||||
** Input: j = type of link variable
|
||||
** *x = buffer for link values
|
||||
** ucf = units conversion factor
|
||||
** Output: returns error code
|
||||
** Purpose: writes results for link variable j to output file
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i;
|
||||
double a,h,q,f;
|
||||
|
||||
/* Load computed results (in proper units) into buffer x */
|
||||
switch(j)
|
||||
{
|
||||
case FLOW: for (i=1; i<=Nlinks; i++)
|
||||
x[i] = (REAL4)(Q[i]*ucf);
|
||||
break;
|
||||
case VELOCITY: for (i=1; i<=Nlinks; i++)
|
||||
{
|
||||
if (Link[i].Type == PUMP) x[i] = 0.0f;
|
||||
else
|
||||
{
|
||||
q = ABS(Q[i]);
|
||||
a = PI*SQR(Link[i].Diam)/4.0;
|
||||
x[i] = (REAL4)(q/a*ucf);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case HEADLOSS: for (i=1; i<=Nlinks; i++)
|
||||
{
|
||||
if (S[i] <= CLOSED) x[i] = 0.0f;
|
||||
else
|
||||
{
|
||||
h = H[Link[i].N1] - H[Link[i].N2];
|
||||
if (Link[i].Type != PUMP) h = ABS(h);
|
||||
if (Link[i].Type <= PIPE)
|
||||
x[i] = (REAL4)(1000.0*h/Link[i].Len);
|
||||
else x[i] = (REAL4)(h*ucf);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LINKQUAL: for (i=1; i<=Nlinks; i++)
|
||||
x[i] = (REAL4)(avgqual(i)*ucf);
|
||||
break;
|
||||
case STATUS: for (i=1; i<=Nlinks; i++)
|
||||
x[i] = (REAL4)S[i];
|
||||
break;
|
||||
case SETTING: for (i=1; i<=Nlinks; i++)
|
||||
{
|
||||
if (K[i] != MISSING)
|
||||
switch (Link[i].Type)
|
||||
{
|
||||
case CV:
|
||||
case PIPE: x[i] = (REAL4)K[i];
|
||||
break;
|
||||
case PUMP: x[i] = (REAL4)K[i];
|
||||
break;
|
||||
case PRV:
|
||||
case PSV:
|
||||
case PBV: x[i] = (REAL4)(K[i]*Ucf[PRESSURE]);
|
||||
break;
|
||||
case FCV: x[i] = (REAL4)(K[i]*Ucf[FLOW]);
|
||||
break;
|
||||
case TCV: x[i] = (REAL4)K[i];
|
||||
break;
|
||||
default: x[i] = 0.0f;
|
||||
}
|
||||
else x[i] = 0.0f;
|
||||
}
|
||||
break;
|
||||
case REACTRATE: /* Overall reaction rate in mass/L/day */
|
||||
if (Qualflag == NONE) memset(x,0,(Nlinks+1 )*sizeof(REAL4));
|
||||
else for (i=1; i<=Nlinks; i++) x[i] = (REAL4)(R[i]*ucf);
|
||||
break;
|
||||
case FRICTION: /* f = 2ghd/(Lu^2) where f = friction factor */
|
||||
/* u = velocity, g = grav. accel., h = head */
|
||||
/*loss, d = diam., & L = pipe length */
|
||||
for (i=1; i<=Nlinks; i++)
|
||||
{
|
||||
if (Link[i].Type <= PIPE && ABS(Q[i]) > TINY)
|
||||
{
|
||||
h = ABS(H[Link[i].N1] - H[Link[i].N2]);
|
||||
f = 39.725*h*pow(Link[i].Diam,5)/Link[i].Len/SQR(Q[i]);
|
||||
x[i] = (REAL4)f;
|
||||
}
|
||||
else x[i] = 0.0f;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Write x[1] to x[Nlinks] to output file */
|
||||
if (fwrite(x+1,sizeof(REAL4),Nlinks,TmpOutFile) < (unsigned)Nlinks)
|
||||
return(308);
|
||||
return(0);
|
||||
} /* End of linkoutput */
|
||||
|
||||
|
||||
int savefinaloutput()
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: returns error code
|
||||
** Purpose: saves time series statistics, reaction rates &
|
||||
** epilog to output file.
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int errcode = 0;
|
||||
REAL4 *x;
|
||||
|
||||
/* Save time series statistic if computed */
|
||||
if (Tstatflag != SERIES && TmpOutFile != NULL)
|
||||
{
|
||||
x = (REAL4 *) calloc(MAX(Nnodes,Nlinks) + 1, sizeof(REAL4));
|
||||
if ( x == NULL ) return 101;
|
||||
ERRCODE(savetimestat(x,NODEHDR));
|
||||
ERRCODE(savetimestat(x,LINKHDR));
|
||||
if (!errcode) Nperiods = 1;
|
||||
fclose(TmpOutFile);
|
||||
free(x);
|
||||
}
|
||||
|
||||
/* Save avg. reaction rates & file epilog */
|
||||
if (OutFile != NULL)
|
||||
{
|
||||
ERRCODE(savenetreacts(Wbulk,Wwall,Wtank,Wsource));
|
||||
ERRCODE(saveepilog());
|
||||
}
|
||||
return(errcode);
|
||||
}
|
||||
|
||||
|
||||
int savetimestat(REAL4 *x, char objtype)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: *x = buffer for node values
|
||||
** objtype = NODEHDR (for nodes) or LINKHDR (for links)
|
||||
** Output: returns error code
|
||||
** Purpose: computes time series statistic for nodes or links
|
||||
** and saves to normal output file.
|
||||
**
|
||||
** NOTE: This routine is dependent on how the output reporting
|
||||
** variables were assigned to FieldType in TYPES.H.
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int n, n1, n2;
|
||||
int i, j, p, errcode = 0;
|
||||
long startbyte, skipbytes;
|
||||
float *stat1, *stat2, xx;
|
||||
|
||||
/*
|
||||
Compute number of bytes in temp output file to skip over (skipbytes)
|
||||
when moving from one time period to the next for a particular variable.
|
||||
*/
|
||||
if (objtype == NODEHDR)
|
||||
{
|
||||
/*
|
||||
For nodes, we start at 0 and skip over node output for all
|
||||
node variables minus 1 plus link output for all link variables.
|
||||
*/
|
||||
startbyte = 0;
|
||||
skipbytes = (Nnodes*(QUALITY-DEMAND) +
|
||||
Nlinks*(FRICTION-FLOW+1))*sizeof(REAL4);
|
||||
n = Nnodes;
|
||||
n1 = DEMAND;
|
||||
n2 = QUALITY;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
For links, we start at the end of all node variables and skip
|
||||
over node output for all node variables plus link output for
|
||||
all link variables minus 1.
|
||||
*/
|
||||
startbyte = Nnodes*(QUALITY-DEMAND+1)*sizeof(REAL4);
|
||||
skipbytes = (Nnodes*(QUALITY-DEMAND+1) +
|
||||
Nlinks*(FRICTION-FLOW))*sizeof(REAL4);
|
||||
n = Nlinks;
|
||||
n1 = FLOW;
|
||||
n2 = FRICTION;
|
||||
}
|
||||
stat1 = (float *) calloc(n+1, sizeof(float));
|
||||
stat2 = (float *) calloc(n+1, sizeof(float));
|
||||
ERRCODE(MEMCHECK(stat1));
|
||||
ERRCODE(MEMCHECK(stat2));
|
||||
|
||||
/* Process each output reporting variable */
|
||||
if (!errcode)
|
||||
{
|
||||
for (j=n1; j<=n2; j++)
|
||||
{
|
||||
|
||||
/* Initialize stat arrays */
|
||||
if (Tstatflag == AVG) memset(stat1, 0, (n+1)*sizeof(float));
|
||||
else for (i=1; i<=n; i++)
|
||||
{
|
||||
stat1[i] = -MISSING; /* +1E10 */
|
||||
stat2[i] = MISSING; /* -1E10 */
|
||||
}
|
||||
|
||||
/* Position temp output file at start of output */
|
||||
fseek(TmpOutFile, startbyte + (j-n1)*n*sizeof(REAL4), SEEK_SET);
|
||||
|
||||
/* Process each time period */
|
||||
for (p=1; p<=Nperiods; p++)
|
||||
{
|
||||
|
||||
/* Get output results for time period & update stats */
|
||||
fread(x+1, sizeof(REAL4), n, TmpOutFile);
|
||||
for (i=1; i<=n; i++)
|
||||
{
|
||||
xx = x[i];
|
||||
if (objtype == LINKHDR)
|
||||
{
|
||||
if (j == FLOW) xx = ABS(xx);
|
||||
if (j == STATUS)
|
||||
{
|
||||
if (xx >= OPEN) xx = 1.0;
|
||||
else xx = 0.0;
|
||||
}
|
||||
}
|
||||
if (Tstatflag == AVG) stat1[i] += xx;
|
||||
else
|
||||
{
|
||||
stat1[i] = MIN(stat1[i], xx);
|
||||
stat2[i] = MAX(stat2[i], xx);
|
||||
}
|
||||
}
|
||||
|
||||
/* Advance file to next period */
|
||||
if (p < Nperiods) fseek(TmpOutFile, skipbytes, SEEK_CUR);
|
||||
}
|
||||
|
||||
/* Compute resultant stat & save to regular output file */
|
||||
switch (Tstatflag)
|
||||
{
|
||||
case AVG: for (i=1; i<=n; i++) x[i] = stat1[i]/(float)Nperiods;
|
||||
break;
|
||||
case MIN: for (i=1; i<=n; i++) x[i] = stat1[i];
|
||||
break;
|
||||
case MAX: for (i=1; i<=n; i++) x[i] = stat2[i];
|
||||
break;
|
||||
case RANGE: for (i=1; i<=n; i++) x[i] = stat2[i] - stat1[i];
|
||||
break;
|
||||
}
|
||||
if (objtype == LINKHDR && j == STATUS)
|
||||
{
|
||||
for (i=1; i<=n; i++)
|
||||
{
|
||||
if (x[i] < 0.5f) x[i] = CLOSED;
|
||||
else x[i] = OPEN;
|
||||
}
|
||||
}
|
||||
if (fwrite(x+1, sizeof(REAL4), n, OutFile) < (unsigned) n) errcode = 308;
|
||||
|
||||
/* Update internal output variables where applicable */
|
||||
if (objtype == NODEHDR) switch (j)
|
||||
{
|
||||
case DEMAND: for (i=1; i<=n; i++) D[i] = x[i]/Ucf[DEMAND];
|
||||
break;
|
||||
case HEAD: for (i=1; i<=n; i++) H[i] = x[i]/Ucf[HEAD];
|
||||
break;
|
||||
case QUALITY: for (i=1; i<=n; i++) C[i] = x[i]/Ucf[QUALITY];
|
||||
break;
|
||||
}
|
||||
else if (j == FLOW) for (i=1; i<=n; i++) Q[i] = x[i]/Ucf[FLOW];
|
||||
}
|
||||
}
|
||||
|
||||
/* Free allocated memory */
|
||||
free(stat1);
|
||||
free(stat2);
|
||||
return(errcode);
|
||||
}
|
||||
|
||||
|
||||
int savenetreacts(double wbulk, double wwall, double wtank, double wsource)
|
||||
/*
|
||||
**-----------------------------------------------------
|
||||
** Writes average network-wide reaction rates (in
|
||||
** mass/hr) to binary output file.
|
||||
**-----------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int errcode = 0;
|
||||
double t;
|
||||
REAL4 w[4];
|
||||
if (Dur > 0) t = (double)Dur/3600.;
|
||||
else t = 1.;
|
||||
w[0] = (REAL4)(wbulk/t);
|
||||
w[1] = (REAL4)(wwall/t);
|
||||
w[2] = (REAL4)(wtank/t);
|
||||
w[3] = (REAL4)(wsource/t);
|
||||
if (fwrite(w,sizeof(REAL4),4,OutFile) < 4) errcode = 308;
|
||||
return(errcode);
|
||||
}
|
||||
|
||||
|
||||
int saveepilog()
|
||||
/*
|
||||
**-------------------------------------------------
|
||||
** Writes Nperiods, Warnflag, & Magic Number to
|
||||
** end of binary output file.
|
||||
**-------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int errcode = 0;
|
||||
INT4 i;
|
||||
i = Nperiods;
|
||||
if (fwrite(&i,sizeof(INT4),1,OutFile) < 1) errcode = 308;
|
||||
i = Warnflag;
|
||||
if (fwrite(&i,sizeof(INT4),1,OutFile) < 1) errcode = 308;
|
||||
i = MAGICNUMBER;
|
||||
if (fwrite(&i,sizeof(INT4),1,OutFile) < 1) errcode = 308;
|
||||
return(errcode);
|
||||
}
|
||||
|
||||
|
||||
/********************** END OF OUTPUT.C **********************/
|
||||
1618
src/quality.c
Normal file
1618
src/quality.c
Normal file
File diff suppressed because it is too large
Load Diff
1214
src/report.c
Normal file
1214
src/report.c
Normal file
File diff suppressed because it is too large
Load Diff
967
src/rules.c
Normal file
967
src/rules.c
Normal file
@@ -0,0 +1,967 @@
|
||||
/*
|
||||
**********************************************************************
|
||||
|
||||
RULES.C -- Rule processor module for EPANET
|
||||
|
||||
VERSION: 2.00
|
||||
DATE: 5/8/00
|
||||
9/7/00
|
||||
10/25/00
|
||||
3/1/01
|
||||
8/15/07 (2.00.11)
|
||||
AUTHOR: L. Rossman
|
||||
US EPA - NRMRL
|
||||
|
||||
The entry points for this module are:
|
||||
initrules() -- called from ENopen() in EPANET.C
|
||||
addrule() -- called from netsize() in INPUT2.C
|
||||
allocrules() -- called from allocdata() in EPANET.C
|
||||
ruledata() -- called from newline() in INPUT2.C
|
||||
freerules() -- called from freedata() in EPANET.C
|
||||
checkrules() -- called from ruletimestep() in HYDRAUL.C
|
||||
|
||||
**********************************************************************
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include "hash.h"
|
||||
#include "text.h"
|
||||
#include "types.h"
|
||||
#include "funcs.h"
|
||||
#define EXTERN extern
|
||||
#include "vars.h"
|
||||
|
||||
struct Premise /* Rule Premise Clause */
|
||||
{
|
||||
int logop; /* Logical operator */
|
||||
int object; /* Node or link */
|
||||
int index; /* Object's index */
|
||||
int variable; /* Pressure, flow, etc. */
|
||||
int relop; /* Relational operator */
|
||||
int status; /* Variable's status */
|
||||
double value; /* Variable's value */
|
||||
struct Premise *next;
|
||||
};
|
||||
|
||||
struct Action /* Rule Action Clause */
|
||||
{
|
||||
int link; /* Link index */
|
||||
int status; /* Link's status */
|
||||
double setting; /* Link's setting */
|
||||
struct Action *next;
|
||||
};
|
||||
|
||||
struct aRule /* Control Rule Structure */
|
||||
{
|
||||
char label[MAXID+1]; /* Rule character label */
|
||||
double priority; /* Priority level */
|
||||
struct Premise *Pchain; /* Linked list of premises */
|
||||
struct Action *Tchain; /* Linked list of actions if true */
|
||||
struct Action *Fchain; /* Linked list of actions if false */
|
||||
struct aRule *next;
|
||||
};
|
||||
|
||||
struct ActItem /* Action list item */
|
||||
{
|
||||
int ruleindex; /* Index of rule action belongs to */
|
||||
struct Action *action; /* An action structure */
|
||||
struct ActItem *next;
|
||||
};
|
||||
|
||||
struct aRule *Rule; /* Array of rules */
|
||||
struct ActItem *ActList; /* Linked list of action items */
|
||||
int RuleState; /* State of rule interpreter */
|
||||
long Time1; /* Start of rule evaluation time interval (sec) */
|
||||
struct Premise *Plast; /* Previous premise clause */
|
||||
|
||||
enum Rulewords {r_RULE,r_IF,r_AND,r_OR,r_THEN,r_ELSE,r_PRIORITY,r_ERROR};
|
||||
char *Ruleword[] = {w_RULE,w_IF,w_AND,w_OR,w_THEN,w_ELSE,w_PRIORITY,NULL};
|
||||
|
||||
enum Varwords {r_DEMAND, r_HEAD, r_GRADE, r_LEVEL, r_PRESSURE,
|
||||
r_FLOW, r_STATUS, r_SETTING, r_POWER, r_TIME,
|
||||
r_CLOCKTIME, r_FILLTIME, r_DRAINTIME};
|
||||
char *Varword[] = {w_DEMAND, w_HEAD, w_GRADE, w_LEVEL, w_PRESSURE,
|
||||
w_FLOW, w_STATUS, w_SETTING, w_POWER,w_TIME,
|
||||
w_CLOCKTIME,w_FILLTIME,w_DRAINTIME, NULL};
|
||||
|
||||
enum Objects {r_JUNC,r_RESERV,r_TANK,r_PIPE,r_PUMP,r_VALVE,
|
||||
r_NODE,r_LINK,r_SYSTEM};
|
||||
char *Object[] = {w_JUNC,w_RESERV,w_TANK,w_PIPE,w_PUMP,w_VALVE,
|
||||
w_NODE,w_LINK,w_SYSTEM,NULL};
|
||||
|
||||
/* NOTE: place "<=" & ">=" before "<" & ">" so that findmatch() works correctly. */
|
||||
enum Operators { EQ, NE, LE, GE, LT, GT, IS, NOT, BELOW, ABOVE};
|
||||
char *Operator[] = {"=","<>","<=",">=","<",">",w_IS,w_NOT,w_BELOW,w_ABOVE,NULL};
|
||||
|
||||
enum Values {IS_NUMBER,IS_OPEN,IS_CLOSED,IS_ACTIVE};
|
||||
char *Value[] = {"XXXX", w_OPEN, w_CLOSED, w_ACTIVE,NULL};
|
||||
|
||||
/* External variables declared in INPUT2.C */
|
||||
extern char *Tok[MAXTOKS];
|
||||
extern int Ntokens;
|
||||
|
||||
/*
|
||||
** Local function prototypes are defined here and not in FUNCS.H
|
||||
** because some of them utilize the Premise and Action structures
|
||||
** defined locally in this module.
|
||||
*/
|
||||
void newrule(void);
|
||||
int newpremise(int);
|
||||
int newaction(void);
|
||||
int newpriority(void);
|
||||
int evalpremises(int);
|
||||
void updateactlist(int, struct Action *);
|
||||
int checkaction(int, struct Action *);
|
||||
int checkpremise(struct Premise *);
|
||||
int checktime(struct Premise *);
|
||||
int checkstatus(struct Premise *);
|
||||
int checkvalue(struct Premise *);
|
||||
int takeactions(void);
|
||||
void clearactlist(void);
|
||||
void clearrules(void);
|
||||
void ruleerrmsg(int);
|
||||
|
||||
|
||||
void initrules()
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Initializes rule base.
|
||||
** Called by ENopen() in EPANET.C module
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
RuleState = r_PRIORITY;
|
||||
Rule = NULL;
|
||||
}
|
||||
|
||||
|
||||
void addrule(char *tok)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Updates rule count if RULE keyword found in line of input.
|
||||
** Called by netsize() in INPUT2.C module.
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
if (match(tok,w_RULE)) MaxRules++;
|
||||
}
|
||||
|
||||
|
||||
int allocrules()
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Allocates memory for rule-based controls.
|
||||
** Called by allocdata() in EPANET.C module.
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Rule = (struct aRule *) calloc(MaxRules+1,sizeof(struct aRule));
|
||||
if (Rule == NULL) return(101);
|
||||
else return(0);
|
||||
}
|
||||
|
||||
|
||||
void freerules()
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Frees memory used for rule-based controls.
|
||||
** Called by freedata() in EPANET.C module.
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
clearrules();
|
||||
free(Rule);
|
||||
}
|
||||
|
||||
|
||||
int checkrules(long dt)
|
||||
/*
|
||||
**-----------------------------------------------------
|
||||
** Checks which rules should fire at current time.
|
||||
** Called by ruletimestep() in HYDRAUL.C.
|
||||
**-----------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i,
|
||||
r; /* Number of actions actually taken */
|
||||
|
||||
/* Start of rule evaluation time interval */
|
||||
Time1 = Htime - dt + 1;
|
||||
|
||||
/* Iterate through each rule */
|
||||
ActList = NULL;
|
||||
r = 0;
|
||||
for (i=1; i<=Nrules; i++)
|
||||
{
|
||||
/* If premises true, add THEN clauses to action list. */
|
||||
if (evalpremises(i) == TRUE) updateactlist(i,Rule[i].Tchain);
|
||||
|
||||
/* If premises false, add ELSE actions to list. */
|
||||
else
|
||||
{
|
||||
if (Rule[i].Fchain != NULL) updateactlist(i,Rule[i].Fchain);
|
||||
}
|
||||
}
|
||||
|
||||
/* Execute actions then clear list. */
|
||||
if (ActList != NULL) r = takeactions();
|
||||
clearactlist();
|
||||
return(r);
|
||||
}
|
||||
|
||||
|
||||
int ruledata()
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Parses a line from [RULES] section of input.
|
||||
** Called by newline() in INPUT2.C module.
|
||||
** Tok[] is global array of tokens parsed from input line.
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int key, /* Keyword code */
|
||||
err;
|
||||
|
||||
/* Exit if current rule has an error */
|
||||
if (RuleState == r_ERROR) return(0);
|
||||
|
||||
/* Find the key word that begins the rule statement */
|
||||
err = 0;
|
||||
key = findmatch(Tok[0],Ruleword);
|
||||
switch (key)
|
||||
{
|
||||
case -1: err = 201; /* Unrecognized keyword */
|
||||
break;
|
||||
case r_RULE: Nrules++;
|
||||
newrule();
|
||||
RuleState = r_RULE;
|
||||
break;
|
||||
case r_IF: if (RuleState != r_RULE)
|
||||
{
|
||||
err = 221; /* Mis-placed IF clause */
|
||||
break;
|
||||
}
|
||||
RuleState = r_IF;
|
||||
err = newpremise(r_AND);
|
||||
break;
|
||||
case r_AND: if (RuleState == r_IF) err = newpremise(r_AND);
|
||||
else if (RuleState == r_THEN || RuleState == r_ELSE)
|
||||
err = newaction();
|
||||
else err = 221;
|
||||
break;
|
||||
case r_OR: if (RuleState == r_IF) err = newpremise(r_OR);
|
||||
else err = 221;
|
||||
break;
|
||||
case r_THEN: if (RuleState != r_IF)
|
||||
{
|
||||
err = 221; /* Mis-placed THEN clause */
|
||||
break;
|
||||
}
|
||||
RuleState = r_THEN;
|
||||
err = newaction();
|
||||
break;
|
||||
case r_ELSE: if (RuleState != r_THEN)
|
||||
{
|
||||
err = 221; /* Mis-placed ELSE clause */
|
||||
break;
|
||||
}
|
||||
RuleState = r_ELSE;
|
||||
err = newaction();
|
||||
break;
|
||||
case r_PRIORITY: if (RuleState != r_THEN && RuleState != r_ELSE)
|
||||
{
|
||||
err = 221;
|
||||
break;
|
||||
}
|
||||
RuleState = r_PRIORITY;
|
||||
err = newpriority();
|
||||
break;
|
||||
default: err = 201;
|
||||
}
|
||||
|
||||
/* Set RuleState to r_ERROR if errors found */
|
||||
if (err)
|
||||
{
|
||||
RuleState = r_ERROR;
|
||||
ruleerrmsg(err);
|
||||
err = 200;
|
||||
}
|
||||
return(err);
|
||||
}
|
||||
|
||||
|
||||
void clearactlist()
|
||||
/*
|
||||
**----------------------------------------------------------
|
||||
** Clears memory used for action list
|
||||
**----------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
struct ActItem *a;
|
||||
struct ActItem *anext;
|
||||
a = ActList;
|
||||
while (a != NULL)
|
||||
{
|
||||
anext = a->next;
|
||||
free(a);
|
||||
a = anext;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void clearrules()
|
||||
/*
|
||||
**-----------------------------------------------------------
|
||||
** Clears memory used for premises & actions for all rules
|
||||
**-----------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
struct Premise *p;
|
||||
struct Premise *pnext;
|
||||
struct Action *a;
|
||||
struct Action *anext;
|
||||
int i;
|
||||
for (i=1; i<=Nrules; i++)
|
||||
{
|
||||
p = Rule[i].Pchain;
|
||||
while (p != NULL)
|
||||
{
|
||||
pnext = p->next;
|
||||
free(p);
|
||||
p = pnext;
|
||||
}
|
||||
a = Rule[i].Tchain;
|
||||
while (a != NULL)
|
||||
{
|
||||
anext = a->next;
|
||||
free(a);
|
||||
a = anext;
|
||||
}
|
||||
a = Rule[i].Fchain;
|
||||
while (a != NULL)
|
||||
{
|
||||
anext = a->next;
|
||||
free(a);
|
||||
a = anext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void newrule()
|
||||
/*
|
||||
**----------------------------------------------------------
|
||||
** Adds new rule to rule base
|
||||
**----------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
strncpy(Rule[Nrules].label, Tok[1], MAXID);
|
||||
Rule[Nrules].Pchain = NULL;
|
||||
Rule[Nrules].Tchain = NULL;
|
||||
Rule[Nrules].Fchain = NULL;
|
||||
Rule[Nrules].priority = 0.0;
|
||||
Plast = NULL;
|
||||
}
|
||||
|
||||
|
||||
int newpremise(int logop)
|
||||
/*
|
||||
**--------------------------------------------------------------------
|
||||
** Adds new premise to current rule.
|
||||
** Formats are:
|
||||
** IF/AND/OR <object> <id> <variable> <operator> <value>
|
||||
** IF/AND/OR SYSTEM <variable> <operator> <value> (units)
|
||||
**
|
||||
** Calls findmatch() and hour() in INPUT2.C.
|
||||
** Calls findnode() and findlink() in EPANET.C.
|
||||
**---------------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i,j,k,m,r,s,v;
|
||||
double x;
|
||||
struct Premise *p;
|
||||
|
||||
/* Check for correct number of tokens */
|
||||
if (Ntokens != 5 && Ntokens != 6) return(201);
|
||||
|
||||
/* Find network object & id if present */
|
||||
i = findmatch(Tok[1],Object);
|
||||
if (i == r_SYSTEM)
|
||||
{
|
||||
j = 0;
|
||||
v = findmatch(Tok[2],Varword);
|
||||
if (v != r_DEMAND && v != r_TIME && v != r_CLOCKTIME) return(201);
|
||||
}
|
||||
else
|
||||
{
|
||||
v = findmatch(Tok[3],Varword);
|
||||
if (v < 0) return(201);
|
||||
switch (i)
|
||||
{
|
||||
case r_NODE:
|
||||
case r_JUNC:
|
||||
case r_RESERV:
|
||||
case r_TANK: k = r_NODE; break;
|
||||
case r_LINK:
|
||||
case r_PIPE:
|
||||
case r_PUMP:
|
||||
case r_VALVE: k = r_LINK; break;
|
||||
default: return(201);
|
||||
}
|
||||
i = k;
|
||||
if (i == r_NODE)
|
||||
{
|
||||
j = findnode(Tok[2]);
|
||||
if (j == 0) return(203);
|
||||
switch (v)
|
||||
{
|
||||
case r_DEMAND:
|
||||
case r_HEAD:
|
||||
case r_GRADE:
|
||||
case r_LEVEL:
|
||||
case r_PRESSURE: break;
|
||||
|
||||
/*** Updated 9/7/00 ***/
|
||||
case r_FILLTIME:
|
||||
case r_DRAINTIME: if (j <= Njuncs) return(201); break;
|
||||
|
||||
default: return(201);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
j = findlink(Tok[2]);
|
||||
if (j == 0) return(204);
|
||||
switch (v)
|
||||
{
|
||||
case r_FLOW:
|
||||
case r_STATUS:
|
||||
case r_SETTING: break;
|
||||
default: return(201);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse relational operator (r) and check for synonyms */
|
||||
if (i == r_SYSTEM) m = 3;
|
||||
else m = 4;
|
||||
k = findmatch(Tok[m],Operator);
|
||||
if (k < 0) return(201);
|
||||
switch(k)
|
||||
{
|
||||
case IS: r = EQ; break;
|
||||
case NOT: r = NE; break;
|
||||
case BELOW: r = LT; break;
|
||||
case ABOVE: r = GT; break;
|
||||
default: r = k;
|
||||
}
|
||||
|
||||
/* Parse for status (s) or numerical value (x) */
|
||||
s = 0;
|
||||
x = MISSING;
|
||||
if (v == r_TIME || v == r_CLOCKTIME)
|
||||
{
|
||||
if (Ntokens == 6)
|
||||
x = hour(Tok[4],Tok[5])*3600.;
|
||||
else
|
||||
x = hour(Tok[4],"")*3600.;
|
||||
if (x < 0.0) return(202);
|
||||
}
|
||||
else if ((k = findmatch(Tok[Ntokens-1],Value)) > IS_NUMBER) s = k;
|
||||
else
|
||||
{
|
||||
if (!getfloat(Tok[Ntokens-1],&x)) return(202);
|
||||
if (v == r_FILLTIME || v == r_DRAINTIME) x = x*3600.0; //(2.00.11 - LR)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Create new premise structure */
|
||||
p = (struct Premise *) malloc(sizeof(struct Premise));
|
||||
if (p == NULL) return(101);
|
||||
p->object = i;
|
||||
p->index = j;
|
||||
p->variable = v;
|
||||
p->relop = r;
|
||||
p->logop = logop;
|
||||
p->status = s;
|
||||
p->value = x;
|
||||
|
||||
/* Add premise to current rule's premise list */
|
||||
p->next = NULL;
|
||||
if (Plast == NULL) Rule[Nrules].Pchain = p;
|
||||
else Plast->next = p;
|
||||
Plast = p;
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
int newaction()
|
||||
/*
|
||||
**----------------------------------------------------------
|
||||
** Adds new action to current rule.
|
||||
** Format is:
|
||||
** THEN/ELSE/AND LINK <id> <variable> IS <value>
|
||||
**
|
||||
** Calls findlink() from EPANET.C.
|
||||
** Calls getfloat() and findmatch() from INPUT2.C.
|
||||
**----------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int j,k,s;
|
||||
double x;
|
||||
struct Action *a;
|
||||
|
||||
/* Check for correct number of tokens */
|
||||
if (Ntokens != 6) return(201);
|
||||
|
||||
/* Check that link exists */
|
||||
j = findlink(Tok[2]);
|
||||
if (j == 0) return(204);
|
||||
|
||||
/*** Updated 9/7/00 ***/
|
||||
/* Cannot control a CV */
|
||||
if (Link[j].Type == CV) return(207);
|
||||
|
||||
/* Find value for status or setting */
|
||||
s = -1;
|
||||
x = MISSING;
|
||||
if ((k = findmatch(Tok[5],Value)) > IS_NUMBER) s = k;
|
||||
else
|
||||
{
|
||||
if (!getfloat(Tok[5],&x)) return(202);
|
||||
if (x < 0.0) return(202);
|
||||
}
|
||||
|
||||
/*** Updated 9/7/00 ***/
|
||||
/* Cannot change setting for a GPV ***/
|
||||
if (x != MISSING && Link[j].Type == GPV) return(202);
|
||||
|
||||
/*** Updated 3/1/01 ***/
|
||||
/* Set status for pipe in case setting was specified */
|
||||
if (x != MISSING && Link[j].Type == PIPE)
|
||||
{
|
||||
if (x == 0.0) s = IS_CLOSED;
|
||||
else s = IS_OPEN;
|
||||
x = MISSING;
|
||||
}
|
||||
|
||||
/* Create a new action structure */
|
||||
a = (struct Action *) malloc(sizeof(struct Action));
|
||||
if (a == NULL) return(101);
|
||||
a->link = j;
|
||||
a->status = s;
|
||||
a->setting = x;
|
||||
|
||||
/* Add action to current rule's action list */
|
||||
if (RuleState == r_THEN)
|
||||
{
|
||||
a->next = Rule[Nrules].Tchain;
|
||||
Rule[Nrules].Tchain = a;
|
||||
}
|
||||
else
|
||||
{
|
||||
a->next = Rule[Nrules].Fchain;
|
||||
Rule[Nrules].Fchain = a;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
int newpriority()
|
||||
/*
|
||||
**---------------------------------------------------
|
||||
** Adds priority rating to current rule
|
||||
**---------------------------------------------------
|
||||
*/
|
||||
{
|
||||
double x;
|
||||
if (!getfloat(Tok[1],&x)) return(202);
|
||||
Rule[Nrules].priority = x;
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
int evalpremises(int i)
|
||||
/*
|
||||
**----------------------------------------------------------
|
||||
** Checks if premises to rule i are true
|
||||
**----------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int result;
|
||||
struct Premise *p;
|
||||
|
||||
result = TRUE;
|
||||
p = Rule[i].Pchain;
|
||||
while (p != NULL)
|
||||
{
|
||||
if (p->logop == r_OR)
|
||||
{
|
||||
if (result == FALSE)
|
||||
{
|
||||
result = checkpremise(p);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (result == FALSE) return(FALSE);
|
||||
result = checkpremise(p);
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
int checkpremise(struct Premise *p)
|
||||
/*
|
||||
**----------------------------------------------------------
|
||||
** Checks if a particular premise is true
|
||||
**----------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
if (p->variable == r_TIME || p->variable == r_CLOCKTIME)
|
||||
return(checktime(p));
|
||||
else if (p->status > IS_NUMBER)
|
||||
return(checkstatus(p));
|
||||
else
|
||||
return(checkvalue(p));
|
||||
}
|
||||
|
||||
|
||||
int checktime(struct Premise *p)
|
||||
/*
|
||||
**------------------------------------------------------------
|
||||
** Checks if condition on system time holds
|
||||
**------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
char flag;
|
||||
long t1,t2,x;
|
||||
|
||||
/* Get start and end of rule evaluation time interval */
|
||||
if (p->variable == r_TIME)
|
||||
{
|
||||
t1 = Time1;
|
||||
t2 = Htime;
|
||||
}
|
||||
else if (p->variable == r_CLOCKTIME)
|
||||
{
|
||||
t1 = (Time1 + Tstart) % SECperDAY;
|
||||
t2 = (Htime + Tstart) % SECperDAY;
|
||||
}
|
||||
else return(0);
|
||||
|
||||
/* Test premise's time */
|
||||
x = (long)(p->value);
|
||||
switch (p->relop)
|
||||
{
|
||||
/* For inequality, test against current time */
|
||||
case LT: if (t2 >= x) return(0); break;
|
||||
case LE: if (t2 > x) return(0); break;
|
||||
case GT: if (t2 <= x) return(0); break;
|
||||
case GE: if (t2 < x) return(0); break;
|
||||
|
||||
/* For equality, test if within interval */
|
||||
case EQ:
|
||||
case NE:
|
||||
flag = FALSE;
|
||||
if (t2 < t1) /* E.g., 11:00 am to 1:00 am */
|
||||
{
|
||||
if (x >= t1 || x <= t2) flag = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (x >= t1 && x <= t2) flag = TRUE;
|
||||
}
|
||||
if (p->relop == EQ && flag == FALSE) return(0);
|
||||
if (p->relop == NE && flag == TRUE) return(0);
|
||||
break;
|
||||
}
|
||||
|
||||
/* If we get to here then premise was satisfied */
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int checkstatus(struct Premise *p)
|
||||
/*
|
||||
**------------------------------------------------------------
|
||||
** Checks if condition on link status holds
|
||||
**------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
char i;
|
||||
int j;
|
||||
switch (p->status)
|
||||
{
|
||||
case IS_OPEN:
|
||||
case IS_CLOSED:
|
||||
case IS_ACTIVE:
|
||||
i = S[p->index];
|
||||
if (i <= CLOSED) j = IS_CLOSED;
|
||||
else if (i == ACTIVE) j = IS_ACTIVE;
|
||||
else j = IS_OPEN;
|
||||
if (j == p->status &&
|
||||
p->relop == EQ) return(1);
|
||||
if (j != p->status &&
|
||||
p->relop == NE) return(1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
int checkvalue(struct Premise *p)
|
||||
/*
|
||||
**----------------------------------------------------------
|
||||
** Checks if numerical condition on a variable is true.
|
||||
** Uses tolerance of 0.001 when testing conditions.
|
||||
**----------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i,j,v;
|
||||
double x,
|
||||
tol = 1.e-3;
|
||||
|
||||
i = p->index;
|
||||
v = p->variable;
|
||||
switch (v)
|
||||
{
|
||||
|
||||
/*** Updated 10/25/00 ***/
|
||||
case r_DEMAND: if (p->object == r_SYSTEM) x = Dsystem*Ucf[DEMAND];
|
||||
else x = D[i]*Ucf[DEMAND];
|
||||
break;
|
||||
|
||||
case r_HEAD:
|
||||
case r_GRADE: x = H[i]*Ucf[HEAD];
|
||||
break;
|
||||
case r_PRESSURE: x = (H[i]-Node[i].El)*Ucf[PRESSURE];
|
||||
break;
|
||||
case r_LEVEL: x = (H[i]-Node[i].El)*Ucf[HEAD];
|
||||
break;
|
||||
case r_FLOW: x = ABS(Q[i])*Ucf[FLOW];
|
||||
break;
|
||||
case r_SETTING: if (K[i] == MISSING) return(0);
|
||||
x = K[i];
|
||||
switch (Link[i].Type)
|
||||
{
|
||||
case PRV:
|
||||
case PSV:
|
||||
case PBV: x = x*Ucf[PRESSURE]; break;
|
||||
case FCV: x = x*Ucf[FLOW]; break;
|
||||
}
|
||||
break;
|
||||
case r_FILLTIME: if (i <= Njuncs) return(0);
|
||||
j = i-Njuncs;
|
||||
if (Tank[j].A == 0.0) return(0);
|
||||
if (D[i] <= TINY) return(0);
|
||||
x = (Tank[j].Vmax - Tank[j].V)/D[i];
|
||||
break;
|
||||
case r_DRAINTIME: if (i <= Njuncs) return(0);
|
||||
j = i-Njuncs;
|
||||
if (Tank[j].A == 0.0) return(0);
|
||||
if (D[i] >= -TINY) return(0);
|
||||
x = (Tank[j].Vmin - Tank[j].V)/D[i];
|
||||
break;
|
||||
default: return(0);
|
||||
}
|
||||
switch (p->relop)
|
||||
{
|
||||
case EQ: if (ABS(x - p->value) > tol) return(0);
|
||||
break;
|
||||
case NE: if (ABS(x - p->value) < tol) return(0);
|
||||
break;
|
||||
case LT: if (x > p->value + tol) return(0); break;
|
||||
case LE: if (x > p->value - tol) return(0); break;
|
||||
case GT: if (x < p->value - tol) return(0); break;
|
||||
case GE: if (x < p->value + tol) return(0); break;
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
void updateactlist(int i, struct Action *actions)
|
||||
/*
|
||||
**---------------------------------------------------
|
||||
** Adds rule's actions to action list
|
||||
**---------------------------------------------------
|
||||
*/
|
||||
{
|
||||
struct ActItem *item;
|
||||
struct Action *a;
|
||||
|
||||
/* Iterate through each action of Rule i */
|
||||
a = actions;
|
||||
while (a != NULL)
|
||||
{
|
||||
/* Add action to list if not already on it */
|
||||
if (!checkaction(i,a))
|
||||
{
|
||||
item = (struct ActItem *) malloc(sizeof(struct ActItem));
|
||||
if (item != NULL)
|
||||
{
|
||||
item->action = a;
|
||||
item->ruleindex = i;
|
||||
item->next = ActList;
|
||||
ActList = item;
|
||||
}
|
||||
}
|
||||
a = a->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int checkaction(int i, struct Action *a)
|
||||
/*
|
||||
**-----------------------------------------------------------
|
||||
** Checks if an action is already on the Action List
|
||||
**-----------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i1,k,k1;
|
||||
struct ActItem *item;
|
||||
struct Action *a1;
|
||||
|
||||
/* Search action list for link named in action */
|
||||
k = a->link; /* Action applies to link k */
|
||||
item = ActList;
|
||||
while (item != NULL)
|
||||
{
|
||||
a1 = item->action;
|
||||
i1 = item->ruleindex;
|
||||
k1 = a1->link;
|
||||
|
||||
/* If link on list then replace action if rule has higher priority. */
|
||||
if (k1 == k)
|
||||
{
|
||||
if (Rule[i].priority > Rule[i1].priority)
|
||||
{
|
||||
item->action = a;
|
||||
item->ruleindex = i;
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
item = item->next;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
int takeactions()
|
||||
/*
|
||||
**-----------------------------------------------------------
|
||||
** Implements actions on action list
|
||||
**-----------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
struct Action *a;
|
||||
struct ActItem *item;
|
||||
char flag;
|
||||
int k, s, n;
|
||||
double tol = 1.e-3,
|
||||
v, x;
|
||||
|
||||
n = 0;
|
||||
item = ActList;
|
||||
while (item != NULL)
|
||||
{
|
||||
flag = FALSE;
|
||||
a = item->action;
|
||||
k = a->link;
|
||||
s = S[k];
|
||||
v = K[k];
|
||||
x = a->setting;
|
||||
|
||||
/* Switch link from closed to open */
|
||||
if (a->status == IS_OPEN && s <= CLOSED)
|
||||
{
|
||||
setlinkstatus(k, 1, &S[k], &K[k]);
|
||||
flag = TRUE;
|
||||
}
|
||||
|
||||
/* Switch link from not closed to closed */
|
||||
else if (a->status == IS_CLOSED && s > CLOSED)
|
||||
{
|
||||
setlinkstatus(k, 0, &S[k], &K[k]);
|
||||
flag = TRUE;
|
||||
}
|
||||
|
||||
/* Change link's setting */
|
||||
else if (x != MISSING)
|
||||
{
|
||||
switch(Link[k].Type)
|
||||
{
|
||||
case PRV:
|
||||
case PSV:
|
||||
case PBV: x = x/Ucf[PRESSURE]; break;
|
||||
case FCV: x = x/Ucf[FLOW]; break;
|
||||
}
|
||||
if (ABS(x-v) > tol)
|
||||
{
|
||||
setlinksetting(k, x, &S[k], &K[k]);
|
||||
flag = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Report rule action */
|
||||
if (flag == TRUE)
|
||||
{
|
||||
n++;
|
||||
if (Statflag) writeruleaction(k,Rule[item->ruleindex].label);
|
||||
}
|
||||
|
||||
/* Move to next action on list */
|
||||
item = item->next;
|
||||
}
|
||||
return(n);
|
||||
}
|
||||
|
||||
|
||||
void ruleerrmsg(int err)
|
||||
/*
|
||||
**-----------------------------------------------------------
|
||||
** Reports error message
|
||||
**-----------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i;
|
||||
char label[81];
|
||||
char fmt[256];
|
||||
switch (err)
|
||||
{
|
||||
case 201: strcpy(fmt,R_ERR201); break;
|
||||
case 202: strcpy(fmt,R_ERR202); break;
|
||||
case 203: strcpy(fmt,R_ERR203); break;
|
||||
case 204: strcpy(fmt,R_ERR204); break;
|
||||
|
||||
/*** Updated on 9/7/00 ***/
|
||||
case 207: strcpy(fmt,R_ERR207); break;
|
||||
|
||||
case 221: strcpy(fmt,R_ERR221); break;
|
||||
default: return;
|
||||
}
|
||||
if (Nrules > 0)
|
||||
{
|
||||
strcpy(label,t_RULE);
|
||||
strcat(label," ");
|
||||
strcat(label,Rule[Nrules].label);
|
||||
}
|
||||
else strcpy(label,t_RULES_SECT);
|
||||
sprintf(Msg,fmt);
|
||||
strcat(Msg,label);
|
||||
strcat(Msg,":");
|
||||
writeline(Msg);
|
||||
strcpy(fmt,Tok[0]);
|
||||
for (i=1; i<Ntokens; i++)
|
||||
{
|
||||
strcat(fmt," ");
|
||||
strcat(fmt,Tok[i]);
|
||||
}
|
||||
writeline(fmt);
|
||||
}
|
||||
|
||||
/***************** END OF RULES.C ******************/
|
||||
|
||||
750
src/smatrix.c
Normal file
750
src/smatrix.c
Normal file
@@ -0,0 +1,750 @@
|
||||
/*
|
||||
*******************************************************************
|
||||
|
||||
SMATRIX.C -- Sparse matrix routines for EPANET program.
|
||||
|
||||
VERSION: 2.00
|
||||
DATE: 5/8/00
|
||||
AUTHOR: L. Rossman
|
||||
US EPA - NRMRL
|
||||
|
||||
This module contains the sparse matrix routines used to solve
|
||||
a network's hydraulic equations. The entry points into this
|
||||
module are:
|
||||
createsparse() -- called from openhyd() in HYDRAUL.C
|
||||
freesparse() -- called from closehyd() in HYDRAUL.C
|
||||
linsolve() -- called from netsolve() in HYDRAUL.C
|
||||
|
||||
Createsparse() does the following:
|
||||
1. for each node, builds an adjacency list that identifies
|
||||
all links connected to the node (see buildlists())
|
||||
2. re-orders the network's nodes to minimize the number
|
||||
of non-zero entries in the hydraulic solution matrix
|
||||
(see reorder())
|
||||
3. converts the adjacency lists into a compact scheme
|
||||
for storing the non-zero coeffs. in the lower diagonal
|
||||
portion of the solution matrix (see storesparse())
|
||||
Freesparse() frees the memory used for the sparse matrix.
|
||||
Linsolve() solves the linearized system of hydraulic equations.
|
||||
|
||||
********************************************************************
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <math.h>
|
||||
#include "hash.h"
|
||||
#include "text.h"
|
||||
#include "types.h"
|
||||
#include "funcs.h"
|
||||
#define EXTERN extern
|
||||
#include "vars.h"
|
||||
|
||||
int *Degree; /* Number of links adjacent to each node */
|
||||
|
||||
|
||||
int createsparse()
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: returns error code
|
||||
** Purpose: creates sparse representation of coeff. matrix
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int errcode = 0;
|
||||
|
||||
/* Allocate data structures */
|
||||
ERRCODE(allocsparse());
|
||||
if (errcode) return(errcode);
|
||||
|
||||
/* Build node-link adjacency lists with parallel links removed. */
|
||||
Degree = (int *) calloc(Nnodes+1, sizeof(int));
|
||||
ERRCODE(MEMCHECK(Degree));
|
||||
ERRCODE(buildlists(TRUE));
|
||||
if (!errcode)
|
||||
{
|
||||
xparalinks(); /* Remove parallel links */
|
||||
countdegree(); /* Find degree of each junction */
|
||||
} /* (= # of adjacent links) */
|
||||
|
||||
/* Re-order nodes to minimize number of non-zero coeffs. */
|
||||
/* in factorized solution matrix. At same time, adjacency */
|
||||
/* list is updated with links representing non-zero coeffs. */
|
||||
Ncoeffs = Nlinks;
|
||||
ERRCODE(reordernodes());
|
||||
|
||||
/* Allocate memory for sparse storage of positions of non-zero */
|
||||
/* coeffs. and store these positions in vector NZSUB. */
|
||||
ERRCODE(storesparse(Njuncs));
|
||||
|
||||
/* Free memory used for adjacency lists and sort */
|
||||
/* row indexes in NZSUB to optimize linsolve(). */
|
||||
if (!errcode) freelists();
|
||||
ERRCODE(ordersparse(Njuncs));
|
||||
|
||||
/* Re-build adjacency lists without removing parallel */
|
||||
/* links for use in future connectivity checking. */
|
||||
ERRCODE(buildlists(FALSE));
|
||||
|
||||
/* Free allocated memory */
|
||||
free(Degree);
|
||||
return(errcode);
|
||||
} /* End of createsparse */
|
||||
|
||||
|
||||
int allocsparse()
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: returns error code
|
||||
** Purpose: allocates memory for indexing the solution matrix
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int errcode = 0;
|
||||
Adjlist = (Padjlist *) calloc(Nnodes+1, sizeof(Padjlist));
|
||||
Order = (int *) calloc(Nnodes+1, sizeof(int));
|
||||
Row = (int *) calloc(Nnodes+1, sizeof(int));
|
||||
Ndx = (int *) calloc(Nlinks+1, sizeof(int));
|
||||
ERRCODE(MEMCHECK(Adjlist));
|
||||
ERRCODE(MEMCHECK(Order));
|
||||
ERRCODE(MEMCHECK(Row));
|
||||
ERRCODE(MEMCHECK(Ndx));
|
||||
return(errcode);
|
||||
}
|
||||
|
||||
|
||||
void freesparse()
|
||||
/*
|
||||
**----------------------------------------------------------------
|
||||
** Input: None
|
||||
** Output: None
|
||||
** Purpose: Frees memory used for sparse matrix storage
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
freelists();
|
||||
free(Adjlist);
|
||||
free(Order);
|
||||
free(Row);
|
||||
free(Ndx);
|
||||
free(XLNZ);
|
||||
free(NZSUB);
|
||||
free(LNZ);
|
||||
} /* End of freesparse */
|
||||
|
||||
|
||||
int buildlists(int paraflag)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: paraflag = TRUE if list marks parallel links
|
||||
** Output: returns error code
|
||||
** Purpose: builds linked list of links adjacent to each node
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i,j,k;
|
||||
int pmark = 0;
|
||||
int errcode = 0;
|
||||
Padjlist alink;
|
||||
|
||||
/* For each link, update adjacency lists of its end nodes */
|
||||
for (k=1; k<=Nlinks; k++)
|
||||
{
|
||||
i = Link[k].N1;
|
||||
j = Link[k].N2;
|
||||
if (paraflag) pmark = paralink(i,j,k); /* Parallel link check */
|
||||
|
||||
/* Include link in start node i's list */
|
||||
alink = (struct Sadjlist *) malloc(sizeof(struct Sadjlist));
|
||||
if (alink == NULL) return(101);
|
||||
if (!pmark) alink->node = j;
|
||||
else alink->node = 0; /* Parallel link marker */
|
||||
alink->link = k;
|
||||
alink->next = Adjlist[i];
|
||||
Adjlist[i] = alink;
|
||||
|
||||
/* Include link in end node j's list */
|
||||
alink = (struct Sadjlist *) malloc(sizeof(struct Sadjlist));
|
||||
if (alink == NULL) return(101);
|
||||
if (!pmark) alink->node = i;
|
||||
else alink->node = 0; /* Parallel link marker */
|
||||
alink->link = k;
|
||||
alink->next = Adjlist[j];
|
||||
Adjlist[j] = alink;
|
||||
}
|
||||
return(errcode);
|
||||
} /* End of buildlists */
|
||||
|
||||
|
||||
int paralink(int i, int j, int k)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: i = index of start node of link
|
||||
** j = index of end node of link
|
||||
** k = link index
|
||||
** Output: returns 1 if link k parallels another link, else 0
|
||||
** Purpose: checks for parallel links between nodes i and j
|
||||
**
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Padjlist alink;
|
||||
for (alink = Adjlist[i]; alink != NULL; alink = alink->next)
|
||||
{
|
||||
if (alink->node == j) /* Link || to k (same end nodes) */
|
||||
{
|
||||
Ndx[k] = alink->link; /* Assign Ndx entry to this link */
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
Ndx[k] = k; /* Ndx entry if link not parallel */
|
||||
return(0);
|
||||
} /* End of paralink */
|
||||
|
||||
|
||||
void xparalinks()
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: none
|
||||
** Purpose: removes parallel links from nodal adjacency lists
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i;
|
||||
Padjlist alink, /* Current item in adjacency list */
|
||||
blink; /* Previous item in adjacency list */
|
||||
|
||||
/* Scan adjacency list of each node */
|
||||
for (i=1; i<=Nnodes; i++)
|
||||
{
|
||||
alink = Adjlist[i]; /* First item in list */
|
||||
blink = NULL;
|
||||
while (alink != NULL)
|
||||
{
|
||||
if (alink->node == 0) /* Parallel link marker found */
|
||||
{
|
||||
if (blink == NULL) /* This holds at start of list */
|
||||
{
|
||||
Adjlist[i] = alink->next;
|
||||
free(alink); /* Remove item from list */
|
||||
alink = Adjlist[i];
|
||||
}
|
||||
else /* This holds for interior of list */
|
||||
{
|
||||
blink->next = alink->next;
|
||||
free(alink); /* Remove item from list */
|
||||
alink = blink->next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
blink = alink; /* Move to next item in list */
|
||||
alink = alink->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
} /* End of xparalinks */
|
||||
|
||||
|
||||
void freelists()
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: none
|
||||
** Purpose: frees memory used for nodal adjacency lists
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i;
|
||||
Padjlist alink;
|
||||
|
||||
for (i=0; i<=Nnodes; i++)
|
||||
{
|
||||
for (alink = Adjlist[i]; alink != NULL; alink = Adjlist[i])
|
||||
{
|
||||
Adjlist[i] = alink->next;
|
||||
free(alink);
|
||||
}
|
||||
}
|
||||
} /* End of freelists */
|
||||
|
||||
|
||||
void countdegree()
|
||||
/*
|
||||
**----------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: none
|
||||
** Purpose: counts number of nodes directly connected to each node
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i;
|
||||
Padjlist alink;
|
||||
memset(Degree,0,(Nnodes+1)*sizeof(int));
|
||||
|
||||
/* NOTE: For purposes of node re-ordering, Tanks (nodes with */
|
||||
/* indexes above Njuncs) have zero degree of adjacency. */
|
||||
|
||||
for (i=1; i<=Njuncs; i++)
|
||||
for (alink = Adjlist[i]; alink != NULL; alink = alink->next)
|
||||
if (alink->node > 0) Degree[i]++;
|
||||
}
|
||||
|
||||
|
||||
int reordernodes()
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: returns 1 if successful, 0 if not
|
||||
** Purpose: re-orders nodes to minimize # of non-zeros that
|
||||
** will appear in factorized solution matrix
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int k, knode, m, n;
|
||||
for (k=1; k<=Nnodes; k++)
|
||||
{
|
||||
Row[k] = k;
|
||||
Order[k] = k;
|
||||
}
|
||||
n = Njuncs;
|
||||
for (k=1; k<=n; k++) /* Examine each junction */
|
||||
{
|
||||
m = mindegree(k,n); /* Node with lowest degree */
|
||||
knode = Order[m]; /* Node's index */
|
||||
if (!growlist(knode)) return(101); /* Augment adjacency list */
|
||||
Order[m] = Order[k]; /* Switch order of nodes */
|
||||
Order[k] = knode;
|
||||
Degree[knode] = 0; /* In-activate node */
|
||||
}
|
||||
for (k=1; k<=n; k++) /* Assign nodes to rows of */
|
||||
Row[Order[k]] = k; /* coeff. matrix */
|
||||
return(0);
|
||||
} /* End of reordernodes */
|
||||
|
||||
|
||||
int mindegree(int k, int n)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: k = first node in list of active nodes
|
||||
** n = total number of junction nodes
|
||||
** Output: returns node index with fewest direct connections
|
||||
** Purpose: finds active node with fewest direct connections
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i, m;
|
||||
int min = n,
|
||||
imin = n;
|
||||
|
||||
for (i=k; i<=n; i++)
|
||||
{
|
||||
m = Degree[Order[i]];
|
||||
if (m < min)
|
||||
{
|
||||
min = m;
|
||||
imin = i;
|
||||
}
|
||||
}
|
||||
return(imin);
|
||||
} /* End of mindegree */
|
||||
|
||||
|
||||
int growlist(int knode)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: knode = node index
|
||||
** Output: returns 1 if successful, 0 if not
|
||||
** Purpose: creates new entries in knode's adjacency list for
|
||||
** all unlinked pairs of active nodes that are
|
||||
** adjacent to knode
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int node;
|
||||
Padjlist alink;
|
||||
|
||||
/* Iterate through all nodes connected to knode */
|
||||
for (alink = Adjlist[knode]; alink != NULL; alink = alink -> next)
|
||||
{
|
||||
node = alink->node; /* End node of connecting link */
|
||||
if (Degree[node] > 0) /* End node is active */
|
||||
{
|
||||
Degree[node]--; /* Reduce degree of adjacency */
|
||||
if (!newlink(alink)) /* Add to adjacency list */
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
return(1);
|
||||
} /* End of growlist */
|
||||
|
||||
|
||||
int newlink(Padjlist alink)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: alink = element of node's adjacency list
|
||||
** Output: returns 1 if successful, 0 if not
|
||||
** Purpose: links end of current adjacent link to end nodes of
|
||||
** all links that follow it on adjacency list
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int inode, jnode;
|
||||
Padjlist blink;
|
||||
|
||||
/* Scan all entries in adjacency list that follow anode. */
|
||||
inode = alink->node; /* End node of connection to anode */
|
||||
for (blink = alink->next; blink != NULL; blink = blink->next)
|
||||
{
|
||||
jnode = blink->node; /* End node of next connection */
|
||||
|
||||
/* If jnode still active, and inode not connected to jnode, */
|
||||
/* then add a new connection between inode and jnode. */
|
||||
if (Degree[jnode] > 0) /* jnode still active */
|
||||
{
|
||||
if (!linked(inode,jnode)) /* inode not linked to jnode */
|
||||
{
|
||||
|
||||
/* Since new connection represents a non-zero coeff. */
|
||||
/* in the solution matrix, update the coeff. count. */
|
||||
Ncoeffs++;
|
||||
|
||||
/* Update adjacency lists for inode & jnode to */
|
||||
/* reflect the new connection. */
|
||||
if (!addlink(inode,jnode,Ncoeffs)) return(0);
|
||||
if (!addlink(jnode,inode,Ncoeffs)) return(0);
|
||||
Degree[inode]++;
|
||||
Degree[jnode]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return(1);
|
||||
} /* End of newlink */
|
||||
|
||||
|
||||
int linked(int i, int j)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: i = node index
|
||||
** j = node index
|
||||
** Output: returns 1 if nodes i and j are linked, 0 if not
|
||||
** Purpose: checks if nodes i and j are already linked.
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Padjlist alink;
|
||||
for (alink = Adjlist[i]; alink != NULL; alink = alink->next)
|
||||
if (alink->node == j) return(1);
|
||||
return(0);
|
||||
} /* End of linked */
|
||||
|
||||
|
||||
int addlink(int i, int j, int n)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: i = node index
|
||||
** j = node index
|
||||
** n = link index
|
||||
** Output: returns 1 if successful, 0 if not
|
||||
** Purpose: augments node i's adjacency list with node j
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Padjlist alink;
|
||||
alink = (struct Sadjlist *) malloc(sizeof(struct Sadjlist));
|
||||
if (alink == NULL) return(0);
|
||||
alink->node = j;
|
||||
alink->link = n;
|
||||
alink->next = Adjlist[i];
|
||||
Adjlist[i] = alink;
|
||||
return(1);
|
||||
} /* End of addlink */
|
||||
|
||||
|
||||
int storesparse(int n)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: n = number of rows in solution matrix
|
||||
** Output: returns error code
|
||||
** Purpose: stores row indexes of non-zeros of each column of
|
||||
** lower triangular portion of factorized matrix
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Padjlist alink;
|
||||
int i, ii, j, k, l, m;
|
||||
int errcode = 0;
|
||||
|
||||
/* Allocate sparse matrix storage */
|
||||
XLNZ = (int *) calloc(n+2, sizeof(int));
|
||||
NZSUB = (int *) calloc(Ncoeffs+2, sizeof(int));
|
||||
LNZ = (int *) calloc(Ncoeffs+2, sizeof(int));
|
||||
ERRCODE(MEMCHECK(XLNZ));
|
||||
ERRCODE(MEMCHECK(NZSUB));
|
||||
ERRCODE(MEMCHECK(LNZ));
|
||||
if (errcode) return(errcode);
|
||||
|
||||
/* Generate row index pointers for each column of matrix */
|
||||
k = 0;
|
||||
XLNZ[1] = 1;
|
||||
for (i=1; i<=n; i++) /* column */
|
||||
{
|
||||
m = 0;
|
||||
ii = Order[i];
|
||||
for (alink = Adjlist[ii]; alink != NULL; alink = alink->next)
|
||||
{
|
||||
j = Row[alink->node]; /* row */
|
||||
l = alink->link;
|
||||
if (j > i && j <= n)
|
||||
{
|
||||
m++;
|
||||
k++;
|
||||
NZSUB[k] = j;
|
||||
LNZ[k] = l;
|
||||
}
|
||||
}
|
||||
XLNZ[i+1] = XLNZ[i] + m;
|
||||
}
|
||||
return(errcode);
|
||||
} /* End of storesparse */
|
||||
|
||||
|
||||
int ordersparse(int n)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: n = number of rows in solution matrix
|
||||
** Output: returns eror code
|
||||
** Purpose: puts row indexes in ascending order in NZSUB
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i, k;
|
||||
int *xlnzt, *nzsubt, *lnzt, *nzt;
|
||||
int errcode = 0;
|
||||
|
||||
xlnzt = (int *) calloc(n+2, sizeof(int));
|
||||
nzsubt = (int *) calloc(Ncoeffs+2, sizeof(int));
|
||||
lnzt = (int *) calloc(Ncoeffs+2, sizeof(int));
|
||||
nzt = (int *) calloc(n+2, sizeof(int));
|
||||
ERRCODE(MEMCHECK(xlnzt));
|
||||
ERRCODE(MEMCHECK(nzsubt));
|
||||
ERRCODE(MEMCHECK(lnzt));
|
||||
ERRCODE(MEMCHECK(nzt));
|
||||
if (!errcode)
|
||||
{
|
||||
|
||||
/* Count # non-zeros in each row */
|
||||
for (i=1; i<=n; i++) nzt[i] = 0;
|
||||
for (i=1; i<=n; i++)
|
||||
{
|
||||
for (k=XLNZ[i]; k<XLNZ[i+1]; k++) nzt[NZSUB[k]]++;
|
||||
}
|
||||
xlnzt[1] = 1;
|
||||
for (i=1; i<=n; i++) xlnzt[i+1] = xlnzt[i] + nzt[i];
|
||||
|
||||
/* Transpose matrix twice to order column indexes */
|
||||
transpose(n,XLNZ,NZSUB,LNZ,xlnzt,nzsubt,lnzt,nzt);
|
||||
transpose(n,xlnzt,nzsubt,lnzt,XLNZ,NZSUB,LNZ,nzt);
|
||||
}
|
||||
|
||||
/* Reclaim memory */
|
||||
free(xlnzt);
|
||||
free(nzsubt);
|
||||
free(lnzt);
|
||||
free(nzt);
|
||||
return(errcode);
|
||||
} /* End of ordersparse */
|
||||
|
||||
|
||||
void transpose(int n, int *il, int *jl, int *xl, int *ilt, int *jlt,
|
||||
int *xlt, int *nzt)
|
||||
/*
|
||||
**---------------------------------------------------------------------
|
||||
** Input: n = matrix order
|
||||
** il,jl,xl = sparse storage scheme for original matrix
|
||||
** nzt = work array
|
||||
** Output: ilt,jlt,xlt = sparse storage scheme for transposed matrix
|
||||
** Purpose: Determines sparse storage scheme for transpose of a matrix
|
||||
**---------------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i, j, k, kk;
|
||||
|
||||
for (i=1; i<=n; i++) nzt[i] = 0;
|
||||
for (i=1; i<=n; i++)
|
||||
{
|
||||
for (k=il[i]; k<il[i+1]; k++)
|
||||
{
|
||||
j = jl[k];
|
||||
kk = ilt[j] + nzt[j];
|
||||
jlt[kk] = i;
|
||||
xlt[kk] = xl[k];
|
||||
nzt[j]++;
|
||||
}
|
||||
}
|
||||
} /* End of transpose */
|
||||
|
||||
|
||||
int linsolve(int n, double *Aii, double *Aij, double *B)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: n = number of equations
|
||||
** Aii = diagonal entries of solution matrix
|
||||
** Aij = non-zero off-diagonal entries of matrix
|
||||
** B = right hand side coeffs.
|
||||
** Output: B = solution values
|
||||
** returns 0 if solution found, or index of
|
||||
** equation causing system to be ill-conditioned
|
||||
** Purpose: solves sparse symmetric system of linear
|
||||
** equations using Cholesky factorization
|
||||
**
|
||||
** NOTE: This procedure assumes that the solution matrix has
|
||||
** been symbolically factorized with the positions of
|
||||
** the lower triangular, off-diagonal, non-zero coeffs.
|
||||
** stored in the following integer arrays:
|
||||
** XLNZ (start position of each column in NZSUB)
|
||||
** NZSUB (row index of each non-zero in each column)
|
||||
** LNZ (position of each NZSUB entry in Aij array)
|
||||
**
|
||||
** This procedure has been adapted from subroutines GSFCT and
|
||||
** GSSLV in the book "Computer Solution of Large Sparse
|
||||
** Positive Definite Systems" by A. George and J. W-H Liu
|
||||
** (Prentice-Hall, 1981).
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int *link, *first;
|
||||
int i, istop, istrt, isub, j, k, kfirst, newk;
|
||||
int errcode = 0;
|
||||
double bj, diagj, ljk;
|
||||
double *temp;
|
||||
|
||||
temp = (double *) calloc(n+1, sizeof(double));
|
||||
link = (int *) calloc(n+1,sizeof(int));
|
||||
first = (int *) calloc(n+1,sizeof(int));
|
||||
ERRCODE(MEMCHECK(temp));
|
||||
ERRCODE(MEMCHECK(link));
|
||||
ERRCODE(MEMCHECK(first));
|
||||
if (errcode)
|
||||
{
|
||||
errcode = -errcode;
|
||||
goto ENDLINSOLVE;
|
||||
}
|
||||
memset(temp,0,(n+1)*sizeof(double));
|
||||
memset(link,0,(n+1)*sizeof(int));
|
||||
|
||||
/* Begin numerical factorization of matrix A into L */
|
||||
/* Compute column L(*,j) for j = 1,...n */
|
||||
for (j=1; j<=n; j++)
|
||||
{
|
||||
/* For each column L(*,k) that affects L(*,j): */
|
||||
diagj = 0.0;
|
||||
newk = link[j];
|
||||
k = newk;
|
||||
while (k != 0)
|
||||
{
|
||||
|
||||
/* Outer product modification of L(*,j) by */
|
||||
/* L(*,k) starting at first[k] of L(*,k). */
|
||||
newk = link[k];
|
||||
kfirst = first[k];
|
||||
ljk = Aij[LNZ[kfirst]];
|
||||
diagj += ljk*ljk;
|
||||
istrt = kfirst + 1;
|
||||
istop = XLNZ[k+1] - 1;
|
||||
if (istop >= istrt)
|
||||
{
|
||||
|
||||
/* Before modification, update vectors 'first' */
|
||||
/* and 'link' for future modification steps. */
|
||||
first[k] = istrt;
|
||||
isub = NZSUB[istrt];
|
||||
link[k] = link[isub];
|
||||
link[isub] = k;
|
||||
|
||||
/* The actual mod is saved in vector 'temp'. */
|
||||
for (i=istrt; i<=istop; i++)
|
||||
{
|
||||
isub = NZSUB[i];
|
||||
temp[isub] += Aij[LNZ[i]]*ljk;
|
||||
}
|
||||
}
|
||||
k = newk;
|
||||
}
|
||||
|
||||
/* Apply the modifications accumulated */
|
||||
/* in 'temp' to column L(*,j). */
|
||||
diagj = Aii[j] - diagj;
|
||||
if (diagj <= 0.0) /* Check for ill-conditioning */
|
||||
{
|
||||
errcode = j;
|
||||
goto ENDLINSOLVE;
|
||||
}
|
||||
diagj = sqrt(diagj);
|
||||
Aii[j] = diagj;
|
||||
istrt = XLNZ[j];
|
||||
istop = XLNZ[j+1] - 1;
|
||||
if (istop >= istrt)
|
||||
{
|
||||
first[j] = istrt;
|
||||
isub = NZSUB[istrt];
|
||||
link[j] = link[isub];
|
||||
link[isub] = j;
|
||||
for (i=istrt; i<=istop; i++)
|
||||
{
|
||||
isub = NZSUB[i];
|
||||
bj = (Aij[LNZ[i]] - temp[isub])/diagj;
|
||||
Aij[LNZ[i]] = bj;
|
||||
temp[isub] = 0.0;
|
||||
}
|
||||
}
|
||||
} /* next j */
|
||||
|
||||
/* Foward substitution */
|
||||
for (j=1; j<=n; j++)
|
||||
{
|
||||
bj = B[j]/Aii[j];
|
||||
B[j] = bj;
|
||||
istrt = XLNZ[j];
|
||||
istop = XLNZ[j+1] - 1;
|
||||
if (istop >= istrt)
|
||||
{
|
||||
for (i=istrt; i<=istop; i++)
|
||||
{
|
||||
isub = NZSUB[i];
|
||||
B[isub] -= Aij[LNZ[i]]*bj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Backward substitution */
|
||||
for (j=n; j>=1; j--)
|
||||
{
|
||||
bj = B[j];
|
||||
istrt = XLNZ[j];
|
||||
istop = XLNZ[j+1] - 1;
|
||||
if (istop >= istrt)
|
||||
{
|
||||
for (i=istrt; i<=istop; i++)
|
||||
{
|
||||
isub = NZSUB[i];
|
||||
bj -= Aij[LNZ[i]]*B[isub];
|
||||
}
|
||||
}
|
||||
B[j] = bj/Aii[j];
|
||||
}
|
||||
|
||||
ENDLINSOLVE:
|
||||
free(temp);
|
||||
free(link);
|
||||
free(first);
|
||||
return(errcode);
|
||||
} /* End of linsolve */
|
||||
|
||||
|
||||
/************************ END OF SMATRIX.C ************************/
|
||||
|
||||
519
src/text.h
Normal file
519
src/text.h
Normal file
@@ -0,0 +1,519 @@
|
||||
/*
|
||||
****************************************************
|
||||
|
||||
String Constants for EPANET Program
|
||||
|
||||
VERSION: 2.00
|
||||
DATE: 5/8/00
|
||||
10/25/00
|
||||
8/15/07 (2.00.11)
|
||||
AUTHOR: L. Rossman
|
||||
US EPA - NRMRL
|
||||
|
||||
****************************************************
|
||||
*/
|
||||
/* ------------ Keyword Dictionary ---------- */
|
||||
|
||||
#define w_USE "USE"
|
||||
#define w_SAVE "SAVE"
|
||||
|
||||
#define w_NONE "NONE"
|
||||
#define w_ALL "ALL"
|
||||
|
||||
#define w_CHEM "CHEM"
|
||||
#define w_AGE "AGE"
|
||||
#define w_TRACE "TRACE"
|
||||
|
||||
#define w_SYSTEM "SYST"
|
||||
#define w_JUNC "Junc"
|
||||
#define w_RESERV "Reser"
|
||||
#define w_TANK "Tank"
|
||||
#define w_CV "CV"
|
||||
#define w_PIPE "Pipe"
|
||||
#define w_PUMP "Pump"
|
||||
#define w_VALVE "Valve"
|
||||
#define w_PRV "PRV"
|
||||
#define w_PSV "PSV"
|
||||
#define w_PBV "PBV"
|
||||
#define w_FCV "FCV"
|
||||
#define w_TCV "TCV"
|
||||
#define w_GPV "GPV"
|
||||
|
||||
#define w_OPEN "OPEN"
|
||||
#define w_CLOSED "CLOSED"
|
||||
#define w_ACTIVE "ACTIVE"
|
||||
#define w_TIME "TIME"
|
||||
#define w_ABOVE "ABOVE"
|
||||
#define w_BELOW "BELOW"
|
||||
#define w_PRECISION "PREC"
|
||||
#define w_IS "IS"
|
||||
#define w_NOT "NOT"
|
||||
|
||||
#define w_ADD "ADD"
|
||||
#define w_MULTIPLY "MULT"
|
||||
|
||||
#define w_LIMITING "LIMIT"
|
||||
#define w_ORDER "ORDER"
|
||||
#define w_GLOBAL "GLOB"
|
||||
#define w_BULK "BULK"
|
||||
#define w_WALL "WALL"
|
||||
|
||||
#define w_PAGE "PAGE"
|
||||
#define w_STATUS "STATUS"
|
||||
#define w_SUMMARY "SUMM"
|
||||
#define w_MESSAGES "MESS"
|
||||
#define w_ENERGY "ENER"
|
||||
#define w_NODE "NODE"
|
||||
#define w_LINK "LINK"
|
||||
#define w_FILE "FILE"
|
||||
#define w_YES "YES"
|
||||
#define w_NO "NO"
|
||||
#define w_FULL "FULL"
|
||||
|
||||
#define w_HW "H-W"
|
||||
#define w_DW "D-W"
|
||||
#define w_CM "C-M"
|
||||
|
||||
#define w_CFS "CFS"
|
||||
#define w_GPM "GPM"
|
||||
#define w_MGD "MGD"
|
||||
#define w_IMGD "IMGD"
|
||||
#define w_AFD "AFD"
|
||||
#define w_LPS "LPS"
|
||||
#define w_LPM "LPM"
|
||||
#define w_MLD "MLD"
|
||||
#define w_CMH "CMH"
|
||||
#define w_CMD "CMD"
|
||||
#define w_SI "SI"
|
||||
|
||||
#define w_PSI "PSI"
|
||||
#define w_KPA "KPA"
|
||||
#define w_METERS "METERS"
|
||||
|
||||
#define w_ELEV "ELEV"
|
||||
#define w_DEMAND "DEMA"
|
||||
#define w_HEAD "HEAD"
|
||||
#define w_PRESSURE "PRES"
|
||||
#define w_QUALITY "QUAL"
|
||||
|
||||
#define w_DIAM "DIAM"
|
||||
#define w_FLOW "FLOW"
|
||||
#define w_ROUGHNESS "ROUG"
|
||||
#define w_VELOCITY "VELO"
|
||||
#define w_HEADLOSS "HEADL"
|
||||
#define w_SETTING "SETT"
|
||||
#define w_POWER "POWE"
|
||||
#define w_VOLUME "VOLU"
|
||||
#define w_CLOCKTIME "CLOCKTIME"
|
||||
#define w_FILLTIME "FILL"
|
||||
#define w_DRAINTIME "DRAI"
|
||||
#define w_GRADE "GRADE"
|
||||
#define w_LEVEL "LEVEL"
|
||||
|
||||
#define w_DURATION "DURA"
|
||||
#define w_HYDRAULIC "HYDR"
|
||||
#define w_MINIMUM "MINI"
|
||||
#define w_PATTERN "PATT"
|
||||
#define w_REPORT "REPO"
|
||||
#define w_START "STAR"
|
||||
|
||||
#define w_UNITS "UNIT"
|
||||
#define w_MAP "MAP"
|
||||
#define w_VERIFY "VERI"
|
||||
#define w_VISCOSITY "VISC"
|
||||
#define w_DIFFUSIVITY "DIFF"
|
||||
#define w_SPECGRAV "SPEC"
|
||||
#define w_TRIALS "TRIAL"
|
||||
#define w_ACCURACY "ACCU"
|
||||
#define w_SEGMENTS "SEGM"
|
||||
#define w_TOLERANCE "TOLER"
|
||||
#define w_EMITTER "EMIT"
|
||||
|
||||
#define w_PRICE "PRICE"
|
||||
#define w_DMNDCHARGE "DEMAN"
|
||||
|
||||
#define w_HTOL "HTOL"
|
||||
#define w_QTOL "QTOL"
|
||||
#define w_RQTOL "RQTOL"
|
||||
#define w_CHECKFREQ "CHECKFREQ"
|
||||
#define w_MAXCHECK "MAXCHECK"
|
||||
|
||||
#define w_SECONDS "SEC"
|
||||
#define w_MINUTES "MIN"
|
||||
#define w_HOURS "HOU"
|
||||
#define w_DAYS "DAY"
|
||||
#define w_AM "AM"
|
||||
#define w_PM "PM"
|
||||
|
||||
#define w_CONCEN "CONCEN"
|
||||
#define w_MASS "MASS"
|
||||
#define w_SETPOINT "SETPOINT"
|
||||
#define w_FLOWPACED "FLOWPACED"
|
||||
|
||||
#define w_PATTERN "PATT"
|
||||
#define w_CURVE "CURV"
|
||||
|
||||
#define w_EFFIC "EFFI"
|
||||
#define w_HEAD "HEAD"
|
||||
#define w_POWER "POWE"
|
||||
#define w_SPEED "SPEE"
|
||||
|
||||
#define w_MIXED "MIXED"
|
||||
#define w_2COMP "2COMP"
|
||||
#define w_FIFO "FIFO"
|
||||
#define w_LIFO "LIFO"
|
||||
|
||||
#define w_STATISTIC "STAT"
|
||||
#define w_AVG "AVERAGE"
|
||||
#define w_MIN "MINIMUM"
|
||||
#define w_MAX "MAXIMUM"
|
||||
#define w_RANGE "RANGE"
|
||||
|
||||
#define w_UNBALANCED "UNBA"
|
||||
#define w_STOP "STOP"
|
||||
#define w_CONTINUE "CONT"
|
||||
|
||||
#define w_RULE "RULE"
|
||||
#define w_IF "IF"
|
||||
#define w_AND "AND"
|
||||
#define w_OR "OR"
|
||||
#define w_THEN "THEN"
|
||||
#define w_ELSE "ELSE"
|
||||
#define w_PRIORITY "PRIO"
|
||||
|
||||
/* ---------Input Section Names ---------- */
|
||||
#define s_TITLE "[TITL"
|
||||
#define s_JUNCTIONS "[JUNC"
|
||||
#define s_RESERVOIRS "[RESE"
|
||||
#define s_TANKS "[TANK"
|
||||
#define s_PIPES "[PIPE"
|
||||
#define s_PUMPS "[PUMP"
|
||||
#define s_VALVES "[VALV"
|
||||
#define s_CONTROLS "[CONT"
|
||||
#define s_RULES "[RULE"
|
||||
#define s_DEMANDS "[DEMA"
|
||||
#define s_SOURCES "[SOUR"
|
||||
#define s_EMITTERS "[EMIT"
|
||||
#define s_PATTERNS "[PATT"
|
||||
#define s_CURVES "[CURV"
|
||||
#define s_QUALITY "[QUAL"
|
||||
#define s_STATUS "[STAT"
|
||||
#define s_ROUGHNESS "[ROUG"
|
||||
#define s_ENERGY "[ENER"
|
||||
#define s_REACTIONS "[REAC"
|
||||
#define s_MIXING "[MIXI"
|
||||
#define s_REPORT "[REPO"
|
||||
#define s_TIMES "[TIME"
|
||||
#define s_OPTIONS "[OPTI"
|
||||
#define s_COORDS "[COOR"
|
||||
#define s_VERTICES "[VERT"
|
||||
#define s_LABELS "[LABE"
|
||||
#define s_BACKDROP "[BACK"
|
||||
#define s_TAGS "[TAGS"
|
||||
#define s_END "[END"
|
||||
|
||||
/* ---------------- Units ---------------- */
|
||||
/*** Limit units to MAXID or less characters ***/
|
||||
#define u_CFS "cfs"
|
||||
#define u_GPM "gpm"
|
||||
#define u_AFD "a-f/d"
|
||||
#define u_MGD "mgd"
|
||||
#define u_IMGD "Imgd"
|
||||
#define u_LPS "L/s"
|
||||
#define u_LPM "Lpm"
|
||||
#define u_CMH "m3/h"
|
||||
#define u_CMD "m3/d"
|
||||
#define u_MLD "ML/d"
|
||||
#define u_MGperL "mg/L"
|
||||
#define u_UGperL "ug/L"
|
||||
#define u_HOURS "hrs"
|
||||
#define u_MINUTES "min"
|
||||
#define u_PERCENT "% from"
|
||||
#define u_METERS "m"
|
||||
#define u_MMETERS "mm"
|
||||
#define u_MperSEC "m/s"
|
||||
#define u_SQMperSEC "sq m/sec"
|
||||
#define u_per1000M "/1000m"
|
||||
#define u_KW "kw"
|
||||
#define u_FEET "ft"
|
||||
#define u_INCHES "in"
|
||||
#define u_PSI "psi"
|
||||
#define u_KPA "kPa"
|
||||
#define u_FTperSEC "fps"
|
||||
#define u_SQFTperSEC "sq ft/sec"
|
||||
#define u_per1000FT "/1000ft"
|
||||
#define u_HP "hp"
|
||||
|
||||
/* -------------- Curve Types ----------------- */
|
||||
#define c_HEADLOSS "HEADLOSS"
|
||||
#define c_PUMP "PUMP"
|
||||
#define c_EFFIC "EFFIC"
|
||||
#define c_VOLUME "VOLUME"
|
||||
|
||||
/* ------------------ Text Phrases ------------------- */
|
||||
#define t_ABOVE "above"
|
||||
#define t_BELOW "below"
|
||||
#define t_HW "Hazen-Williams"
|
||||
#define t_DW "Darcy-Weisbach"
|
||||
#define t_CM "Chezy-Manning"
|
||||
#define t_CHEMICAL "Chemical"
|
||||
#define t_XHEAD "closed because cannot deliver head"
|
||||
#define t_TEMPCLOSED "temporarily closed"
|
||||
#define t_CLOSED "closed"
|
||||
#define t_OPEN "open"
|
||||
#define t_ACTIVE "active"
|
||||
#define t_XFLOW "open but exceeds maximum flow"
|
||||
#define t_XFCV "open but cannot deliver flow"
|
||||
#define t_XPRESSURE "open but cannot deliver pressure"
|
||||
#define t_FILLING "filling"
|
||||
#define t_EMPTYING "emptying"
|
||||
|
||||
#define t_ELEV "Elevation"
|
||||
#define t_DEMAND "Demand"
|
||||
#define t_HEAD "Head"
|
||||
#define t_PRESSURE "Pressure"
|
||||
#define t_QUALITY "Quality"
|
||||
#define t_LENGTH "Length"
|
||||
#define t_DIAM "Diameter"
|
||||
#define t_FLOW "Flow"
|
||||
#define t_VELOCITY "Velocity"
|
||||
#define t_HEADLOSS "Headloss"
|
||||
#define t_LINKQUAL "Quality"
|
||||
#define t_LINKSTATUS "State"
|
||||
#define t_SETTING "Setting"
|
||||
#define t_REACTRATE "Reaction"
|
||||
#define t_FRICTION "F-Factor"
|
||||
|
||||
#define t_NODEID "Node"
|
||||
#define t_LINKID "Link"
|
||||
#define t_PERDAY "/day"
|
||||
|
||||
#define t_JUNCTION "Junction"
|
||||
#define t_RESERVOIR "Reservoir"
|
||||
#define t_TANK "Tank"
|
||||
#define t_PIPE "Pipe"
|
||||
#define t_PUMP "Pump"
|
||||
#define t_VALVE "Valve"
|
||||
#define t_CONTROL "Control"
|
||||
#define t_RULE "Rule"
|
||||
#define t_DEMANDFOR "Demand for Node"
|
||||
#define t_SOURCE "Source"
|
||||
#define t_EMITTER "Emitter"
|
||||
#define t_PATTERN "Pattern"
|
||||
#define t_CURVE "Curve"
|
||||
#define t_STATUS "Status"
|
||||
#define t_ROUGHNESS "Roughness"
|
||||
#define t_ENERGY "Energy"
|
||||
#define t_REACTION "Reaction"
|
||||
#define t_MIXING "Mixing"
|
||||
#define t_REPORT "Report"
|
||||
#define t_TIME "Times"
|
||||
#define t_OPTION "Options"
|
||||
#define t_RULES_SECT "[RULES] section"
|
||||
#define t_HALTED " EXECUTION HALTED."
|
||||
#define t_FUNCCALL "function call"
|
||||
#define t_CONTINUED " (continued)"
|
||||
#define t_perM3 " /m3"
|
||||
#define t_perMGAL "/Mgal"
|
||||
#define t_DIFFER "DIFFERENTIAL"
|
||||
|
||||
|
||||
/* ------------------ Format Messages ------------------*/
|
||||
#define LOGO1 \
|
||||
"******************************************************************"
|
||||
#define LOGO2 \
|
||||
"* E P A N E T *"
|
||||
#define LOGO3 \
|
||||
"* Hydraulic and Water Quality *"
|
||||
#define LOGO4 \
|
||||
"* Analysis for Pipe Networks *"
|
||||
#define LOGO5 \
|
||||
"* Version 2.00.11 *" //(2.00.11 - LR)
|
||||
#define LOGO6 \
|
||||
"******************************************************************"
|
||||
#define FMT01 "\n... EPANET Version 2.0\n"
|
||||
#define FMT02 "\n o Retrieving network data"
|
||||
#define FMT03 "\n Correct syntax is:\n epanet <input file> <output file>\n"
|
||||
#define FMT04 "\n Cannot use duplicate file names."
|
||||
#define FMT05 "\n Cannot open input file "
|
||||
#define FMT06 "\n Cannot open report file "
|
||||
#define FMT07 "\n Cannot open output file "
|
||||
#define FMT08 "\n Cannot open temporary output file"
|
||||
#define FMT09 "\n\n... EPANET completed.\n"
|
||||
#define FMT10 "\n\n... EPANET completed. There are warnings.\n"
|
||||
#define FMT11 "\n\n... EPANET completed. There are errors.\n"
|
||||
#define FMT14 "\n o Computing hydraulics at hour "
|
||||
#define FMT15 "\n o Computing water quality at hour "
|
||||
#define FMT16 "\n o Transferring results to file"
|
||||
#define FMT17 "\n o Writing output report to "
|
||||
#define FMT18 " Page 1 "
|
||||
#define FMT19 " Input Data File ................... %s"
|
||||
#define FMT20 " Number of Junctions................ %-d"
|
||||
#define FMT21a " Number of Reservoirs............... %-d"
|
||||
#define FMT21b " Number of Tanks ................... %-d"
|
||||
#define FMT22 " Number of Pipes ................... %-d"
|
||||
#define FMT23 " Number of Pumps ................... %-d"
|
||||
#define FMT24 " Number of Valves .................. %-d"
|
||||
#define FMT25 " Headloss Formula .................. %s"
|
||||
#define FMT26 " Hydraulic Timestep ................ %-.2f %s"
|
||||
#define FMT27 " Hydraulic Accuracy ................ %-.6f"
|
||||
#define FMT28 " Maximum Trials .................... %-d"
|
||||
#define FMT29 " Quality Analysis .................. None"
|
||||
#define FMT30 " Quality Analysis .................. %s"
|
||||
#define FMT31 " Quality Analysis .................. Trace From Node %s"
|
||||
#define FMT32 " Quality Analysis .................. Age"
|
||||
#define FMT33 " Water Quality Time Step ........... %-.2f min"
|
||||
#define FMT34 " Water Quality Tolerance ........... %-.2f %s"
|
||||
#define FMT36 " Specific Gravity .................. %-.2f"
|
||||
#define FMT37a " Relative Kinematic Viscosity ...... %-.2f"
|
||||
#define FMT37b " Relative Chemical Diffusivity ..... %-.2f"
|
||||
#define FMT38 " Demand Multiplier ................. %-.2f"
|
||||
#define FMT39 " Total Duration .................... %-.2f %s"
|
||||
#define FMT40 " Reporting Criteria:"
|
||||
#define FMT41 " No Nodes"
|
||||
#define FMT42 " All Nodes"
|
||||
#define FMT43 " Selected Nodes"
|
||||
#define FMT44 " No Links"
|
||||
#define FMT45 " All Links"
|
||||
#define FMT46 " Selected Links"
|
||||
#define FMT47 " with %s below %-.2f %s"
|
||||
#define FMT48 " with %s above %-.2f %s"
|
||||
|
||||
/* ---------- Status Report Format Strings ------------ */
|
||||
#define FMT49 "Hydraulic Status:"
|
||||
|
||||
/*** Updated 6/24/02 ***/
|
||||
#define FMT50 "%10s: Tank %s is %s at %-.2f %s"
|
||||
#define FMT51 "%10s: Reservoir %s is %s"
|
||||
#define FMT52 "%10s: %s %s %s"
|
||||
#define FMT53 "%10s: %s %s changed from %s to %s"
|
||||
#define FMT54 "%10s: %s %s changed by %s %s control"
|
||||
#define FMT55 "%10s: %s %s changed by timer control"
|
||||
#define FMT56 " %s %s setting changed to %-.2f"
|
||||
#define FMT57 " %s %s switched from %s to %s"
|
||||
#define FMT58 "%10s: Balanced after %-d trials"
|
||||
#define FMT59 "%10s: Unbalanced after %-d trials (flow change = %-.6f)"
|
||||
#define FMT61 "%10s: Valve %s caused ill-conditioning"
|
||||
#define FMT62 "%10s: System ill-conditioned at node %s"
|
||||
#define FMT63 "%10s: %s %s changed by rule %s"
|
||||
#define FMT64 "%10s: Balancing the network:"
|
||||
#define FMT65 " Trial %2d: relative flow change = %-.6f"
|
||||
/*** End of update ***/
|
||||
|
||||
/* -------------------- Energy Report Table ------------------- */
|
||||
#define FMT71 "Energy Usage:"
|
||||
#define FMT72 \
|
||||
" Usage Avg. Kw-hr Avg. Peak Cost"
|
||||
#define FMT73 \
|
||||
"Pump Factor Effic. %s Kw Kw /day"
|
||||
#define FMT74 "%38s Demand Charge: %9.2f"
|
||||
#define FMT75 "%38s Total Cost: %9.2f"
|
||||
|
||||
/* -------------------- Node Report Table --------------------- */
|
||||
#define FMT76 "%s Node Results:"
|
||||
#define FMT77 "Node Results:"
|
||||
#define FMT78 "Node Results at %s hrs:"
|
||||
|
||||
/* -------------------- Link Report Table --------------------- */
|
||||
#define FMT79 "%s Link Results:"
|
||||
#define FMT80 "Link Results:"
|
||||
#define FMT81 "Link Results at %s hrs:"
|
||||
#define FMT82 "\n\f\n Page %-d %60.60s\n"
|
||||
|
||||
/* ------------------- Progress Messages ---------------------- */
|
||||
#define FMT100 "Retrieving network data..."
|
||||
#define FMT101 "Computing hydraulics at hour %s"
|
||||
#define FMT102 "Computing water quality at hour %s"
|
||||
#define FMT103 "Saving results to file..."
|
||||
#define FMT104 "Analysis begun %s"
|
||||
#define FMT105 "Analysis ended %s"
|
||||
|
||||
/*------------------- Error Messages --------------------*/
|
||||
#define ERR101 "System Error 101: insufficient memory available."
|
||||
#define ERR102 "System Error 102: no network data available."
|
||||
#define ERR103 "System Error 103: hydraulics not initialized."
|
||||
#define ERR104 "System Error 104: no hydraulics for water quality analysis."
|
||||
#define ERR105 "System Error 105: water quality not initialized."
|
||||
#define ERR106 "System Error 106: no results saved to report on."
|
||||
#define ERR107 "System Error 107: hydraulics supplied from external file."
|
||||
#define ERR108 "System Error 108: cannot use external file while hydraulics solver is active."
|
||||
#define ERR109 "System Error 109: cannot change time parameter when solver is active."
|
||||
#define ERR110 "System Error 110: cannot solve network hydraulic equations."
|
||||
#define ERR120 "System Error 120: cannot solve water quality transport equations."
|
||||
|
||||
#define ERR200 "Input Error 200: one or more errors in input file."
|
||||
#define ERR201 \
|
||||
"Input Error 201: syntax error in following line of [%s] section:"
|
||||
#define ERR202 "Input Error 202: %s %s contains illegal numeric value."
|
||||
#define ERR203 "Input Error 203: %s %s refers to undefined node."
|
||||
#define ERR204 "Input Error 204: %s %s refers to undefined link."
|
||||
#define ERR205 "Input Error 205: %s %s refers to undefined time pattern."
|
||||
#define ERR206 "Input Error 206: %s %s refers to undefined curve."
|
||||
#define ERR207 "Input Error 207: %s %s attempts to control a CV."
|
||||
|
||||
#define ERR208 "Input Error 208: %s specified for undefined Node %s."
|
||||
#define ERR209 "Input Error 209: illegal %s value for Node %s."
|
||||
#define ERR210 "Input Error 210: %s specified for undefined Link %s."
|
||||
#define ERR211 "Input Error 211: illegal %s value for Link %s."
|
||||
#define ERR212 "Input Error 212: trace node %.0s %s is undefined."
|
||||
#define ERR213 "Input Error 213: illegal option value in [%s] section:"
|
||||
#define ERR214 \
|
||||
"Input Error 214: following line of [%s] section contains too many characters:"
|
||||
#define ERR215 "Input Error 215: %s %s is a duplicate ID."
|
||||
#define ERR216 "Input Error 216: %s data specified for undefined Pump %s."
|
||||
#define ERR217 "Input Error 217: invalid %s data for Pump %s."
|
||||
#define ERR219 "Input Error 219: %s %s illegally connected to a tank."
|
||||
#define ERR220 "Input Error 220: %s %s illegally connected to another valve."
|
||||
|
||||
/*** Updated on 10/25/00 ***/
|
||||
#define ERR222 "Input Error 222: %s %s has same start and end nodes."
|
||||
|
||||
#define ERR223 "Input Error 223: not enough nodes in network"
|
||||
#define ERR224 "Input Error 224: no tanks or reservoirs in network."
|
||||
#define ERR225 "Input Error 225: invalid lower/upper levels for Tank %s."
|
||||
#define ERR226 "Input Error 226: no head curve supplied for Pump %s."
|
||||
#define ERR227 "Input Error 227: invalid head curve for Pump %s."
|
||||
#define ERR230 "Input Error 230: Curve %s has nonincreasing x-values."
|
||||
#define ERR233 "Input Error 233: Node %s is unconnected."
|
||||
#define ERR240 "Input Error 240: %s %s refers to undefined source."
|
||||
#define ERR241 "Input Error 241: %s %s refers to undefined control."
|
||||
#define ERR250 "Input Error 250: function call contains invalid format."
|
||||
#define ERR251 "Input Error 251: function call contains invalid parameter code."
|
||||
|
||||
#define ERR301 "File Error 301: identical file names."
|
||||
#define ERR302 "File Error 302: cannot open input file."
|
||||
#define ERR303 "File Error 303: cannot open report file."
|
||||
#define ERR304 "File Error 304: cannot open binary output file."
|
||||
#define ERR305 "File Error 305: cannot open hydraulics file."
|
||||
#define ERR306 "File Error 306: hydraulics file does not match network data."
|
||||
#define ERR307 "File Error 307: cannot read hydraulics file."
|
||||
#define ERR308 "File Error 308: cannot save results to file."
|
||||
#define ERR309 "File Error 309: cannot save results to report file."
|
||||
|
||||
#define R_ERR201 "Input Error 201: syntax error in following line of "
|
||||
#define R_ERR202 "Input Error 202: illegal numeric value in following line of "
|
||||
#define R_ERR203 "Input Error 203: undefined node in following line of "
|
||||
#define R_ERR204 "Input Error 204: undefined link in following line of "
|
||||
#define R_ERR207 "Input Error 207: attempt to control a CV in following line of "
|
||||
|
||||
#define R_ERR221 "Input Error 221: mis-placed clause in following line of "
|
||||
|
||||
/*-------------------- Specific Warning Messages -------------------------*/
|
||||
#define WARN01 "WARNING: System unbalanced at %s hrs."
|
||||
#define WARN02 \
|
||||
"WARNING: Maximum trials exceeded at %s hrs. System may be unstable."
|
||||
#define WARN03a "WARNING: Node %s disconnected at %s hrs"
|
||||
#define WARN03b "WARNING: %d additional nodes disconnected at %s hrs"
|
||||
#define WARN03c "WARNING: System disconnected because of Link %s"
|
||||
#define WARN04 "WARNING: Pump %s %s at %s hrs."
|
||||
#define WARN05 "WARNING: %s %s %s at %s hrs."
|
||||
#define WARN06 "WARNING: Negative pressures at %s hrs."
|
||||
|
||||
/*-------------------- General Warning Messages -------------------------*/
|
||||
#define WARN1 "WARNING: System hydraulically unbalanced."
|
||||
#define WARN2 "WARNING: System may be hydraulically unstable."
|
||||
#define WARN3 "WARNING: System disconnected."
|
||||
#define WARN4 "WARNING: Pumps cannot deliver enough flow or head."
|
||||
#define WARN5 "WARNING: Valves cannot deliver enough flow."
|
||||
#define WARN6 "WARNING: System has negative pressures."
|
||||
|
||||
209
src/toolkit.h
Normal file
209
src/toolkit.h
Normal file
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
*******************************************************************
|
||||
|
||||
TOOLKIT.H - Prototypes for EPANET Functions Exported to DLL Toolkit
|
||||
|
||||
VERSION: 2.00
|
||||
DATE: 5/8/00
|
||||
10/25/00
|
||||
3/1/01
|
||||
8/15/07 (2.00.11)
|
||||
AUTHOR: L. Rossman
|
||||
US EPA - NRMRL
|
||||
|
||||
*******************************************************************
|
||||
*/
|
||||
|
||||
// --- Define DLLEXPORT
|
||||
|
||||
#ifdef DLL
|
||||
#ifdef __cplusplus
|
||||
#define DLLEXPORT extern "C" __declspec(dllexport) __stdcall
|
||||
#else
|
||||
#define DLLEXPORT __declspec(dllexport) __stdcall
|
||||
#endif
|
||||
#else
|
||||
#ifdef __cplusplus
|
||||
#define DLLEXPORT extern "C"
|
||||
#else
|
||||
#define DLLEXPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// --- Define the EPANET toolkit constants
|
||||
|
||||
#define EN_ELEVATION 0 /* Node parameters */
|
||||
#define EN_BASEDEMAND 1
|
||||
#define EN_PATTERN 2
|
||||
#define EN_EMITTER 3
|
||||
#define EN_INITQUAL 4
|
||||
#define EN_SOURCEQUAL 5
|
||||
#define EN_SOURCEPAT 6
|
||||
#define EN_SOURCETYPE 7
|
||||
#define EN_TANKLEVEL 8
|
||||
#define EN_DEMAND 9
|
||||
#define EN_HEAD 10
|
||||
#define EN_PRESSURE 11
|
||||
#define EN_QUALITY 12
|
||||
#define EN_SOURCEMASS 13
|
||||
#define EN_INITVOLUME 14
|
||||
#define EN_MIXMODEL 15
|
||||
#define EN_MIXZONEVOL 16
|
||||
|
||||
#define EN_DIAMETER 0 /* Link parameters */
|
||||
#define EN_LENGTH 1
|
||||
#define EN_ROUGHNESS 2
|
||||
#define EN_MINORLOSS 3
|
||||
#define EN_INITSTATUS 4
|
||||
#define EN_INITSETTING 5
|
||||
#define EN_KBULK 6
|
||||
#define EN_KWALL 7
|
||||
#define EN_FLOW 8
|
||||
#define EN_VELOCITY 9
|
||||
#define EN_HEADLOSS 10
|
||||
#define EN_STATUS 11
|
||||
#define EN_SETTING 12
|
||||
#define EN_ENERGY 13
|
||||
|
||||
#define EN_DURATION 0 /* Time parameters */
|
||||
#define EN_HYDSTEP 1
|
||||
#define EN_QUALSTEP 2
|
||||
#define EN_PATTERNSTEP 3
|
||||
#define EN_PATTERNSTART 4
|
||||
#define EN_REPORTSTEP 5
|
||||
#define EN_REPORTSTART 6
|
||||
#define EN_RULESTEP 7
|
||||
#define EN_STATISTIC 8
|
||||
#define EN_PERIODS 9
|
||||
|
||||
#define EN_NODECOUNT 0 /* Component counts */
|
||||
#define EN_TANKCOUNT 1
|
||||
#define EN_LINKCOUNT 2
|
||||
#define EN_PATCOUNT 3
|
||||
#define EN_CURVECOUNT 4
|
||||
#define EN_CONTROLCOUNT 5
|
||||
|
||||
#define EN_JUNCTION 0 /* Node types */
|
||||
#define EN_RESERVOIR 1
|
||||
#define EN_TANK 2
|
||||
|
||||
#define EN_CVPIPE 0 /* Link types. */
|
||||
#define EN_PIPE 1 /* See LinkType in TYPES.H */
|
||||
#define EN_PUMP 2
|
||||
#define EN_PRV 3
|
||||
#define EN_PSV 4
|
||||
#define EN_PBV 5
|
||||
#define EN_FCV 6
|
||||
#define EN_TCV 7
|
||||
#define EN_GPV 8
|
||||
|
||||
#define EN_NONE 0 /* Quality analysis types. */
|
||||
#define EN_CHEM 1 /* See QualType in TYPES.H */
|
||||
#define EN_AGE 2
|
||||
#define EN_TRACE 3
|
||||
|
||||
#define EN_CONCEN 0 /* Source quality types. */
|
||||
#define EN_MASS 1 /* See SourceType in TYPES.H. */
|
||||
#define EN_SETPOINT 2
|
||||
#define EN_FLOWPACED 3
|
||||
|
||||
#define EN_CFS 0 /* Flow units types. */
|
||||
#define EN_GPM 1 /* See FlowUnitsType */
|
||||
#define EN_MGD 2 /* in TYPES.H. */
|
||||
#define EN_IMGD 3
|
||||
#define EN_AFD 4
|
||||
#define EN_LPS 5
|
||||
#define EN_LPM 6
|
||||
#define EN_MLD 7
|
||||
#define EN_CMH 8
|
||||
#define EN_CMD 9
|
||||
|
||||
#define EN_TRIALS 0 /* Misc. options */
|
||||
#define EN_ACCURACY 1
|
||||
#define EN_TOLERANCE 2
|
||||
#define EN_EMITEXPON 3
|
||||
#define EN_DEMANDMULT 4
|
||||
|
||||
#define EN_LOWLEVEL 0 /* Control types. */
|
||||
#define EN_HILEVEL 1 /* See ControlType */
|
||||
#define EN_TIMER 2 /* in TYPES.H. */
|
||||
#define EN_TIMEOFDAY 3
|
||||
|
||||
#define EN_AVERAGE 1 /* Time statistic types. */
|
||||
#define EN_MINIMUM 2 /* See TstatType in TYPES.H */
|
||||
#define EN_MAXIMUM 3
|
||||
#define EN_RANGE 4
|
||||
|
||||
#define EN_NOSAVE 0 /* Save-results-to-file flag */
|
||||
#define EN_SAVE 1
|
||||
|
||||
#define EN_INITFLOW 10 /* Re-initialize flows flag */
|
||||
|
||||
|
||||
// --- Declare the EPANET toolkit functions
|
||||
|
||||
int DLLEXPORT ENepanet(char *, char *, char *, void (*) (char *));
|
||||
|
||||
int DLLEXPORT ENopen(char *, char *, char *);
|
||||
int DLLEXPORT ENsaveinpfile(char *);
|
||||
int DLLEXPORT ENclose(void);
|
||||
|
||||
int DLLEXPORT ENsolveH(void);
|
||||
int DLLEXPORT ENsaveH(void);
|
||||
int DLLEXPORT ENopenH(void);
|
||||
int DLLEXPORT ENinitH(int);
|
||||
int DLLEXPORT ENrunH(long *);
|
||||
int DLLEXPORT ENnextH(long *);
|
||||
int DLLEXPORT ENcloseH(void);
|
||||
int DLLEXPORT ENsavehydfile(char *);
|
||||
int DLLEXPORT ENusehydfile(char *);
|
||||
|
||||
int DLLEXPORT ENsolveQ(void);
|
||||
int DLLEXPORT ENopenQ(void);
|
||||
int DLLEXPORT ENinitQ(int);
|
||||
int DLLEXPORT ENrunQ(long *);
|
||||
int DLLEXPORT ENnextQ(long *);
|
||||
int DLLEXPORT ENstepQ(long *);
|
||||
int DLLEXPORT ENcloseQ(void);
|
||||
|
||||
int DLLEXPORT ENwriteline(char *);
|
||||
int DLLEXPORT ENreport(void);
|
||||
int DLLEXPORT ENresetreport(void);
|
||||
int DLLEXPORT ENsetreport(char *);
|
||||
|
||||
int DLLEXPORT ENgetcontrol(int, int *, int *, float *,
|
||||
int *, float *);
|
||||
int DLLEXPORT ENgetcount(int, int *);
|
||||
int DLLEXPORT ENgetoption(int, float *);
|
||||
int DLLEXPORT ENgettimeparam(int, long *);
|
||||
int DLLEXPORT ENgetflowunits(int *);
|
||||
int DLLEXPORT ENgetpatternindex(char *, int *);
|
||||
int DLLEXPORT ENgetpatternid(int, char *);
|
||||
int DLLEXPORT ENgetpatternlen(int, int *);
|
||||
int DLLEXPORT ENgetpatternvalue(int, int, float *);
|
||||
int DLLEXPORT ENgetqualtype(int *, int *);
|
||||
int DLLEXPORT ENgeterror(int, char *, int);
|
||||
|
||||
int DLLEXPORT ENgetnodeindex(char *, int *);
|
||||
int DLLEXPORT ENgetnodeid(int, char *);
|
||||
int DLLEXPORT ENgetnodetype(int, int *);
|
||||
int DLLEXPORT ENgetnodevalue(int, int, float *);
|
||||
|
||||
int DLLEXPORT ENgetlinkindex(char *, int *);
|
||||
int DLLEXPORT ENgetlinkid(int, char *);
|
||||
int DLLEXPORT ENgetlinktype(int, int *);
|
||||
int DLLEXPORT ENgetlinknodes(int, int *, int *);
|
||||
int DLLEXPORT ENgetlinkvalue(int, int, float *);
|
||||
|
||||
int DLLEXPORT ENgetversion(int *);
|
||||
|
||||
int DLLEXPORT ENsetcontrol(int, int, int, float, int, float);
|
||||
int DLLEXPORT ENsetnodevalue(int, int, float);
|
||||
int DLLEXPORT ENsetlinkvalue(int, int, float);
|
||||
int DLLEXPORT ENsetpattern(int, float *, int);
|
||||
int DLLEXPORT ENsetpatternvalue(int, int, float);
|
||||
int DLLEXPORT ENsettimeparam(int, long);
|
||||
int DLLEXPORT ENsetoption(int, float);
|
||||
int DLLEXPORT ENsetstatusreport(int);
|
||||
int DLLEXPORT ENsetqualtype(int, char *, char *, char *);
|
||||
|
||||
447
src/types.h
Normal file
447
src/types.h
Normal file
@@ -0,0 +1,447 @@
|
||||
/*
|
||||
***********************************************************************
|
||||
|
||||
TYPES.H -- Global constants and data types for EPANET program
|
||||
|
||||
VERSION: 2.00
|
||||
DATE: 5/8/00
|
||||
9/7/00
|
||||
10/25/00
|
||||
3/1/01
|
||||
12/6/01
|
||||
6/24/02
|
||||
8/15/07 (2.00.11)
|
||||
AUTHOR: L. Rossman
|
||||
US EPA - NRMRL
|
||||
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
/*********************************************************/
|
||||
/* All floats have been re-declared as doubles (7/3/07). */
|
||||
/*********************************************************/
|
||||
|
||||
/*
|
||||
-----------------------------
|
||||
Global Constants
|
||||
-----------------------------
|
||||
*/
|
||||
/*** Updated ***/
|
||||
#define CODEVERSION 20011 //(2.00.11 - LR)
|
||||
#define MAGICNUMBER 516114521
|
||||
#define VERSION 200
|
||||
#define EOFMARK 0x1A /* Use 0x04 for UNIX systems */
|
||||
#define MAXTITLE 3 /* Max. # title lines */
|
||||
#define MAXID 31 /* Max. # characters in ID name */ //(2.00.11 - LR)
|
||||
#define MAXMSG 79 /* Max. # characters in message text */
|
||||
#define MAXLINE 255 /* Max. # characters read from input line */
|
||||
#define MAXFNAME 259 /* Max. # characters in file name */
|
||||
#define MAXTOKS 40 /* Max. items per line of input */
|
||||
#define TZERO 1.E-4 /* Zero time tolerance */
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#define FULL 2
|
||||
#define BIG 1.E10
|
||||
#define TINY 1.E-6
|
||||
#define MISSING -1.E10
|
||||
#define PI 3.141592654
|
||||
|
||||
/*** Updated 9/7/00 ***/
|
||||
/* Various conversion factors */
|
||||
#define GPMperCFS 448.831
|
||||
#define AFDperCFS 1.9837
|
||||
#define MGDperCFS 0.64632
|
||||
#define IMGDperCFS 0.5382
|
||||
#define LPSperCFS 28.317
|
||||
#define LPMperCFS 1699.0
|
||||
#define CMHperCFS 101.94
|
||||
#define CMDperCFS 2446.6
|
||||
#define MLDperCFS 2.4466
|
||||
#define M3perFT3 0.028317
|
||||
#define LperFT3 28.317
|
||||
#define MperFT 0.3048
|
||||
#define PSIperFT 0.4333
|
||||
#define KPAperPSI 6.895
|
||||
#define KWperHP 0.7457
|
||||
#define SECperDAY 86400
|
||||
|
||||
#define DIFFUS 1.3E-8 /* Diffusivity of chlorine */
|
||||
/* @ 20 deg C (sq ft/sec) */
|
||||
#define VISCOS 1.1E-5 /* Kinematic viscosity of water */
|
||||
/* @ 20 deg C (sq ft/sec) */
|
||||
|
||||
#define SEPSTR " \t\n\r" /* Token separator characters */
|
||||
|
||||
/*
|
||||
---------------------------------------------------------------------
|
||||
Macro to test for successful allocation of memory
|
||||
---------------------------------------------------------------------
|
||||
*/
|
||||
#define MEMCHECK(x) (((x) == NULL) ? 101 : 0 )
|
||||
#define FREE(x) (free((x)))
|
||||
|
||||
/*
|
||||
---------------------------------------------------------------------
|
||||
Conversion macros to be used in place of functions
|
||||
---------------------------------------------------------------------
|
||||
*/
|
||||
#define INT(x) ((int)(x)) /* integer portion of x */
|
||||
#define FRAC(x) ((x)-(int)(x)) /* fractional part of x */
|
||||
#define ABS(x) (((x)<0) ? -(x) : (x)) /* absolute value of x */
|
||||
#define MIN(x,y) (((x)<=(y)) ? (x) : (y)) /* minimum of x and y */
|
||||
#define MAX(x,y) (((x)>=(y)) ? (x) : (y)) /* maximum of x and y */
|
||||
#define ROUND(x) (((x)>=0) ? (int)((x)+.5) : (int)((x)-.5))
|
||||
/* round-off of x */
|
||||
#define MOD(x,y) ((x)%(y)) /* x modulus y */
|
||||
#define SQR(x) ((x)*(x)) /* x-squared */
|
||||
#define SGN(x) (((x)<0) ? (-1) : (1)) /* sign of x */
|
||||
#define UCHAR(x) (((x) >= 'a' && (x) <= 'z') ? ((x)&~32) : (x))
|
||||
/* uppercase char of x */
|
||||
/*
|
||||
------------------------------------------------------
|
||||
Macro to evaluate function x with error checking
|
||||
(Fatal errors are numbered higher than 100)
|
||||
------------------------------------------------------
|
||||
*/
|
||||
#define ERRCODE(x) (errcode = ((errcode>100) ? (errcode) : (x)))
|
||||
|
||||
/*
|
||||
------------------------------------------------------
|
||||
Macro to find Pump index of Link[x]
|
||||
(Diameter = pump index for pump links)
|
||||
------------------------------------------------------
|
||||
*/
|
||||
#define PUMPINDEX(x) (ROUND(Link[(x)].Diam))
|
||||
|
||||
/*
|
||||
------------------------------------------------------
|
||||
Global Data Structures
|
||||
------------------------------------------------------
|
||||
*/
|
||||
typedef float REAL4; //(2.00.11 - LR)
|
||||
typedef long INT4; //(2.00.11 - LR)
|
||||
|
||||
struct IDstring /* Holds component ID labels */
|
||||
{
|
||||
char ID[MAXID+1];
|
||||
};
|
||||
|
||||
struct Floatlist /* Element of list of floats */
|
||||
{
|
||||
double value;
|
||||
struct Floatlist *next;
|
||||
};
|
||||
typedef struct Floatlist SFloatlist;
|
||||
|
||||
struct Tmplist /* Element of temp list for Pattern & Curve data */
|
||||
{
|
||||
int i;
|
||||
char ID[MAXID+1];
|
||||
SFloatlist *x;
|
||||
SFloatlist *y;
|
||||
struct Tmplist *next;
|
||||
};
|
||||
typedef struct Tmplist STmplist;
|
||||
|
||||
typedef struct /* TIME PATTERN OBJECT */
|
||||
{
|
||||
char ID[MAXID+1]; /* Pattern ID */
|
||||
int Length; /* Pattern length */
|
||||
double *F; /* Pattern factors */
|
||||
} Spattern;
|
||||
|
||||
typedef struct /* CURVE OBJECT */
|
||||
{
|
||||
char ID[MAXID+1]; /* Curve ID */
|
||||
int Type; /* Curve type */
|
||||
int Npts; /* Number of points */
|
||||
double *X; /* X-values */
|
||||
double *Y; /* Y-values */
|
||||
} Scurve;
|
||||
|
||||
struct Sdemand /* DEMAND CATEGORY OBJECT */
|
||||
{
|
||||
double Base; /* Baseline demand */
|
||||
int Pat; /* Pattern index */
|
||||
struct Sdemand *next; /* Next record */
|
||||
};
|
||||
typedef struct Sdemand *Pdemand; /* Pointer to demand object */
|
||||
|
||||
struct Ssource /* WQ SOURCE OBJECT */
|
||||
{
|
||||
/*int Node;*/ /* Node index of source */
|
||||
double C0; /* Base concentration/mass */
|
||||
int Pat; /* Pattern index */
|
||||
double Smass; /* Actual mass flow rate */
|
||||
char Type; /* SourceType (see below) */
|
||||
};
|
||||
typedef struct Ssource *Psource; /* Pointer to WQ source object */
|
||||
|
||||
typedef struct /* NODE OBJECT */
|
||||
{
|
||||
char ID[MAXID+1]; /* Node ID */
|
||||
double El; /* Elevation */
|
||||
Pdemand D; /* Demand pointer */
|
||||
Psource S; /* Source pointer */
|
||||
double C0; /* Initial quality */
|
||||
double Ke; /* Emitter coeff. */
|
||||
char Rpt; /* Reporting flag */
|
||||
} Snode;
|
||||
|
||||
typedef struct /* LINK OBJECT */
|
||||
{
|
||||
char ID[MAXID+1]; /* Link ID */
|
||||
int N1; /* Start node index */
|
||||
int N2; /* End node index */
|
||||
double Diam; /* Diameter */
|
||||
double Len; /* Length */
|
||||
double Kc; /* Roughness */
|
||||
double Km; /* Minor loss coeff. */
|
||||
double Kb; /* Bulk react. coeff */
|
||||
double Kw; /* Wall react. coeff */
|
||||
double R; /* Flow resistance */
|
||||
char Type; /* Link type */
|
||||
char Stat; /* Initial status */
|
||||
char Rpt; /* Reporting flag */
|
||||
} Slink;
|
||||
|
||||
typedef struct /* TANK OBJECT */
|
||||
{
|
||||
int Node; /* Node index of tank */
|
||||
double A; /* Tank area */
|
||||
double Hmin; /* Minimum water elev */
|
||||
double Hmax; /* Maximum water elev */
|
||||
double H0; /* Initial water elev */
|
||||
double Vmin; /* Minimum volume */
|
||||
double Vmax; /* Maximum volume */
|
||||
double V0; /* Initial volume */
|
||||
double Kb; /* Reaction coeff. (1/days) */
|
||||
double V; /* Tank volume */
|
||||
double C; /* Concentration */
|
||||
int Pat; /* Fixed grade time pattern */
|
||||
int Vcurve; /* Vol.- elev. curve index */
|
||||
char MixModel; /* Type of mixing model */
|
||||
/* (see MixType below) */
|
||||
double V1max; /* Mixing compartment size */
|
||||
} Stank;
|
||||
|
||||
typedef struct /* PUMP OBJECT */
|
||||
{
|
||||
int Link; /* Link index of pump */
|
||||
int Ptype; /* Pump curve type */
|
||||
/* (see PumpType below) */
|
||||
double Q0; /* Initial flow */
|
||||
double Qmax; /* Maximum flow */
|
||||
double Hmax; /* Maximum head */
|
||||
double H0; /* Shutoff head */
|
||||
double R; /* Flow coeffic. */
|
||||
double N; /* Flow exponent */
|
||||
int Hcurve; /* Head v. flow curve index */
|
||||
int Ecurve; /* Effic. v. flow curve index */
|
||||
int Upat; /* Utilization pattern index */
|
||||
int Epat; /* Energy cost pattern index */
|
||||
double Ecost; /* Unit energy cost */
|
||||
double Energy[6]; /* Energy usage statistics: */
|
||||
/* 0 = pump utilization */
|
||||
/* 1 = avg. efficiency */
|
||||
/* 2 = avg. kW/flow */
|
||||
/* 3 = avg. kwatts */
|
||||
/* 4 = peak kwatts */
|
||||
/* 5 = cost/day */
|
||||
} Spump;
|
||||
|
||||
typedef struct /* VALVE OBJECT */
|
||||
{
|
||||
int Link; /* Link index of valve */
|
||||
} Svalve;
|
||||
|
||||
typedef struct /* CONTROL STATEMENT */
|
||||
{
|
||||
int Link; /* Link index */
|
||||
int Node; /* Control node index */
|
||||
long Time; /* Control time */
|
||||
double Grade; /* Control grade */
|
||||
double Setting; /* New link setting */
|
||||
char Status; /* New link status */
|
||||
char Type; /* Control type */
|
||||
/* (see ControlType below) */
|
||||
} Scontrol;
|
||||
|
||||
struct Sadjlist /* NODE ADJACENCY LIST ITEM */
|
||||
{
|
||||
int node; /* Index of connecting node */
|
||||
int link; /* Index of connecting link */
|
||||
struct Sadjlist *next; /* Next item in list */
|
||||
};
|
||||
/* Pointer to adjacency list item */
|
||||
typedef struct Sadjlist *Padjlist;
|
||||
|
||||
struct Sseg /* PIPE SEGMENT record used */
|
||||
{ /* for WQ routing */
|
||||
double v; /* Segment volume */
|
||||
double c; /* Water quality value */
|
||||
struct Sseg *prev; /* Record for previous segment */
|
||||
};
|
||||
typedef struct Sseg *Pseg; /* Pointer to pipe segment */
|
||||
|
||||
typedef struct /* FIELD OBJECT of report table */
|
||||
{
|
||||
char Name[MAXID+1]; /* Name of reported variable */
|
||||
char Units[MAXID+1]; /* Units of reported variable */
|
||||
char Enabled; /* Enabled if in table */
|
||||
int Precision; /* Number of decimal places */
|
||||
double RptLim[2]; /* Lower/upper report limits */
|
||||
} SField;
|
||||
|
||||
|
||||
/*
|
||||
----------------------------------------------
|
||||
Global Enumeration Variables
|
||||
----------------------------------------------
|
||||
*/
|
||||
enum Hydtype /* Hydraulics solution option: */
|
||||
{USE, /* use from previous run */
|
||||
SAVE, /* save after current run */
|
||||
SCRATCH}; /* use temporary file */
|
||||
|
||||
enum QualType /* Water quality analysis option: */
|
||||
{NONE, /* no quality analysis */
|
||||
CHEM, /* analyze a chemical */
|
||||
AGE, /* analyze water age */
|
||||
TRACE}; /* trace % of flow from a source */
|
||||
|
||||
enum NodeType /* Type of node: */
|
||||
{JUNC, /* junction */
|
||||
RESERV, /* reservoir */
|
||||
TANK}; /* tank */
|
||||
|
||||
enum LinkType /* Type of link: */
|
||||
{CV, /* pipe with check valve */
|
||||
PIPE, /* regular pipe */
|
||||
PUMP, /* pump */
|
||||
PRV, /* pressure reducing valve */
|
||||
PSV, /* pressure sustaining valve */
|
||||
PBV, /* pressure breaker valve */
|
||||
FCV, /* flow control valve */
|
||||
TCV, /* throttle control valve */
|
||||
GPV}; /* general purpose valve */
|
||||
|
||||
enum CurveType /* Type of curve: */
|
||||
{V_CURVE, /* volume curve */
|
||||
P_CURVE, /* pump curve */
|
||||
E_CURVE, /* efficiency curve */
|
||||
H_CURVE}; /* head loss curve */
|
||||
|
||||
enum PumpType /* Type of pump curve: */
|
||||
{CONST_HP, /* constant horsepower */
|
||||
POWER_FUNC, /* power function */
|
||||
CUSTOM, /* user-defined custom curve */
|
||||
NOCURVE};
|
||||
|
||||
enum SourceType /* Type of source quality input */
|
||||
{CONCEN, /* inflow concentration */
|
||||
MASS, /* mass inflow booster */
|
||||
SETPOINT, /* setpoint booster */
|
||||
FLOWPACED}; /* flow paced booster */
|
||||
|
||||
enum ControlType /* Control condition type: */
|
||||
{LOWLEVEL, /* act when grade below set level */
|
||||
HILEVEL, /* act when grade above set level */
|
||||
TIMER, /* act when set time reached */
|
||||
TIMEOFDAY}; /* act when time of day occurs */
|
||||
|
||||
enum StatType /* Link/Tank status: */
|
||||
{XHEAD, /* pump cannot deliver head (closed) */
|
||||
TEMPCLOSED, /* temporarily closed */
|
||||
CLOSED, /* closed */
|
||||
OPEN, /* open */
|
||||
ACTIVE, /* valve active (partially open) */
|
||||
XFLOW, /* pump exceeds maximum flow */
|
||||
XFCV, /* FCV cannot supply flow */
|
||||
XPRESSURE, /* valve cannot supply pressure */
|
||||
FILLING, /* tank filling */
|
||||
EMPTYING}; /* tank emptying */
|
||||
|
||||
enum FormType /* Head loss formula: */
|
||||
{HW, /* Hazen-Williams */
|
||||
DW, /* Darcy-Weisbach */
|
||||
CM}; /* Chezy-Manning */
|
||||
|
||||
enum UnitsType /* Unit system: */
|
||||
{US, /* US */
|
||||
SI}; /* SI (metric) */
|
||||
|
||||
enum FlowUnitsType /* Flow units: */
|
||||
{CFS, /* cubic feet per second */
|
||||
GPM, /* gallons per minute */
|
||||
MGD, /* million gallons per day */
|
||||
IMGD, /* imperial million gal. per day */
|
||||
AFD, /* acre-feet per day */
|
||||
LPS, /* liters per second */
|
||||
LPM, /* liters per minute */
|
||||
MLD, /* megaliters per day */
|
||||
CMH, /* cubic meters per hour */
|
||||
CMD}; /* cubic meters per day */
|
||||
|
||||
enum PressUnitsType /* Pressure units: */
|
||||
{PSI, /* pounds per square inch */
|
||||
KPA, /* kiloPascals */
|
||||
METERS}; /* meters */
|
||||
|
||||
enum RangeType /* Range limits: */
|
||||
{LOW, /* lower limit */
|
||||
HI, /* upper limit */
|
||||
PREC}; /* precision */
|
||||
|
||||
enum MixType /* Tank mixing regimes */
|
||||
{MIX1, /* 1-compartment model */
|
||||
MIX2, /* 2-compartment model */
|
||||
FIFO, /* First in, first out model */
|
||||
LIFO}; /* Last in, first out model */
|
||||
|
||||
enum TstatType /* Time series statistics */
|
||||
{SERIES, /* none */
|
||||
AVG, /* time-averages */
|
||||
MIN, /* minimum values */
|
||||
MAX, /* maximum values */
|
||||
RANGE}; /* max - min values */
|
||||
|
||||
#define MAXVAR 21 /* Max. # types of network variables */
|
||||
/* (equals # items enumed below) */
|
||||
enum FieldType /* Network variables: */
|
||||
{ELEV, /* nodal elevation */
|
||||
DEMAND, /* nodal demand flow */
|
||||
HEAD, /* nodal hydraulic head */
|
||||
PRESSURE, /* nodal pressure */
|
||||
QUALITY, /* nodal water quality */
|
||||
|
||||
LENGTH, /* link length */
|
||||
DIAM, /* link diameter */
|
||||
FLOW, /* link flow rate */
|
||||
VELOCITY, /* link flow velocity */
|
||||
HEADLOSS, /* link head loss */
|
||||
LINKQUAL, /* avg. water quality in link */
|
||||
STATUS, /* link status */
|
||||
SETTING, /* pump/valve setting */
|
||||
REACTRATE, /* avg. reaction rate in link */
|
||||
FRICTION, /* link friction factor */
|
||||
|
||||
POWER, /* pump power output */
|
||||
TIME, /* simulation time */
|
||||
VOLUME, /* tank volume */
|
||||
CLOCKTIME, /* simulation time of day */
|
||||
FILLTIME, /* time to fill a tank */
|
||||
DRAINTIME}; /* time to drain a tank */
|
||||
|
||||
enum SectType {_TITLE,_JUNCTIONS,_RESERVOIRS,_TANKS,_PIPES,_PUMPS,
|
||||
_VALVES,_CONTROLS,_RULES,_DEMANDS,_SOURCES,_EMITTERS,
|
||||
_PATTERNS,_CURVES,_QUALITY,_STATUS,_ROUGHNESS,_ENERGY,
|
||||
_REACTIONS,_MIXING,_REPORT,_TIMES,_OPTIONS,
|
||||
_COORDS,_VERTICES,_LABELS,_BACKDROP,_TAGS,_END};
|
||||
|
||||
enum HdrType /* Type of table heading */
|
||||
{STATHDR, /* Hydraulic Status */
|
||||
ENERHDR, /* Energy Usage */
|
||||
NODEHDR, /* Node Results */
|
||||
LINKHDR}; /* Link Results */
|
||||
|
||||
190
src/vars.h
Normal file
190
src/vars.h
Normal file
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
************************************************************************
|
||||
Global Variables for EPANET Program
|
||||
|
||||
VERSION: 2.00
|
||||
DATE: 5/8/00
|
||||
6/24/02
|
||||
AUTHOR: L. Rossman
|
||||
US EPA - NRMRL
|
||||
|
||||
************************************************************************
|
||||
*/
|
||||
EXTERN FILE *InFile, /* Input file pointer */
|
||||
*OutFile, /* Output file pointer */
|
||||
*RptFile, /* Report file pointer */
|
||||
*HydFile, /* Hydraulics file pointer */
|
||||
*TmpOutFile; /* Temporary file handle */
|
||||
EXTERN long HydOffset, /* Hydraulics file byte offset */
|
||||
OutOffset1, /* 1st output file byte offset */
|
||||
OutOffset2; /* 2nd output file byte offset */
|
||||
EXTERN char Msg[MAXMSG+1], /* Text of output message */
|
||||
InpFname[MAXFNAME+1], /* Input file name */
|
||||
Rpt1Fname[MAXFNAME+1], /* Primary report file name */
|
||||
Rpt2Fname[MAXFNAME+1], /* Secondary report file name */
|
||||
HydFname[MAXFNAME+1], /* Hydraulics file name */
|
||||
OutFname[MAXFNAME+1], /* Binary output file name */
|
||||
MapFname[MAXFNAME+1], /* Map file name */
|
||||
Title[MAXTITLE][MAXMSG+1], /* Problem title */
|
||||
ChemName[MAXID+1], /* Name of chemical */
|
||||
ChemUnits[MAXID+1], /* Units of chemical */
|
||||
DefPatID[MAXID+1], /* Default demand pattern ID */
|
||||
|
||||
/*** Updated 6/24/02 ***/
|
||||
Atime[13], /* Clock time (hrs:min:sec) */
|
||||
|
||||
Hydflag, /* Hydraulics flag */
|
||||
Qualflag, /* Water quality flag */
|
||||
Unitsflag, /* Unit system flag */
|
||||
Flowflag, /* Flow units flag */
|
||||
Pressflag, /* Pressure units flag */
|
||||
Formflag, /* Hydraulic formula flag */
|
||||
Rptflag, /* Report flag */
|
||||
Summaryflag, /* Report summary flag */
|
||||
Messageflag, /* Error/warning message flag */
|
||||
Statflag, /* Status report flag */
|
||||
Energyflag, /* Energy report flag */
|
||||
Nodeflag, /* Node report flag */
|
||||
Linkflag, /* Link report flag */
|
||||
Tstatflag, /* Time statistics flag */
|
||||
Warnflag, /* Warning flag */
|
||||
Openflag, /* Input processed flag */
|
||||
OpenHflag, /* Hydraul. system opened flag */
|
||||
SaveHflag, /* Hydraul. results saved flag */
|
||||
OpenQflag, /* Quality system opened flag */
|
||||
SaveQflag, /* Quality results saved flag */
|
||||
Saveflag; /* General purpose save flag */
|
||||
EXTERN int MaxNodes, /* Node count from input file */
|
||||
MaxLinks, /* Link count from input file */
|
||||
MaxJuncs, /* Junction count */
|
||||
MaxPipes, /* Pipe count */
|
||||
MaxTanks, /* Tank count */
|
||||
MaxPumps, /* Pump count */
|
||||
MaxValves, /* Valve count */
|
||||
MaxControls, /* Control count */
|
||||
MaxRules, /* Rule count */
|
||||
MaxPats, /* Pattern count */
|
||||
MaxCurves, /* Curve count */
|
||||
Nnodes, /* Number of network nodes */
|
||||
Ntanks, /* Number of tanks */
|
||||
Njuncs, /* Number of junction nodes */
|
||||
Nlinks, /* Number of network links */
|
||||
Npipes, /* Number of pipes */
|
||||
Npumps, /* Number of pumps */
|
||||
Nvalves, /* Number of valves */
|
||||
Ncontrols, /* Number of simple controls */
|
||||
Nrules, /* Number of control rules */
|
||||
Npats, /* Number of time patterns */
|
||||
Ncurves, /* Number of data curves */
|
||||
Nperiods, /* Number of reporting periods */
|
||||
Ncoeffs, /* Number of non-0 matrix coeffs*/
|
||||
DefPat, /* Default demand pattern */
|
||||
Epat, /* Energy cost time pattern */
|
||||
MaxIter, /* Max. hydraulic trials */
|
||||
ExtraIter, /* Extra hydraulic trials */
|
||||
TraceNode, /* Source node for flow tracing */
|
||||
PageSize, /* Lines/page in output report */
|
||||
CheckFreq, /* Hydraulics solver parameter */
|
||||
MaxCheck; /* Hydraulics solver parameter */
|
||||
EXTERN double Ucf[MAXVAR], /* Unit conversion factors */
|
||||
Ctol, /* Water quality tolerance */
|
||||
Htol, /* Hydraulic head tolerance */
|
||||
Qtol, /* Flow rate tolerance */
|
||||
RQtol, /* Flow resistance tolerance */
|
||||
Hexp, /* Exponent in headloss formula */
|
||||
Qexp, /* Exponent in orifice formula */
|
||||
Dmult, /* Demand multiplier */
|
||||
Hacc, /* Hydraulics solution accuracy */
|
||||
BulkOrder, /* Bulk flow reaction order */
|
||||
WallOrder, /* Pipe wall reaction order */
|
||||
TankOrder, /* Tank reaction order */
|
||||
Kbulk, /* Global bulk reaction coeff. */
|
||||
Kwall, /* Global wall reaction coeff. */
|
||||
Climit, /* Limiting potential quality */
|
||||
Rfactor, /* Roughness-reaction factor */
|
||||
Diffus, /* Diffusivity (sq ft/sec) */
|
||||
Viscos, /* Kin. viscosity (sq ft/sec) */
|
||||
SpGrav, /* Specific gravity */
|
||||
Ecost, /* Base energy cost per kwh */
|
||||
Dcost, /* Energy demand charge/kw/day */
|
||||
Epump, /* Global pump efficiency */
|
||||
Emax, /* Peak energy usage */
|
||||
Dsystem, /* Total system demand */
|
||||
Wbulk, /* Avg. bulk reaction rate */
|
||||
Wwall, /* Avg. wall reaction rate */
|
||||
Wtank, /* Avg. tank reaction rate */
|
||||
Wsource; /* Avg. mass inflow */
|
||||
EXTERN long Tstart, /* Starting time of day (sec) */
|
||||
Hstep, /* Nominal hyd. time step (sec) */
|
||||
Qstep, /* Quality time step (sec) */
|
||||
Pstep, /* Time pattern time step (sec) */
|
||||
Pstart, /* Starting pattern time (sec) */
|
||||
Rstep, /* Reporting time step (sec) */
|
||||
Rstart, /* Time when reporting starts */
|
||||
Rtime, /* Next reporting time */
|
||||
Htime, /* Current hyd. time (sec) */
|
||||
Qtime, /* Current quality time (sec) */
|
||||
Hydstep, /* Actual hydraulic time step */
|
||||
Rulestep, /* Rule evaluation time step */
|
||||
Dur; /* Duration of simulation (sec) */
|
||||
EXTERN SField Field[MAXVAR]; /* Output reporting fields */
|
||||
|
||||
/* Array pointers not allocated and freed in same routine */
|
||||
EXTERN char *S, /* Link status */
|
||||
*OldStat; /* Previous link/tank status */
|
||||
EXTERN double *D, /* Node actual demand */
|
||||
*C, /* Node actual quality */
|
||||
*E, /* Emitter flows */
|
||||
*K, /* Link settings */
|
||||
*Q, /* Link flows */
|
||||
*R, /* Pipe reaction rate */
|
||||
*X; /* General purpose array */
|
||||
EXTERN double *H; /* Node heads */
|
||||
EXTERN STmplist *Patlist; /* Temporary time pattern list */
|
||||
EXTERN STmplist *Curvelist; /* Temporary list of curves */
|
||||
EXTERN Spattern *Pattern; /* Time patterns */
|
||||
EXTERN Scurve *Curve; /* Curve data */
|
||||
EXTERN Snode *Node; /* Node data */
|
||||
EXTERN Slink *Link; /* Link data */
|
||||
EXTERN Stank *Tank; /* Tank data */
|
||||
EXTERN Spump *Pump; /* Pump data */
|
||||
EXTERN Svalve *Valve; /* Valve data */
|
||||
EXTERN Scontrol *Control; /* Control data */
|
||||
EXTERN HTtable *Nht, *Lht; /* Hash tables for ID labels */
|
||||
EXTERN Padjlist *Adjlist; /* Node adjacency lists */
|
||||
|
||||
/*
|
||||
** NOTE: Hydraulic analysis of the pipe network at a given point in time
|
||||
** is done by repeatedly solving a linearized version of the
|
||||
** equations for conservation of flow & energy:
|
||||
**
|
||||
** A*H = F
|
||||
**
|
||||
** where H = vector of heads (unknowns) at each node,
|
||||
** F = vector of right-hand side coeffs.
|
||||
** A = square matrix of coeffs.
|
||||
** and both A and F are updated at each iteration until there is
|
||||
** negligible change in pipe flows.
|
||||
**
|
||||
** Each row (or column) of A corresponds to a junction in the pipe
|
||||
** network. Each link (pipe, pump or valve) in the network has a
|
||||
** non-zero entry in the row-column of A that corresponds to its
|
||||
** end points. This results in A being symmetric and very sparse.
|
||||
** The following arrays are used to efficiently manage this sparsity:
|
||||
*/
|
||||
|
||||
EXTERN double *Aii, /* Diagonal coeffs. of A */
|
||||
*Aij, /* Non-zero, off-diagonal coeffs. of A */
|
||||
*F; /* Right hand side coeffs. */
|
||||
EXTERN double *P, /* Inverse headloss derivatives */
|
||||
*Y; /* Flow correction factors */
|
||||
EXTERN int *Order, /* Node-to-row of A */
|
||||
*Row, /* Row-to-node of A */
|
||||
*Ndx; /* Index of link's coeff. in Aij */
|
||||
/*
|
||||
** The following arrays store the positions of the non-zero coeffs.
|
||||
** of the lower triangular portion of A whose values are stored in Aij:
|
||||
*/
|
||||
EXTERN int *XLNZ, /* Start position of each column in NZSUB */
|
||||
*NZSUB, /* Row index of each coeff. in each column */
|
||||
*LNZ; /* Position of each coeff. in Aij array */
|
||||
Reference in New Issue
Block a user