Initial commit

This commit is contained in:
Michael Tryby
2014-05-05 18:00:25 -04:00
parent 1672e9332a
commit 993cfce8a4
25 changed files with 17210 additions and 0 deletions

76
src/Engine Updates.txt Normal file
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

57
src/epanet2.def Normal file
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

655
src/inpfile.c Normal file
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

204
src/mempool.c Normal file
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

1214
src/report.c Normal file

File diff suppressed because it is too large Load Diff

967
src/rules.c Normal file
View 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
View 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
View 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
View 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
View 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
View 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 */