Code cleanup
1. Added a standard header to each code module and removed obsolete comments. 2. Re-named several of the sub-structs in the project struct and re-arranged some of their contents. 3. Re-named _defaultModel to _defaultProject. 4. Removed the need to call EN_createproject and EN_deleteproject when working with the default project. 5. Made X & Y coords. part of Snode properties instead of a separate struct. 6. Moved the non-API functions in epanet.c into a new module named project.c. 7. Re-factored the quality module so that it uses the same nodal adjacency lists as the hydraulics solver. 8. Re-factored the sparse matrix module (smatrix.c) to be more memory efficient. 9. Restricted line lengths to < 90 columns. 10. Grouped the placement of functions in EPANET2.H and EPANET.C by category.
This commit is contained in:
1986
include/epanet2.h
1986
include/epanet2.h
File diff suppressed because it is too large
Load Diff
@@ -1,14 +1,14 @@
|
||||
/*
|
||||
***********************************************************************
|
||||
|
||||
ENUMSTXT.H -- Text strings for enumerated data types in EPANET
|
||||
|
||||
VERSION: 2.00
|
||||
DATE: 5/8/00
|
||||
AUTHOR: L. Rossman
|
||||
US EPA - NRMRL
|
||||
|
||||
**********************************************************************
|
||||
*****************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Module: enumstxt.h
|
||||
Description: text strings for enumerated data types
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 11/27/2018
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef ENUMSTXT_H
|
||||
|
||||
8936
src/epanet.c
8936
src/epanet.c
File diff suppressed because it is too large
Load Diff
@@ -57,7 +57,7 @@ DAT(257,ENERR_NO_RULE,"function applied to nonexistent rule")
|
||||
DAT(258,ENERR_NO_CONDITION_ACTION,"function applied to nonexistent rule clause")
|
||||
|
||||
DAT(260,ENERR_DEL_TRACE_NODE,"cannot delete node assigned as a Trace Node")
|
||||
DAT(261,ENERR_DEL_NODE_LINK, "cannot delete a node or link contained in a control or rule")
|
||||
DAT(261,ENERR_DEL_NODE_LINK, "cannot delete a node or link contained in a control")
|
||||
|
||||
DAT(301,ENERR_FILES_ARE_SAME,"identical file names")
|
||||
DAT(302,ENERR_CANT_OPEN_INP,"cannot open input file")
|
||||
@@ -69,9 +69,6 @@ DAT(307,ENERR_CANT_READ_HYD,"cannot read hydraulics file")
|
||||
DAT(308,ENERR_CANT_SAVE_RES,"cannot save results to file")
|
||||
DAT(309,ENERR_CANT_SAVE_RPT,"cannot save results to report file")
|
||||
|
||||
DAT(401,ENERR_QSTEP_NOT_DIVISIBLE,"Qstep is not dividable by Hstep")
|
||||
|
||||
|
||||
DAT(411,ENERR_NO_MEM_ALLOC,"no memory allocated for results")
|
||||
DAT(412,ENERR_NO_RESULTS_NO_FILE,"no results; binary file hasn't been opened")
|
||||
DAT(435,ENERR_RUN_TERMINATED,"run terminated; no results in binary file")
|
||||
|
||||
360
src/funcs.h
360
src/funcs.h
@@ -1,227 +1,175 @@
|
||||
/*
|
||||
**************************************************************************
|
||||
|
||||
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
|
||||
2/14/08 (2.00.12)
|
||||
AUTHOR: L. Rossman
|
||||
US EPA - NRMRL
|
||||
|
||||
**************************************************************************
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Module: funcs.h
|
||||
Description: prototypes of external functions called by various modules
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 11/27/2018
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/*****************************************************************/
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
#ifndef FUNCS_H
|
||||
#define FUNCS_H
|
||||
|
||||
void initpointers(EN_Project *pr); /* Initializes pointers */
|
||||
int allocdata(EN_Project *pr); /* Allocates memory */
|
||||
void freeTmplist(STmplist *); /* Frees items in linked list */
|
||||
void freeFloatlist(SFloatlist *); /* Frees list of floats */
|
||||
void freedata(EN_Project *pr); /* Frees allocated memory */
|
||||
int openfiles(EN_Project *pr, const char *,
|
||||
const char *,const char *); /* Opens input & report files */
|
||||
int openhydfile(EN_Project *pr); /* Opens hydraulics file */
|
||||
int openoutfile(EN_Project *pr); /* Opens binary output file */
|
||||
int strcomp(const char *, const char *); /* Compares two strings */
|
||||
char* getTmpName(char* fname); /* Gets temporary file name */
|
||||
double interp(int n, double x[], double y[],
|
||||
double xx); /* Interpolates a data curve */
|
||||
// ------- PROJECT.C ------------
|
||||
|
||||
int findnode(EN_Network *n, char *); /* Finds node's index from ID */
|
||||
int findlink(EN_Network *n, char *); /* Finds link's index from ID */
|
||||
int findtank(EN_Network *n, int); /* Find tank index from node index */ // (AH)
|
||||
int findvalve(EN_Network *n, int); /* Find valve index from node index */ // (AH)
|
||||
int findpump(EN_Network *n, int); /* Find pump index from node index */ // (AH)
|
||||
char *geterrmsg(int errcode, char *msg); /* Gets text of error message */
|
||||
void errmsg(EN_Project *p, int); /* Reports program error */
|
||||
void writewin(void (*vp)(char *), char *); /* Passes text to calling app */
|
||||
void initpointers(Project *);
|
||||
int allocdata(Project *);
|
||||
void freeTmplist(STmplist *);
|
||||
void freeFloatlist(SFloatlist *);
|
||||
void freedata(Project *);
|
||||
|
||||
/* ------- INPUT1.C --------------------*/
|
||||
int getdata(EN_Project *pr); /* Gets network data */
|
||||
void setdefaults(EN_Project *pr); /* Sets default values */
|
||||
void initreport(report_options_t *r); /* Initializes report options */
|
||||
void adjustdata(EN_Project *pr); /* Adjusts input data */
|
||||
int inittanks(EN_Project *pr); /* Initializes tank levels */
|
||||
void initunits(EN_Project *pr); /* Determines reporting units */
|
||||
void convertunits(EN_Project *pr); /* Converts data to std. units*/
|
||||
int openfiles(Project *, const char *, const char *,const char *);
|
||||
int openhydfile(Project *);
|
||||
int openoutfile(Project *);
|
||||
|
||||
/* -------- INPUT2.C -------------------*/
|
||||
int netsize(EN_Project *pr); /* Determines network size */
|
||||
int readdata(EN_Project *pr); /* Reads in network data */
|
||||
int newline(EN_Project *pr, int, char *); /* Processes new line of data */
|
||||
int addnodeID(EN_Network *n, int, char *); /* Adds node ID to data base */
|
||||
int addlinkID(EN_Network *n, int, char *); /* Adds link ID to data base */
|
||||
int addpattern(parser_data_t *par, char *); /* Adds pattern to data base */
|
||||
int addcurve(parser_data_t *par, char *); /* Adds curve to data base */
|
||||
STmplist *findID(char *, STmplist *); /* Locates ID on linked list */
|
||||
int unlinked(EN_Project *pr); /* Checks for unlinked nodes */
|
||||
int getpumpparams(EN_Project *pr); /* Computes pump curve coeffs.*/
|
||||
int updatepumpparams(EN_Project *pr, int); // Updates pump curve coeffs.
|
||||
int getpatterns(EN_Project *pr); /* Gets pattern data from list*/
|
||||
int getcurves(EN_Project *pr); /* Gets curve data from list */
|
||||
int findmatch(char *, char *[]); /* Finds keyword in line */
|
||||
int match(const char *, const char *); /* Checks for word match */
|
||||
int gettokens(char *s, char** Tok, int maxToks,
|
||||
char *comment); /* Tokenizes input line */
|
||||
int getfloat(char *, double *); /* Converts string to double */
|
||||
double hour(char *, char *); /* Converts time to hours */
|
||||
int setreport(EN_Project *pr, char *); /* Processes reporting command*/
|
||||
void inperrmsg(EN_Project *pr, int,int,char *); /* Input error message */
|
||||
int buildadjlists(Network *);
|
||||
void freeadjlists(Network *);
|
||||
|
||||
/* ---------- INPUT3.C -----------------*/
|
||||
int juncdata(EN_Project *pr); /* Processes junction data */
|
||||
int tankdata(EN_Project *pr); /* Processes tank data */
|
||||
int pipedata(EN_Project *pr); /* Processes pipe data */
|
||||
int pumpdata(EN_Project *pr); /* Processes pump data */
|
||||
int valvedata(EN_Project *pr); /* Processes valve data */
|
||||
int patterndata(EN_Project *pr); /* Processes pattern data */
|
||||
int curvedata(EN_Project *pr); /* Processes curve data */
|
||||
int coordata(EN_Project *pr); /* Processes coordinate data */
|
||||
int demanddata(EN_Project *pr); /* Processes demand data */
|
||||
int controldata(EN_Project *pr); /* Processes simple controls */
|
||||
int energydata(EN_Project *pr); /* Processes energy data */
|
||||
int sourcedata(EN_Project *pr); /* Processes source data */
|
||||
int emitterdata(EN_Project *pr); /* Processes emitter data */
|
||||
int qualdata(EN_Project *pr); /* Processes quality data */
|
||||
int reactdata(EN_Project *pr); /* Processes reaction data */
|
||||
int mixingdata(EN_Project *pr); /* Processes tank mixing data */
|
||||
int statusdata(EN_Project *pr); /* Processes link status data */
|
||||
int reportdata(EN_Project *pr); /* Processes report options */
|
||||
int timedata(EN_Project *pr); /* Processes time options */
|
||||
int optiondata(EN_Project *pr); /* Processes analysis options */
|
||||
int optionchoice(EN_Project *pr, int); /* Processes option choices */
|
||||
int optionvalue(EN_Project *pr, int); /* Processes option values */
|
||||
int getpumpcurve(EN_Project *pr, int); /* Constructs a pump curve */
|
||||
int powercurve(double, double, double, /* Coeffs. of power pump curve*/
|
||||
double, double, double *,
|
||||
double *, double *);
|
||||
int valvecheck(EN_Project *pr, int, int, int); /* Checks valve placement */
|
||||
void changestatus(EN_Network *net, int, StatType,
|
||||
double); /* Changes status of a link */
|
||||
int incontrols(Project *, int, int);
|
||||
int findnode(Network *, char *);
|
||||
int findlink(Network *, char *);
|
||||
int findtank(Network *, int);
|
||||
int findvalve(Network *, int);
|
||||
int findpump(Network *, int);
|
||||
|
||||
/* -------------- RULES.C --------------*/
|
||||
void initrules(EN_Project *pr); /* Initializes rule base */
|
||||
void addrule(parser_data_t *par, char *); /* Adds rule to rule base */
|
||||
int allocrules(EN_Project *pr); /* Allocates memory for rule */
|
||||
void adjustrules(EN_Project *pr, int, int); // Shifts object indices down
|
||||
void adjusttankrules(EN_Project *pr); // Shifts tank indices up
|
||||
int ruledata(EN_Project *pr); /* Processes rule input data */
|
||||
int checkrules(EN_Project *pr, long); /* Checks all rules */
|
||||
void deleterule(EN_Project *pr, int); // Deletes a rule
|
||||
void freerules(EN_Project *pr); /* Frees rule base memory */
|
||||
int writerule(EN_Project *pr, FILE *, int); /* Writes rule to an INP file */
|
||||
void ruleerrmsg(EN_Project *pr); /* Reports rule parser error */
|
||||
Spremise *getpremise(Spremise *, int); // Retrieves a rule's premise
|
||||
Saction *getaction(Saction *, int); // Retrieves a rule's action
|
||||
char *getTmpName(char *);
|
||||
int strcomp(const char *, const char *);
|
||||
double interp(int, double [], double [], double);
|
||||
char *geterrmsg(int, char *);
|
||||
void errmsg(Project *, int);
|
||||
void writewin(void (*vp)(char *), char *);
|
||||
|
||||
/* ------------- REPORT.C --------------*/
|
||||
int writereport(EN_Project *pr); /* Writes formatted report */
|
||||
void writelogo(EN_Project *pr); /* Writes program logo */
|
||||
void writesummary(EN_Project *pr); /* Writes network summary */
|
||||
void writehydstat(EN_Project *pr, int,double); /* Writes hydraulic status */
|
||||
void writeenergy(EN_Project *pr); /* Writes energy usage */
|
||||
int writeresults(EN_Project *pr); /* Writes node/link results */
|
||||
void writeheader(EN_Project *pr, int,int); /* Writes heading on report */
|
||||
void writeline(EN_Project *pr, char *); /* Writes line to report file */
|
||||
void writerelerr(EN_Project *pr, int, double); /* Writes convergence error */
|
||||
void writestatchange(EN_Project *pr, int,char,char); /* Writes link status change */
|
||||
void writecontrolaction(EN_Project *pr, int, int); /* Writes control action taken*/
|
||||
void writeruleaction(EN_Project *pr, int, char *); /* Writes rule action taken */
|
||||
int writehydwarn(EN_Project *pr, int,double); /* Writes hydraulic warnings */
|
||||
void writehyderr(EN_Project *pr, int); /* Writes hydraulic error msg.*/
|
||||
void writemassbalance(EN_Project *pr); // Writes mass balance ratio
|
||||
int disconnected(EN_Project *pr); /* Checks for disconnections */
|
||||
void marknodes(EN_Project *pr, int, int *, char *); /* Identifies connected nodes */
|
||||
void getclosedlink(EN_Project *pr, int, char *); /* Finds a disconnecting link */
|
||||
void writelimits(EN_Project *pr, int,int); /* Writes reporting limits */
|
||||
int checklimits(report_options_t *rep, double *,
|
||||
int,int); /* Checks variable limits */
|
||||
void writetime(EN_Project *pr, 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(EN_Network *net, int); /* Determines node type */
|
||||
// ------- INPUT1.C ----------------
|
||||
|
||||
/* --------- HYDRAUL.C -----------------*/
|
||||
int openhyd(EN_Project *pr); /* Opens hydraulics solver */
|
||||
void inithyd(EN_Project *pr, int initFlags); /* Re-sets initial conditions */
|
||||
int runhyd(EN_Project *pr, long *); /* Solves 1-period hydraulics */
|
||||
int nexthyd(EN_Project *pr, long *); /* Moves to next time period */
|
||||
void closehyd(EN_Project *pr); /* Closes hydraulics solver */
|
||||
void setlinkstatus(EN_Project *pr, int, char,
|
||||
StatType *, double *); /* Sets link status */
|
||||
void setlinksetting(EN_Project *pr, int, double,
|
||||
StatType *, double *); /* Sets pump/valve setting */
|
||||
int tanktimestep(EN_Project *pr, long *); /* Time till tanks fill/drain */
|
||||
void getenergy(EN_Project *pr, int, double *,
|
||||
double *); /* Computes link energy use */
|
||||
double tankvolume(EN_Project *pr, int, double); /* Finds tank vol. from grade */
|
||||
double tankgrade(EN_Project *pr, int, double); /* Finds tank grade from vol. */
|
||||
int getdata(Project *);
|
||||
void setdefaults(Project *);
|
||||
void initreport(Report *);
|
||||
void adjustdata(Project *);
|
||||
int inittanks(Project *);
|
||||
void initunits(Project *);
|
||||
void convertunits(Project *);
|
||||
|
||||
/* ----------- HYDSOLVER.C - ----------*/
|
||||
int hydsolve(EN_Project *pr, int *,double *); /* Solves network equations */
|
||||
//-------- INPUT2.C -----------------
|
||||
|
||||
/* ----------- HYDCOEFFS.C --------------*/
|
||||
void resistcoeff(EN_Project *pr, int k); /* Finds pipe flow resistance */
|
||||
void headlosscoeffs(EN_Project *pr); // Finds link head loss coeffs.
|
||||
void matrixcoeffs(EN_Project *pr); /* Finds hyd. matrix coeffs. */
|
||||
void emitheadloss(EN_Project *pr, int, // Finds emitter head loss
|
||||
double *, double *);
|
||||
double demandflowchange(EN_Project *pr, int, // Change in demand outflow
|
||||
double, double);
|
||||
void demandparams(EN_Project *pr, double *, // PDA function parameters
|
||||
double *);
|
||||
int netsize(Project *);
|
||||
int readdata(Project *);
|
||||
int updatepumpparams(Project *, int);
|
||||
int getpatterns(Project *);
|
||||
int getcurves(Project *);
|
||||
int findmatch(char *, char *[]);
|
||||
int match(const char *, const char *);
|
||||
int gettokens(char *, char **, int, char *);
|
||||
int getfloat(char *, double *);
|
||||
double hour(char *, char *);
|
||||
int setreport(Project *, char *);
|
||||
|
||||
/* ----------- SMATRIX.C ---------------*/
|
||||
int createsparse(EN_Project *pr); /* Creates sparse matrix */
|
||||
void freesparse(EN_Project *pr); /* Frees matrix memory */
|
||||
int linsolve(EN_Project *pr, int); /* Solves set of linear eqns. */
|
||||
// ------- INPUT3.C -----------------
|
||||
|
||||
/* ----------- QUALITY.C ---------------*/
|
||||
int openqual(EN_Project *pr); /* Opens WQ solver system */
|
||||
int initqual(EN_Project *pr); /* Initializes WQ solver */
|
||||
int runqual(EN_Project *pr, long *); /* Gets current WQ results */
|
||||
int nextqual(EN_Project *pr, long *); /* Updates WQ by hyd.timestep */
|
||||
int stepqual(EN_Project *pr, long *); /* Updates WQ by WQ time step */
|
||||
int closequal(EN_Project *pr); /* Closes WQ solver system */
|
||||
double avgqual(EN_Project *pr, int); /* Finds avg. quality in pipe */
|
||||
int juncdata(Project *);
|
||||
int tankdata(Project *);
|
||||
int pipedata(Project *);
|
||||
int pumpdata(Project *);
|
||||
int valvedata(Project *);
|
||||
int patterndata(Project *);
|
||||
int curvedata(Project *);
|
||||
int coordata(Project *);
|
||||
int demanddata(Project *);
|
||||
int controldata(Project *);
|
||||
int energydata(Project *);
|
||||
int sourcedata(Project *);
|
||||
int emitterdata(Project *);
|
||||
int qualdata(Project *);
|
||||
int reactdata(Project *);
|
||||
int mixingdata(Project *);
|
||||
int statusdata(Project *);
|
||||
int reportdata(Project *);
|
||||
int timedata(Project *);
|
||||
int optiondata(Project *);
|
||||
int valvecheck(Project *, int, int, int);
|
||||
|
||||
/* ------------ OUTPUT.C ---------------*/
|
||||
int savenetdata(EN_Project *pr); /* Saves basic data to file */
|
||||
int savehyd(EN_Project *pr, long *); /* Saves hydraulic solution */
|
||||
int savehydstep(EN_Project *pr, long *); /* Saves hydraulic timestep */
|
||||
int saveenergy(EN_Project *pr); /* Saves energy usage */
|
||||
int readhyd(EN_Project *pr, long *); /* Reads hydraulics from file */
|
||||
int readhydstep(EN_Project *pr, long *); /* Reads time step from file */
|
||||
int saveoutput(EN_Project *pr); /* Saves results to file */
|
||||
int nodeoutput(EN_Project *pr, int, REAL4 *,
|
||||
double); /* Saves node results to file */
|
||||
int linkoutput(EN_Project *pr, int, REAL4 *,
|
||||
double); /* Saves link results to file */
|
||||
int savefinaloutput(EN_Project *pr); /* Finishes saving output */
|
||||
int savetimestat(EN_Project *pr, REAL4 *,
|
||||
HdrType); /* Saves time stats to file */
|
||||
int savenetreacts(EN_Project *pr, double,
|
||||
double,double, double); /* Saves react. rates to file */
|
||||
int saveepilog(EN_Project *pr); /* Saves output file epilog */
|
||||
// ------- RULES.C ------------------
|
||||
|
||||
void initrules(Project *);
|
||||
void addrule(Parser *, char *);
|
||||
void deleterule(Project *, int);
|
||||
int allocrules(Project *);
|
||||
void freerules(Project *);
|
||||
int ruledata(Project *);
|
||||
void ruleerrmsg(Project *);
|
||||
void adjustrules(Project *, int, int);
|
||||
void adjusttankrules(Project *);
|
||||
Spremise *getpremise(Spremise *, int);
|
||||
Saction *getaction(Saction *, int);
|
||||
int writerule(Project *, FILE *, int);
|
||||
int checkrules(Project *, long);
|
||||
|
||||
/* ------------ INPFILE.C --------------*/
|
||||
int saveinpfile(EN_Project *pr, const char *); /* Saves network to text file */
|
||||
// ------- REPORT.C -----------------
|
||||
|
||||
int writereport(Project *);
|
||||
void writelogo(Project *);
|
||||
void writesummary(Project *);
|
||||
void writehydstat(Project *, int, double);
|
||||
void writeheader(Project *, int,int);
|
||||
void writeline(Project *, char *);
|
||||
void writerelerr(Project *, int, double);
|
||||
void writestatchange(Project *, int,char,char);
|
||||
void writecontrolaction(Project *, int, int);
|
||||
void writeruleaction(Project *, int, char *);
|
||||
int writehydwarn(Project *, int,double);
|
||||
void writehyderr(Project *, int);
|
||||
void writemassbalance(Project *);
|
||||
void writetime(Project *, char *);
|
||||
char *clocktime(char *, long);
|
||||
|
||||
// ------- HYDRAUL.C -----------------
|
||||
|
||||
int openhyd(Project *);
|
||||
void inithyd(Project *, int initFlags);
|
||||
int runhyd(Project *, long *);
|
||||
int nexthyd(Project *, long *);
|
||||
void closehyd(Project *);
|
||||
void setlinkstatus(Project *, int, char, StatusType *, double *);
|
||||
void setlinksetting(Project *, int, double, StatusType *, double *);
|
||||
int tanktimestep(Project *, long *);
|
||||
void getenergy(Project *, int, double *, double *);
|
||||
double tankvolume(Project *, int, double);
|
||||
double tankgrade(Project *, int, double);
|
||||
|
||||
// ------- HYDCOEFFS.C -----------------
|
||||
|
||||
void resistcoeff(Project *, int);
|
||||
void headlosscoeffs(Project *);
|
||||
void matrixcoeffs(Project *);
|
||||
void emitheadloss(Project *, int, double *, double *);
|
||||
double demandflowchange(Project *, int, double, double);
|
||||
void demandparams(Project *, double *, double *);
|
||||
|
||||
// ------- QUALITY.C --------------------
|
||||
|
||||
int openqual(Project *);
|
||||
int initqual(Project *);
|
||||
int runqual(Project *, long *);
|
||||
int nextqual(Project *, long *);
|
||||
int stepqual(Project *, long *);
|
||||
int closequal(Project *);
|
||||
double avgqual(Project *, int);
|
||||
|
||||
// ------- OUTPUT.C ---------------------
|
||||
|
||||
int savenetdata(Project *);
|
||||
int savehyd(Project *, long *);
|
||||
int savehydstep(Project *, long *);
|
||||
int saveenergy(Project *);
|
||||
int readhyd(Project *, long *);
|
||||
int readhydstep(Project *, long *);
|
||||
int saveoutput(Project *);
|
||||
int savefinaloutput(Project *);
|
||||
|
||||
// ------- INPFILE.C --------------------
|
||||
|
||||
int saveinpfile(Project *, const char *);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <math.h>
|
||||
|
||||
int genmmd(int* neqns, int* xadj, int* adjncy, int* invp, int* perm,
|
||||
|
||||
38
src/hash.c
38
src/hash.c
@@ -1,20 +1,14 @@
|
||||
/*-----------------------------------------------------------------------------
|
||||
** hash.c
|
||||
**
|
||||
** Implementation of a simple Hash Table that uses a string as a key
|
||||
** and an associated integer as data.
|
||||
**
|
||||
** Written by L. Rossman
|
||||
** Last Updated on 10/19/18
|
||||
**
|
||||
** Interface Functions:
|
||||
** hashtable_create - creates a hash table
|
||||
** hashtable_insert - inserts a string & its data value into a table
|
||||
** hashtable_find - retrieves the data value associated with a string
|
||||
** hashtable_findkey - retrieves the key associated with a data value
|
||||
** hashtable_delete - deletes an entry from a table
|
||||
** hashtable_free - frees a hash table
|
||||
**
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Module: hash.c
|
||||
Description: implementation of a simple hash table
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 11/27/2018
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __APPLE__
|
||||
@@ -27,6 +21,7 @@
|
||||
|
||||
#define HASHTABLEMAXSIZE 128000
|
||||
|
||||
// An entry in the hash table
|
||||
typedef struct DataEntryStruct
|
||||
{
|
||||
char *key;
|
||||
@@ -34,6 +29,7 @@ typedef struct DataEntryStruct
|
||||
struct DataEntryStruct *next;
|
||||
} DataEntry;
|
||||
|
||||
// Hash a string to an integer
|
||||
unsigned int gethash(char *str)
|
||||
{
|
||||
unsigned int hash = 5381;
|
||||
@@ -47,6 +43,7 @@ unsigned int gethash(char *str)
|
||||
return retHash;
|
||||
}
|
||||
|
||||
// Produce a duplicate string
|
||||
char *dupstr(const char *s)
|
||||
{
|
||||
size_t size = strlen(s) + 1;
|
||||
@@ -55,6 +52,7 @@ char *dupstr(const char *s)
|
||||
return p;
|
||||
}
|
||||
|
||||
// Create a hash table
|
||||
HashTable *hashtable_create()
|
||||
{
|
||||
int i;
|
||||
@@ -66,6 +64,7 @@ HashTable *hashtable_create()
|
||||
return ht;
|
||||
}
|
||||
|
||||
// Insert an entry into the hash table
|
||||
int hashtable_insert(HashTable *ht, char *key, int data)
|
||||
{
|
||||
unsigned int i = gethash(key);
|
||||
@@ -80,6 +79,7 @@ int hashtable_insert(HashTable *ht, char *key, int data)
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Change the hash table's data entry for a particular key
|
||||
int hashtable_update(HashTable *ht, char *key, int new_data)
|
||||
{
|
||||
unsigned int i = gethash(key);
|
||||
@@ -99,6 +99,7 @@ int hashtable_update(HashTable *ht, char *key, int new_data)
|
||||
return NOTFOUND;
|
||||
}
|
||||
|
||||
// Delete an entry in the hash table
|
||||
int hashtable_delete(HashTable *ht, char *key)
|
||||
{
|
||||
unsigned int i = gethash(key);
|
||||
@@ -124,6 +125,7 @@ int hashtable_delete(HashTable *ht, char *key)
|
||||
return NOTFOUND;
|
||||
}
|
||||
|
||||
// Find the data for a particular key
|
||||
int hashtable_find(HashTable *ht, char *key)
|
||||
{
|
||||
unsigned int i = gethash(key);
|
||||
@@ -142,6 +144,7 @@ int hashtable_find(HashTable *ht, char *key)
|
||||
return NOTFOUND;
|
||||
}
|
||||
|
||||
// Find a particular key in the hash table
|
||||
char *hashtable_findkey(HashTable *ht, char *key)
|
||||
{
|
||||
unsigned int i = gethash(key);
|
||||
@@ -156,6 +159,7 @@ char *hashtable_findkey(HashTable *ht, char *key)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Delete a hash table and free all of its memory
|
||||
void hashtable_free(HashTable *ht)
|
||||
{
|
||||
DataEntry *entry, *nextentry;
|
||||
|
||||
16
src/hash.h
16
src/hash.h
@@ -1,9 +1,15 @@
|
||||
/* HASH.H
|
||||
**
|
||||
** Header file for Hash Table module HASH.C
|
||||
**
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Module: hash.h
|
||||
Description: header for a simple hash table
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 11/27/2018
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef HASH_H
|
||||
#define HASH_H
|
||||
|
||||
|
||||
434
src/hydcoeffs.c
434
src/hydcoeffs.c
@@ -1,9 +1,14 @@
|
||||
/*
|
||||
*********************************************************************
|
||||
|
||||
HYDCOEFFS.C -- hydraulic coefficients for the EPANET Program
|
||||
|
||||
*******************************************************************
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Module: hydcoeffs.c
|
||||
Description: computes coefficients for a hydraulic solution matrix
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 11/27/2018
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -29,40 +34,44 @@ const double AA = -1.5634601348517065795e+00; // -2*.9*2/ln(10)
|
||||
const double AB = 3.28895476345399058690e-03; // 5.74/(4000^.9)
|
||||
const double AC = -5.14214965799093883760e-03; // AA*AB
|
||||
|
||||
// External functions
|
||||
//void resistcoeff(EN_Project *pr, int k);
|
||||
//void headlosscoeffs(EN_Project *pr);
|
||||
//void matrixcoeffs(EN_Project *pr);
|
||||
//void emitheadloss(EN_Project *pr, int i, double *hloss, double *dhdq);
|
||||
//double demandflowchange(EN_Project *pr, int i, double dp, double n);
|
||||
//void demandparams(EN_Project *pr, double *dp, double *n);
|
||||
// Definitions of very small and very big coefficients
|
||||
const double CSMALL = 1.e-6;
|
||||
const double CBIG = 1.e8;
|
||||
|
||||
// Exported functions
|
||||
//void resistcoeff(Project *, int );
|
||||
//void headlosscoeffs(Project *);
|
||||
//void matrixcoeffs(Project *);
|
||||
//void emitheadloss(Project *, int, double *, double *);
|
||||
//double demandflowchange(Project *, int, double, double);
|
||||
//void demandparams(Project *, double *, double *);
|
||||
|
||||
// Local functions
|
||||
static void linkcoeffs(EN_Project *pr);
|
||||
static void nodecoeffs(EN_Project *pr);
|
||||
static void valvecoeffs(EN_Project *pr);
|
||||
static void emittercoeffs(EN_Project *pr);
|
||||
static void demandcoeffs(EN_Project *pr);
|
||||
static void linkcoeffs(Project *pr);
|
||||
static void nodecoeffs(Project *pr);
|
||||
static void valvecoeffs(Project *pr);
|
||||
static void emittercoeffs(Project *pr);
|
||||
static void demandcoeffs(Project *pr);
|
||||
static void demandheadloss(double d, double dfull, double dp,
|
||||
double n, double *hloss, double *hgrad);
|
||||
|
||||
static void pipecoeff(EN_Project *pr, int k);
|
||||
static void DWpipecoeff(EN_Project *pr, int k);
|
||||
static void pipecoeff(Project *pr, int k);
|
||||
static void DWpipecoeff(Project *pr, int k);
|
||||
static double frictionFactor(double q, double e, double s, double *dfdq);
|
||||
|
||||
static void pumpcoeff(EN_Project *pr, int k);
|
||||
static void curvecoeff(EN_Project *pr, int i, double q, double *h0, double *r);
|
||||
static void pumpcoeff(Project *pr, int k);
|
||||
static void curvecoeff(Project *pr, int i, double q, double *h0, double *r);
|
||||
|
||||
static void valvecoeff(EN_Project *pr, int k);
|
||||
static void gpvcoeff(EN_Project *pr, int k);
|
||||
static void pbvcoeff(EN_Project *pr, int k);
|
||||
static void tcvcoeff(EN_Project *pr, int k);
|
||||
static void prvcoeff(EN_Project *pr, int k, int n1, int n2);
|
||||
static void psvcoeff(EN_Project *pr, int k, int n1, int n2);
|
||||
static void fcvcoeff(EN_Project *pr, int k, int n1, int n2);
|
||||
static void valvecoeff(Project *pr, int k);
|
||||
static void gpvcoeff(Project *pr, int k);
|
||||
static void pbvcoeff(Project *pr, int k);
|
||||
static void tcvcoeff(Project *pr, int k);
|
||||
static void prvcoeff(Project *pr, int k, int n1, int n2);
|
||||
static void psvcoeff(Project *pr, int k, int n1, int n2);
|
||||
static void fcvcoeff(Project *pr, int k, int n1, int n2);
|
||||
|
||||
|
||||
void resistcoeff(EN_Project *pr, int k)
|
||||
void resistcoeff(Project *pr, int k)
|
||||
/*
|
||||
**--------------------------------------------------------------------
|
||||
** Input: k = link index
|
||||
@@ -71,10 +80,10 @@ void resistcoeff(EN_Project *pr, int k)
|
||||
**--------------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
double e, d, L;
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
EN_Network *net = &pr->network;
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
double e, d, L;
|
||||
Slink *link = &net->Link[k];
|
||||
|
||||
link->Qa = 0.0;
|
||||
@@ -121,7 +130,7 @@ void resistcoeff(EN_Project *pr, int k)
|
||||
}
|
||||
|
||||
|
||||
void headlosscoeffs(EN_Project *pr)
|
||||
void headlosscoeffs(Project *pr)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
@@ -131,9 +140,10 @@ void headlosscoeffs(EN_Project *pr)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
int k;
|
||||
EN_Network *net = &pr->network;
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
|
||||
for (k = 1; k <= net->Nlinks; k++)
|
||||
{
|
||||
@@ -159,13 +169,13 @@ void headlosscoeffs(EN_Project *pr)
|
||||
case PRV:
|
||||
case PSV:
|
||||
if (hyd->LinkSetting[k] == MISSING) valvecoeff(pr, k);
|
||||
else hyd->solver.P[k] = 0.0;
|
||||
else hyd->P[k] = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void matrixcoeffs(EN_Project *pr)
|
||||
void matrixcoeffs(Project *pr)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
@@ -174,16 +184,16 @@ void matrixcoeffs(EN_Project *pr)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
solver_t *sol = &hyd->solver;
|
||||
EN_Network *net = &pr->network;
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Smatrix *sm = &hyd->smatrix;
|
||||
|
||||
// Reset values of all diagonal coeffs. (Aii), off-diagonal
|
||||
// coeffs. (Aij), r.h.s. coeffs. (F) and node flow balance (X_tmp)
|
||||
memset(sol->Aii, 0, (net->Nnodes + 1) * sizeof(double));
|
||||
memset(sol->Aij, 0, (hyd->Ncoeffs + 1) * sizeof(double));
|
||||
memset(sol->F, 0, (net->Nnodes + 1) * sizeof(double));
|
||||
memset(hyd->X_tmp, 0, (net->Nnodes + 1) * sizeof(double));
|
||||
// coeffs. (Aij), r.h.s. coeffs. (F) and node excess flow (Xflow)
|
||||
memset(sm->Aii, 0, (net->Nnodes + 1) * sizeof(double));
|
||||
memset(sm->Aij, 0, (sm->Ncoeffs + 1) * sizeof(double));
|
||||
memset(sm->F, 0, (net->Nnodes + 1) * sizeof(double));
|
||||
memset(hyd->Xflow, 0, (net->Nnodes + 1) * sizeof(double));
|
||||
|
||||
// Compute matrix coeffs. from links, emitters, and nodal demands
|
||||
linkcoeffs(pr);
|
||||
@@ -199,7 +209,7 @@ void matrixcoeffs(EN_Project *pr)
|
||||
}
|
||||
|
||||
|
||||
void linkcoeffs(EN_Project *pr)
|
||||
void linkcoeffs(Project *pr)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
@@ -209,80 +219,81 @@ void linkcoeffs(EN_Project *pr)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int k, n1, n2;
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Smatrix *sm = &hyd->smatrix;
|
||||
|
||||
EN_Network *net = &pr->network;
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
solver_t *sol = &hyd->solver;
|
||||
int k, n1, n2;
|
||||
Slink *link;
|
||||
|
||||
// Examine each link of network
|
||||
for (k = 1; k <= net->Nlinks; k++)
|
||||
{
|
||||
if (sol->P[k] == 0.0) continue;
|
||||
if (hyd->P[k] == 0.0) continue;
|
||||
link = &net->Link[k];
|
||||
n1 = link->N1; // Start node of link
|
||||
n2 = link->N2; // End node of link
|
||||
|
||||
// Update nodal flow balance (X_tmp)
|
||||
// Update nodal flow excess (Xflow)
|
||||
// (Flow out of node is (-), flow into node is (+))
|
||||
hyd->X_tmp[n1] -= hyd->LinkFlows[k];
|
||||
hyd->X_tmp[n2] += hyd->LinkFlows[k];
|
||||
hyd->Xflow[n1] -= hyd->LinkFlow[k];
|
||||
hyd->Xflow[n2] += hyd->LinkFlow[k];
|
||||
|
||||
// Add to off-diagonal coeff. of linear system matrix
|
||||
sol->Aij[sol->Ndx[k]] -= sol->P[k];
|
||||
sm->Aij[sm->Ndx[k]] -= hyd->P[k];
|
||||
|
||||
// Update linear system coeffs. associated with start node n1
|
||||
// ... node n1 is junction
|
||||
if (n1 <= net->Njuncs)
|
||||
{
|
||||
sol->Aii[sol->Row[n1]] += sol->P[k]; // Diagonal coeff.
|
||||
sol->F[sol->Row[n1]] += sol->Y[k]; // RHS coeff.
|
||||
sm->Aii[sm->Row[n1]] += hyd->P[k]; // Diagonal coeff.
|
||||
sm->F[sm->Row[n1]] += hyd->Y[k]; // RHS coeff.
|
||||
}
|
||||
|
||||
// ... node n1 is a tank/reservoir
|
||||
else sol->F[sol->Row[n2]] += (sol->P[k] * hyd->NodeHead[n1]);
|
||||
else sm->F[sm->Row[n2]] += (hyd->P[k] * hyd->NodeHead[n1]);
|
||||
|
||||
// Update linear system coeffs. associated with end node n2
|
||||
// ... node n2 is junction
|
||||
if (n2 <= net->Njuncs)
|
||||
{
|
||||
sol->Aii[sol->Row[n2]] += sol->P[k]; // Diagonal coeff.
|
||||
sol->F[sol->Row[n2]] -= sol->Y[k]; // RHS coeff.
|
||||
sm->Aii[sm->Row[n2]] += hyd->P[k]; // Diagonal coeff.
|
||||
sm->F[sm->Row[n2]] -= hyd->Y[k]; // RHS coeff.
|
||||
}
|
||||
|
||||
// ... node n2 is a tank/reservoir
|
||||
else sol->F[sol->Row[n1]] += (sol->P[k] * hyd->NodeHead[n2]);
|
||||
else sm->F[sm->Row[n1]] += (hyd->P[k] * hyd->NodeHead[n2]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void nodecoeffs(EN_Project *pr)
|
||||
void nodecoeffs(Project *pr)
|
||||
/*
|
||||
**----------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: none
|
||||
** Purpose: completes calculation of nodal flow balance array
|
||||
** (X_tmp) & r.h.s. (F) of linearized hydraulic eqns.
|
||||
** (Xflow) & r.h.s. (F) of linearized hydraulic eqns.
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Smatrix *sm = &hyd->smatrix;
|
||||
|
||||
int i;
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
solver_t *sol = &hyd->solver;
|
||||
EN_Network *net = &pr->network;
|
||||
|
||||
// For junction nodes, subtract demand flow from net
|
||||
// flow balance & add flow balance to RHS array F
|
||||
// flow excess & add flow excess to RHS array F
|
||||
for (i = 1; i <= net->Njuncs; i++)
|
||||
{
|
||||
hyd->X_tmp[i] -= hyd->DemandFlows[i];
|
||||
sol->F[sol->Row[i]] += hyd->X_tmp[i];
|
||||
hyd->Xflow[i] -= hyd->DemandFlow[i];
|
||||
sm->F[sm->Row[i]] += hyd->Xflow[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void valvecoeffs(EN_Project *pr)
|
||||
void valvecoeffs(Project *pr)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
@@ -293,10 +304,10 @@ void valvecoeffs(EN_Project *pr)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i, k, n1, n2;
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
EN_Network *net = &pr->network;
|
||||
int i, k, n1, n2;
|
||||
Slink *link;
|
||||
Svalve *valve;
|
||||
|
||||
@@ -333,7 +344,7 @@ void valvecoeffs(EN_Project *pr)
|
||||
}
|
||||
|
||||
|
||||
void emittercoeffs(EN_Project *pr)
|
||||
void emittercoeffs(Project *pr)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
@@ -348,12 +359,12 @@ void emittercoeffs(EN_Project *pr)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Smatrix *sm = &hyd->smatrix;
|
||||
|
||||
int i, row;
|
||||
double hloss, hgrad;
|
||||
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
solver_t *sol = &hyd->solver;
|
||||
EN_Network *net = &pr->network;
|
||||
Snode *node;
|
||||
|
||||
for (i = 1; i <= net->Njuncs; i++)
|
||||
@@ -366,19 +377,19 @@ void emittercoeffs(EN_Project *pr)
|
||||
emitheadloss(pr, i, &hloss, &hgrad);
|
||||
|
||||
// Row of solution matrix
|
||||
row = sol->Row[i];
|
||||
row = sm->Row[i];
|
||||
|
||||
// Addition to matrix diagonal & r.h.s
|
||||
sol->Aii[row] += 1.0 / hgrad;
|
||||
sol->F[row] += (hloss + node->El) / hgrad;
|
||||
sm->Aii[row] += 1.0 / hgrad;
|
||||
sm->F[row] += (hloss + node->El) / hgrad;
|
||||
|
||||
// Update to node flow balance
|
||||
hyd->X_tmp[i] -= hyd->EmitterFlows[i];
|
||||
// Update to node flow excess
|
||||
hyd->Xflow[i] -= hyd->EmitterFlow[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void emitheadloss(EN_Project *pr, int i, double *hloss, double *hgrad)
|
||||
void emitheadloss(Project *pr, int i, double *hloss, double *hgrad)
|
||||
/*
|
||||
**-------------------------------------------------------------
|
||||
** Input: i = node index
|
||||
@@ -388,10 +399,11 @@ void emitheadloss(EN_Project *pr, int i, double *hloss, double *hgrad)
|
||||
**-------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
double ke;
|
||||
double q;
|
||||
double qa;
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
|
||||
// Set adjusted emitter coeff.
|
||||
ke = MAX(CSMALL, pr->network.Node[i].Ke);
|
||||
@@ -400,7 +412,7 @@ void emitheadloss(EN_Project *pr, int i, double *hloss, double *hgrad)
|
||||
qa = pow(hyd->RQtol / ke / hyd->Qexp, 1.0 / (hyd->Qexp - 1.0));
|
||||
|
||||
// Use linear head loss relation for small flow
|
||||
q = hyd->EmitterFlows[i];
|
||||
q = hyd->EmitterFlow[i];
|
||||
if (fabs(q) <= qa)
|
||||
{
|
||||
*hgrad = hyd->RQtol;
|
||||
@@ -416,7 +428,7 @@ void emitheadloss(EN_Project *pr, int i, double *hloss, double *hgrad)
|
||||
}
|
||||
|
||||
|
||||
void demandparams(EN_Project *pr, double *dp, double *n)
|
||||
void demandparams(Project *pr, double *dp, double *n)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
@@ -427,7 +439,7 @@ void demandparams(EN_Project *pr, double *dp, double *n)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
// If required pressure equals minimum pressure, use a linear demand
|
||||
// curve with a 0.01 PSI pressure range to approximate an all or
|
||||
@@ -447,7 +459,7 @@ void demandparams(EN_Project *pr, double *dp, double *n)
|
||||
}
|
||||
|
||||
|
||||
void demandcoeffs(EN_Project *pr)
|
||||
void demandcoeffs(Project *pr)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
@@ -462,16 +474,16 @@ void demandcoeffs(EN_Project *pr)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Smatrix *sm = &hyd->smatrix;
|
||||
|
||||
int i, row;
|
||||
double dp, // pressure range over which demand can vary (ft)
|
||||
n, // exponent in head loss v. demand function
|
||||
hloss, // head loss in supplying demand (ft)
|
||||
hgrad; // gradient of demand head loss (ft/cfs)
|
||||
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
solver_t *sol = &hyd->solver;
|
||||
EN_Network *net = &pr->network;
|
||||
|
||||
// Get demand function parameters
|
||||
if (hyd->DemandModel == DDA) return;
|
||||
demandparams(pr, &dp, &n);
|
||||
@@ -483,18 +495,18 @@ void demandcoeffs(EN_Project *pr)
|
||||
if (hyd->NodeDemand[i] <= 0.0) continue;
|
||||
|
||||
// Find head loss for demand outflow at node's elevation
|
||||
demandheadloss(hyd->DemandFlows[i], hyd->NodeDemand[i], dp, n,
|
||||
demandheadloss(hyd->DemandFlow[i], hyd->NodeDemand[i], dp, n,
|
||||
&hloss, &hgrad);
|
||||
|
||||
// Update row of solution matrix A & its r.h.s. F
|
||||
row = sol->Row[i];
|
||||
sol->Aii[row] += 1.0 / hgrad;
|
||||
sol->F[row] += (hloss + net->Node[i].El + hyd->Pmin) / hgrad;
|
||||
row = sm->Row[i];
|
||||
sm->Aii[row] += 1.0 / hgrad;
|
||||
sm->F[row] += (hloss + net->Node[i].El + hyd->Pmin) / hgrad;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
double demandflowchange(EN_Project *pr, int i, double dp, double n)
|
||||
double demandflowchange(Project *pr, int i, double dp, double n)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: i = node index
|
||||
@@ -506,10 +518,11 @@ double demandflowchange(EN_Project *pr, int i, double dp, double n)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
double hloss, hgrad;
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
demandheadloss(hyd->DemandFlows[i], hyd->NodeDemand[i], dp, n, &hloss, &hgrad);
|
||||
double hloss, hgrad;
|
||||
|
||||
demandheadloss(hyd->DemandFlow[i], hyd->NodeDemand[i], dp, n, &hloss, &hgrad);
|
||||
return (hloss - hyd->NodeHead[i] + pr->network.Node[i].El + hyd->Pmin) / hgrad;
|
||||
}
|
||||
|
||||
@@ -563,7 +576,7 @@ void demandheadloss(double d, double dfull, double dp, double n,
|
||||
}
|
||||
|
||||
|
||||
void pipecoeff(EN_Project *pr, int k)
|
||||
void pipecoeff(Project *pr, int k)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: k = link index
|
||||
@@ -575,20 +588,19 @@ void pipecoeff(EN_Project *pr, int k)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
double hloss, // Head loss
|
||||
hgrad, // Head loss gradient
|
||||
ml, // Minor loss coeff.
|
||||
q, // Abs. value of flow
|
||||
r; // Resistance coeff.
|
||||
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
solver_t *sol = &hyd->solver;
|
||||
|
||||
// For closed pipe use headloss formula: hloss = CBIG*q
|
||||
if (hyd->LinkStatus[k] <= CLOSED)
|
||||
{
|
||||
sol->P[k] = 1.0 / CBIG;
|
||||
sol->Y[k] = hyd->LinkFlows[k];
|
||||
hyd->P[k] = 1.0 / CBIG;
|
||||
hyd->Y[k] = hyd->LinkFlow[k];
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -599,7 +611,7 @@ void pipecoeff(EN_Project *pr, int k)
|
||||
return;
|
||||
}
|
||||
|
||||
q = ABS(hyd->LinkFlows[k]);
|
||||
q = ABS(hyd->LinkFlow[k]);
|
||||
ml = pr->network.Link[k].Km;
|
||||
r = pr->network.Link[k].R;
|
||||
|
||||
@@ -625,15 +637,15 @@ void pipecoeff(EN_Project *pr, int k)
|
||||
}
|
||||
|
||||
// Adjust head loss sign for flow direction
|
||||
hloss *= SGN(hyd->LinkFlows[k]);
|
||||
hloss *= SGN(hyd->LinkFlow[k]);
|
||||
|
||||
// P and Y coeffs.
|
||||
sol->P[k] = 1.0 / hgrad;
|
||||
sol->Y[k] = hloss / hgrad;
|
||||
hyd->P[k] = 1.0 / hgrad;
|
||||
hyd->Y[k] = hloss / hgrad;
|
||||
}
|
||||
|
||||
|
||||
void DWpipecoeff(EN_Project *pr, int k)
|
||||
void DWpipecoeff(Project *pr, int k)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: k = link index
|
||||
@@ -643,16 +655,14 @@ void DWpipecoeff(EN_Project *pr, int k)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
solver_t *sol = &hyd->solver;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Slink *link = &pr->network.Link[k];
|
||||
|
||||
double q = ABS(hyd->LinkFlows[k]);
|
||||
double q = ABS(hyd->LinkFlow[k]);
|
||||
double r = link->R; // Resistance coeff.
|
||||
double ml = link->Km; // Minor loss coeff.
|
||||
double e = link->Kc / link->Diam; // Relative roughness
|
||||
double s = hyd->Viscos * link->Diam; // Viscosity / diameter
|
||||
|
||||
double hloss, hgrad, f, dfdq, r1;
|
||||
|
||||
// Compute head loss and its derivative
|
||||
@@ -660,7 +670,7 @@ void DWpipecoeff(EN_Project *pr, int k)
|
||||
if (q <= A2 * s)
|
||||
{
|
||||
r = 16.0 * PI * s * r;
|
||||
hloss = hyd->LinkFlows[k] * (r + ml * q);
|
||||
hloss = hyd->LinkFlow[k] * (r + ml * q);
|
||||
hgrad = r + 2.0 * ml * q;
|
||||
}
|
||||
|
||||
@@ -670,13 +680,13 @@ void DWpipecoeff(EN_Project *pr, int k)
|
||||
dfdq = 0.0;
|
||||
f = frictionFactor(q, e, s, &dfdq);
|
||||
r1 = f * r + ml;
|
||||
hloss = r1 * q * hyd->LinkFlows[k];
|
||||
hloss = r1 * q * hyd->LinkFlow[k];
|
||||
hgrad = (2.0 * r1 * q) + (dfdq * r * q * q);
|
||||
}
|
||||
|
||||
// Compute P and Y coefficients
|
||||
sol->P[k] = 1.0 / hgrad;
|
||||
sol->Y[k] = hloss / hgrad;
|
||||
hyd->P[k] = 1.0 / hgrad;
|
||||
hyd->Y[k] = hloss / hgrad;
|
||||
}
|
||||
|
||||
|
||||
@@ -730,7 +740,7 @@ double frictionFactor(double q, double e, double s, double *dfdq)
|
||||
}
|
||||
|
||||
|
||||
void pumpcoeff(EN_Project *pr, int k)
|
||||
void pumpcoeff(Project *pr, int k)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: k = link index
|
||||
@@ -739,6 +749,8 @@ void pumpcoeff(EN_Project *pr, int k)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
int p; // Pump index
|
||||
double h0, // Shutoff head
|
||||
q, // Abs. value of flow
|
||||
@@ -748,22 +760,19 @@ void pumpcoeff(EN_Project *pr, int k)
|
||||
qa, // Flow limit for linear head loss
|
||||
hloss, // Head loss across pump
|
||||
hgrad; // Head loss gradient
|
||||
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
solver_t *sol = &hyd->solver;
|
||||
Spump *pump;
|
||||
|
||||
// Use high resistance pipe if pump closed or cannot deliver head
|
||||
setting = hyd->LinkSetting[k];
|
||||
if (hyd->LinkStatus[k] <= CLOSED || setting == 0.0)
|
||||
{
|
||||
sol->P[k] = 1.0 / CBIG;
|
||||
sol->Y[k] = hyd->LinkFlows[k];
|
||||
hyd->P[k] = 1.0 / CBIG;
|
||||
hyd->Y[k] = hyd->LinkFlow[k];
|
||||
return;
|
||||
}
|
||||
|
||||
// Obtain reference to pump object & its speed setting
|
||||
q = ABS(hyd->LinkFlows[k]);
|
||||
q = ABS(hyd->LinkFlow[k]);
|
||||
p = findpump(&pr->network, k);
|
||||
pump = &pr->network.Pump[p];
|
||||
|
||||
@@ -783,7 +792,7 @@ void pumpcoeff(EN_Project *pr, int k)
|
||||
|
||||
// Compute head loss and its gradient
|
||||
hgrad = pump->R * setting ;
|
||||
hloss = pump->H0 * SQR(setting) + hgrad * hyd->LinkFlows[k];
|
||||
hloss = pump->H0 * SQR(setting) + hgrad * hyd->LinkFlow[k];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -798,23 +807,23 @@ void pumpcoeff(EN_Project *pr, int k)
|
||||
if (q <= qa)
|
||||
{
|
||||
hgrad = hyd->RQtol;
|
||||
hloss = h0 + hgrad * hyd->LinkFlows[k];
|
||||
hloss = h0 + hgrad * hyd->LinkFlow[k];
|
||||
}
|
||||
// ... use original pump curve for normal flows
|
||||
else
|
||||
{
|
||||
hgrad = n * r * pow(q, n - 1.0);
|
||||
hloss = h0 + hgrad * hyd->LinkFlows[k] / n;
|
||||
hloss = h0 + hgrad * hyd->LinkFlow[k] / n;
|
||||
}
|
||||
}
|
||||
|
||||
// P and Y coeffs.
|
||||
sol->P[k] = 1.0 / hgrad;
|
||||
sol->Y[k] = hloss / hgrad;
|
||||
hyd->P[k] = 1.0 / hgrad;
|
||||
hyd->Y[k] = hloss / hgrad;
|
||||
}
|
||||
|
||||
|
||||
void curvecoeff(EN_Project *pr, int i, double q, double *h0, double *r)
|
||||
void curvecoeff(Project *pr, int i, double q, double *h0, double *r)
|
||||
/*
|
||||
**-------------------------------------------------------------------
|
||||
** Input: i = curve index
|
||||
@@ -854,7 +863,7 @@ void curvecoeff(EN_Project *pr, int i, double q, double *h0, double *r)
|
||||
}
|
||||
|
||||
|
||||
void gpvcoeff(EN_Project *pr, int k)
|
||||
void gpvcoeff(Project *pr, int k)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: k = link index
|
||||
@@ -868,8 +877,7 @@ void gpvcoeff(EN_Project *pr, int k)
|
||||
r, // Slope of head loss curve segment
|
||||
q; // Abs. value of flow
|
||||
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
solver_t *sol = &hyd->solver;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
// Treat as a pipe if valve closed
|
||||
if (hyd->LinkStatus[k] == CLOSED) valvecoeff(pr, k);
|
||||
@@ -883,7 +891,7 @@ void gpvcoeff(EN_Project *pr, int k)
|
||||
i = (int)ROUND(hyd->LinkSetting[k]);
|
||||
|
||||
// Adjusted flow rate
|
||||
q = ABS(hyd->LinkFlows[k]);
|
||||
q = ABS(hyd->LinkFlow[k]);
|
||||
q = MAX(q, TINY);
|
||||
|
||||
// Intercept and slope of curve segment containing q
|
||||
@@ -891,13 +899,13 @@ void gpvcoeff(EN_Project *pr, int k)
|
||||
r = MAX(r, TINY);
|
||||
|
||||
// Resulting P and Y coeffs.
|
||||
sol->P[k] = 1.0 / r;
|
||||
sol->Y[k] = (h0 / r + q) * SGN(hyd->LinkFlows[k]);
|
||||
hyd->P[k] = 1.0 / r;
|
||||
hyd->Y[k] = (h0 / r + q) * SGN(hyd->LinkFlow[k]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void pbvcoeff(EN_Project *pr, int k)
|
||||
void pbvcoeff(Project *pr, int k)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: k = link index
|
||||
@@ -906,8 +914,7 @@ void pbvcoeff(EN_Project *pr, int k)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
solver_t *sol = &hyd->solver;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Slink *link = &pr->network.Link[k];
|
||||
|
||||
// If valve fixed OPEN or CLOSED then treat as a pipe
|
||||
@@ -920,21 +927,21 @@ void pbvcoeff(EN_Project *pr, int k)
|
||||
else
|
||||
{
|
||||
// Treat as a pipe if minor loss > valve setting
|
||||
if (link->Km * SQR(hyd->LinkFlows[k]) > hyd->LinkSetting[k])
|
||||
if (link->Km * SQR(hyd->LinkFlow[k]) > hyd->LinkSetting[k])
|
||||
{
|
||||
valvecoeff(pr, k);
|
||||
}
|
||||
// Otherwise force headloss across valve to be equal to setting
|
||||
else
|
||||
{
|
||||
sol->P[k] = CBIG;
|
||||
sol->Y[k] = hyd->LinkSetting[k] * CBIG;
|
||||
hyd->P[k] = CBIG;
|
||||
hyd->Y[k] = hyd->LinkSetting[k] * CBIG;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void tcvcoeff(EN_Project *pr, int k)
|
||||
void tcvcoeff(Project *pr, int k)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: k = link index
|
||||
@@ -944,7 +951,7 @@ void tcvcoeff(EN_Project *pr, int k)
|
||||
*/
|
||||
{
|
||||
double km;
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Slink *link = &pr->network.Link[k];
|
||||
|
||||
// Save original loss coeff. for open valve
|
||||
@@ -964,7 +971,7 @@ void tcvcoeff(EN_Project *pr, int k)
|
||||
}
|
||||
|
||||
|
||||
void prvcoeff(EN_Project *pr, int k, int n1, int n2)
|
||||
void prvcoeff(Project *pr, int k, int n1, int n2)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: k = link index
|
||||
@@ -976,13 +983,14 @@ void prvcoeff(EN_Project *pr, int k, int n1, int n2)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Smatrix *sm = &hyd->smatrix;
|
||||
|
||||
int i, j; // Rows of solution matrix
|
||||
double hset; // Valve head setting
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
solver_t *sol = &hyd->solver;
|
||||
|
||||
i = sol->Row[n1]; // Matrix rows of nodes
|
||||
j = sol->Row[n2];
|
||||
i = sm->Row[n1]; // Matrix rows of nodes
|
||||
j = sm->Row[n2];
|
||||
hset = pr->network.Node[n2].El +
|
||||
hyd->LinkSetting[k]; // Valve setting
|
||||
|
||||
@@ -991,15 +999,15 @@ void prvcoeff(EN_Project *pr, int k, int n1, int n2)
|
||||
|
||||
// Set coeffs. to force head at downstream
|
||||
// node equal to valve setting & force flow
|
||||
// to equal to flow imbalance at downstream node.
|
||||
// to equal to flow excess at downstream node.
|
||||
|
||||
sol->P[k] = 0.0;
|
||||
sol->Y[k] = hyd->LinkFlows[k] + hyd->X_tmp[n2]; // Force flow balance
|
||||
sol->F[j] += (hset * CBIG); // Force head = hset
|
||||
sol->Aii[j] += CBIG; // at downstream node
|
||||
if (hyd->X_tmp[n2] < 0.0)
|
||||
hyd->P[k] = 0.0;
|
||||
hyd->Y[k] = hyd->LinkFlow[k] + hyd->Xflow[n2]; // Force flow balance
|
||||
sm->F[j] += (hset * CBIG); // Force head = hset
|
||||
sm->Aii[j] += CBIG; // at downstream node
|
||||
if (hyd->Xflow[n2] < 0.0)
|
||||
{
|
||||
sol->F[i] += hyd->X_tmp[n2];
|
||||
sm->F[i] += hyd->Xflow[n2];
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -1008,15 +1016,15 @@ void prvcoeff(EN_Project *pr, int k, int n1, int n2)
|
||||
// compute matrix coeffs. using the valvecoeff() function.
|
||||
|
||||
valvecoeff(pr, k);
|
||||
sol->Aij[sol->Ndx[k]] -= sol->P[k];
|
||||
sol->Aii[i] += sol->P[k];
|
||||
sol->Aii[j] += sol->P[k];
|
||||
sol->F[i] += (sol->Y[k] - hyd->LinkFlows[k]);
|
||||
sol->F[j] -= (sol->Y[k] - hyd->LinkFlows[k]);
|
||||
sm->Aij[sm->Ndx[k]] -= hyd->P[k];
|
||||
sm->Aii[i] += hyd->P[k];
|
||||
sm->Aii[j] += hyd->P[k];
|
||||
sm->F[i] += (hyd->Y[k] - hyd->LinkFlow[k]);
|
||||
sm->F[j] -= (hyd->Y[k] - hyd->LinkFlow[k]);
|
||||
}
|
||||
|
||||
|
||||
void psvcoeff(EN_Project *pr, int k, int n1, int n2)
|
||||
void psvcoeff(Project *pr, int k, int n1, int n2)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: k = link index
|
||||
@@ -1028,13 +1036,14 @@ void psvcoeff(EN_Project *pr, int k, int n1, int n2)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Smatrix *sm = &hyd->smatrix;
|
||||
|
||||
int i, j; // Rows of solution matrix
|
||||
double hset; // Valve head setting
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
solver_t *sol = &hyd->solver;
|
||||
|
||||
i = sol->Row[n1]; // Matrix rows of nodes
|
||||
j = sol->Row[n2];
|
||||
i = sm->Row[n1]; // Matrix rows of nodes
|
||||
j = sm->Row[n2];
|
||||
hset = pr->network.Node[n1].El +
|
||||
hyd->LinkSetting[k]; // Valve setting
|
||||
|
||||
@@ -1042,15 +1051,15 @@ void psvcoeff(EN_Project *pr, int k, int n1, int n2)
|
||||
{
|
||||
// Set coeffs. to force head at upstream
|
||||
// node equal to valve setting & force flow
|
||||
// equal to flow imbalance at upstream node.
|
||||
// equal to flow excess at upstream node.
|
||||
|
||||
sol->P[k] = 0.0;
|
||||
sol->Y[k] = hyd->LinkFlows[k] - hyd->X_tmp[n1]; // Force flow balance
|
||||
sol->F[i] += (hset * CBIG); // Force head = hset
|
||||
sol->Aii[i] += CBIG; // at upstream node
|
||||
if (hyd->X_tmp[n1] > 0.0)
|
||||
hyd->P[k] = 0.0;
|
||||
hyd->Y[k] = hyd->LinkFlow[k] - hyd->Xflow[n1]; // Force flow balance
|
||||
sm->F[i] += (hset * CBIG); // Force head = hset
|
||||
sm->Aii[i] += CBIG; // at upstream node
|
||||
if (hyd->Xflow[n1] > 0.0)
|
||||
{
|
||||
sol->F[j] += hyd->X_tmp[n1];
|
||||
sm->F[j] += hyd->Xflow[n1];
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -1059,15 +1068,15 @@ void psvcoeff(EN_Project *pr, int k, int n1, int n2)
|
||||
// compute matrix coeffs. using the valvecoeff() function.
|
||||
|
||||
valvecoeff(pr, k);
|
||||
sol->Aij[sol->Ndx[k]] -= sol->P[k];
|
||||
sol->Aii[i] += sol->P[k];
|
||||
sol->Aii[j] += sol->P[k];
|
||||
sol->F[i] += (sol->Y[k] - hyd->LinkFlows[k]);
|
||||
sol->F[j] -= (sol->Y[k] - hyd->LinkFlows[k]);
|
||||
sm->Aij[sm->Ndx[k]] -= hyd->P[k];
|
||||
sm->Aii[i] += hyd->P[k];
|
||||
sm->Aii[j] += hyd->P[k];
|
||||
sm->F[i] += (hyd->Y[k] - hyd->LinkFlow[k]);
|
||||
sm->F[j] -= (hyd->Y[k] - hyd->LinkFlow[k]);
|
||||
}
|
||||
|
||||
|
||||
void fcvcoeff(EN_Project *pr, int k, int n1, int n2)
|
||||
void fcvcoeff(Project *pr, int k, int n1, int n2)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: k = link index
|
||||
@@ -1079,14 +1088,15 @@ void fcvcoeff(EN_Project *pr, int k, int n1, int n2)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Smatrix *sm = &hyd->smatrix;
|
||||
|
||||
int i, j; // Rows in solution matrix
|
||||
double q; // Valve flow setting
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
solver_t *sol = &hyd->solver;
|
||||
|
||||
q = hyd->LinkSetting[k];
|
||||
i = hyd->solver.Row[n1];
|
||||
j = hyd->solver.Row[n2];
|
||||
i = sm->Row[n1];
|
||||
j = sm->Row[n2];
|
||||
|
||||
// If valve active, break network at valve and treat
|
||||
// flow setting as external demand at upstream node
|
||||
@@ -1094,15 +1104,15 @@ void fcvcoeff(EN_Project *pr, int k, int n1, int n2)
|
||||
|
||||
if (hyd->LinkStatus[k] == ACTIVE)
|
||||
{
|
||||
hyd->X_tmp[n1] -= q;
|
||||
sol->F[i] -= q;
|
||||
hyd->X_tmp[n2] += q;
|
||||
sol->F[j] += q;
|
||||
sol->P[k] = 1.0 / CBIG;
|
||||
sol->Aij[sol->Ndx[k]] -= sol->P[k];
|
||||
sol->Aii[i] += sol->P[k];
|
||||
sol->Aii[j] += sol->P[k];
|
||||
sol->Y[k] = hyd->LinkFlows[k] - q;
|
||||
hyd->Xflow[n1] -= q;
|
||||
hyd->Xflow[n2] += q;
|
||||
hyd->Y[k] = hyd->LinkFlow[k] - q;
|
||||
sm->F[i] -= q;
|
||||
sm->F[j] += q;
|
||||
hyd->P[k] = 1.0 / CBIG;
|
||||
sm->Aij[sm->Ndx[k]] -= hyd->P[k];
|
||||
sm->Aii[i] += hyd->P[k];
|
||||
sm->Aii[j] += hyd->P[k];
|
||||
}
|
||||
|
||||
// Otherwise treat valve as an open pipe
|
||||
@@ -1110,16 +1120,16 @@ void fcvcoeff(EN_Project *pr, int k, int n1, int n2)
|
||||
else
|
||||
{
|
||||
valvecoeff(pr, k);
|
||||
sol->Aij[sol->Ndx[k]] -= sol->P[k];
|
||||
sol->Aii[i] += sol->P[k];
|
||||
sol->Aii[j] += sol->P[k];
|
||||
sol->F[i] += (sol->Y[k] - hyd->LinkFlows[k]);
|
||||
sol->F[j] -= (sol->Y[k] - hyd->LinkFlows[k]);
|
||||
sm->Aij[sm->Ndx[k]] -= hyd->P[k];
|
||||
sm->Aii[i] += hyd->P[k];
|
||||
sm->Aii[j] += hyd->P[k];
|
||||
sm->F[i] += (hyd->Y[k] - hyd->LinkFlow[k]);
|
||||
sm->F[j] -= (hyd->Y[k] - hyd->LinkFlow[k]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void valvecoeff(EN_Project *pr, int k)
|
||||
void valvecoeff(Project *pr, int k)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: k = link index
|
||||
@@ -1129,20 +1139,18 @@ void valvecoeff(EN_Project *pr, int k)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Slink *link = &pr->network.Link[k];
|
||||
|
||||
double flow, q, y, qa, hgrad;
|
||||
|
||||
EN_Network *net = &pr->network;
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
solver_t *sol = &hyd->solver;
|
||||
Slink *link = &net->Link[k];
|
||||
|
||||
flow = hyd->LinkFlows[k];
|
||||
flow = hyd->LinkFlow[k];
|
||||
|
||||
// Valve is closed. Use a very small matrix coeff.
|
||||
if (hyd->LinkStatus[k] <= CLOSED)
|
||||
{
|
||||
sol->P[k] = 1.0 / CBIG;
|
||||
sol->Y[k] = flow;
|
||||
hyd->P[k] = 1.0 / CBIG;
|
||||
hyd->Y[k] = flow;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1164,15 +1172,15 @@ void valvecoeff(EN_Project *pr, int k)
|
||||
}
|
||||
|
||||
// P and Y coeffs.
|
||||
sol->P[k] = 1.0 / hgrad;
|
||||
sol->Y[k] = y;
|
||||
hyd->P[k] = 1.0 / hgrad;
|
||||
hyd->Y[k] = y;
|
||||
}
|
||||
|
||||
// If no minor loss coeff. specified use a
|
||||
// low resistance linear head loss relation
|
||||
else
|
||||
{
|
||||
sol->P[k] = 1.0 / CSMALL;
|
||||
sol->Y[k] = flow;
|
||||
hyd->P[k] = 1.0 / CSMALL;
|
||||
hyd->Y[k] = flow;
|
||||
}
|
||||
}
|
||||
|
||||
1066
src/hydraul.c
1066
src/hydraul.c
File diff suppressed because it is too large
Load Diff
225
src/hydsolver.c
225
src/hydsolver.c
@@ -1,13 +1,15 @@
|
||||
/*
|
||||
*********************************************************************
|
||||
|
||||
HYDSOLVER.C -- Equilibrium hydraulic solver for the EPANET Program
|
||||
|
||||
This module contains a pipe network hydraulic solver that computes
|
||||
flows and pressures within the network at a specific point in time.
|
||||
|
||||
The solver implements Todini's Global Gradient Algorithm.
|
||||
*******************************************************************
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Module: hydsolver.c
|
||||
Description: computes flows and pressures throughout a pipe network using
|
||||
Todini's Global Gradient Algorithm
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 11/27/2018
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -33,32 +35,29 @@ typedef struct {
|
||||
int maxflowlink;
|
||||
} Hydbalance;
|
||||
|
||||
// External functions
|
||||
//int hydsolve(EN_Project *pr, int *iter, double *relerr);
|
||||
//void headlosscoeffs(EN_Project *pr);
|
||||
//void matrixcoeffs(EN_Project *pr);
|
||||
// Exported functions
|
||||
int hydsolve(Project *, int *, double *);
|
||||
|
||||
extern int valvestatus(EN_Project *pr); //(see HYDSTATUS.C)
|
||||
extern int linkstatus(EN_Project *pr); //(see HYDSTATUS.C)
|
||||
// Imported functions
|
||||
extern int linsolve(Smatrix *, int); //(see SMATRIX.C)
|
||||
extern int valvestatus(Project *); //(see HYDSTATUS.C)
|
||||
extern int linkstatus(Project *); //(see HYDSTATUS.C)
|
||||
|
||||
// Local functions
|
||||
static int badvalve(EN_Project *pr, int);
|
||||
static int pswitch(EN_Project *pr);
|
||||
static int badvalve(Project *, int);
|
||||
static int pswitch(Project *);
|
||||
|
||||
static double newflows(EN_Project *pr, Hydbalance *hbal);
|
||||
static void newlinkflows(EN_Project *pr, Hydbalance *hbal, double *qsum,
|
||||
double *dqsum);
|
||||
static void newemitterflows(EN_Project *pr, Hydbalance *hbal, double *qsum,
|
||||
double *dqsum);
|
||||
static void newdemandflows(EN_Project *pr, Hydbalance *hbal, double *qsum,
|
||||
double *dqsum);
|
||||
static double newflows(Project *, Hydbalance *);
|
||||
static void newlinkflows(Project *, Hydbalance *, double *, double *);
|
||||
static void newemitterflows(Project *, Hydbalance *, double *, double *);
|
||||
static void newdemandflows(Project *, Hydbalance *, double *, double *);
|
||||
|
||||
static void checkhydbalance(EN_Project *pr, Hydbalance *hbal);
|
||||
static int hasconverged(EN_Project *pr, double *relerr, Hydbalance *hbal);
|
||||
static void reporthydbal(EN_Project *pr, Hydbalance *hbal);
|
||||
static void checkhydbalance(Project *, Hydbalance *);
|
||||
static int hasconverged(Project *, double *, Hydbalance *);
|
||||
static void reporthydbal(Project *, Hydbalance *);
|
||||
|
||||
|
||||
int hydsolve(EN_Project *pr, int *iter, double *relerr)
|
||||
int hydsolve(Project *pr, int *iter, double *relerr)
|
||||
/*
|
||||
**-------------------------------------------------------------------
|
||||
** Input: none
|
||||
@@ -68,11 +67,8 @@ int hydsolve(EN_Project *pr, int *iter, double *relerr)
|
||||
** Purpose: solves network nodal equations for heads and flows
|
||||
** using Todini's Gradient algorithm
|
||||
**
|
||||
*** Updated 9/7/00 ***
|
||||
*** Updated 2.00.11 ***
|
||||
*** Updated 2.00.12 ***
|
||||
** Notes: Status checks on CVs, pumps and pipes to tanks are made
|
||||
** every hyd->CheckFreq iteration, up until MaxCheck iterations
|
||||
** every CheckFreq iteration, up until MaxCheck iterations
|
||||
** are reached. Status checks on control valves are made
|
||||
** every iteration if DampLimit = 0 or only when the
|
||||
** convergence error is at or below DampLimit. If DampLimit
|
||||
@@ -87,6 +83,11 @@ int hydsolve(EN_Project *pr, int *iter, double *relerr)
|
||||
**-------------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Smatrix *sm = &hyd->smatrix;
|
||||
Report *rpt = &pr->report;
|
||||
|
||||
int i; // Node index
|
||||
int errcode = 0; // Node causing solution error
|
||||
int nextcheck; // Next status check trial
|
||||
@@ -96,47 +97,32 @@ int hydsolve(EN_Project *pr, int *iter, double *relerr)
|
||||
int statChange; // Non-valve status change flag
|
||||
Hydbalance hydbal; // Hydraulic balance errors
|
||||
|
||||
EN_Network *net = &pr->network;
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
solver_t *sol = &hyd->solver;
|
||||
report_options_t *rep = &pr->report;
|
||||
|
||||
// Initialize status checking & relaxation factor
|
||||
nextcheck = hyd->CheckFreq;
|
||||
hyd->RelaxFactor = 1.0;
|
||||
|
||||
// Repeat iterations until convergence or trial limit is exceeded.
|
||||
// (ExtraIter used to increase trials in case of status cycling.)
|
||||
if (pr->report.Statflag == FULL)
|
||||
{
|
||||
writerelerr(pr, 0, 0);
|
||||
}
|
||||
if (rpt->Statflag == FULL) writerelerr(pr, 0, 0);
|
||||
maxtrials = hyd->MaxIter;
|
||||
if (hyd->ExtraIter > 0)
|
||||
{
|
||||
maxtrials += hyd->ExtraIter;
|
||||
}
|
||||
if (hyd->ExtraIter > 0) maxtrials += hyd->ExtraIter;
|
||||
*iter = 1;
|
||||
while (*iter <= maxtrials)
|
||||
{
|
||||
/*
|
||||
** Compute coefficient matrices A & F and solve A*H = F
|
||||
** where H = heads, A = Jacobian coeffs. derived from
|
||||
** head loss gradients, & F = flow correction terms.
|
||||
** Solution for H is returned in F from call to linsolve().
|
||||
*/
|
||||
// Compute coefficient matrices A & F and solve A*H = F
|
||||
// where H = heads, A = Jacobian coeffs. derived from
|
||||
// head loss gradients, & F = flow correction terms.
|
||||
// Solution for H is returned in F from call to linsolve().
|
||||
|
||||
headlosscoeffs(pr);
|
||||
matrixcoeffs(pr);
|
||||
errcode = linsolve(pr, net->Njuncs);
|
||||
|
||||
// Quit if memory allocation error
|
||||
if (errcode < 0) break;
|
||||
errcode = linsolve(sm, net->Njuncs);
|
||||
|
||||
// Matrix ill-conditioning problem - if control valve causing problem,
|
||||
// fix its status & continue, otherwise quit with no solution.
|
||||
if (errcode > 0)
|
||||
{
|
||||
if (badvalve(pr, sol->Order[errcode])) continue;
|
||||
if (badvalve(pr, sm->Order[errcode])) continue;
|
||||
else break;
|
||||
}
|
||||
|
||||
@@ -144,13 +130,13 @@ int hydsolve(EN_Project *pr, int *iter, double *relerr)
|
||||
// (Row[i] = row of solution matrix corresponding to node i)
|
||||
for (i = 1; i <= net->Njuncs; i++)
|
||||
{
|
||||
hyd->NodeHead[i] = sol->F[sol->Row[i]]; // Update heads
|
||||
hyd->NodeHead[i] = sm->F[sm->Row[i]]; // Update heads
|
||||
}
|
||||
newerr = newflows(pr, &hydbal); // Update flows
|
||||
*relerr = newerr;
|
||||
|
||||
// Write convergence error to status report if called for
|
||||
if (rep->Statflag == FULL)
|
||||
if (rpt->Statflag == FULL)
|
||||
{
|
||||
writerelerr(pr, *iter, *relerr);
|
||||
}
|
||||
@@ -199,17 +185,16 @@ int hydsolve(EN_Project *pr, int *iter, double *relerr)
|
||||
}
|
||||
|
||||
// Iterations ended - report any errors.
|
||||
if (errcode < 0) errcode = 101; // Memory allocation error
|
||||
else if (errcode > 0)
|
||||
if (errcode > 0)
|
||||
{
|
||||
writehyderr(pr, sol->Order[errcode]); // Ill-conditioned matrix error
|
||||
writehyderr(pr, sm->Order[errcode]); // Ill-conditioned matrix error
|
||||
errcode = 110;
|
||||
}
|
||||
|
||||
// Replace junction demands with total outflow values
|
||||
for (i = 1; i <= net->Njuncs; i++)
|
||||
{
|
||||
hyd->NodeDemand[i] = hyd->DemandFlows[i] + hyd->EmitterFlows[i];
|
||||
hyd->NodeDemand[i] = hyd->DemandFlow[i] + hyd->EmitterFlow[i];
|
||||
}
|
||||
|
||||
// Save convergence info
|
||||
@@ -218,11 +203,11 @@ int hydsolve(EN_Project *pr, int *iter, double *relerr)
|
||||
hyd->MaxFlowChange = hydbal.maxflowchange;
|
||||
hyd->Iterations = *iter;
|
||||
|
||||
return(errcode);
|
||||
return errcode;
|
||||
}
|
||||
|
||||
|
||||
int badvalve(EN_Project *pr, int n)
|
||||
int badvalve(Project *pr, int n)
|
||||
/*
|
||||
**-----------------------------------------------------------------
|
||||
** Input: n = node index
|
||||
@@ -235,12 +220,12 @@ int badvalve(EN_Project *pr, int n)
|
||||
**-----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i, k, n1, n2;
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Report *rpt = &pr->report;
|
||||
Times *time = &pr->times;
|
||||
|
||||
EN_Network *net = &pr->network;
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
report_options_t *rep = &pr->report;
|
||||
time_options_t *time = &pr->time_options;
|
||||
int i, k, n1, n2;
|
||||
Slink *link;
|
||||
LinkType t;
|
||||
|
||||
@@ -257,19 +242,14 @@ int badvalve(EN_Project *pr, int n)
|
||||
{
|
||||
if (hyd->LinkStatus[k] == ACTIVE)
|
||||
{
|
||||
if (rep->Statflag == FULL)
|
||||
if (rpt->Statflag == FULL)
|
||||
{
|
||||
sprintf(pr->Msg, FMT61, clocktime(rep->Atime, time->Htime), link->ID);
|
||||
sprintf(pr->Msg, FMT61,
|
||||
clocktime(rpt->Atime, time->Htime), link->ID);
|
||||
writeline(pr, pr->Msg);
|
||||
}
|
||||
if (link->Type == FCV)
|
||||
{
|
||||
hyd->LinkStatus[k] = XFCV;
|
||||
}
|
||||
else
|
||||
{
|
||||
hyd->LinkStatus[k] = XPRESSURE;
|
||||
}
|
||||
if (link->Type == FCV) hyd->LinkStatus[k] = XFCV;
|
||||
else hyd->LinkStatus[k] = XPRESSURE;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -280,7 +260,7 @@ int badvalve(EN_Project *pr, int n)
|
||||
}
|
||||
|
||||
|
||||
int pswitch(EN_Project *pr)
|
||||
int pswitch(Project *pr)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
@@ -290,6 +270,10 @@ int pswitch(EN_Project *pr)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Report *rpt = &pr->report;
|
||||
|
||||
int i, // Control statement index
|
||||
k, // Index of link being controlled
|
||||
n, // Node controlling link k
|
||||
@@ -297,10 +281,6 @@ int pswitch(EN_Project *pr)
|
||||
change, // Flag for status or setting change
|
||||
anychange = 0; // Flag for 1 or more control actions
|
||||
char s; // Current link status
|
||||
|
||||
EN_Network *net = &pr->network;
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
report_options_t *rep = &pr->report;
|
||||
Slink *link;
|
||||
|
||||
// Check each control statement
|
||||
@@ -358,7 +338,7 @@ int pswitch(EN_Project *pr)
|
||||
{
|
||||
hyd->LinkSetting[k] = net->Control[i].Setting;
|
||||
}
|
||||
if (rep->Statflag == FULL)
|
||||
if (rpt->Statflag == FULL)
|
||||
{
|
||||
writestatchange(pr, k, s, hyd->LinkStatus[k]);
|
||||
}
|
||||
@@ -366,11 +346,11 @@ int pswitch(EN_Project *pr)
|
||||
}
|
||||
}
|
||||
}
|
||||
return(anychange);
|
||||
return anychange;
|
||||
}
|
||||
|
||||
|
||||
double newflows(EN_Project *pr, Hydbalance *hbal)
|
||||
double newflows(Project *pr, Hydbalance *hbal)
|
||||
/*
|
||||
**----------------------------------------------------------------
|
||||
** Input: hbal = ptr. to hydraulic balance information
|
||||
@@ -380,12 +360,12 @@ double newflows(EN_Project *pr, Hydbalance *hbal)
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
double dqsum, // Network flow change
|
||||
qsum; // Network total flow
|
||||
|
||||
EN_Network *net = &pr->network;
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
|
||||
// Initialize sum of flows & corrections
|
||||
qsum = 0.0;
|
||||
dqsum = 0.0;
|
||||
@@ -404,7 +384,7 @@ double newflows(EN_Project *pr, Hydbalance *hbal)
|
||||
}
|
||||
|
||||
|
||||
void newlinkflows(EN_Project *pr, Hydbalance *hbal, double *qsum, double *dqsum)
|
||||
void newlinkflows(Project *pr, Hydbalance *hbal, double *qsum, double *dqsum)
|
||||
/*
|
||||
**----------------------------------------------------------------
|
||||
** Input: hbal = ptr. to hydraulic balance information
|
||||
@@ -415,13 +395,12 @@ void newlinkflows(EN_Project *pr, Hydbalance *hbal, double *qsum, double *dqsum
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
double dh, /* Link head loss */
|
||||
dq; /* Link flow change */
|
||||
int k, n, n1, n2;
|
||||
|
||||
EN_Network *net = &pr->network;
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
solver_t *sol = &hyd->solver;
|
||||
Slink *link;
|
||||
|
||||
// Initialize net inflows (i.e., demands) at fixed grade nodes
|
||||
@@ -445,7 +424,7 @@ void newlinkflows(EN_Project *pr, Hydbalance *hbal, double *qsum, double *dqsum
|
||||
// where P & Y were computed in hlosscoeff() in hydcoeffs.c
|
||||
|
||||
dh = hyd->NodeHead[n1] - hyd->NodeHead[n2];
|
||||
dq = sol->Y[k] - sol->P[k] * dh;
|
||||
dq = hyd->Y[k] - hyd->P[k] * dh;
|
||||
|
||||
// Adjust flow change by the relaxation factor
|
||||
dq *= hyd->RelaxFactor;
|
||||
@@ -454,15 +433,15 @@ void newlinkflows(EN_Project *pr, Hydbalance *hbal, double *qsum, double *dqsum
|
||||
if (link->Type == PUMP)
|
||||
{
|
||||
n = findpump(net, k);
|
||||
if (net->Pump[n].Ptype == CONST_HP && dq > hyd->LinkFlows[k])
|
||||
if (net->Pump[n].Ptype == CONST_HP && dq > hyd->LinkFlow[k])
|
||||
{
|
||||
dq = hyd->LinkFlows[k] / 2.0;
|
||||
dq = hyd->LinkFlow[k] / 2.0;
|
||||
}
|
||||
}
|
||||
|
||||
// Update link flow and system flow summation
|
||||
hyd->LinkFlows[k] -= dq;
|
||||
*qsum += ABS(hyd->LinkFlows[k]);
|
||||
hyd->LinkFlow[k] -= dq;
|
||||
*qsum += ABS(hyd->LinkFlow[k]);
|
||||
*dqsum += ABS(dq);
|
||||
|
||||
// Update identity of element with max. flow change
|
||||
@@ -476,14 +455,14 @@ void newlinkflows(EN_Project *pr, Hydbalance *hbal, double *qsum, double *dqsum
|
||||
// Update net flows to fixed grade nodes
|
||||
if (hyd->LinkStatus[k] > CLOSED)
|
||||
{
|
||||
if (n1 > net->Njuncs) hyd->NodeDemand[n1] -= hyd->LinkFlows[k];
|
||||
if (n2 > net->Njuncs) hyd->NodeDemand[n2] += hyd->LinkFlows[k];
|
||||
if (n1 > net->Njuncs) hyd->NodeDemand[n1] -= hyd->LinkFlow[k];
|
||||
if (n2 > net->Njuncs) hyd->NodeDemand[n2] += hyd->LinkFlow[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void newemitterflows(EN_Project *pr, Hydbalance *hbal, double *qsum,
|
||||
void newemitterflows(Project *pr, Hydbalance *hbal, double *qsum,
|
||||
double *dqsum)
|
||||
/*
|
||||
**----------------------------------------------------------------
|
||||
@@ -495,10 +474,11 @@ void newemitterflows(EN_Project *pr, Hydbalance *hbal, double *qsum,
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
int i;
|
||||
double hloss, hgrad, dh, dq;
|
||||
EN_Network *net = &pr->network;
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
|
||||
// Examine each network junction
|
||||
for (i = 1; i <= net->Njuncs; i++)
|
||||
@@ -512,10 +492,10 @@ void newemitterflows(EN_Project *pr, Hydbalance *hbal, double *qsum,
|
||||
// Find emitter flow change
|
||||
dh = hyd->NodeHead[i] - net->Node[i].El;
|
||||
dq = (hloss - dh) / hgrad;
|
||||
hyd->EmitterFlows[i] -= dq;
|
||||
hyd->EmitterFlow[i] -= dq;
|
||||
|
||||
// Update system flow summation
|
||||
*qsum += ABS(hyd->EmitterFlows[i]);
|
||||
*qsum += ABS(hyd->EmitterFlow[i]);
|
||||
*dqsum += ABS(dq);
|
||||
|
||||
// Update identity of element with max. flow change
|
||||
@@ -529,7 +509,7 @@ void newemitterflows(EN_Project *pr, Hydbalance *hbal, double *qsum,
|
||||
}
|
||||
|
||||
|
||||
void newdemandflows(EN_Project *pr, Hydbalance *hbal, double *qsum, double *dqsum)
|
||||
void newdemandflows(Project *pr, Hydbalance *hbal, double *qsum, double *dqsum)
|
||||
/*
|
||||
**----------------------------------------------------------------
|
||||
** Input: hbal = ptr. to hydraulic balance information
|
||||
@@ -541,12 +521,13 @@ void newdemandflows(EN_Project *pr, Hydbalance *hbal, double *qsum, double *dqsu
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
double dp, // pressure range over which demand can vary (ft)
|
||||
dq, // change in demand flow (cfs)
|
||||
n; // exponent in head loss v. demand function
|
||||
int k;
|
||||
EN_Network *net = &pr->network;
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
|
||||
// Get demand function parameters
|
||||
if (hyd->DemandModel == DDA) return;
|
||||
@@ -560,10 +541,10 @@ void newdemandflows(EN_Project *pr, Hydbalance *hbal, double *qsum, double *dqsu
|
||||
|
||||
// Find change in demand flow (see hydcoeffs.c)
|
||||
dq = demandflowchange(pr, k, dp, n);
|
||||
hyd->DemandFlows[k] -= dq;
|
||||
hyd->DemandFlow[k] -= dq;
|
||||
|
||||
// Update system flow summation
|
||||
*qsum += ABS(hyd->DemandFlows[k]);
|
||||
*qsum += ABS(hyd->DemandFlow[k]);
|
||||
*dqsum += ABS(dq);
|
||||
|
||||
// Update identity of element with max. flow change
|
||||
@@ -577,7 +558,7 @@ void newdemandflows(EN_Project *pr, Hydbalance *hbal, double *qsum, double *dqsu
|
||||
}
|
||||
|
||||
|
||||
void checkhydbalance(EN_Project *pr, Hydbalance *hbal)
|
||||
void checkhydbalance(Project *pr, Hydbalance *hbal)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: hbal = hydraulic balance errors
|
||||
@@ -586,25 +567,25 @@ void checkhydbalance(EN_Project *pr, Hydbalance *hbal)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
int k, n1, n2;
|
||||
double dh, headerror, headloss;
|
||||
|
||||
EN_Network *net = &pr->network;
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
solver_t *sol = &hyd->solver;
|
||||
Slink *link;
|
||||
|
||||
hbal->maxheaderror = 0.0;
|
||||
hbal->maxheadlink = 1;
|
||||
headlosscoeffs(pr);
|
||||
for (k = 1; k <= net->Nlinks; k++)
|
||||
{
|
||||
if (hyd->LinkStatus[k] <= CLOSED) continue;
|
||||
if (sol->P[k] == 0.0) continue;
|
||||
if (hyd->P[k] == 0.0) continue;
|
||||
link = &net->Link[k];
|
||||
n1 = link->N1;
|
||||
n2 = link->N2;
|
||||
dh = hyd->NodeHead[n1] - hyd->NodeHead[n2];
|
||||
headloss = sol->Y[k] / sol->P[k];
|
||||
headloss = hyd->Y[k] / hyd->P[k];
|
||||
headerror = ABS(dh - headloss);
|
||||
if (headerror > hbal->maxheaderror)
|
||||
{
|
||||
@@ -615,7 +596,7 @@ void checkhydbalance(EN_Project *pr, Hydbalance *hbal)
|
||||
}
|
||||
|
||||
|
||||
int hasconverged(EN_Project *pr, double *relerr, Hydbalance *hbal)
|
||||
int hasconverged(Project *pr, double *relerr, Hydbalance *hbal)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: relerr = current total relative flow change
|
||||
@@ -626,7 +607,7 @@ int hasconverged(EN_Project *pr, double *relerr, Hydbalance *hbal)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
if (*relerr > hyd->Hacc) return 0;
|
||||
checkhydbalance(pr, hbal);
|
||||
@@ -642,7 +623,7 @@ int hasconverged(EN_Project *pr, double *relerr, Hydbalance *hbal)
|
||||
}
|
||||
|
||||
|
||||
void reporthydbal(EN_Project *pr, Hydbalance *hbal)
|
||||
void reporthydbal(Project *pr, Hydbalance *hbal)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: hbal = current hydraulic balance errors
|
||||
|
||||
142
src/hydstatus.c
142
src/hydstatus.c
@@ -1,29 +1,34 @@
|
||||
/*
|
||||
*********************************************************************
|
||||
|
||||
HYDSTATUS.C -- Hydraulic status updating for the EPANET Program
|
||||
|
||||
*******************************************************************
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Module: hydstatus.c
|
||||
Description: updates hydraulic status of network elements
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 11/27/2018
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "types.h"
|
||||
#include "funcs.h"
|
||||
|
||||
// External functions
|
||||
int valvestatus(EN_Project *pr);
|
||||
int linkstatus(EN_Project *pr);
|
||||
// Exported functions
|
||||
int valvestatus(Project *);
|
||||
int linkstatus(Project *);
|
||||
|
||||
// Local functions
|
||||
static StatType cvstatus(EN_Project *pr, StatType, double, double);
|
||||
static StatType pumpstatus(EN_Project *pr, int, double);
|
||||
static StatType prvstatus(EN_Project *pr, int, StatType, double, double, double);
|
||||
static StatType psvstatus(EN_Project *pr, int, StatType, double, double, double);
|
||||
static StatType fcvstatus(EN_Project *pr, int, StatType, double, double);
|
||||
static void tankstatus(EN_Project *pr, int, int, int);
|
||||
static StatusType cvstatus(Project *, StatusType, double, double);
|
||||
static StatusType pumpstatus(Project *, int, double);
|
||||
static StatusType prvstatus(Project *, int, StatusType, double, double, double);
|
||||
static StatusType psvstatus(Project *, int, StatusType, double, double, double);
|
||||
static StatusType fcvstatus(Project *, int, StatusType, double, double);
|
||||
static void tankstatus(Project *, int, int, int);
|
||||
|
||||
|
||||
int valvestatus(EN_Project *pr)
|
||||
int valvestatus(Project *pr)
|
||||
/*
|
||||
**-----------------------------------------------------------------
|
||||
** Input: none
|
||||
@@ -34,17 +39,17 @@ int valvestatus(EN_Project *pr)
|
||||
**-----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Report *rpt = &pr->report;
|
||||
|
||||
int change = FALSE, // Status change flag
|
||||
i, k, // Valve & link indexes
|
||||
n1, n2; // Start & end nodes
|
||||
StatType status; // Valve status settings
|
||||
double hset; // Valve head setting
|
||||
StatusType status; // Valve status settings
|
||||
Slink *link;
|
||||
|
||||
EN_Network *net = &pr->network;
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
report_options_t *rep = &pr->report;
|
||||
|
||||
// Examine each valve
|
||||
for (i = 1; i <= net->Nvalves; i++)
|
||||
{
|
||||
@@ -80,7 +85,7 @@ int valvestatus(EN_Project *pr)
|
||||
// Check for a status change
|
||||
if (status != hyd->LinkStatus[k])
|
||||
{
|
||||
if (rep->Statflag == FULL)
|
||||
if (rpt->Statflag == FULL)
|
||||
{
|
||||
writestatchange(pr, k, status, hyd->LinkStatus[k]);
|
||||
}
|
||||
@@ -88,10 +93,10 @@ int valvestatus(EN_Project *pr)
|
||||
}
|
||||
}
|
||||
return change;
|
||||
} /* End of valvestatus() */
|
||||
}
|
||||
|
||||
|
||||
int linkstatus(EN_Project *pr)
|
||||
int linkstatus(Project *pr)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
@@ -101,16 +106,16 @@ int linkstatus(EN_Project *pr)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Report *rpt = &pr->report;
|
||||
|
||||
int change = FALSE, // Status change flag
|
||||
k, // Link index
|
||||
n1, // Start node index
|
||||
n2; // End node index
|
||||
double dh; // Head difference across link
|
||||
StatType status; // Current status
|
||||
|
||||
EN_Network *net = &pr->network;
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
report_options_t *rep = &pr->report;
|
||||
StatusType status; // Current status
|
||||
Slink *link;
|
||||
|
||||
// Examine each link
|
||||
@@ -132,7 +137,7 @@ int linkstatus(EN_Project *pr)
|
||||
if (link->Type == CVPIPE)
|
||||
{
|
||||
hyd->LinkStatus[k] = cvstatus(pr, hyd->LinkStatus[k], dh,
|
||||
hyd->LinkFlows[k]);
|
||||
hyd->LinkFlow[k]);
|
||||
}
|
||||
if (link->Type == PUMP && hyd->LinkStatus[k] >= OPEN &&
|
||||
hyd->LinkSetting[k] > 0.0)
|
||||
@@ -157,7 +162,7 @@ int linkstatus(EN_Project *pr)
|
||||
if (status != hyd->LinkStatus[k])
|
||||
{
|
||||
change = TRUE;
|
||||
if (rep->Statflag == FULL)
|
||||
if (rpt->Statflag == FULL)
|
||||
{
|
||||
writestatchange(pr, k, status, hyd->LinkStatus[k]);
|
||||
}
|
||||
@@ -167,7 +172,7 @@ int linkstatus(EN_Project *pr)
|
||||
}
|
||||
|
||||
|
||||
StatType cvstatus(EN_Project *pr, StatType s, double dh, double q)
|
||||
StatusType cvstatus(Project *pr, StatusType s, double dh, double q)
|
||||
/*
|
||||
**--------------------------------------------------
|
||||
** Input: s = current link status
|
||||
@@ -178,7 +183,7 @@ StatType cvstatus(EN_Project *pr, StatType s, double dh, double q)
|
||||
**--------------------------------------------------
|
||||
*/
|
||||
{
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
// Prevent reverse flow through CVs
|
||||
if (ABS(dh) > hyd->Htol)
|
||||
@@ -195,7 +200,7 @@ StatType cvstatus(EN_Project *pr, StatType s, double dh, double q)
|
||||
}
|
||||
|
||||
|
||||
StatType pumpstatus(EN_Project *pr, int k, double dh)
|
||||
StatusType pumpstatus(Project *pr, int k, double dh)
|
||||
/*
|
||||
**--------------------------------------------------
|
||||
** Input: k = link index
|
||||
@@ -205,10 +210,11 @@ StatType pumpstatus(EN_Project *pr, int k, double dh)
|
||||
**--------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Network *net = &pr->network;
|
||||
|
||||
int p;
|
||||
double hmax;
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
EN_Network *net = &pr->network;
|
||||
|
||||
// Find maximum head (hmax) pump can deliver
|
||||
p = findpump(net, k);
|
||||
@@ -231,7 +237,7 @@ StatType pumpstatus(EN_Project *pr, int k, double dh)
|
||||
}
|
||||
|
||||
|
||||
StatType prvstatus(EN_Project *pr, int k, StatType s, double hset,
|
||||
StatusType prvstatus(Project *pr, int k, StatusType s, double hset,
|
||||
double h1, double h2)
|
||||
/*
|
||||
**-----------------------------------------------------------
|
||||
@@ -245,28 +251,31 @@ StatType prvstatus(EN_Project *pr, int k, StatType s, double hset,
|
||||
**-----------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
StatType status; // Valve's new status
|
||||
double hml; // Head loss when fully opened
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
double htol = hyd->Htol;
|
||||
Slink *link = &pr->network.Link[k];
|
||||
StatusType status; // Valve's new status
|
||||
double hml; // Head loss when fully opened
|
||||
double htol;
|
||||
Slink *link;
|
||||
|
||||
htol = hyd->Htol;
|
||||
link = &pr->network.Link[k];
|
||||
|
||||
// Head loss when fully open
|
||||
hml = link->Km * SQR(hyd->LinkFlows[k]);
|
||||
hml = link->Km * SQR(hyd->LinkFlow[k]);
|
||||
|
||||
// Rules for updating valve's status from current value s
|
||||
status = s;
|
||||
switch (s)
|
||||
{
|
||||
case ACTIVE:
|
||||
if (hyd->LinkFlows[k] < -hyd->Qtol) status = CLOSED;
|
||||
if (hyd->LinkFlow[k] < -hyd->Qtol) status = CLOSED;
|
||||
else if (h1 - hml < hset - htol) status = OPEN;
|
||||
else status = ACTIVE;
|
||||
break;
|
||||
|
||||
case OPEN:
|
||||
if (hyd->LinkFlows[k] < -hyd->Qtol) status = CLOSED;
|
||||
if (hyd->LinkFlow[k] < -hyd->Qtol) status = CLOSED;
|
||||
else if (h2 >= hset + htol) status = ACTIVE;
|
||||
else status = OPEN;
|
||||
break;
|
||||
@@ -278,7 +287,7 @@ StatType prvstatus(EN_Project *pr, int k, StatType s, double hset,
|
||||
break;
|
||||
|
||||
case XPRESSURE:
|
||||
if (hyd->LinkFlows[k] < -hyd->Qtol) status = CLOSED;
|
||||
if (hyd->LinkFlow[k] < -hyd->Qtol) status = CLOSED;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -288,7 +297,7 @@ StatType prvstatus(EN_Project *pr, int k, StatType s, double hset,
|
||||
}
|
||||
|
||||
|
||||
StatType psvstatus(EN_Project *pr, int k, StatType s, double hset,
|
||||
StatusType psvstatus(Project *pr, int k, StatusType s, double hset,
|
||||
double h1, double h2)
|
||||
/*
|
||||
**-----------------------------------------------------------
|
||||
@@ -302,28 +311,31 @@ StatType psvstatus(EN_Project *pr, int k, StatType s, double hset,
|
||||
**-----------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
StatType status; // Valve's new status
|
||||
double hml; // Head loss when fully opened
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
double htol = hyd->Htol;
|
||||
Slink *link = &pr->network.Link[k];
|
||||
StatusType status; // Valve's new status
|
||||
double hml; // Head loss when fully opened
|
||||
double htol;
|
||||
Slink *link;
|
||||
|
||||
htol = hyd->Htol;
|
||||
link = &pr->network.Link[k];
|
||||
|
||||
// Head loss when fully open
|
||||
hml = link->Km * SQR(hyd->LinkFlows[k]);
|
||||
hml = link->Km * SQR(hyd->LinkFlow[k]);
|
||||
|
||||
// Rules for updating valve's status from current value s
|
||||
status = s;
|
||||
switch (s)
|
||||
{
|
||||
case ACTIVE:
|
||||
if (hyd->LinkFlows[k] < -hyd->Qtol) status = CLOSED;
|
||||
if (hyd->LinkFlow[k] < -hyd->Qtol) status = CLOSED;
|
||||
else if (h2 + hml > hset + htol) status = OPEN;
|
||||
else status = ACTIVE;
|
||||
break;
|
||||
|
||||
case OPEN:
|
||||
if (hyd->LinkFlows[k] < -hyd->Qtol) status = CLOSED;
|
||||
if (hyd->LinkFlow[k] < -hyd->Qtol) status = CLOSED;
|
||||
else if (h1 < hset - htol) status = ACTIVE;
|
||||
else status = OPEN;
|
||||
break;
|
||||
@@ -335,7 +347,7 @@ StatType psvstatus(EN_Project *pr, int k, StatType s, double hset,
|
||||
break;
|
||||
|
||||
case XPRESSURE:
|
||||
if (hyd->LinkFlows[k] < -hyd->Qtol) status = CLOSED;
|
||||
if (hyd->LinkFlow[k] < -hyd->Qtol) status = CLOSED;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -345,7 +357,7 @@ StatType psvstatus(EN_Project *pr, int k, StatType s, double hset,
|
||||
}
|
||||
|
||||
|
||||
StatType fcvstatus(EN_Project *pr, int k, StatType s, double h1, double h2)
|
||||
StatusType fcvstatus(Project *pr, int k, StatusType s, double h1, double h2)
|
||||
/*
|
||||
**-----------------------------------------------------------
|
||||
** Input: k = link index
|
||||
@@ -364,19 +376,19 @@ StatType fcvstatus(EN_Project *pr, int k, StatType s, double h1, double h2)
|
||||
**-----------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
StatType status; // New valve status
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
StatusType status; // New valve status
|
||||
|
||||
status = s;
|
||||
if (h1 - h2 < -hyd->Htol)
|
||||
{
|
||||
status = XFCV;
|
||||
}
|
||||
else if (hyd->LinkFlows[k] < -hyd->Qtol)
|
||||
else if (hyd->LinkFlow[k] < -hyd->Qtol)
|
||||
{
|
||||
status = XFCV;
|
||||
}
|
||||
else if (s == XFCV && hyd->LinkFlows[k] >= hyd->LinkSetting[k])
|
||||
else if (s == XFCV && hyd->LinkFlow[k] >= hyd->LinkSetting[k])
|
||||
{
|
||||
status = ACTIVE;
|
||||
}
|
||||
@@ -384,7 +396,7 @@ StatType fcvstatus(EN_Project *pr, int k, StatType s, double h1, double h2)
|
||||
}
|
||||
|
||||
|
||||
void tankstatus(EN_Project *pr, int k, int n1, int n2)
|
||||
void tankstatus(Project *pr, int k, int n1, int n2)
|
||||
/*
|
||||
**----------------------------------------------------------------
|
||||
** Input: k = link index
|
||||
@@ -395,19 +407,19 @@ void tankstatus(EN_Project *pr, int k, int n1, int n2)
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
int i, n;
|
||||
double h, q;
|
||||
Stank *tank;
|
||||
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
EN_Network *net = &pr->network;
|
||||
Slink *link = &net->Link[k];
|
||||
|
||||
// Return if link is closed
|
||||
if (hyd->LinkStatus[k] <= CLOSED) return;
|
||||
|
||||
// Make node n1 be the tank, reversing flow (q) if need be
|
||||
q = hyd->LinkFlows[k];
|
||||
q = hyd->LinkFlow[k];
|
||||
i = n1 - net->Njuncs;
|
||||
if (i <= 0)
|
||||
{
|
||||
|
||||
679
src/inpfile.c
679
src/inpfile.c
File diff suppressed because it is too large
Load Diff
859
src/input1.c
859
src/input1.c
File diff suppressed because it is too large
Load Diff
917
src/input2.c
917
src/input2.c
File diff suppressed because it is too large
Load Diff
2594
src/input3.c
2594
src/input3.c
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,17 @@
|
||||
/* mempool.c
|
||||
**
|
||||
** A simple fast pooled memory allocation package.
|
||||
**
|
||||
** Based on code by Steve Hill in Graphics Gems III,
|
||||
** David Kirk (ed.), Academic Press, Boston, MA, 1992
|
||||
**
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Module: mempool.c
|
||||
Description: a simple fast poooled memory allocation package
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 11/27/2018
|
||||
|
||||
This module is based code by Steve Hill in Graphics Gems III,
|
||||
David Kirk (ed.), Academic Press, Boston, MA, 1992
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
/*
|
||||
** mempool.h
|
||||
**
|
||||
** Header for mempool.c
|
||||
**
|
||||
** A simple pooled memory allocator
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Module: mempool.h
|
||||
Description: header for a simple pooled memory allocator
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 11/27/2018
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef MEMPOOL_H
|
||||
|
||||
835
src/output.c
835
src/output.c
File diff suppressed because it is too large
Load Diff
838
src/project.c
Normal file
838
src/project.c
Normal file
@@ -0,0 +1,838 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Module: project.c
|
||||
Description: project data management routines
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 11/27/2018
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifndef __APPLE__
|
||||
#include <malloc.h>
|
||||
#else
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
//*** Need to define WINDOWS to use the getTmpName function ***//
|
||||
// --- define WINDOWS
|
||||
#undef WINDOWS
|
||||
#ifdef _WIN32
|
||||
#define WINDOWS
|
||||
#endif
|
||||
#ifdef __WIN32__
|
||||
#define WINDOWS
|
||||
#endif
|
||||
#ifdef WINDOWS
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "types.h"
|
||||
#include "funcs.h"
|
||||
|
||||
int openfiles(Project *pr, const char *f1, const char *f2, const char *f3)
|
||||
/*----------------------------------------------------------------
|
||||
** Input: f1 = pointer to name of input file
|
||||
** f2 = pointer to name of report file
|
||||
** f3 = pointer to name of binary output file
|
||||
** Output: none
|
||||
** Returns: error code
|
||||
** Purpose: opens input & report files
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
// Initialize file pointers to NULL
|
||||
pr->parser.InFile = NULL;
|
||||
pr->report.RptFile = NULL;
|
||||
pr->outfile.OutFile = NULL;
|
||||
pr->outfile.HydFile = NULL;
|
||||
|
||||
// Save file names
|
||||
strncpy(pr->parser.InpFname, f1, MAXFNAME);
|
||||
strncpy(pr->report.Rpt1Fname, f2, MAXFNAME);
|
||||
strncpy(pr->outfile.OutFname, f3, MAXFNAME);
|
||||
if (strlen(f3) > 0) pr->outfile.Outflag = SAVE;
|
||||
else pr->outfile.Outflag = SCRATCH;
|
||||
|
||||
// Check that file names are not identical
|
||||
if (strcomp(f1, f2) || strcomp(f1, f3) ||
|
||||
(strcomp(f2, f3) && (strlen(f2) > 0 || strlen(f3) > 0))) return 301;
|
||||
|
||||
// Attempt to open input and report files
|
||||
if (strlen(f1) > 0)
|
||||
{
|
||||
if ((pr->parser.InFile = fopen(f1, "rt")) == NULL) return 302;
|
||||
}
|
||||
if (strlen(f2) == 0) pr->report.RptFile = stdout;
|
||||
else if ((pr->report.RptFile = fopen(f2, "wt")) == NULL) return 303;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int openhydfile(Project *pr)
|
||||
/*----------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: none
|
||||
** Returns: error code
|
||||
** Purpose: opens file that saves hydraulics solution
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
const int Nnodes = pr->network.Nnodes;
|
||||
const int Ntanks = pr->network.Ntanks;
|
||||
const int Nlinks = pr->network.Nlinks;
|
||||
const int Nvalves = pr->network.Nvalves;
|
||||
const int Npumps = pr->network.Npumps;
|
||||
|
||||
INT4 nsize[6]; // Temporary array
|
||||
INT4 magic;
|
||||
INT4 version;
|
||||
int errcode = 0;
|
||||
|
||||
// If HydFile currently open, then close it if its not a scratch file
|
||||
if (pr->outfile.HydFile != NULL)
|
||||
{
|
||||
if (pr->outfile.Hydflag == SCRATCH) return 0;
|
||||
fclose(pr->outfile.HydFile);
|
||||
}
|
||||
|
||||
// Use Hydflag to determine the type of hydraulics file to use.
|
||||
// Write error message if the file cannot be opened.
|
||||
pr->outfile.HydFile = NULL;
|
||||
switch (pr->outfile.Hydflag)
|
||||
{
|
||||
case SCRATCH:
|
||||
strcpy(pr->outfile.HydFname, pr->TmpHydFname);
|
||||
pr->outfile.HydFile = fopen(pr->outfile.HydFname, "w+b");
|
||||
break;
|
||||
case SAVE:
|
||||
pr->outfile.HydFile = fopen(pr->outfile.HydFname, "w+b");
|
||||
break;
|
||||
case USE:
|
||||
pr->outfile.HydFile = fopen(pr->outfile.HydFname, "rb");
|
||||
break;
|
||||
}
|
||||
if (pr->outfile.HydFile == NULL) return 305;
|
||||
|
||||
// If a previous hydraulics solution is not being used, then
|
||||
// save the current network size parameters to the file.
|
||||
if (pr->outfile.Hydflag != USE)
|
||||
{
|
||||
magic = MAGICNUMBER;
|
||||
version = ENGINE_VERSION;
|
||||
nsize[0] = Nnodes;
|
||||
nsize[1] = Nlinks;
|
||||
nsize[2] = Ntanks;
|
||||
nsize[3] = Npumps;
|
||||
nsize[4] = Nvalves;
|
||||
nsize[5] = (int)pr->times.Dur;
|
||||
fwrite(&magic, sizeof(INT4), 1, pr->outfile.HydFile);
|
||||
fwrite(&version, sizeof(INT4), 1, pr->outfile.HydFile);
|
||||
fwrite(nsize, sizeof(INT4), 6, pr->outfile.HydFile);
|
||||
}
|
||||
|
||||
// If a previous hydraulics solution is being used, then
|
||||
// make sure its network size parameters match those of
|
||||
// the current network
|
||||
if (pr->outfile.Hydflag == USE)
|
||||
{
|
||||
fread(&magic, sizeof(INT4), 1, pr->outfile.HydFile);
|
||||
if (magic != MAGICNUMBER) return 306;
|
||||
fread(&version, sizeof(INT4), 1, pr->outfile.HydFile);
|
||||
if (version != ENGINE_VERSION) return 306;
|
||||
if (fread(nsize, sizeof(INT4), 6, pr->outfile.HydFile) < 6) return 306;
|
||||
if (nsize[0] != Nnodes || nsize[1] != Nlinks || nsize[2] != Ntanks ||
|
||||
nsize[3] != Npumps || nsize[4] != Nvalves ||
|
||||
nsize[5] != pr->times.Dur
|
||||
) return 306;
|
||||
pr->outfile.SaveHflag = TRUE;
|
||||
}
|
||||
|
||||
// Save current position in hydraulics file
|
||||
// where storage of hydraulic results begins
|
||||
pr->outfile.HydOffset = ftell(pr->outfile.HydFile);
|
||||
return errcode;
|
||||
}
|
||||
|
||||
int openoutfile(Project *pr)
|
||||
/*----------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: none
|
||||
** Returns: error code
|
||||
** Purpose: opens binary output file.
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int errcode = 0;
|
||||
|
||||
// Close output file if already opened
|
||||
if (pr->outfile.OutFile != NULL)
|
||||
{
|
||||
fclose(pr->outfile.OutFile);
|
||||
pr->outfile.OutFile = NULL;
|
||||
}
|
||||
if (pr->outfile.TmpOutFile != NULL)
|
||||
{
|
||||
fclose(pr->outfile.TmpOutFile);
|
||||
pr->outfile.TmpOutFile = NULL;
|
||||
}
|
||||
|
||||
// If output file name was supplied, then attempt to
|
||||
// open it. Otherwise open a temporary output file.
|
||||
if (pr->outfile.Outflag == SAVE)
|
||||
{
|
||||
pr->outfile.OutFile = fopen(pr->outfile.OutFname, "w+b");
|
||||
if (pr->outfile.OutFile == NULL) errcode = 304;
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(pr->outfile.OutFname, pr->TmpOutFname);
|
||||
pr->outfile.OutFile = fopen(pr->outfile.OutFname, "w+b");
|
||||
if (pr->outfile.OutFile == NULL) errcode = 304;
|
||||
}
|
||||
|
||||
// Save basic network data & energy usage results
|
||||
ERRCODE(savenetdata(pr));
|
||||
pr->outfile.OutOffset1 = ftell(pr->outfile.OutFile);
|
||||
ERRCODE(saveenergy(pr));
|
||||
pr->outfile.OutOffset2 = ftell(pr->outfile.OutFile);
|
||||
|
||||
// Open temporary file if computing time series statistic
|
||||
if (!errcode)
|
||||
{
|
||||
if (pr->report.Tstatflag != SERIES)
|
||||
{
|
||||
pr->outfile.TmpOutFile = fopen(pr->TmpStatFname, "w+b");
|
||||
if (pr->outfile.TmpOutFile == NULL) errcode = 304;
|
||||
}
|
||||
else pr->outfile.TmpOutFile = pr->outfile.OutFile;
|
||||
}
|
||||
return errcode;
|
||||
}
|
||||
|
||||
void initpointers(Project *pr)
|
||||
/*----------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: none
|
||||
** Purpose: initializes data array pointers to NULL
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
pr->hydraul.NodeDemand = NULL;
|
||||
pr->hydraul.NodeHead = NULL;
|
||||
pr->hydraul.LinkFlow = NULL;
|
||||
pr->hydraul.LinkStatus = NULL;
|
||||
pr->hydraul.LinkSetting = NULL;
|
||||
pr->hydraul.OldStatus = NULL;
|
||||
pr->hydraul.P = NULL;
|
||||
pr->hydraul.Y = NULL;
|
||||
pr->hydraul.Xflow = NULL;
|
||||
|
||||
pr->quality.NodeQual = NULL;
|
||||
pr->quality.PipeRateCoeff = NULL;
|
||||
|
||||
pr->network.Node = NULL;
|
||||
pr->network.Link = NULL;
|
||||
pr->network.Tank = NULL;
|
||||
pr->network.Pump = NULL;
|
||||
pr->network.Valve = NULL;
|
||||
pr->network.Pattern = NULL;
|
||||
pr->network.Curve = NULL;
|
||||
pr->network.Control = NULL;
|
||||
pr->network.Adjlist = NULL;
|
||||
pr->network.NodeHashTable = NULL;
|
||||
pr->network.LinkHashTable = NULL;
|
||||
|
||||
pr->parser.Patlist = NULL;
|
||||
pr->parser.Curvelist = NULL;
|
||||
|
||||
pr->hydraul.smatrix.Aii = NULL;
|
||||
pr->hydraul.smatrix.Aij = NULL;
|
||||
pr->hydraul.smatrix.F = NULL;
|
||||
pr->hydraul.smatrix.Order = NULL;
|
||||
pr->hydraul.smatrix.Row = NULL;
|
||||
pr->hydraul.smatrix.Ndx = NULL;
|
||||
pr->hydraul.smatrix.XLNZ = NULL;
|
||||
pr->hydraul.smatrix.NZSUB = NULL;
|
||||
pr->hydraul.smatrix.LNZ = NULL;
|
||||
|
||||
initrules(pr);
|
||||
}
|
||||
|
||||
int allocdata(Project *pr)
|
||||
/*----------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: none
|
||||
** Returns: error code
|
||||
** Purpose: allocates memory for network data structures
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int n;
|
||||
int errcode = 0;
|
||||
|
||||
// Allocate node & link ID hash tables
|
||||
pr->network.NodeHashTable = hashtable_create();
|
||||
pr->network.LinkHashTable = hashtable_create();
|
||||
ERRCODE(MEMCHECK(pr->network.NodeHashTable));
|
||||
ERRCODE(MEMCHECK(pr->network.LinkHashTable));
|
||||
|
||||
// Allocate memory for network nodes
|
||||
//*************************************************************
|
||||
// NOTE: Because network components of a given type are indexed
|
||||
// starting from 1, their arrays must be sized 1
|
||||
// element larger than the number of components.
|
||||
//*************************************************************
|
||||
if (!errcode)
|
||||
{
|
||||
n = pr->parser.MaxNodes + 1;
|
||||
pr->network.Node = (Snode *)calloc(n, sizeof(Snode));
|
||||
pr->hydraul.NodeDemand = (double *)calloc(n, sizeof(double));
|
||||
pr->hydraul.NodeHead = (double *)calloc(n, sizeof(double));
|
||||
pr->quality.NodeQual = (double *)calloc(n, sizeof(double));
|
||||
ERRCODE(MEMCHECK(pr->network.Node));
|
||||
ERRCODE(MEMCHECK(pr->hydraul.NodeDemand));
|
||||
ERRCODE(MEMCHECK(pr->hydraul.NodeHead));
|
||||
ERRCODE(MEMCHECK(pr->quality.NodeQual));
|
||||
}
|
||||
|
||||
// Allocate memory for network links
|
||||
if (!errcode)
|
||||
{
|
||||
n = pr->parser.MaxLinks + 1;
|
||||
pr->network.Link = (Slink *)calloc(n, sizeof(Slink));
|
||||
pr->hydraul.LinkFlow = (double *)calloc(n, sizeof(double));
|
||||
pr->hydraul.LinkSetting = (double *)calloc(n, sizeof(double));
|
||||
pr->hydraul.LinkStatus = (StatusType *)calloc(n, sizeof(StatusType));
|
||||
ERRCODE(MEMCHECK(pr->network.Link));
|
||||
ERRCODE(MEMCHECK(pr->hydraul.LinkFlow));
|
||||
ERRCODE(MEMCHECK(pr->hydraul.LinkSetting));
|
||||
ERRCODE(MEMCHECK(pr->hydraul.LinkStatus));
|
||||
}
|
||||
|
||||
// Allocate memory for tanks, sources, pumps, valves,
|
||||
// controls, demands, time patterns, & operating curves
|
||||
if (!errcode)
|
||||
{
|
||||
pr->network.Tank =
|
||||
(Stank *)calloc(pr->parser.MaxTanks + 1, sizeof(Stank));
|
||||
pr->network.Pump =
|
||||
(Spump *)calloc(pr->parser.MaxPumps + 1, sizeof(Spump));
|
||||
pr->network.Valve =
|
||||
(Svalve *)calloc(pr->parser.MaxValves + 1, sizeof(Svalve));
|
||||
pr->network.Control =
|
||||
(Scontrol *)calloc(pr->parser.MaxControls + 1, sizeof(Scontrol));
|
||||
pr->network.Pattern =
|
||||
(Spattern *)calloc(pr->parser.MaxPats + 1, sizeof(Spattern));
|
||||
pr->network.Curve =
|
||||
(Scurve *)calloc(pr->parser.MaxCurves + 1, sizeof(Scurve));
|
||||
ERRCODE(MEMCHECK(pr->network.Tank));
|
||||
ERRCODE(MEMCHECK(pr->network.Pump));
|
||||
ERRCODE(MEMCHECK(pr->network.Valve));
|
||||
ERRCODE(MEMCHECK(pr->network.Control));
|
||||
ERRCODE(MEMCHECK(pr->network.Pattern));
|
||||
ERRCODE(MEMCHECK(pr->network.Curve));
|
||||
}
|
||||
|
||||
// Initialize pointers used in patterns, curves, and demand category lists
|
||||
if (!errcode)
|
||||
{
|
||||
for (n = 0; n <= pr->parser.MaxPats; n++)
|
||||
{
|
||||
pr->network.Pattern[n].Length = 0;
|
||||
pr->network.Pattern[n].F = NULL;
|
||||
}
|
||||
for (n = 0; n <= pr->parser.MaxCurves; n++)
|
||||
{
|
||||
pr->network.Curve[n].Npts = 0;
|
||||
pr->network.Curve[n].Type = G_CURVE;
|
||||
pr->network.Curve[n].X = NULL;
|
||||
pr->network.Curve[n].Y = NULL;
|
||||
}
|
||||
for (n = 0; n <= pr->parser.MaxNodes; n++)
|
||||
{
|
||||
pr->network.Node[n].D = NULL; // node demand
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate memory for rule base (see RULES.C)
|
||||
if (!errcode) errcode = allocrules(pr);
|
||||
return errcode;
|
||||
}
|
||||
|
||||
void freeTmplist(STmplist *t)
|
||||
/*----------------------------------------------------------------
|
||||
** Input: t = pointer to start of a temporary list
|
||||
** Output: none
|
||||
** Purpose: frees memory used for temporary storage
|
||||
** of pattern & curve data
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
STmplist *tnext;
|
||||
while (t != NULL)
|
||||
{
|
||||
tnext = t->next;
|
||||
freeFloatlist(t->x);
|
||||
freeFloatlist(t->y);
|
||||
free(t);
|
||||
t = tnext;
|
||||
}
|
||||
}
|
||||
|
||||
void freeFloatlist(SFloatlist *f)
|
||||
/*----------------------------------------------------------------
|
||||
** Input: f = pointer to start of list of floats
|
||||
** Output: none
|
||||
** Purpose: frees memory used for storing list of floats
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
SFloatlist *fnext;
|
||||
while (f != NULL)
|
||||
{
|
||||
fnext = f->next;
|
||||
free(f);
|
||||
f = fnext;
|
||||
}
|
||||
}
|
||||
|
||||
void freedata(Project *pr)
|
||||
/*----------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: none
|
||||
** Purpose: frees memory allocated for network data structures.
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int j;
|
||||
Pdemand demand, nextdemand;
|
||||
Psource source;
|
||||
|
||||
// Free memory for computed results
|
||||
free(pr->hydraul.NodeDemand);
|
||||
free(pr->hydraul.NodeHead);
|
||||
free(pr->hydraul.LinkFlow);
|
||||
free(pr->hydraul.LinkSetting);
|
||||
free(pr->hydraul.LinkStatus);
|
||||
free(pr->quality.NodeQual);
|
||||
|
||||
// Free memory used for nodal adjacency lists
|
||||
freeadjlists(&pr->network);
|
||||
|
||||
// Free memory for node data
|
||||
if (pr->network.Node != NULL)
|
||||
{
|
||||
for (j = 0; j <= pr->parser.MaxNodes; j++)
|
||||
{
|
||||
// Free memory used for demand category list
|
||||
demand = pr->network.Node[j].D;
|
||||
while (demand != NULL)
|
||||
{
|
||||
nextdemand = demand->next;
|
||||
free(demand);
|
||||
demand = nextdemand;
|
||||
}
|
||||
// Free memory used for WQ source data
|
||||
source = pr->network.Node[j].S;
|
||||
if (source != NULL) free(source);
|
||||
}
|
||||
free(pr->network.Node);
|
||||
}
|
||||
|
||||
// Free memory for other network objects
|
||||
free(pr->network.Link);
|
||||
free(pr->network.Tank);
|
||||
free(pr->network.Pump);
|
||||
free(pr->network.Valve);
|
||||
free(pr->network.Control);
|
||||
|
||||
// Free memory for time patterns
|
||||
if (pr->network.Pattern != NULL)
|
||||
{
|
||||
for (j = 0; j <= pr->parser.MaxPats; j++) free(pr->network.Pattern[j].F);
|
||||
free(pr->network.Pattern);
|
||||
}
|
||||
|
||||
// Free memory for curves
|
||||
if (pr->network.Curve != NULL)
|
||||
{
|
||||
for (j = 0; j <= pr->parser.MaxCurves; j++)
|
||||
{
|
||||
free(pr->network.Curve[j].X);
|
||||
free(pr->network.Curve[j].Y);
|
||||
}
|
||||
free(pr->network.Curve);
|
||||
}
|
||||
|
||||
// Free memory for rule base (see RULES.C)
|
||||
freerules(pr);
|
||||
|
||||
// Free hash table memory
|
||||
if (pr->network.NodeHashTable != NULL)
|
||||
{
|
||||
hashtable_free(pr->network.NodeHashTable);
|
||||
}
|
||||
if (pr->network.LinkHashTable != NULL)
|
||||
{
|
||||
hashtable_free(pr->network.LinkHashTable);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int buildadjlists(Network *net)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: returns error code
|
||||
** Purpose: builds linked list of links adjacent to each node
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i, j, k;
|
||||
int errcode = 0;
|
||||
Padjlist alink;
|
||||
|
||||
// Create an array of adjacency lists
|
||||
freeadjlists(net);
|
||||
net->Adjlist = (Padjlist *)calloc(net->Nnodes + 1, sizeof(Padjlist));
|
||||
if (net->Adjlist == NULL) return 101;
|
||||
for (i = 0; i <= net->Nnodes; i++) net->Adjlist[i] = NULL;
|
||||
|
||||
// For each link, update adjacency lists of its end nodes
|
||||
for (k = 1; k <= net->Nlinks; k++)
|
||||
{
|
||||
i = net->Link[k].N1;
|
||||
j = net->Link[k].N2;
|
||||
|
||||
// Include link in start node i's list
|
||||
alink = (struct Sadjlist *) malloc(sizeof(struct Sadjlist));
|
||||
if (alink == NULL)
|
||||
{
|
||||
errcode = 101;
|
||||
break;
|
||||
}
|
||||
alink->node = j;
|
||||
alink->link = k;
|
||||
alink->next = net->Adjlist[i];
|
||||
net->Adjlist[i] = alink;
|
||||
|
||||
// Include link in end node j's list
|
||||
alink = (struct Sadjlist *) malloc(sizeof(struct Sadjlist));
|
||||
if (alink == NULL)
|
||||
{
|
||||
errcode = 101;
|
||||
break;
|
||||
}
|
||||
alink->node = i;
|
||||
alink->link = k;
|
||||
alink->next = net->Adjlist[j];
|
||||
net->Adjlist[j] = alink;
|
||||
}
|
||||
if (errcode) freeadjlists(net);
|
||||
return errcode;
|
||||
}
|
||||
|
||||
|
||||
void freeadjlists(Network *net)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: none
|
||||
** Purpose: frees memory used for nodal adjacency lists
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i;
|
||||
Padjlist alink;
|
||||
|
||||
if (net->Adjlist == NULL) return;
|
||||
for (i = 0; i <= net->Nnodes; i++)
|
||||
{
|
||||
for (alink = net->Adjlist[i]; alink != NULL; alink = net->Adjlist[i])
|
||||
{
|
||||
net->Adjlist[i] = alink->next;
|
||||
free(alink);
|
||||
}
|
||||
}
|
||||
FREE(net->Adjlist);
|
||||
}
|
||||
|
||||
int incontrols(Project *pr, int objType, int index)
|
||||
/*----------------------------------------------------------------
|
||||
** Input: objType = type of object (either NODE or LINK)
|
||||
** index = the object's index
|
||||
** Output: none
|
||||
** Returns: 1 if any controls contain the object; 0 if not
|
||||
** Purpose: determines if any simple or rule-based controls
|
||||
** contain a particular node or link.
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Rules *rules = &pr->rules;
|
||||
|
||||
int i, ruleObject;
|
||||
Spremise *premise;
|
||||
Saction *action;
|
||||
|
||||
// Check simple controls
|
||||
for (i = 1; i <= net->Ncontrols; i++)
|
||||
{
|
||||
if (objType == NODE && net->Control[i].Node == index) return 1;
|
||||
if (objType == LINK && net->Control[i].Link == index) return 1;
|
||||
}
|
||||
|
||||
// Check rule-based controls
|
||||
for (i = 1; i <= net->Nrules; i++)
|
||||
{
|
||||
// Convert objType to a rule object type
|
||||
if (objType == NODE) ruleObject = 6;
|
||||
else ruleObject = 7;
|
||||
|
||||
// Check rule's premises
|
||||
premise = net->Rule[i].Premises;
|
||||
while (premise != NULL)
|
||||
{
|
||||
if (ruleObject == premise->object && premise->index == index) return 1;
|
||||
premise = premise->next;
|
||||
}
|
||||
|
||||
// Rule actions only need to be checked for link objects
|
||||
if (objType == LINK)
|
||||
{
|
||||
// Check rule's THEN actions
|
||||
action = net->Rule[i].ThenActions;
|
||||
while (action != NULL)
|
||||
{
|
||||
if (action->link == index) return 1;
|
||||
action = action->next;
|
||||
}
|
||||
|
||||
// Check rule's ELSE actions
|
||||
action = net->Rule[i].ElseActions;
|
||||
while (action != NULL)
|
||||
{
|
||||
if (action->link == index) return 1;
|
||||
action = action->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int findnode(Network *network, char *id)
|
||||
/*----------------------------------------------------------------
|
||||
** Input: id = node ID
|
||||
** Output: none
|
||||
** Returns: index of node with given ID, or 0 if ID not found
|
||||
** Purpose: uses hash table to find index of node with given ID
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
return (hashtable_find(network->NodeHashTable, id));
|
||||
}
|
||||
|
||||
int findlink(Network *network, char *id)
|
||||
/*----------------------------------------------------------------
|
||||
** Input: id = link ID
|
||||
** Output: none
|
||||
** Returns: index of link with given ID, or 0 if ID not found
|
||||
** Purpose: uses hash table to find index of link with given ID
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
return (hashtable_find(network->LinkHashTable, id));
|
||||
}
|
||||
|
||||
int findtank(Network *network, int index)
|
||||
/*----------------------------------------------------------------
|
||||
** Input: index = node index
|
||||
** Output: none
|
||||
** Returns: index of tank with given node id, or NOTFOUND if tank not found
|
||||
** Purpose: for use in the deletenode function
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i;
|
||||
for (i = 1; i <= network->Ntanks; i++)
|
||||
{
|
||||
if (network->Tank[i].Node == index) return i;
|
||||
}
|
||||
return NOTFOUND;
|
||||
}
|
||||
|
||||
int findpump(Network *network, int index)
|
||||
/*----------------------------------------------------------------
|
||||
** Input: index = link ID
|
||||
** Output: none
|
||||
** Returns: index of pump with given link id, or NOTFOUND if pump not found
|
||||
** Purpose: for use in the deletelink function
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i;
|
||||
for (i = 1; i <= network->Npumps; i++)
|
||||
{
|
||||
if (network->Pump[i].Link == index) return i;
|
||||
}
|
||||
return NOTFOUND;
|
||||
}
|
||||
|
||||
int findvalve(Network *network, int index)
|
||||
/*----------------------------------------------------------------
|
||||
** Input: index = link ID
|
||||
** Output: none
|
||||
** Returns: index of valve with given link id, or NOTFOUND if valve not found
|
||||
** Purpose: for use in the deletelink function
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i;
|
||||
for (i = 1; i <= network->Nvalves; i++)
|
||||
{
|
||||
if (network->Valve[i].Link == index) return i;
|
||||
}
|
||||
return NOTFOUND;
|
||||
}
|
||||
|
||||
char *getTmpName(char *fname)
|
||||
//----------------------------------------------------------------
|
||||
// Input: fname = file name string
|
||||
// Output: returns pointer to file name
|
||||
// Purpose: creates a temporary file name with path prepended to it.
|
||||
//----------------------------------------------------------------
|
||||
{
|
||||
#ifdef _WIN32
|
||||
|
||||
char* name = NULL;
|
||||
|
||||
// --- use Windows _tempnam function to get a pointer to an
|
||||
// unused file name that begins with "en"
|
||||
name = _tempnam(NULL, "en");
|
||||
if (name == NULL) return NULL;
|
||||
|
||||
// --- copy the file name to fname
|
||||
if (strlen(name) < MAXFNAME) strncpy(fname, name, MAXFNAME);
|
||||
else fname = NULL;
|
||||
|
||||
// --- free the pointer returned by _tempnam
|
||||
if (name) free(name);
|
||||
|
||||
// --- for non-Windows systems:
|
||||
#else
|
||||
// --- use system function mkstemp() to create a temporary file name
|
||||
strcpy(fname, "enXXXXXX");
|
||||
mkstemp(fname);
|
||||
#endif
|
||||
return fname;
|
||||
}
|
||||
|
||||
int strcomp(const char *s1, const char *s2)
|
||||
/*---------------------------------------------------------------
|
||||
** Input: s1 = character string
|
||||
** s2 = character string
|
||||
** Output: none
|
||||
** Returns: 1 if s1 is same as s2, 0 otherwise
|
||||
** Purpose: case insensitive comparison of strings s1 & s2
|
||||
**---------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i;
|
||||
for (i = 0; UCHAR(s1[i]) == UCHAR(s2[i]); i++)
|
||||
{
|
||||
if (!s1[i + 1] && !s2[i + 1]) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
double interp(int n, double x[], double y[], double xx)
|
||||
/*----------------------------------------------------------------
|
||||
** Input: n = number of data pairs defining a curve
|
||||
** x = x-data values of curve
|
||||
** y = y-data values of curve
|
||||
** xx = specified x-value
|
||||
** Output: none
|
||||
** Returns: y-value on curve at x = xx
|
||||
** Purpose: uses linear interpolation to find y-value on a
|
||||
** data curve corresponding to specified x-value.
|
||||
** NOTE: does not extrapolate beyond endpoints of curve.
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int k, m;
|
||||
double dx, dy;
|
||||
|
||||
m = n - 1; // Highest data index
|
||||
if (xx <= x[0]) return (y[0]); // xx off low end of curve
|
||||
for (k = 1; k <= m; k++) // Bracket xx on curve
|
||||
{
|
||||
if (x[k] >= xx) // Interp. over interval
|
||||
{
|
||||
dx = x[k] - x[k - 1];
|
||||
dy = y[k] - y[k - 1];
|
||||
if (ABS(dx) < TINY) return (y[k]);
|
||||
else return (y[k] - (x[k] - xx) * dy / dx);
|
||||
}
|
||||
}
|
||||
return (y[m]); // xx off high end of curve
|
||||
}
|
||||
|
||||
char *geterrmsg(int errcode, char *msg)
|
||||
/*----------------------------------------------------------------
|
||||
** Input: errcode = error code
|
||||
** Output: none
|
||||
** Returns: pointer to string with error message
|
||||
** Purpose: retrieves text of error message
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
switch (errcode) { /* Warnings */
|
||||
#define DAT(code,enumer,string) case code: strcpy(msg, string); break;
|
||||
//#define DAT(code,enumer,string) case code: sprintf(msg, "Error %d: %s", code, string); break;
|
||||
#include "errors.dat"
|
||||
#undef DAT
|
||||
default:
|
||||
strcpy(msg, "");
|
||||
}
|
||||
return (msg);
|
||||
}
|
||||
|
||||
void errmsg(Project *pr, int errcode)
|
||||
/*----------------------------------------------------------------
|
||||
** Input: errcode = error code
|
||||
** Output: none
|
||||
** Purpose: writes error message to report file
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
if (errcode == 309) /* Report file write error - */
|
||||
{ /* Do not write msg to file. */
|
||||
|
||||
}
|
||||
else if (pr->report.RptFile != NULL && pr->report.Messageflag)
|
||||
{
|
||||
writeline(pr, geterrmsg(errcode, pr->Msg));
|
||||
}
|
||||
}
|
||||
|
||||
void writewin(void(*vp)(char *), char *s)
|
||||
/*----------------------------------------------------------------
|
||||
** Input: text string
|
||||
** Output: none
|
||||
** Purpose: passes character string to viewprog() in
|
||||
** application which calls the EPANET DLL
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
char progmsg[MAXMSG + 1];
|
||||
if (vp != NULL)
|
||||
{
|
||||
strncpy(progmsg, s, MAXMSG);
|
||||
vp(progmsg);
|
||||
}
|
||||
}
|
||||
264
src/quality.c
264
src/quality.c
@@ -1,13 +1,14 @@
|
||||
/*
|
||||
*********************************************************************
|
||||
|
||||
QUALITY.C -- water quality engine module for the EPANET program
|
||||
|
||||
This module works together with QUALROUTE.C and QUALREACT.C to
|
||||
compute transport and reaction of a water quality constituent within
|
||||
a pipe network over a series of time steps.
|
||||
|
||||
*********************************************************************
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Module: quality.c
|
||||
Description: implements EPANET's water quality engine
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 11/27/2018
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -24,36 +25,35 @@ a pipe network over a series of time steps.
|
||||
#include "funcs.h"
|
||||
|
||||
// Stagnant flow tolerance
|
||||
const double QZERO = 0.005 / GPMperCFS; // 0.005 gpm = 1.114e-5 cfs
|
||||
const double Q_STAGNANT = 0.005 / GPMperCFS; // 0.005 gpm = 1.114e-5 cfs
|
||||
|
||||
// Exported Functions (declared in FUNCS.H)
|
||||
//int openqual(EN_Project *pr);
|
||||
//void initqual(EN_Project *pr);
|
||||
//int runqual(EN_Project *pr, long *);
|
||||
//int nextqual(EN_Project *pr, long *);
|
||||
//int stepqual(EN_Project *pr, long *);
|
||||
//int closequal(EN_Project *pr);
|
||||
//double avgqual(EN_Project *pr, int);
|
||||
double findsourcequal(EN_Project *pr, int, double, double, long);
|
||||
// Exported functions (declared in FUNCS.H)
|
||||
//int openqual(Project *);
|
||||
//void initqual(Project *);
|
||||
//int runqual(Project *, long *);
|
||||
//int nextqual(Project *, long *);
|
||||
//int stepqual(Project *, long *);
|
||||
//int closequal(Project *);
|
||||
//double avgqual(Project *, int);
|
||||
double findsourcequal(Project *, int, double, double, long);
|
||||
|
||||
// Imported Functions
|
||||
extern char setreactflag(EN_Project *pr);
|
||||
// Imported functions
|
||||
extern char setreactflag(Project *);
|
||||
extern double getucf(double);
|
||||
extern void ratecoeffs(EN_Project *pr);
|
||||
extern int buildilists(EN_Project *pr);
|
||||
extern void initsegs(EN_Project *pr);
|
||||
extern void reversesegs(EN_Project *pr, int);
|
||||
extern int sortnodes(EN_Project *pr);
|
||||
extern void transport(EN_Project *pr, long);
|
||||
extern void ratecoeffs(Project *);
|
||||
extern void initsegs(Project *);
|
||||
extern void reversesegs(Project *, int);
|
||||
extern int sortnodes(Project *);
|
||||
extern void transport(Project *, long);
|
||||
|
||||
// Local Functions
|
||||
static double sourcequal(EN_Project *pr, Psource);
|
||||
static void evalmassbalance(EN_Project *pr);
|
||||
static double findstoredmass(EN_Project *pr);
|
||||
static int flowdirchanged(EN_Project *pr);
|
||||
// Local functions
|
||||
static double sourcequal(Project *, Psource);
|
||||
static void evalmassbalance(Project *);
|
||||
static double findstoredmass(Project *);
|
||||
static int flowdirchanged(Project *);
|
||||
|
||||
|
||||
int openqual(EN_Project *pr)
|
||||
int openqual(Project *pr)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
@@ -62,16 +62,23 @@ int openqual(EN_Project *pr)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Quality *qual = &pr->quality;
|
||||
|
||||
int errcode = 0;
|
||||
int n;
|
||||
|
||||
quality_t *qual = &pr->quality;
|
||||
EN_Network *net = &pr->network;
|
||||
// Build nodal adjacency lists if they don't already exist
|
||||
if (net->Adjlist == NULL)
|
||||
{
|
||||
errcode = buildadjlists(net);
|
||||
if (errcode ) return errcode;
|
||||
}
|
||||
|
||||
// Create a memory pool for water quality segments
|
||||
qual->OutOfMemory = FALSE;
|
||||
qual->SegPool = mempool_create();
|
||||
if (qual->SegPool == NULL) errcode = 101;;
|
||||
if (qual->SegPool == NULL) errcode = 101;
|
||||
|
||||
// Allocate arrays for link flow direction & reaction rates
|
||||
n = net->Nlinks + 1;
|
||||
@@ -83,34 +90,19 @@ int openqual(EN_Project *pr)
|
||||
qual->FirstSeg = (Pseg *)calloc(n, sizeof(Pseg));
|
||||
qual->LastSeg = (Pseg *)calloc(n, sizeof(Pseg));
|
||||
|
||||
// Allocate memory for sorted nodes and link incidence lists
|
||||
// ... Ilist contains the list of link indexes that are incident
|
||||
// on each node in compact format
|
||||
n = 2 * net->Nlinks + 2;
|
||||
qual->Ilist = (int *)calloc(n, sizeof(int));
|
||||
// ... IlistPtr holds the position in Ilist where the
|
||||
// incidence list for each node begins
|
||||
n = net->Nnodes + 1;
|
||||
qual->IlistPtr = (int *)calloc(n + 2, sizeof(int));
|
||||
// ... SortedNodes contains the list of node indexes in topological
|
||||
// order
|
||||
// Allocate memory for topologically sorted nodes
|
||||
qual->SortedNodes = (int *)calloc(n, sizeof(int));
|
||||
|
||||
ERRCODE(MEMCHECK(qual->FlowDir));
|
||||
ERRCODE(MEMCHECK(qual->PipeRateCoeff));
|
||||
ERRCODE(MEMCHECK(qual->FirstSeg));
|
||||
ERRCODE(MEMCHECK(qual->LastSeg));
|
||||
ERRCODE(MEMCHECK(qual->Ilist));
|
||||
ERRCODE(MEMCHECK(qual->IlistPtr));
|
||||
ERRCODE(MEMCHECK(qual->SortedNodes));
|
||||
|
||||
// Build link incidence lists
|
||||
if (!errcode) errcode = buildilists(pr);
|
||||
return errcode;
|
||||
}
|
||||
|
||||
|
||||
int initqual(EN_Project *pr)
|
||||
int initqual(Project *pr)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
@@ -119,22 +111,24 @@ int initqual(EN_Project *pr)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Quality *qual = &pr->quality;
|
||||
Times *time = &pr->times;
|
||||
|
||||
int i;
|
||||
int errcode = 0;
|
||||
EN_Network *net = &pr->network;
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
quality_t *qual = &pr->quality;
|
||||
|
||||
// Re-position hydraulics file
|
||||
if (!hyd->OpenHflag)
|
||||
{
|
||||
fseek(pr->out_files.HydFile, pr->out_files.HydOffset, SEEK_SET);
|
||||
fseek(pr->outfile.HydFile, pr->outfile.HydOffset, SEEK_SET);
|
||||
}
|
||||
|
||||
// Set elapsed times to zero
|
||||
qual->Qtime = 0;
|
||||
pr->time_options.Htime = 0;
|
||||
pr->time_options.Rtime = pr->time_options.Rstart;
|
||||
time->Qtime = 0;
|
||||
time->Htime = 0;
|
||||
time->Rtime = time->Rstart;
|
||||
pr->report.Nperiods = 0;
|
||||
|
||||
// Initialize node quality
|
||||
@@ -183,17 +177,17 @@ int initqual(EN_Project *pr)
|
||||
qual->Wsource = 0.0;
|
||||
|
||||
// Initialize mass balance components
|
||||
qual->massbalance.initial = findstoredmass(pr);
|
||||
qual->massbalance.inflow = 0.0;
|
||||
qual->massbalance.outflow = 0.0;
|
||||
qual->massbalance.reacted = 0.0;
|
||||
qual->massbalance.final = 0.0;
|
||||
qual->massbalance.ratio = 0.0;
|
||||
qual->MassBalance.initial = findstoredmass(pr);
|
||||
qual->MassBalance.inflow = 0.0;
|
||||
qual->MassBalance.outflow = 0.0;
|
||||
qual->MassBalance.reacted = 0.0;
|
||||
qual->MassBalance.final = 0.0;
|
||||
qual->MassBalance.ratio = 0.0;
|
||||
return errcode;
|
||||
}
|
||||
|
||||
|
||||
int runqual(EN_Project *pr, long *t)
|
||||
int runqual(Project *pr, long *t)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
@@ -204,19 +198,19 @@ int runqual(EN_Project *pr, long *t)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Quality *qual = &pr->quality;
|
||||
Times *time = &pr->times;
|
||||
|
||||
long hydtime; // Hydraulic solution time
|
||||
long hydstep; // Hydraulic time step
|
||||
int errcode = 0;
|
||||
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
quality_t *qual = &pr->quality;
|
||||
time_options_t *time = &pr->time_options;
|
||||
|
||||
// Update reported simulation time
|
||||
*t = qual->Qtime;
|
||||
*t = time->Qtime;
|
||||
|
||||
// Read hydraulic solution from hydraulics file
|
||||
if (qual->Qtime == time->Htime)
|
||||
if (time->Qtime == time->Htime)
|
||||
{
|
||||
// Read hydraulic results from file
|
||||
if (!hyd->OpenHflag)
|
||||
@@ -229,7 +223,7 @@ int runqual(EN_Project *pr, long *t)
|
||||
// Save current results to output file
|
||||
if (time->Htime >= time->Rtime)
|
||||
{
|
||||
if (pr->save_options.Saveflag)
|
||||
if (pr->outfile.Saveflag)
|
||||
{
|
||||
errcode = saveoutput(pr);
|
||||
pr->report.Nperiods++;
|
||||
@@ -239,7 +233,7 @@ int runqual(EN_Project *pr, long *t)
|
||||
if (errcode) return errcode;
|
||||
|
||||
// If simulating water quality
|
||||
if (qual->Qualflag != NONE && qual->Qtime < time->Dur)
|
||||
if (qual->Qualflag != NONE && time->Qtime < time->Dur)
|
||||
{
|
||||
// ... compute reaction rate coeffs.
|
||||
if (qual->Reactflag && qual->Qualflag != AGE) ratecoeffs(pr);
|
||||
@@ -256,7 +250,7 @@ int runqual(EN_Project *pr, long *t)
|
||||
}
|
||||
|
||||
|
||||
int nextqual(EN_Project *pr, long *tstep)
|
||||
int nextqual(Project *pr, long *tstep)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
@@ -267,17 +261,17 @@ int nextqual(EN_Project *pr, long *tstep)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Quality *qual = &pr->quality;
|
||||
Times *time = &pr->times;
|
||||
|
||||
long hydstep; // Time step until next hydraulic event
|
||||
long dt, qtime;
|
||||
int errcode = 0;
|
||||
|
||||
quality_t *qual = &pr->quality;
|
||||
time_options_t *time = &pr->time_options;
|
||||
|
||||
// Find time step till next hydraulic event
|
||||
*tstep = 0;
|
||||
hydstep = 0;
|
||||
if (time->Htime <= time->Dur) hydstep = time->Htime - qual->Qtime;
|
||||
if (time->Htime <= time->Dur) hydstep = time->Htime - time->Qtime;
|
||||
|
||||
// Perform water quality routing over this time step
|
||||
if (qual->Qualflag != NONE && hydstep > 0)
|
||||
@@ -286,7 +280,7 @@ int nextqual(EN_Project *pr, long *tstep)
|
||||
qtime = 0;
|
||||
while (!qual->OutOfMemory && qtime < hydstep)
|
||||
{
|
||||
dt = MIN(qual->Qstep, hydstep - qtime);
|
||||
dt = MIN(time->Qstep, hydstep - qtime);
|
||||
qtime += dt;
|
||||
transport(pr, dt);
|
||||
}
|
||||
@@ -298,7 +292,7 @@ int nextqual(EN_Project *pr, long *tstep)
|
||||
|
||||
// Update current time
|
||||
if (!errcode) *tstep = hydstep;
|
||||
qual->Qtime += hydstep;
|
||||
time->Qtime += hydstep;
|
||||
|
||||
// If no more time steps remain
|
||||
if (!errcode && *tstep == 0)
|
||||
@@ -310,13 +304,13 @@ int nextqual(EN_Project *pr, long *tstep)
|
||||
}
|
||||
|
||||
// ... write the final portion of the binary output file
|
||||
if (pr->save_options.Saveflag) errcode = savefinaloutput(pr);
|
||||
if (pr->outfile.Saveflag) errcode = savefinaloutput(pr);
|
||||
}
|
||||
return errcode;
|
||||
}
|
||||
|
||||
|
||||
int stepqual(EN_Project *pr, long *tleft)
|
||||
int stepqual(Project *pr, long *tleft)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
@@ -327,19 +321,20 @@ int stepqual(EN_Project *pr, long *tleft)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Quality *qual = &pr->quality;
|
||||
Times *time = &pr->times;
|
||||
|
||||
long dt, hstep, t, tstep;
|
||||
int errcode = 0;
|
||||
|
||||
quality_t *qual = &pr->quality;
|
||||
|
||||
tstep = qual->Qstep;
|
||||
tstep = time->Qstep;
|
||||
do
|
||||
{
|
||||
// Set local time step to quality time step
|
||||
dt = tstep;
|
||||
|
||||
// Find time step until next hydraulic event
|
||||
hstep = pr->time_options.Htime - qual->Qtime;
|
||||
hstep = time->Htime - time->Qtime;
|
||||
|
||||
// If next hydraulic event occurs before end of local time step
|
||||
if (hstep < dt)
|
||||
@@ -349,21 +344,21 @@ int stepqual(EN_Project *pr, long *tleft)
|
||||
|
||||
// ... transport quality over local time step
|
||||
if (qual->Qualflag != NONE) transport(pr, dt);
|
||||
qual->Qtime += dt;
|
||||
time->Qtime += dt;
|
||||
|
||||
// ... quit if running quality concurrently with hydraulics
|
||||
if (pr->hydraulics.OpenHflag) break;
|
||||
if (pr->hydraul.OpenHflag) break;
|
||||
|
||||
// ... otherwise call runqual() to update hydraulics
|
||||
errcode = runqual(pr, &t);
|
||||
qual->Qtime = t;
|
||||
time->Qtime = t;
|
||||
}
|
||||
|
||||
// Otherwise transport quality over current local time step
|
||||
else
|
||||
{
|
||||
if (qual->Qualflag != NONE) transport(pr, dt);
|
||||
qual->Qtime += dt;
|
||||
time->Qtime += dt;
|
||||
}
|
||||
|
||||
// Reduce quality time step by local time step
|
||||
@@ -376,7 +371,7 @@ int stepqual(EN_Project *pr, long *tleft)
|
||||
evalmassbalance(pr);
|
||||
|
||||
// Update total simulation time left
|
||||
*tleft = pr->time_options.Dur - qual->Qtime;
|
||||
*tleft = time->Dur - time->Qtime;
|
||||
|
||||
// If no more time steps remain
|
||||
if (!errcode && *tleft == 0)
|
||||
@@ -388,13 +383,13 @@ int stepqual(EN_Project *pr, long *tleft)
|
||||
}
|
||||
|
||||
// ... write the final portion of the binary output file
|
||||
if (pr->save_options.Saveflag) errcode = savefinaloutput(pr);
|
||||
if (pr->outfile.Saveflag) errcode = savefinaloutput(pr);
|
||||
}
|
||||
return errcode;
|
||||
}
|
||||
|
||||
|
||||
int closequal(EN_Project *pr)
|
||||
int closequal(Project *pr)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
@@ -403,7 +398,7 @@ int closequal(EN_Project *pr)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
quality_t *qual = &pr->quality;
|
||||
Quality *qual = &pr->quality;
|
||||
int errcode = 0;
|
||||
|
||||
if (qual->SegPool) mempool_delete(qual->SegPool);
|
||||
@@ -411,14 +406,12 @@ int closequal(EN_Project *pr)
|
||||
FREE(qual->LastSeg);
|
||||
FREE(qual->PipeRateCoeff);
|
||||
FREE(qual->FlowDir);
|
||||
FREE(qual->Ilist);
|
||||
FREE(qual->IlistPtr);
|
||||
FREE(qual->SortedNodes);
|
||||
return errcode;
|
||||
}
|
||||
|
||||
|
||||
double avgqual(EN_Project *pr, int k)
|
||||
double avgqual(Project *pr, int k)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: k = link index
|
||||
@@ -427,12 +420,12 @@ double avgqual(EN_Project *pr, int k)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Quality *qual = &pr->quality;
|
||||
|
||||
double vsum = 0.0, msum = 0.0;
|
||||
Pseg seg;
|
||||
|
||||
EN_Network *net = &pr->network;
|
||||
quality_t *qual = &pr->quality;
|
||||
|
||||
if (qual->Qualflag == NONE) return 0.0;
|
||||
|
||||
// Sum up the quality and volume in each segment of the link
|
||||
@@ -459,7 +452,7 @@ double avgqual(EN_Project *pr, int k)
|
||||
}
|
||||
|
||||
|
||||
double findsourcequal(EN_Project *pr, int n, double volin, double volout, long tstep)
|
||||
double findsourcequal(Project *pr, int n, double volin, double volout, long tstep)
|
||||
/*
|
||||
**---------------------------------------------------------------------
|
||||
** Input: n = node index
|
||||
@@ -472,14 +465,14 @@ double findsourcequal(EN_Project *pr, int n, double volin, double volout, long t
|
||||
**---------------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Quality *qual = &pr->quality;
|
||||
Times *time = &pr->times;
|
||||
|
||||
double massadded = 0.0, c;
|
||||
Psource source;
|
||||
|
||||
EN_Network *net = &pr->network;
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
quality_t *qual = &pr->quality;
|
||||
time_options_t *time = &pr->time_options;
|
||||
|
||||
// Sources only apply to CHEMICAL analyses
|
||||
if (qual->Qualflag != CHEM) return 0.0;
|
||||
|
||||
@@ -487,7 +480,7 @@ double findsourcequal(EN_Project *pr, int n, double volin, double volout, long t
|
||||
source = net->Node[n].S;
|
||||
if (source == NULL) return 0.0;
|
||||
if (source->C0 == 0.0) return 0.0;
|
||||
if (volout / tstep <= QZERO) return 0.0;
|
||||
if (volout / tstep <= Q_STAGNANT) return 0.0;
|
||||
|
||||
// Added source concentration depends on source type
|
||||
c = sourcequal(pr, source);
|
||||
@@ -540,7 +533,7 @@ double findsourcequal(EN_Project *pr, int n, double volin, double volout, long t
|
||||
}
|
||||
|
||||
|
||||
double sourcequal(EN_Project *pr, Psource source)
|
||||
double sourcequal(Project *pr, Psource source)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: source = a water quality source object
|
||||
@@ -549,14 +542,14 @@ double sourcequal(EN_Project *pr, Psource source)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Quality *qual = &pr->quality;
|
||||
Times *time = &pr->times;
|
||||
|
||||
int i;
|
||||
long k;
|
||||
double c;
|
||||
|
||||
EN_Network *net = &pr->network;
|
||||
quality_t *qual = &pr->quality;
|
||||
time_options_t *time = &pr->time_options;
|
||||
|
||||
// Get source concentration (or mass flow) in original units
|
||||
c = source->C0;
|
||||
|
||||
@@ -568,13 +561,13 @@ double sourcequal(EN_Project *pr, Psource source)
|
||||
// Apply time pattern if assigned
|
||||
i = source->Pat;
|
||||
if (i == 0) return c;
|
||||
k = ((qual->Qtime + time->Pstart) / time->Pstep) %
|
||||
k = ((time->Qtime + time->Pstart) / time->Pstep) %
|
||||
(long)net->Pattern[i].Length;
|
||||
return (c * net->Pattern[i].F[k]);
|
||||
}
|
||||
|
||||
|
||||
void evalmassbalance(EN_Project *pr)
|
||||
void evalmassbalance(Project *pr)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
@@ -584,27 +577,28 @@ void evalmassbalance(EN_Project *pr)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Quality *qual = &pr->quality;
|
||||
|
||||
double massin;
|
||||
double massout;
|
||||
double massreacted;
|
||||
quality_t *qual = &pr->quality;
|
||||
|
||||
if (qual->Qualflag == NONE) qual->massbalance.ratio = 1.0;
|
||||
if (qual->Qualflag == NONE) qual->MassBalance.ratio = 1.0;
|
||||
else
|
||||
{
|
||||
qual->massbalance.final = findstoredmass(pr);
|
||||
massin = qual->massbalance.initial + qual->massbalance.inflow;
|
||||
massout = qual->massbalance.outflow + qual->massbalance.final;
|
||||
massreacted = qual->massbalance.reacted;
|
||||
qual->MassBalance.final = findstoredmass(pr);
|
||||
massin = qual->MassBalance.initial + qual->MassBalance.inflow;
|
||||
massout = qual->MassBalance.outflow + qual->MassBalance.final;
|
||||
massreacted = qual->MassBalance.reacted;
|
||||
if (massreacted > 0.0) massout += massreacted;
|
||||
else massin -= massreacted;
|
||||
if (massin == 0.0) qual->massbalance.ratio = 1.0;
|
||||
else qual->massbalance.ratio = massout / massin;
|
||||
if (massin == 0.0) qual->MassBalance.ratio = 1.0;
|
||||
else qual->MassBalance.ratio = massout / massin;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
double findstoredmass(EN_Project *pr)
|
||||
double findstoredmass(Project *pr)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
@@ -614,13 +608,13 @@ double findstoredmass(EN_Project *pr)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Quality *qual = &pr->quality;
|
||||
|
||||
int i, k;
|
||||
double totalmass = 0.0;
|
||||
Pseg seg;
|
||||
|
||||
EN_Network *net = &pr->network;
|
||||
quality_t *qual = &pr->quality;
|
||||
|
||||
// Mass residing in each pipe
|
||||
for (k = 1; k <= net->Nlinks; k++)
|
||||
{
|
||||
@@ -654,7 +648,7 @@ double findstoredmass(EN_Project *pr)
|
||||
return totalmass;
|
||||
}
|
||||
|
||||
int flowdirchanged(EN_Project *pr)
|
||||
int flowdirchanged(Project *pr)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
@@ -663,25 +657,25 @@ int flowdirchanged(EN_Project *pr)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Quality *qual = &pr->quality;
|
||||
|
||||
int k;
|
||||
int result = FALSE;
|
||||
int newdir;
|
||||
int olddir;
|
||||
double q;
|
||||
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
quality_t *qual = &pr->quality;
|
||||
|
||||
// Examine each network link
|
||||
for (k = 1; k <= pr->network.Nlinks; k++)
|
||||
{
|
||||
// Determine sign (+1 or -1) of new flow rate
|
||||
olddir = qual->FlowDir[k];
|
||||
q = (hyd->LinkStatus[k] <= CLOSED) ? 0.0 : hyd->LinkFlows[k];
|
||||
q = (hyd->LinkStatus[k] <= CLOSED) ? 0.0 : hyd->LinkFlow[k];
|
||||
newdir = SGN(q);
|
||||
|
||||
// Indicate if flow is negligible
|
||||
if (fabs(q) < QZERO) newdir = 0;
|
||||
if (fabs(q) < Q_STAGNANT) newdir = 0;
|
||||
|
||||
// Reverse link's volume segments if flow direction changes sign
|
||||
if (newdir * olddir < 0) reversesegs(pr, k);
|
||||
@@ -696,5 +690,3 @@ int flowdirchanged(EN_Project *pr)
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/************************* End of QUALITY.C ***************************/
|
||||
|
||||
166
src/qualreact.c
166
src/qualreact.c
@@ -1,40 +1,45 @@
|
||||
/*
|
||||
*********************************************************************
|
||||
|
||||
QUALREACT.C -- water quality reaction module for the EPANET program
|
||||
|
||||
*********************************************************************
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Module: qualreact.c
|
||||
Description: computes water quality reactions within pipes and tanks
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 11/27/2018
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include "types.h"
|
||||
|
||||
// Exported Functions
|
||||
char setreactflag(EN_Project *pr);
|
||||
// Exported functions
|
||||
char setreactflag(Project *);
|
||||
double getucf(double);
|
||||
void ratecoeffs(EN_Project *pr);
|
||||
void reactpipes(EN_Project *pr, long);
|
||||
void reacttanks(EN_Project *pr, long);
|
||||
double mixtank(EN_Project *pr, int, double, double ,double);
|
||||
void ratecoeffs(Project *);
|
||||
void reactpipes(Project *, long);
|
||||
void reacttanks(Project *, long);
|
||||
double mixtank(Project *, int, double, double ,double);
|
||||
|
||||
// Imported Functions
|
||||
extern void addseg(EN_Project *pr, int, double, double);
|
||||
// Imported functions
|
||||
extern void addseg(Project *, int, double, double);
|
||||
|
||||
// Local Functions
|
||||
static double piperate(EN_Project *pr, int);
|
||||
static double pipereact(EN_Project *pr, int, double, double, long);
|
||||
static double tankreact(EN_Project *pr, double, double, double, long);
|
||||
static double bulkrate(EN_Project *pr, double, double, double);
|
||||
static double wallrate(EN_Project *pr, double, double, double, double);
|
||||
// Local functions
|
||||
static double piperate(Project *, int);
|
||||
static double pipereact(Project *, int, double, double, long);
|
||||
static double tankreact(Project *, double, double, double, long);
|
||||
static double bulkrate(Project *, double, double, double);
|
||||
static double wallrate(Project *, double, double, double, double);
|
||||
|
||||
static void tankmix1(EN_Project *pr, int, double, double, double);
|
||||
static void tankmix2(EN_Project *pr, int, double, double, double);
|
||||
static void tankmix3(EN_Project *pr, int, double, double, double);
|
||||
static void tankmix4(EN_Project *pr, int, double, double, double);
|
||||
static void tankmix1(Project *, int, double, double, double);
|
||||
static void tankmix2(Project *, int, double, double, double);
|
||||
static void tankmix3(Project *, int, double, double, double);
|
||||
static void tankmix4(Project *, int, double, double, double);
|
||||
|
||||
|
||||
char setreactflag(EN_Project *pr)
|
||||
char setreactflag(Project *pr)
|
||||
/*
|
||||
**-----------------------------------------------------------
|
||||
** Input: none
|
||||
@@ -43,8 +48,8 @@ char setreactflag(EN_Project *pr)
|
||||
**-----------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
int i;
|
||||
EN_Network *net = &pr->network;
|
||||
|
||||
if (pr->quality.Qualflag == TRACE) return 0;
|
||||
else if (pr->quality.Qualflag == AGE) return 1;
|
||||
@@ -82,7 +87,7 @@ double getucf(double order)
|
||||
}
|
||||
|
||||
|
||||
void ratecoeffs(EN_Project *pr)
|
||||
void ratecoeffs(Project *pr)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
@@ -91,12 +96,12 @@ void ratecoeffs(EN_Project *pr)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Quality *qual = &pr->quality;
|
||||
|
||||
int k;
|
||||
double kw;
|
||||
|
||||
EN_Network *net = &pr->network;
|
||||
quality_t *qual = &pr->quality;
|
||||
|
||||
for (k = 1; k <= net->Nlinks; k++)
|
||||
{
|
||||
kw = net->Link[k].Kw;
|
||||
@@ -107,7 +112,7 @@ void ratecoeffs(EN_Project *pr)
|
||||
}
|
||||
|
||||
|
||||
void reactpipes(EN_Project *pr, long dt)
|
||||
void reactpipes(Project *pr, long dt)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: dt = time step
|
||||
@@ -116,13 +121,13 @@ void reactpipes(EN_Project *pr, long dt)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Quality *qual = &pr->quality;
|
||||
|
||||
int k;
|
||||
Pseg seg;
|
||||
double cseg, rsum, vsum;
|
||||
|
||||
EN_Network *net = &pr->network;
|
||||
quality_t *qual = &pr->quality;
|
||||
|
||||
// Examine each link in network
|
||||
for (k = 1; k <= net->Nlinks; k++)
|
||||
{
|
||||
@@ -140,7 +145,7 @@ void reactpipes(EN_Project *pr, long dt)
|
||||
seg->c = pipereact(pr, k, seg->c, seg->v, dt);
|
||||
|
||||
// Update reaction component of mass balance
|
||||
qual->massbalance.reacted += (cseg - seg->c) * seg->v;
|
||||
qual->MassBalance.reacted += (cseg - seg->c) * seg->v;
|
||||
|
||||
// Accumulate volume-weighted reaction rate
|
||||
if (qual->Qualflag == CHEM)
|
||||
@@ -158,7 +163,7 @@ void reactpipes(EN_Project *pr, long dt)
|
||||
}
|
||||
|
||||
|
||||
void reacttanks(EN_Project *pr, long dt)
|
||||
void reacttanks(Project *pr, long dt)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: dt = time step
|
||||
@@ -167,12 +172,12 @@ void reacttanks(EN_Project *pr, long dt)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Quality *qual = &pr->quality;
|
||||
|
||||
int i, k;
|
||||
double c;
|
||||
Pseg seg;
|
||||
|
||||
EN_Network *net = &pr->network;
|
||||
quality_t *qual = &pr->quality;
|
||||
Stank *tank;
|
||||
|
||||
// Examine each tank in network
|
||||
@@ -191,14 +196,14 @@ void reacttanks(EN_Project *pr, long dt)
|
||||
{
|
||||
c = seg->c;
|
||||
seg->c = tankreact(pr, seg->c, seg->v, tank->Kb, dt);
|
||||
qual->massbalance.reacted += (c - seg->c) * seg->v;
|
||||
qual->MassBalance.reacted += (c - seg->c) * seg->v;
|
||||
seg = seg->prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
double piperate(EN_Project *pr, int k)
|
||||
double piperate(Project *pr, int k)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: k = link index
|
||||
@@ -209,11 +214,11 @@ double piperate(EN_Project *pr, int k)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
double a, d, u, q, kf, kw, y, Re, Sh;
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Quality *qual = &pr->quality;
|
||||
|
||||
EN_Network *net = &pr->network;
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
quality_t *qual = &pr->quality;
|
||||
double a, d, u, q, kf, kw, y, Re, Sh;
|
||||
|
||||
d = net->Link[k].Diam; // Pipe diameter, ft
|
||||
|
||||
@@ -226,7 +231,7 @@ double piperate(EN_Project *pr, int k)
|
||||
|
||||
// Compute Reynolds No.
|
||||
// Flow rate made consistent with how its saved to hydraulics file
|
||||
q = (hyd->LinkStatus[k] <= CLOSED) ? 0.0 : hyd->LinkFlows[k];
|
||||
q = (hyd->LinkStatus[k] <= CLOSED) ? 0.0 : hyd->LinkFlow[k];
|
||||
a = PI * d * d / 4.0; // pipe area
|
||||
u = fabs(q) / a; // flow velocity
|
||||
Re = u * d / hyd->Viscos; // Reynolds number
|
||||
@@ -258,7 +263,7 @@ double piperate(EN_Project *pr, int k)
|
||||
}
|
||||
|
||||
|
||||
double pipereact(EN_Project *pr, int k, double c, double v, long dt)
|
||||
double pipereact(Project *pr, int k, double c, double v, long dt)
|
||||
/*
|
||||
**------------------------------------------------------------
|
||||
** Input: k = link index
|
||||
@@ -271,10 +276,10 @@ double pipereact(EN_Project *pr, int k, double c, double v, long dt)
|
||||
**------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
double cnew, dc, dcbulk, dcwall, rbulk, rwall;
|
||||
Network *net = &pr->network;
|
||||
Quality *qual = &pr->quality;
|
||||
|
||||
EN_Network *net = &pr->network;
|
||||
quality_t *qual = &pr->quality;
|
||||
double cnew, dc, dcbulk, dcwall, rbulk, rwall;
|
||||
|
||||
// For water age (hrs), update concentration by timestep
|
||||
if (qual->Qualflag == AGE)
|
||||
@@ -294,7 +299,7 @@ double pipereact(EN_Project *pr, int k, double c, double v, long dt)
|
||||
dcwall = rwall * (double)dt;
|
||||
|
||||
// Update cumulative mass reacted
|
||||
if (pr->time_options.Htime >= pr->time_options.Rstart)
|
||||
if (pr->times.Htime >= pr->times.Rstart)
|
||||
{
|
||||
qual->Wbulk += fabs(dcbulk) * v;
|
||||
qual->Wwall += fabs(dcwall) * v;
|
||||
@@ -308,7 +313,7 @@ double pipereact(EN_Project *pr, int k, double c, double v, long dt)
|
||||
}
|
||||
|
||||
|
||||
double tankreact(EN_Project *pr, double c, double v, double kb, long dt)
|
||||
double tankreact(Project *pr, double c, double v, double kb, long dt)
|
||||
/*
|
||||
**-------------------------------------------------------
|
||||
** Input: c = current quality in tank
|
||||
@@ -321,8 +326,9 @@ double tankreact(EN_Project *pr, double c, double v, double kb, long dt)
|
||||
**-------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Quality *qual = &pr->quality;
|
||||
|
||||
double cnew, dc, rbulk;
|
||||
quality_t *qual = &pr->quality;
|
||||
|
||||
// For water age, update concentration by timestep
|
||||
if (qual->Qualflag == AGE)
|
||||
@@ -338,7 +344,7 @@ double tankreact(EN_Project *pr, double c, double v, double kb, long dt)
|
||||
|
||||
// Find concentration change & update quality
|
||||
dc = rbulk * (double)dt;
|
||||
if (pr->time_options.Htime >= pr->time_options.Rstart)
|
||||
if (pr->times.Htime >= pr->times.Rstart)
|
||||
{
|
||||
qual->Wtank += fabs(dc) * v;
|
||||
}
|
||||
@@ -349,7 +355,7 @@ double tankreact(EN_Project *pr, double c, double v, double kb, long dt)
|
||||
}
|
||||
|
||||
|
||||
double bulkrate(EN_Project *pr, double c, double kb, double order)
|
||||
double bulkrate(Project *pr, double c, double kb, double order)
|
||||
/*
|
||||
**-----------------------------------------------------------
|
||||
** Input: c = current WQ concentration
|
||||
@@ -360,8 +366,9 @@ double bulkrate(EN_Project *pr, double c, double kb, double order)
|
||||
**-----------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Quality *qual = &pr->quality;
|
||||
|
||||
double c1;
|
||||
quality_t *qual = &pr->quality;
|
||||
|
||||
// Find bulk reaction potential taking into account
|
||||
// limiting potential & reaction order.
|
||||
@@ -396,7 +403,7 @@ double bulkrate(EN_Project *pr, double c, double kb, double order)
|
||||
}
|
||||
|
||||
|
||||
double wallrate(EN_Project *pr, double c, double d, double kw, double kf)
|
||||
double wallrate(Project *pr, double c, double d, double kw, double kf)
|
||||
/*
|
||||
**------------------------------------------------------------
|
||||
** Input: c = current WQ concentration
|
||||
@@ -410,7 +417,8 @@ double wallrate(EN_Project *pr, double c, double d, double kw, double kf)
|
||||
**------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
quality_t *qual = &pr->quality;
|
||||
Quality *qual = &pr->quality;
|
||||
|
||||
if (kw == 0.0 || d == 0.0) return (0.0);
|
||||
|
||||
if (qual->WallOrder == 0.0) // 0-order reaction */
|
||||
@@ -424,7 +432,7 @@ double wallrate(EN_Project *pr, double c, double d, double kw, double kf)
|
||||
}
|
||||
|
||||
|
||||
double mixtank(EN_Project *pr, int n, double volin, double massin, double volout)
|
||||
double mixtank(Project *pr, int n, double volin, double massin, double volout)
|
||||
/*
|
||||
**------------------------------------------------------------
|
||||
** Input: n = node index
|
||||
@@ -436,11 +444,11 @@ double mixtank(EN_Project *pr, int n, double volin, double massin, double volout
|
||||
**------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Quality *qual = &pr->quality;
|
||||
|
||||
int i;
|
||||
double vnet;
|
||||
EN_Network *net = &pr->network;
|
||||
quality_t *qual = &pr->quality;
|
||||
|
||||
i = n - net->Njuncs;
|
||||
vnet = volin - volout;
|
||||
switch (net->Tank[i].MixModel)
|
||||
@@ -454,7 +462,7 @@ double mixtank(EN_Project *pr, int n, double volin, double massin, double volout
|
||||
}
|
||||
|
||||
|
||||
void tankmix1(EN_Project *pr, int i, double vin, double win, double vnet)
|
||||
void tankmix1(Project *pr, int i, double vin, double win, double vnet)
|
||||
/*
|
||||
**---------------------------------------------
|
||||
** Input: i = tank index
|
||||
@@ -466,13 +474,13 @@ void tankmix1(EN_Project *pr, int i, double vin, double win, double vnet)
|
||||
**---------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Quality *qual = &pr->quality;
|
||||
|
||||
int k;
|
||||
double vnew;
|
||||
Pseg seg;
|
||||
|
||||
EN_Network *net = &pr->network;
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
quality_t *qual = &pr->quality;
|
||||
Stank *tank = &net->Tank[i];
|
||||
|
||||
k = net->Nlinks + i;
|
||||
@@ -488,7 +496,7 @@ void tankmix1(EN_Project *pr, int i, double vin, double win, double vnet)
|
||||
}
|
||||
|
||||
|
||||
void tankmix2(EN_Project *pr, int i, double vin, double win, double vnet)
|
||||
void tankmix2(Project *pr, int i, double vin, double win, double vnet)
|
||||
/*
|
||||
**------------------------------------------------
|
||||
** Input: i = tank index
|
||||
@@ -500,14 +508,14 @@ void tankmix2(EN_Project *pr, int i, double vin, double win, double vnet)
|
||||
**------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Quality *qual = &pr->quality;
|
||||
|
||||
int k;
|
||||
double vt, // Transferred volume
|
||||
vmz; // Full mixing zone volume
|
||||
Pseg mixzone, // Mixing zone segment
|
||||
stagzone; // Stagnant zone segment
|
||||
|
||||
EN_Network *net = &pr->network;
|
||||
quality_t *qual = &pr->quality;
|
||||
Stank *tank = &pr->network.Tank[i];
|
||||
|
||||
// Identify segments for each compartment
|
||||
@@ -568,7 +576,7 @@ void tankmix2(EN_Project *pr, int i, double vin, double win, double vnet)
|
||||
}
|
||||
|
||||
|
||||
void tankmix3(EN_Project *pr, int i, double vin, double win, double vnet)
|
||||
void tankmix3(Project *pr, int i, double vin, double win, double vnet)
|
||||
/*
|
||||
**----------------------------------------------------------
|
||||
** Input: i = tank index
|
||||
@@ -580,14 +588,14 @@ void tankmix3(EN_Project *pr, int i, double vin, double win, double vnet)
|
||||
**----------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Quality *qual = &pr->quality;
|
||||
|
||||
int k;
|
||||
double vout, vseg;
|
||||
double cin, vsum, wsum;
|
||||
Pseg seg;
|
||||
|
||||
EN_Network *net = &pr->network;
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
quality_t *qual = &pr->quality;
|
||||
Stank *tank = &pr->network.Tank[i];
|
||||
|
||||
k = net->Nlinks + i;
|
||||
@@ -639,7 +647,7 @@ void tankmix3(EN_Project *pr, int i, double vin, double win, double vnet)
|
||||
}
|
||||
|
||||
|
||||
void tankmix4(EN_Project *pr, int i, double vin, double win, double vnet)
|
||||
void tankmix4(Project *pr, int i, double vin, double win, double vnet)
|
||||
/*
|
||||
**----------------------------------------------------------
|
||||
** Input: i = tank index
|
||||
@@ -651,12 +659,12 @@ void tankmix4(EN_Project *pr, int i, double vin, double win, double vnet)
|
||||
**----------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Quality *qual = &pr->quality;
|
||||
|
||||
int k, n;
|
||||
double cin, vsum, wsum, vseg;
|
||||
Pseg seg;
|
||||
|
||||
EN_Network *net = &pr->network;
|
||||
quality_t *qual = &pr->quality;
|
||||
Stank *tank = &pr->network.Tank[i];
|
||||
|
||||
k = net->Nlinks + i;
|
||||
|
||||
278
src/qualroute.c
278
src/qualroute.c
@@ -1,46 +1,55 @@
|
||||
/*
|
||||
*********************************************************************
|
||||
|
||||
QUALROUTE.C -- water quality routing module for the EPANET program
|
||||
|
||||
*********************************************************************
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Module: qualroute.c
|
||||
Description: computes water quality transport over a single time step
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 11/27/2018
|
||||
******************************************************************************
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#ifndef __APPLE__
|
||||
#include <malloc.h>
|
||||
#else
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#include <math.h>
|
||||
#include "mempool.h"
|
||||
#include "types.h"
|
||||
|
||||
// Macro to compute the volume of a link
|
||||
#define LINKVOL(k) (0.785398 * net->Link[(k)].Len * SQR(net->Link[(k)].Diam))
|
||||
|
||||
// Macro to get link flow compatible with flow saved to hydraulics file
|
||||
#define LINKFLOW(k) ((hyd->LinkStatus[k] <= CLOSED) ? 0.0 : hyd->LinkFlows[k])
|
||||
#define LINKFLOW(k) ((hyd->LinkStatus[k] <= CLOSED) ? 0.0 : hyd->LinkFlow[k])
|
||||
|
||||
// Exported Functions
|
||||
int buildilists(EN_Project *pr);
|
||||
int sortnodes(EN_Project *pr);
|
||||
void transport(EN_Project *pr, long);
|
||||
void initsegs(EN_Project *pr);
|
||||
void reversesegs(EN_Project *pr, int);
|
||||
void addseg(EN_Project *pr, int, double, double);
|
||||
// Exported functions
|
||||
int sortnodes(Project *);
|
||||
void transport(Project *, long);
|
||||
void initsegs(Project *);
|
||||
void reversesegs(Project *, int);
|
||||
void addseg(Project *, int, double, double);
|
||||
|
||||
// Imported Functions
|
||||
extern double findsourcequal(EN_Project *pr, int, double, double, long);
|
||||
extern void reactpipes(EN_Project *pr, long);
|
||||
extern void reacttanks(EN_Project *pr, long);
|
||||
extern double mixtank(EN_Project *pr, int, double, double, double);
|
||||
// Imported functions
|
||||
extern double findsourcequal(Project *, int, double, double, long);
|
||||
extern void reactpipes(Project *, long);
|
||||
extern void reacttanks(Project *, long);
|
||||
extern double mixtank(Project *, int, double, double, double);
|
||||
|
||||
// Local Functions
|
||||
static void evalnodeinflow(EN_Project *pr, int, long, double *, double *);
|
||||
static void evalnodeoutflow(EN_Project *pr, int, double, long);
|
||||
static double findnodequal(EN_Project *pr, int, double, double, double, long);
|
||||
static double noflowqual(EN_Project *pr, int);
|
||||
static void updatemassbalance(EN_Project *pr, int, double, double, long);
|
||||
static int selectnonstacknode(EN_Project *pr, int, int *);
|
||||
// Local functions
|
||||
static void evalnodeinflow(Project *, int, long, double *, double *);
|
||||
static void evalnodeoutflow(Project *, int, double, long);
|
||||
static double findnodequal(Project *, int, double, double, double, long);
|
||||
static double noflowqual(Project *, int);
|
||||
static void updatemassbalance(Project *, int, double, double, long);
|
||||
static int selectnonstacknode(Project *, int, int *);
|
||||
|
||||
|
||||
void transport(EN_Project *pr, long tstep)
|
||||
void transport(Project *pr, long tstep)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: tstep = length of current time step
|
||||
@@ -50,12 +59,13 @@ void transport(EN_Project *pr, long tstep)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i, j, k, m, n;
|
||||
double volin, massin, volout, nodequal;
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Quality *qual = &pr->quality;
|
||||
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
quality_t *qual = &pr->quality;
|
||||
EN_Network *net = &pr->network;
|
||||
int j, k, m, n;
|
||||
double volin, massin, volout, nodequal;
|
||||
Padjlist alink;
|
||||
|
||||
// React contents of each pipe and tank
|
||||
if (qual->Reactflag)
|
||||
@@ -76,10 +86,10 @@ void transport(EN_Project *pr, long tstep)
|
||||
volout = 0.0;
|
||||
|
||||
// ... examine each link with flow into the node
|
||||
for (i = qual->IlistPtr[n]; i < qual->IlistPtr[n + 1]; i++)
|
||||
for (alink = net->Adjlist[n]; alink != NULL; alink = alink->next)
|
||||
{
|
||||
// ... k is index of next link incident on node n
|
||||
k = qual->Ilist[i];
|
||||
k = alink->link;
|
||||
|
||||
// ... link has flow into node - add it to node's inflow
|
||||
// (m is index of link's downstream node)
|
||||
@@ -107,10 +117,10 @@ void transport(EN_Project *pr, long tstep)
|
||||
nodequal = findnodequal(pr, n, volin, massin, volout, tstep);
|
||||
|
||||
// ... examine each link with flow out of the node
|
||||
for (i = qual->IlistPtr[n]; i < qual->IlistPtr[n + 1]; i++)
|
||||
for (alink = net->Adjlist[n]; alink != NULL; alink = alink->next)
|
||||
{
|
||||
// ... link k incident on node n has upstream node m equal to n
|
||||
k = qual->Ilist[i];
|
||||
k = alink->link;
|
||||
m = net->Link[k].N1;
|
||||
if (qual->FlowDir[k] < 0) m = net->Link[k].N2;
|
||||
if (m == n)
|
||||
@@ -123,7 +133,7 @@ void transport(EN_Project *pr, long tstep)
|
||||
}
|
||||
}
|
||||
|
||||
void evalnodeinflow(EN_Project *pr, int k, long tstep, double *volin,
|
||||
void evalnodeinflow(Project *pr, int k, long tstep, double *volin,
|
||||
double *massin)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
@@ -137,13 +147,13 @@ void evalnodeinflow(EN_Project *pr, int k, long tstep, double *volin,
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Quality *qual = &pr->quality;
|
||||
|
||||
double q, v, vseg;
|
||||
Pseg seg;
|
||||
|
||||
EN_Network *net = &pr->network;
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
quality_t *qual = &pr->quality;
|
||||
|
||||
// Get flow rate (q) and flow volume (v) through link
|
||||
q = LINKFLOW(k);
|
||||
v = fabs(q) * tstep;
|
||||
@@ -185,7 +195,7 @@ void evalnodeinflow(EN_Project *pr, int k, long tstep, double *volin,
|
||||
}
|
||||
|
||||
|
||||
double findnodequal(EN_Project *pr, int n, double volin,
|
||||
double findnodequal(Project *pr, int n, double volin,
|
||||
double massin, double volout, long tstep)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
@@ -200,9 +210,9 @@ double findnodequal(EN_Project *pr, int n, double volin,
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
EN_Network *net = &pr->network;
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
quality_t *qual = &pr->quality;
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Quality *qual = &pr->quality;
|
||||
|
||||
// Node is a junction - update its water quality
|
||||
if (net->Node[n].Type == JUNCTION)
|
||||
@@ -262,7 +272,7 @@ double findnodequal(EN_Project *pr, int n, double volin,
|
||||
}
|
||||
|
||||
|
||||
double noflowqual(EN_Project *pr, int n)
|
||||
double noflowqual(Project *pr, int n)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: n = node index
|
||||
@@ -274,19 +284,20 @@ double noflowqual(EN_Project *pr, int n)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i, k, inflow, kount = 0;
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Quality *qual = &pr->quality;
|
||||
|
||||
int k, inflow, kount = 0;
|
||||
double c = 0.0;
|
||||
FlowDirection dir;
|
||||
|
||||
EN_Network *net = &pr->network;
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
quality_t *qual = &pr->quality;
|
||||
Padjlist alink;
|
||||
|
||||
// Examine each link incident on the node
|
||||
for (i = qual->IlistPtr[n]; i < qual->IlistPtr[n + 1]; i++)
|
||||
for (alink = net->Adjlist[n]; alink != NULL; alink = alink->next)
|
||||
{
|
||||
// ... index of an incident link
|
||||
k = qual->Ilist[i];
|
||||
k = alink->link;
|
||||
dir = qual->FlowDir[k];
|
||||
|
||||
// Node n is link's downstream node - add quality
|
||||
@@ -313,7 +324,7 @@ double noflowqual(EN_Project *pr, int n)
|
||||
}
|
||||
|
||||
|
||||
void evalnodeoutflow(EN_Project *pr, int k, double c, long tstep)
|
||||
void evalnodeoutflow(Project *pr, int k, double c, long tstep)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: k = link index
|
||||
@@ -325,12 +336,12 @@ void evalnodeoutflow(EN_Project *pr, int k, double c, long tstep)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Quality *qual = &pr->quality;
|
||||
|
||||
double v;
|
||||
Pseg seg;
|
||||
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
quality_t *qual = &pr->quality;
|
||||
|
||||
// Find flow volume (v) released over time step
|
||||
v = fabs(LINKFLOW(k)) * tstep;
|
||||
if (v == 0.0) return;
|
||||
@@ -358,7 +369,7 @@ void evalnodeoutflow(EN_Project *pr, int k, double c, long tstep)
|
||||
}
|
||||
|
||||
|
||||
void updatemassbalance(EN_Project *pr, int n, double massin,
|
||||
void updatemassbalance(Project *pr, int n, double massin,
|
||||
double volout, long tstep)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
@@ -372,14 +383,13 @@ void updatemassbalance(EN_Project *pr, int n, double massin,
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Quality *qual = &pr->quality;
|
||||
|
||||
double masslost = 0.0,
|
||||
massadded = 0.0;
|
||||
|
||||
EN_Network *net = &pr->network;
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
quality_t *qual = &pr->quality;
|
||||
|
||||
|
||||
switch (net->Node[n].Type)
|
||||
{
|
||||
// Junctions lose mass from outflow demand & gain it from source inflow
|
||||
@@ -401,82 +411,12 @@ void updatemassbalance(EN_Project *pr, int n, double massin,
|
||||
massadded = qual->SourceQual * volout;
|
||||
break;
|
||||
}
|
||||
qual->massbalance.outflow += masslost;
|
||||
qual->massbalance.inflow += massadded;
|
||||
qual->MassBalance.outflow += masslost;
|
||||
qual->MassBalance.inflow += massadded;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int buildilists(EN_Project *pr)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: returns an error code
|
||||
** Purpose: Creates link incidence lists for each node stored
|
||||
** in compact form.
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i, j, k, n, n1, n2;
|
||||
int *degree = NULL;
|
||||
|
||||
quality_t *qual = &pr->quality;
|
||||
EN_Network *net = &pr->network;
|
||||
|
||||
// Allocate an array to count # links incident on each node
|
||||
n = net->Nnodes + 1;
|
||||
degree = (int *)calloc(n, sizeof(int));
|
||||
if (degree == NULL) return 101;
|
||||
|
||||
// Count # links incident on each node
|
||||
for (k = 1; k <= net->Nlinks; k++)
|
||||
{
|
||||
degree[net->Link[k].N1]++;
|
||||
degree[net->Link[k].N2]++;
|
||||
}
|
||||
|
||||
// Use incidence counts to determine start position of
|
||||
// each node's incidence list in Xilist
|
||||
qual->IlistPtr[1] = 1;
|
||||
for (i = 1; i <= n; i++)
|
||||
{
|
||||
qual->IlistPtr[i + 1] = qual->IlistPtr[i] + degree[i];
|
||||
}
|
||||
|
||||
// Add each link to the incidence lists of its start & end nodes
|
||||
for (i = 1; i <= net->Nnodes; i++) degree[i] = 0;
|
||||
for (k = 1; k <= net->Nlinks; k++)
|
||||
{
|
||||
// j is index of next unused location in link's start node list
|
||||
n1 = net->Link[k].N1;
|
||||
j = qual->IlistPtr[n1] + degree[n1];
|
||||
qual->Ilist[j] = k;
|
||||
degree[n1]++;
|
||||
|
||||
// Repeat same for end node
|
||||
n2 = net->Link[k].N2;
|
||||
j = qual->IlistPtr[n2] + degree[n2];
|
||||
qual->Ilist[j] = k;
|
||||
degree[n2]++;
|
||||
}
|
||||
free(degree);
|
||||
|
||||
/*//////// QA CHECK
|
||||
for (i = 1; i <= net->Nnodes; i++)
|
||||
{
|
||||
printf("\nNode %s: ", net->Node[i].ID);
|
||||
for (j = qual->IlistPtr[i]; j < qual->IlistPtr[i + 1]; j++)
|
||||
{
|
||||
printf(" %s,", net->Link[qual->Ilist[j]].ID);
|
||||
}
|
||||
}
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int sortnodes(EN_Project *pr)
|
||||
int sortnodes(Project *pr)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
@@ -487,6 +427,10 @@ int sortnodes(EN_Project *pr)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Quality *qual = &pr->quality;
|
||||
|
||||
int i, j, k, n;
|
||||
int *indegree = NULL;
|
||||
int *stack = NULL;
|
||||
@@ -494,10 +438,7 @@ int sortnodes(EN_Project *pr)
|
||||
int numsorted = 0;
|
||||
int errcode = 0;
|
||||
FlowDirection dir;
|
||||
|
||||
EN_Network *net = &pr->network;
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
quality_t *qual = &pr->quality;
|
||||
Padjlist alink;
|
||||
|
||||
// Allocate an array to count # links with inflow to each node
|
||||
// and for a stack to hold nodes waiting to be processed
|
||||
@@ -548,10 +489,10 @@ int sortnodes(EN_Project *pr)
|
||||
|
||||
// ... for each outflow link from this node reduce the in-degree
|
||||
// of its downstream node
|
||||
for (j = qual->IlistPtr[i]; j < qual->IlistPtr[i + 1]; j++)
|
||||
for (alink = net->Adjlist[i]; alink != NULL; alink = alink->next)
|
||||
{
|
||||
// ... k is the index of the next link incident on node i
|
||||
k = qual->Ilist[j];
|
||||
k = alink->link;
|
||||
|
||||
// ... skip link if flow is negligible
|
||||
if (qual->FlowDir[k] == 0) continue;
|
||||
@@ -579,25 +520,11 @@ int sortnodes(EN_Project *pr)
|
||||
if (numsorted < net->Nnodes) errcode = 120;
|
||||
FREE(indegree);
|
||||
FREE(stack);
|
||||
/*
|
||||
/////////////////// QA CHECK
|
||||
snprintf(pr->Msg, MAXMSG, "\n\nSorted Nodes:");
|
||||
writeline(pr, pr->Msg);
|
||||
for (i = 1; i <= net->Nnodes; i++)
|
||||
{
|
||||
j = qual->SortedNodes[i];
|
||||
snprintf(pr->Msg, MAXMSG, "%s", net->Node[j].ID);
|
||||
writeline(pr, pr->Msg);
|
||||
}
|
||||
//printf("\n");
|
||||
//system("pause");
|
||||
/////////////////
|
||||
*/
|
||||
return errcode;
|
||||
}
|
||||
|
||||
|
||||
int selectnonstacknode(EN_Project *pr, int numsorted, int *indegree)
|
||||
int selectnonstacknode(Project *pr, int numsorted, int *indegree)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: numsorted = number of nodes that have been sorted
|
||||
@@ -607,24 +534,21 @@ int selectnonstacknode(EN_Project *pr, int numsorted, int *indegree)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
int i, j, k, m, n;
|
||||
Network *net = &pr->network;
|
||||
Quality *qual = &pr->quality;
|
||||
|
||||
quality_t *qual = &pr->quality;
|
||||
EN_Network *net = &pr->network;
|
||||
int i, m, n;
|
||||
Padjlist alink;
|
||||
|
||||
// Examine each sorted node in last in - first out order
|
||||
for (i = numsorted; i > 0; i--)
|
||||
{
|
||||
// For each link connected to the sorted node
|
||||
m = qual->SortedNodes[i];
|
||||
for (j = qual->IlistPtr[m]; j < qual->IlistPtr[m + 1]; j++)
|
||||
for (alink = net->Adjlist[m]; alink != NULL; alink = alink->next)
|
||||
{
|
||||
// ... k is index of next link incident on node m
|
||||
k = qual->Ilist[j];
|
||||
|
||||
// ... n is the node of link k opposite to node m
|
||||
n = net->Link[k].N2;
|
||||
if (n == m) n = net->Link[k].N1;
|
||||
n = alink->node;
|
||||
|
||||
// ... select node n if it still has inflow links
|
||||
if (indegree[n] > 0) return n;
|
||||
@@ -643,7 +567,7 @@ int selectnonstacknode(EN_Project *pr, int numsorted, int *indegree)
|
||||
}
|
||||
|
||||
|
||||
void initsegs(EN_Project *pr)
|
||||
void initsegs(Project *pr)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
@@ -653,13 +577,13 @@ void initsegs(EN_Project *pr)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
Quality *qual = &pr->quality;
|
||||
|
||||
int j, k;
|
||||
double c, v, v1;
|
||||
|
||||
EN_Network *net = &pr->network;
|
||||
hydraulics_t *hyd = &pr->hydraulics;
|
||||
quality_t *qual = &pr->quality;
|
||||
|
||||
// Add one segment with assigned downstream node quality to each pipe
|
||||
for (k = 1; k <= net->Nlinks; k++)
|
||||
{
|
||||
@@ -706,7 +630,7 @@ void initsegs(EN_Project *pr)
|
||||
}
|
||||
|
||||
|
||||
void reversesegs(EN_Project *pr, int k)
|
||||
void reversesegs(Project *pr, int k)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: k = link index
|
||||
@@ -715,8 +639,8 @@ void reversesegs(EN_Project *pr, int k)
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Quality *qual = &pr->quality;
|
||||
Pseg seg, nseg, pseg;
|
||||
quality_t *qual = &pr->quality;
|
||||
|
||||
seg = qual->FirstSeg[k];
|
||||
qual->FirstSeg[k] = qual->LastSeg[k];
|
||||
@@ -732,7 +656,7 @@ void reversesegs(EN_Project *pr, int k)
|
||||
}
|
||||
|
||||
|
||||
void addseg(EN_Project *pr, int k, double v, double c)
|
||||
void addseg(Project *pr, int k, double v, double c)
|
||||
/*
|
||||
**-------------------------------------------------------------
|
||||
** Input: k = segment chain index
|
||||
@@ -744,8 +668,8 @@ void addseg(EN_Project *pr, int k, double v, double c)
|
||||
**-------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Quality *qual = &pr->quality;
|
||||
Pseg seg;
|
||||
quality_t *qual = &pr->quality;
|
||||
|
||||
// Grab the next free segment from the segment pool if available
|
||||
if (qual->FreeSeg != NULL)
|
||||
|
||||
1239
src/report.c
1239
src/report.c
File diff suppressed because it is too large
Load Diff
1204
src/rules.c
1204
src/rules.c
File diff suppressed because it is too large
Load Diff
668
src/smatrix.c
668
src/smatrix.c
File diff suppressed because it is too large
Load Diff
72
src/text.h
72
src/text.h
@@ -1,22 +1,21 @@
|
||||
/*
|
||||
****************************************************
|
||||
|
||||
String Constants for EPANET Program
|
||||
|
||||
VERSION: 2.00
|
||||
DATE: 5/8/00
|
||||
10/25/00
|
||||
8/15/07 (2.00.11)
|
||||
2/14/08 (2.00.12)
|
||||
AUTHOR: L. Rossman
|
||||
US EPA - NRMRL
|
||||
|
||||
****************************************************
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Module: text.h
|
||||
Description: string constants used throughout EPANET
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 11/27/2018
|
||||
******************************************************************************
|
||||
*/
|
||||
/* ------------ Keyword Dictionary ---------- */
|
||||
|
||||
#ifndef TEXT_H
|
||||
#define TEXT_H
|
||||
|
||||
//------- Keyword Dictionary ------------------------------
|
||||
|
||||
#define w_USE "USE"
|
||||
#define w_SAVE "SAVE"
|
||||
|
||||
@@ -194,7 +193,8 @@ AUTHOR: L. Rossman
|
||||
#define w_ELSE "ELSE"
|
||||
#define w_PRIORITY "PRIO"
|
||||
|
||||
/* ---------Input Section Names ---------- */
|
||||
// ------ Input File Section Names ------------------------
|
||||
|
||||
#define s_TITLE "[TITLE]"
|
||||
#define s_JUNCTIONS "[JUNCTIONS]"
|
||||
#define s_RESERVOIRS "[RESERVOIRS]"
|
||||
@@ -225,8 +225,8 @@ AUTHOR: L. Rossman
|
||||
#define s_TAGS "[TAGS]"
|
||||
#define s_END "[END]"
|
||||
|
||||
/* ---------------- Units ---------------- */
|
||||
/*** Limit units to MAXID or less characters ***/
|
||||
//------- Units -------------------------------------------
|
||||
|
||||
#define u_CFS "cfs"
|
||||
#define u_GPM "gpm"
|
||||
#define u_AFD "a-f/d"
|
||||
@@ -257,13 +257,15 @@ AUTHOR: L. Rossman
|
||||
#define u_per1000FT "/1000ft"
|
||||
#define u_HP "hp"
|
||||
|
||||
/* -------------- Curve Types ----------------- */
|
||||
//------- Curve Types -------------------------------------
|
||||
|
||||
#define c_HEADLOSS "HEADLOSS"
|
||||
#define c_PUMP "PUMP"
|
||||
#define c_EFFIC "EFFIC"
|
||||
#define c_VOLUME "VOLUME"
|
||||
|
||||
/* ------------------ Text Phrases ------------------- */
|
||||
//------- Text Phrases ------------------------------------
|
||||
|
||||
#define t_ABOVE "above"
|
||||
#define t_BELOW "below"
|
||||
#define t_HW "Hazen-Williams"
|
||||
@@ -334,7 +336,8 @@ AUTHOR: L. Rossman
|
||||
#define t_ORIFICE "Orifice Flow"
|
||||
|
||||
|
||||
/* ------------------ Format Messages ------------------*/
|
||||
//----- Summary Report Format Strings ---------------------
|
||||
|
||||
#define LOGO1 \
|
||||
"******************************************************************"
|
||||
#define LOGO2 \
|
||||
@@ -399,10 +402,9 @@ AUTHOR: L. Rossman
|
||||
#define FMT47 " with %s below %-.2f %s"
|
||||
#define FMT48 " with %s above %-.2f %s"
|
||||
|
||||
/* ---------- Status Report Format Strings ------------ */
|
||||
#define FMT49 "Hydraulic Status:"
|
||||
//----- Status Report Format Strings ----------------------
|
||||
|
||||
/*** Updated 6/24/02 ***/
|
||||
#define FMT49 "Hydraulic Status:"
|
||||
#define FMT50 "%10s: Tank %s is %s at %-.2f %s"
|
||||
#define FMT51 "%10s: Reservoir %s is %s"
|
||||
#define FMT52 "%10s: %s %s %s"
|
||||
@@ -422,13 +424,12 @@ AUTHOR: L. Rossman
|
||||
#define FMT63 "%10s: %s %s changed by rule %s"
|
||||
#define FMT64 "%10s: Balancing the network:\n"
|
||||
#define FMT65 " Trial %2d: relative flow change = %-.6f"
|
||||
/*** End of update ***/
|
||||
|
||||
#define FMT66 " maximum flow change = %.4f for Link %s"
|
||||
#define FMT67 " maximum flow change = %.4f for Node %s"
|
||||
#define FMT68 " maximum head error = %.4f for Link %s\n"
|
||||
|
||||
/* -------------------- Energy Report Table ------------------- */
|
||||
//----- Energy Report Table -------------------------------
|
||||
|
||||
#define FMT71 "Energy Usage:"
|
||||
#define FMT72 \
|
||||
" Usage Avg. Kw-hr Avg. Peak Cost"
|
||||
@@ -437,18 +438,21 @@ AUTHOR: L. Rossman
|
||||
#define FMT74 "%38s Demand Charge: %9.2f"
|
||||
#define FMT75 "%38s Total Cost: %9.2f"
|
||||
|
||||
/* -------------------- Node Report Table --------------------- */
|
||||
//----- Node Report Table ---------------------------------
|
||||
|
||||
#define FMT76 "%s Node Results:"
|
||||
#define FMT77 "Node Results:"
|
||||
#define FMT78 "Node Results at %s hrs:"
|
||||
|
||||
/* -------------------- Link Report Table --------------------- */
|
||||
//----- 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 ---------------------- */
|
||||
//----- Progress Messages ---------------------------------
|
||||
|
||||
#define FMT100 " Retrieving network data ... "
|
||||
#define FMT101 " Computing hydraulics at hour %-10s "
|
||||
#define FMT102 " Computing water quality at hour %-10s "
|
||||
@@ -457,16 +461,17 @@ AUTHOR: L. Rossman
|
||||
#define FMT104 "Analysis begun %s"
|
||||
#define FMT105 "Analysis ended %s"
|
||||
|
||||
/*------------------- Error Messages --------------------*/
|
||||
//----- Rule Error Messages -------------------------------
|
||||
|
||||
#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 -------------------------*/
|
||||
//----- Specific Warning Messages -------------------------
|
||||
|
||||
#define WARN01 "WARNING: System unbalanced at %s hrs."
|
||||
#define WARN02 \
|
||||
"WARNING: Maximum trials exceeded at %s hrs. System may be unstable."
|
||||
@@ -477,7 +482,8 @@ AUTHOR: L. Rossman
|
||||
#define WARN05 "WARNING: %s %s %s at %s hrs."
|
||||
#define WARN06 "WARNING: Negative pressures at %s hrs."
|
||||
|
||||
/*-------------------- General Warning Messages -------------------------*/
|
||||
//----- General Warning Messages --------------------------
|
||||
|
||||
#define WARN1 "WARNING: System hydraulically unbalanced."
|
||||
#define WARN2 "WARNING: System may be hydraulically unstable."
|
||||
#define WARN3 "WARNING: System disconnected."
|
||||
|
||||
1231
src/types.h
1231
src/types.h
File diff suppressed because it is too large
Load Diff
@@ -21,9 +21,9 @@ Find /i "x86" < checkOS.tmp > StringCheck.tmp
|
||||
If %ERRORLEVEL% == 1 (
|
||||
CALL "%SDK_PATH%bin\"SetEnv.cmd /x64 /release
|
||||
rem : create EPANET2.DLL
|
||||
cl -o epanet2.dll epanet.c util\errormanager.c hash.c hydraul.c hydcoeffs.c hydstatus.c hydsolver.c inpfile.c input1.c input2.c input3.c mempool.c output.c quality.c qualroute.c qualreact.c report.c rules.c smatrix.c genmmd.c /I ..\include /I ..\run /link /DLL
|
||||
cl -o epanet2.dll epanet.c hash.c hydraul.c hydcoeffs.c hydstatus.c hydsolver.c inpfile.c input1.c input2.c input3.c mempool.c output.c project.c quality.c qualroute.c qualreact.c report.c rules.c smatrix.c genmmd.c /I ..\include /I ..\run /link /DLL
|
||||
rem : create EPANET2.EXE
|
||||
cl -o epanet2.exe epanet.c util\errormanager.c ..\run\main.c hash.c hydraul.c hydcoeffs.c hydstatus.c hydsolver.c inpfile.c input1.c input2.c input3.c mempool.c output.c quality.c qualroute.c qualreact.c report.c rules.c smatrix.c genmmd.c /I ..\include /I ..\run /I ..\src /link
|
||||
cl -o epanet2.exe epanet.c ..\run\main.c hash.c hydraul.c hydcoeffs.c hydstatus.c hydsolver.c inpfile.c input1.c input2.c input3.c mempool.c output.c project.c quality.c qualroute.c qualreact.c report.c rules.c smatrix.c genmmd.c /I ..\include /I ..\run /I ..\src /link
|
||||
md "%Build_PATH%"\64bit
|
||||
move /y "%SRC_PATH%"\*.dll "%Build_PATH%"\64bit
|
||||
move /y "%SRC_PATH%"\*.exe "%Build_PATH%"\64bit
|
||||
@@ -35,9 +35,9 @@ rem : 32 bit with DEF
|
||||
CALL "%SDK_PATH%bin\"SetEnv.cmd /x86 /release
|
||||
echo "32 bit with epanet2.def mapping"
|
||||
rem : create EPANET2.DLL
|
||||
cl -o epanet2.dll epanet.c util\errormanager.c hash.c hydraul.c hydcoeffs.c hydstatus.c hydsolver.c inpfile.c input1.c input2.c input3.c mempool.c output.c quality.c qualroute.c qualreact.c report.c rules.c smatrix.c genmmd.c /I ..\include /I ..\run /link /DLL /def:..\win_build\WinSDK\epanet2.def /MAP
|
||||
cl -o epanet2.dll epanet.c hash.c hydraul.c hydcoeffs.c hydstatus.c hydsolver.c inpfile.c input1.c input2.c input3.c mempool.c output.c project.c quality.c qualroute.c qualreact.c report.c rules.c smatrix.c genmmd.c /I ..\include /I ..\run /link /DLL /def:..\win_build\WinSDK\epanet2.def /MAP
|
||||
rem : create EPANET2.EXE
|
||||
cl -o epanet2.exe epanet.c util\errormanager.c ..\run\main.c hash.c hydraul.c hydcoeffs.c hydstatus.c hydsolver.c inpfile.c input1.c input2.c input3.c mempool.c output.c quality.c qualroute.c qualreact.c report.c rules.c smatrix.c genmmd.c /I ..\include /I ..\run /I ..\src /link
|
||||
cl -o epanet2.exe epanet.c ..\run\main.c hash.c hydraul.c hydcoeffs.c hydstatus.c hydsolver.c inpfile.c input1.c input2.c input3.c mempool.c output.c project.c quality.c qualroute.c qualreact.c report.c rules.c smatrix.c genmmd.c /I ..\include /I ..\run /I ..\src /link
|
||||
md "%Build_PATH%"\32bit
|
||||
move /y "%SRC_PATH%"\*.dll "%Build_PATH%"\32bit
|
||||
move /y "%SRC_PATH%"\*.exe "%Build_PATH%"\32bit
|
||||
|
||||
Reference in New Issue
Block a user