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:
Lew Rossman
2018-11-27 14:22:06 -05:00
parent 2988800448
commit 9a540cc0f4
29 changed files with 15140 additions and 15461 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +1,14 @@
/* /*
*********************************************************************** *****************************************************************************
Project: OWA EPANET
ENUMSTXT.H -- Text strings for enumerated data types in EPANET Version: 2.2
Module: enumstxt.h
VERSION: 2.00 Description: text strings for enumerated data types
DATE: 5/8/00 Authors: see AUTHORS
AUTHOR: L. Rossman Copyright: see AUTHORS
US EPA - NRMRL License: see LICENSE
Last Updated: 11/27/2018
********************************************************************** ******************************************************************************
*/ */
#ifndef ENUMSTXT_H #ifndef ENUMSTXT_H

File diff suppressed because it is too large Load Diff

View File

@@ -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(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(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(301,ENERR_FILES_ARE_SAME,"identical file names")
DAT(302,ENERR_CANT_OPEN_INP,"cannot open input file") 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(308,ENERR_CANT_SAVE_RES,"cannot save results to file")
DAT(309,ENERR_CANT_SAVE_RPT,"cannot save results to report 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(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(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") DAT(435,ENERR_RUN_TERMINATED,"run terminated; no results in binary file")

View File

@@ -1,227 +1,175 @@
/* /*
************************************************************************** ******************************************************************************
Project: OWA EPANET
FUNCS.H -- Function Prototypes for EPANET Program Version: 2.2
Module: funcs.h
VERSION: 2.00 Description: prototypes of external functions called by various modules
DATE: 5/8/00 Authors: see AUTHORS
9/25/00 Copyright: see AUTHORS
10/25/00 License: see LICENSE
12/29/00 Last Updated: 11/27/2018
3/1/01 ******************************************************************************
2/14/08 (2.00.12)
AUTHOR: L. Rossman
US EPA - NRMRL
**************************************************************************
*/ */
/*****************************************************************/
/* Most float arguments have been changed to double - 7/3/07 */
/*****************************************************************/
/* ------- EPANET.C --------------------*/
/*
** NOTE: The exportable functions that can be called
** via the DLL are prototyped in TOOLKIT.H.
*/
#ifndef FUNCS_H #ifndef FUNCS_H
#define FUNCS_H #define FUNCS_H
void initpointers(EN_Project *pr); /* Initializes pointers */ // ------- PROJECT.C ------------
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 */
int findnode(EN_Network *n, char *); /* Finds node's index from ID */ void initpointers(Project *);
int findlink(EN_Network *n, char *); /* Finds link's index from ID */ int allocdata(Project *);
int findtank(EN_Network *n, int); /* Find tank index from node index */ // (AH) void freeTmplist(STmplist *);
int findvalve(EN_Network *n, int); /* Find valve index from node index */ // (AH) void freeFloatlist(SFloatlist *);
int findpump(EN_Network *n, int); /* Find pump index from node index */ // (AH) void freedata(Project *);
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 */
/* ------- INPUT1.C --------------------*/ int openfiles(Project *, const char *, const char *,const char *);
int getdata(EN_Project *pr); /* Gets network data */ int openhydfile(Project *);
void setdefaults(EN_Project *pr); /* Sets default values */ int openoutfile(Project *);
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*/
/* -------- INPUT2.C -------------------*/ int buildadjlists(Network *);
int netsize(EN_Project *pr); /* Determines network size */ void freeadjlists(Network *);
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 */
/* ---------- INPUT3.C -----------------*/ int incontrols(Project *, int, int);
int juncdata(EN_Project *pr); /* Processes junction data */ int findnode(Network *, char *);
int tankdata(EN_Project *pr); /* Processes tank data */ int findlink(Network *, char *);
int pipedata(EN_Project *pr); /* Processes pipe data */ int findtank(Network *, int);
int pumpdata(EN_Project *pr); /* Processes pump data */ int findvalve(Network *, int);
int valvedata(EN_Project *pr); /* Processes valve data */ int findpump(Network *, int);
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 */
/* -------------- RULES.C --------------*/ char *getTmpName(char *);
void initrules(EN_Project *pr); /* Initializes rule base */ int strcomp(const char *, const char *);
void addrule(parser_data_t *par, char *); /* Adds rule to rule base */ double interp(int, double [], double [], double);
int allocrules(EN_Project *pr); /* Allocates memory for rule */ char *geterrmsg(int, char *);
void adjustrules(EN_Project *pr, int, int); // Shifts object indices down void errmsg(Project *, int);
void adjusttankrules(EN_Project *pr); // Shifts tank indices up void writewin(void (*vp)(char *), char *);
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
/* ------------- REPORT.C --------------*/ // ------- INPUT1.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 */
/* --------- HYDRAUL.C -----------------*/ int getdata(Project *);
int openhyd(EN_Project *pr); /* Opens hydraulics solver */ void setdefaults(Project *);
void inithyd(EN_Project *pr, int initFlags); /* Re-sets initial conditions */ void initreport(Report *);
int runhyd(EN_Project *pr, long *); /* Solves 1-period hydraulics */ void adjustdata(Project *);
int nexthyd(EN_Project *pr, long *); /* Moves to next time period */ int inittanks(Project *);
void closehyd(EN_Project *pr); /* Closes hydraulics solver */ void initunits(Project *);
void setlinkstatus(EN_Project *pr, int, char, void convertunits(Project *);
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. */
/* ----------- HYDSOLVER.C - ----------*/ //-------- INPUT2.C -----------------
int hydsolve(EN_Project *pr, int *,double *); /* Solves network equations */
/* ----------- HYDCOEFFS.C --------------*/ int netsize(Project *);
void resistcoeff(EN_Project *pr, int k); /* Finds pipe flow resistance */ int readdata(Project *);
void headlosscoeffs(EN_Project *pr); // Finds link head loss coeffs. int updatepumpparams(Project *, int);
void matrixcoeffs(EN_Project *pr); /* Finds hyd. matrix coeffs. */ int getpatterns(Project *);
void emitheadloss(EN_Project *pr, int, // Finds emitter head loss int getcurves(Project *);
double *, double *); int findmatch(char *, char *[]);
double demandflowchange(EN_Project *pr, int, // Change in demand outflow int match(const char *, const char *);
double, double); int gettokens(char *, char **, int, char *);
void demandparams(EN_Project *pr, double *, // PDA function parameters int getfloat(char *, double *);
double *); double hour(char *, char *);
int setreport(Project *, char *);
/* ----------- SMATRIX.C ---------------*/ // ------- INPUT3.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. */
/* ----------- QUALITY.C ---------------*/ int juncdata(Project *);
int openqual(EN_Project *pr); /* Opens WQ solver system */ int tankdata(Project *);
int initqual(EN_Project *pr); /* Initializes WQ solver */ int pipedata(Project *);
int runqual(EN_Project *pr, long *); /* Gets current WQ results */ int pumpdata(Project *);
int nextqual(EN_Project *pr, long *); /* Updates WQ by hyd.timestep */ int valvedata(Project *);
int stepqual(EN_Project *pr, long *); /* Updates WQ by WQ time step */ int patterndata(Project *);
int closequal(EN_Project *pr); /* Closes WQ solver system */ int curvedata(Project *);
double avgqual(EN_Project *pr, int); /* Finds avg. quality in pipe */ 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 ---------------*/ // ------- RULES.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 */
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 --------------*/ // ------- REPORT.C -----------------
int saveinpfile(EN_Project *pr, const char *); /* Saves network to text file */
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 #endif

View File

@@ -4,7 +4,6 @@
* *
*/ */
#include <math.h> #include <math.h>
int genmmd(int* neqns, int* xadj, int* adjncy, int* invp, int* perm, int genmmd(int* neqns, int* xadj, int* adjncy, int* invp, int* perm,

View File

@@ -1,20 +1,14 @@
/*----------------------------------------------------------------------------- /*
** hash.c ******************************************************************************
** Project: OWA EPANET
** Implementation of a simple Hash Table that uses a string as a key Version: 2.2
** and an associated integer as data. Module: hash.c
** Description: implementation of a simple hash table
** Written by L. Rossman Authors: see AUTHORS
** Last Updated on 10/19/18 Copyright: see AUTHORS
** License: see LICENSE
** Interface Functions: Last Updated: 11/27/2018
** 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
**
*/ */
#ifndef __APPLE__ #ifndef __APPLE__
@@ -27,6 +21,7 @@
#define HASHTABLEMAXSIZE 128000 #define HASHTABLEMAXSIZE 128000
// An entry in the hash table
typedef struct DataEntryStruct typedef struct DataEntryStruct
{ {
char *key; char *key;
@@ -34,6 +29,7 @@ typedef struct DataEntryStruct
struct DataEntryStruct *next; struct DataEntryStruct *next;
} DataEntry; } DataEntry;
// Hash a string to an integer
unsigned int gethash(char *str) unsigned int gethash(char *str)
{ {
unsigned int hash = 5381; unsigned int hash = 5381;
@@ -47,6 +43,7 @@ unsigned int gethash(char *str)
return retHash; return retHash;
} }
// Produce a duplicate string
char *dupstr(const char *s) char *dupstr(const char *s)
{ {
size_t size = strlen(s) + 1; size_t size = strlen(s) + 1;
@@ -55,6 +52,7 @@ char *dupstr(const char *s)
return p; return p;
} }
// Create a hash table
HashTable *hashtable_create() HashTable *hashtable_create()
{ {
int i; int i;
@@ -66,6 +64,7 @@ HashTable *hashtable_create()
return ht; return ht;
} }
// Insert an entry into the hash table
int hashtable_insert(HashTable *ht, char *key, int data) int hashtable_insert(HashTable *ht, char *key, int data)
{ {
unsigned int i = gethash(key); unsigned int i = gethash(key);
@@ -80,6 +79,7 @@ int hashtable_insert(HashTable *ht, char *key, int data)
return 1; return 1;
} }
// Change the hash table's data entry for a particular key
int hashtable_update(HashTable *ht, char *key, int new_data) int hashtable_update(HashTable *ht, char *key, int new_data)
{ {
unsigned int i = gethash(key); unsigned int i = gethash(key);
@@ -99,6 +99,7 @@ int hashtable_update(HashTable *ht, char *key, int new_data)
return NOTFOUND; return NOTFOUND;
} }
// Delete an entry in the hash table
int hashtable_delete(HashTable *ht, char *key) int hashtable_delete(HashTable *ht, char *key)
{ {
unsigned int i = gethash(key); unsigned int i = gethash(key);
@@ -124,6 +125,7 @@ int hashtable_delete(HashTable *ht, char *key)
return NOTFOUND; return NOTFOUND;
} }
// Find the data for a particular key
int hashtable_find(HashTable *ht, char *key) int hashtable_find(HashTable *ht, char *key)
{ {
unsigned int i = gethash(key); unsigned int i = gethash(key);
@@ -142,6 +144,7 @@ int hashtable_find(HashTable *ht, char *key)
return NOTFOUND; return NOTFOUND;
} }
// Find a particular key in the hash table
char *hashtable_findkey(HashTable *ht, char *key) char *hashtable_findkey(HashTable *ht, char *key)
{ {
unsigned int i = gethash(key); unsigned int i = gethash(key);
@@ -156,6 +159,7 @@ char *hashtable_findkey(HashTable *ht, char *key)
return NULL; return NULL;
} }
// Delete a hash table and free all of its memory
void hashtable_free(HashTable *ht) void hashtable_free(HashTable *ht)
{ {
DataEntry *entry, *nextentry; DataEntry *entry, *nextentry;

View File

@@ -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 #ifndef HASH_H
#define HASH_H #define HASH_H

View File

@@ -1,9 +1,14 @@
/* /*
********************************************************************* ******************************************************************************
Project: OWA EPANET
HYDCOEFFS.C -- hydraulic coefficients for the EPANET Program 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> #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 AB = 3.28895476345399058690e-03; // 5.74/(4000^.9)
const double AC = -5.14214965799093883760e-03; // AA*AB const double AC = -5.14214965799093883760e-03; // AA*AB
// External functions // Definitions of very small and very big coefficients
//void resistcoeff(EN_Project *pr, int k); const double CSMALL = 1.e-6;
//void headlosscoeffs(EN_Project *pr); const double CBIG = 1.e8;
//void matrixcoeffs(EN_Project *pr);
//void emitheadloss(EN_Project *pr, int i, double *hloss, double *dhdq); // Exported functions
//double demandflowchange(EN_Project *pr, int i, double dp, double n); //void resistcoeff(Project *, int );
//void demandparams(EN_Project *pr, double *dp, double *n); //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 // Local functions
static void linkcoeffs(EN_Project *pr); static void linkcoeffs(Project *pr);
static void nodecoeffs(EN_Project *pr); static void nodecoeffs(Project *pr);
static void valvecoeffs(EN_Project *pr); static void valvecoeffs(Project *pr);
static void emittercoeffs(EN_Project *pr); static void emittercoeffs(Project *pr);
static void demandcoeffs(EN_Project *pr); static void demandcoeffs(Project *pr);
static void demandheadloss(double d, double dfull, double dp, static void demandheadloss(double d, double dfull, double dp,
double n, double *hloss, double *hgrad); double n, double *hloss, double *hgrad);
static void pipecoeff(EN_Project *pr, int k); static void pipecoeff(Project *pr, int k);
static void DWpipecoeff(EN_Project *pr, int k); static void DWpipecoeff(Project *pr, int k);
static double frictionFactor(double q, double e, double s, double *dfdq); static double frictionFactor(double q, double e, double s, double *dfdq);
static void pumpcoeff(EN_Project *pr, int k); static void pumpcoeff(Project *pr, int k);
static void curvecoeff(EN_Project *pr, int i, double q, double *h0, double *r); static void curvecoeff(Project *pr, int i, double q, double *h0, double *r);
static void valvecoeff(EN_Project *pr, int k); static void valvecoeff(Project *pr, int k);
static void gpvcoeff(EN_Project *pr, int k); static void gpvcoeff(Project *pr, int k);
static void pbvcoeff(EN_Project *pr, int k); static void pbvcoeff(Project *pr, int k);
static void tcvcoeff(EN_Project *pr, int k); static void tcvcoeff(Project *pr, int k);
static void prvcoeff(EN_Project *pr, int k, int n1, int n2); static void prvcoeff(Project *pr, int k, int n1, int n2);
static void psvcoeff(EN_Project *pr, int k, int n1, int n2); static void psvcoeff(Project *pr, int k, int n1, int n2);
static void fcvcoeff(EN_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 ** 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; double e, d, L;
hydraulics_t *hyd = &pr->hydraulics;
Slink *link = &net->Link[k]; Slink *link = &net->Link[k];
link->Qa = 0.0; 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 ** Input: none
@@ -131,9 +140,10 @@ void headlosscoeffs(EN_Project *pr)
**-------------------------------------------------------------- **--------------------------------------------------------------
*/ */
{ {
Network *net = &pr->network;
Hydraul *hyd = &pr->hydraul;
int k; int k;
EN_Network *net = &pr->network;
hydraulics_t *hyd = &pr->hydraulics;
for (k = 1; k <= net->Nlinks; k++) for (k = 1; k <= net->Nlinks; k++)
{ {
@@ -159,13 +169,13 @@ void headlosscoeffs(EN_Project *pr)
case PRV: case PRV:
case PSV: case PSV:
if (hyd->LinkSetting[k] == MISSING) valvecoeff(pr, k); 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 ** Input: none
@@ -174,16 +184,16 @@ void matrixcoeffs(EN_Project *pr)
**-------------------------------------------------------------- **--------------------------------------------------------------
*/ */
{ {
hydraulics_t *hyd = &pr->hydraulics; Network *net = &pr->network;
solver_t *sol = &hyd->solver; Hydraul *hyd = &pr->hydraul;
EN_Network *net = &pr->network; Smatrix *sm = &hyd->smatrix;
// Reset values of all diagonal coeffs. (Aii), off-diagonal // Reset values of all diagonal coeffs. (Aii), off-diagonal
// coeffs. (Aij), r.h.s. coeffs. (F) and node flow balance (X_tmp) // coeffs. (Aij), r.h.s. coeffs. (F) and node excess flow (Xflow)
memset(sol->Aii, 0, (net->Nnodes + 1) * sizeof(double)); memset(sm->Aii, 0, (net->Nnodes + 1) * sizeof(double));
memset(sol->Aij, 0, (hyd->Ncoeffs + 1) * sizeof(double)); memset(sm->Aij, 0, (sm->Ncoeffs + 1) * sizeof(double));
memset(sol->F, 0, (net->Nnodes + 1) * sizeof(double)); memset(sm->F, 0, (net->Nnodes + 1) * sizeof(double));
memset(hyd->X_tmp, 0, (net->Nnodes + 1) * sizeof(double)); memset(hyd->Xflow, 0, (net->Nnodes + 1) * sizeof(double));
// Compute matrix coeffs. from links, emitters, and nodal demands // Compute matrix coeffs. from links, emitters, and nodal demands
linkcoeffs(pr); linkcoeffs(pr);
@@ -199,7 +209,7 @@ void matrixcoeffs(EN_Project *pr)
} }
void linkcoeffs(EN_Project *pr) void linkcoeffs(Project *pr)
/* /*
**-------------------------------------------------------------- **--------------------------------------------------------------
** Input: none ** 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; int k, n1, n2;
hydraulics_t *hyd = &pr->hydraulics;
solver_t *sol = &hyd->solver;
Slink *link; Slink *link;
// Examine each link of network // Examine each link of network
for (k = 1; k <= net->Nlinks; k++) 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]; link = &net->Link[k];
n1 = link->N1; // Start node of link n1 = link->N1; // Start node of link
n2 = link->N2; // End 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 (+)) // (Flow out of node is (-), flow into node is (+))
hyd->X_tmp[n1] -= hyd->LinkFlows[k]; hyd->Xflow[n1] -= hyd->LinkFlow[k];
hyd->X_tmp[n2] += hyd->LinkFlows[k]; hyd->Xflow[n2] += hyd->LinkFlow[k];
// Add to off-diagonal coeff. of linear system matrix // 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 // Update linear system coeffs. associated with start node n1
// ... node n1 is junction // ... node n1 is junction
if (n1 <= net->Njuncs) if (n1 <= net->Njuncs)
{ {
sol->Aii[sol->Row[n1]] += sol->P[k]; // Diagonal coeff. sm->Aii[sm->Row[n1]] += hyd->P[k]; // Diagonal coeff.
sol->F[sol->Row[n1]] += sol->Y[k]; // RHS coeff. sm->F[sm->Row[n1]] += hyd->Y[k]; // RHS coeff.
} }
// ... node n1 is a tank/reservoir // ... 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 // Update linear system coeffs. associated with end node n2
// ... node n2 is junction // ... node n2 is junction
if (n2 <= net->Njuncs) if (n2 <= net->Njuncs)
{ {
sol->Aii[sol->Row[n2]] += sol->P[k]; // Diagonal coeff. sm->Aii[sm->Row[n2]] += hyd->P[k]; // Diagonal coeff.
sol->F[sol->Row[n2]] -= sol->Y[k]; // RHS coeff. sm->F[sm->Row[n2]] -= hyd->Y[k]; // RHS coeff.
} }
// ... node n2 is a tank/reservoir // ... 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 ** Input: none
** Output: none ** Output: none
** Purpose: completes calculation of nodal flow balance array ** 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; 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 // 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++) for (i = 1; i <= net->Njuncs; i++)
{ {
hyd->X_tmp[i] -= hyd->DemandFlows[i]; hyd->Xflow[i] -= hyd->DemandFlow[i];
sol->F[sol->Row[i]] += hyd->X_tmp[i]; sm->F[sm->Row[i]] += hyd->Xflow[i];
} }
} }
void valvecoeffs(EN_Project *pr) void valvecoeffs(Project *pr)
/* /*
**-------------------------------------------------------------- **--------------------------------------------------------------
** Input: none ** 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; int i, k, n1, n2;
EN_Network *net = &pr->network;
Slink *link; Slink *link;
Svalve *valve; Svalve *valve;
@@ -333,7 +344,7 @@ void valvecoeffs(EN_Project *pr)
} }
void emittercoeffs(EN_Project *pr) void emittercoeffs(Project *pr)
/* /*
**-------------------------------------------------------------- **--------------------------------------------------------------
** Input: none ** 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; int i, row;
double hloss, hgrad; double hloss, hgrad;
hydraulics_t *hyd = &pr->hydraulics;
solver_t *sol = &hyd->solver;
EN_Network *net = &pr->network;
Snode *node; Snode *node;
for (i = 1; i <= net->Njuncs; i++) for (i = 1; i <= net->Njuncs; i++)
@@ -366,19 +377,19 @@ void emittercoeffs(EN_Project *pr)
emitheadloss(pr, i, &hloss, &hgrad); emitheadloss(pr, i, &hloss, &hgrad);
// Row of solution matrix // Row of solution matrix
row = sol->Row[i]; row = sm->Row[i];
// Addition to matrix diagonal & r.h.s // Addition to matrix diagonal & r.h.s
sol->Aii[row] += 1.0 / hgrad; sm->Aii[row] += 1.0 / hgrad;
sol->F[row] += (hloss + node->El) / hgrad; sm->F[row] += (hloss + node->El) / hgrad;
// Update to node flow balance // Update to node flow excess
hyd->X_tmp[i] -= hyd->EmitterFlows[i]; 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 ** 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 ke;
double q; double q;
double qa; double qa;
hydraulics_t *hyd = &pr->hydraulics;
// Set adjusted emitter coeff. // Set adjusted emitter coeff.
ke = MAX(CSMALL, pr->network.Node[i].Ke); 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)); qa = pow(hyd->RQtol / ke / hyd->Qexp, 1.0 / (hyd->Qexp - 1.0));
// Use linear head loss relation for small flow // Use linear head loss relation for small flow
q = hyd->EmitterFlows[i]; q = hyd->EmitterFlow[i];
if (fabs(q) <= qa) if (fabs(q) <= qa)
{ {
*hgrad = hyd->RQtol; *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 ** 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 // If required pressure equals minimum pressure, use a linear demand
// curve with a 0.01 PSI pressure range to approximate an all or // 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 ** 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; int i, row;
double dp, // pressure range over which demand can vary (ft) double dp, // pressure range over which demand can vary (ft)
n, // exponent in head loss v. demand function n, // exponent in head loss v. demand function
hloss, // head loss in supplying demand (ft) hloss, // head loss in supplying demand (ft)
hgrad; // gradient of demand head loss (ft/cfs) 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 // Get demand function parameters
if (hyd->DemandModel == DDA) return; if (hyd->DemandModel == DDA) return;
demandparams(pr, &dp, &n); demandparams(pr, &dp, &n);
@@ -483,18 +495,18 @@ void demandcoeffs(EN_Project *pr)
if (hyd->NodeDemand[i] <= 0.0) continue; if (hyd->NodeDemand[i] <= 0.0) continue;
// Find head loss for demand outflow at node's elevation // 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); &hloss, &hgrad);
// Update row of solution matrix A & its r.h.s. F // Update row of solution matrix A & its r.h.s. F
row = sol->Row[i]; row = sm->Row[i];
sol->Aii[row] += 1.0 / hgrad; sm->Aii[row] += 1.0 / hgrad;
sol->F[row] += (hloss + net->Node[i].El + hyd->Pmin) / 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 ** Input: i = node index
@@ -506,10 +518,11 @@ double demandflowchange(EN_Project *pr, int i, double dp, double n)
**-------------------------------------------------------------- **--------------------------------------------------------------
*/ */
{ {
double hloss, hgrad; Hydraul *hyd = &pr->hydraul;
hydraulics_t *hyd = &pr->hydraulics;
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; 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 ** Input: k = link index
@@ -575,20 +588,19 @@ void pipecoeff(EN_Project *pr, int k)
**-------------------------------------------------------------- **--------------------------------------------------------------
*/ */
{ {
Hydraul *hyd = &pr->hydraul;
double hloss, // Head loss double hloss, // Head loss
hgrad, // Head loss gradient hgrad, // Head loss gradient
ml, // Minor loss coeff. ml, // Minor loss coeff.
q, // Abs. value of flow q, // Abs. value of flow
r; // Resistance coeff. r; // Resistance coeff.
hydraulics_t *hyd = &pr->hydraulics;
solver_t *sol = &hyd->solver;
// For closed pipe use headloss formula: hloss = CBIG*q // For closed pipe use headloss formula: hloss = CBIG*q
if (hyd->LinkStatus[k] <= CLOSED) if (hyd->LinkStatus[k] <= CLOSED)
{ {
sol->P[k] = 1.0 / CBIG; hyd->P[k] = 1.0 / CBIG;
sol->Y[k] = hyd->LinkFlows[k]; hyd->Y[k] = hyd->LinkFlow[k];
return; return;
} }
@@ -599,7 +611,7 @@ void pipecoeff(EN_Project *pr, int k)
return; return;
} }
q = ABS(hyd->LinkFlows[k]); q = ABS(hyd->LinkFlow[k]);
ml = pr->network.Link[k].Km; ml = pr->network.Link[k].Km;
r = pr->network.Link[k].R; r = pr->network.Link[k].R;
@@ -625,15 +637,15 @@ void pipecoeff(EN_Project *pr, int k)
} }
// Adjust head loss sign for flow direction // Adjust head loss sign for flow direction
hloss *= SGN(hyd->LinkFlows[k]); hloss *= SGN(hyd->LinkFlow[k]);
// P and Y coeffs. // P and Y coeffs.
sol->P[k] = 1.0 / hgrad; hyd->P[k] = 1.0 / hgrad;
sol->Y[k] = hloss / hgrad; hyd->Y[k] = hloss / hgrad;
} }
void DWpipecoeff(EN_Project *pr, int k) void DWpipecoeff(Project *pr, int k)
/* /*
**-------------------------------------------------------------- **--------------------------------------------------------------
** Input: k = link index ** Input: k = link index
@@ -643,16 +655,14 @@ void DWpipecoeff(EN_Project *pr, int k)
**-------------------------------------------------------------- **--------------------------------------------------------------
*/ */
{ {
hydraulics_t *hyd = &pr->hydraulics; Hydraul *hyd = &pr->hydraul;
solver_t *sol = &hyd->solver;
Slink *link = &pr->network.Link[k]; 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 r = link->R; // Resistance coeff.
double ml = link->Km; // Minor loss coeff. double ml = link->Km; // Minor loss coeff.
double e = link->Kc / link->Diam; // Relative roughness double e = link->Kc / link->Diam; // Relative roughness
double s = hyd->Viscos * link->Diam; // Viscosity / diameter double s = hyd->Viscos * link->Diam; // Viscosity / diameter
double hloss, hgrad, f, dfdq, r1; double hloss, hgrad, f, dfdq, r1;
// Compute head loss and its derivative // Compute head loss and its derivative
@@ -660,7 +670,7 @@ void DWpipecoeff(EN_Project *pr, int k)
if (q <= A2 * s) if (q <= A2 * s)
{ {
r = 16.0 * PI * s * r; 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; hgrad = r + 2.0 * ml * q;
} }
@@ -670,13 +680,13 @@ void DWpipecoeff(EN_Project *pr, int k)
dfdq = 0.0; dfdq = 0.0;
f = frictionFactor(q, e, s, &dfdq); f = frictionFactor(q, e, s, &dfdq);
r1 = f * r + ml; 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); hgrad = (2.0 * r1 * q) + (dfdq * r * q * q);
} }
// Compute P and Y coefficients // Compute P and Y coefficients
sol->P[k] = 1.0 / hgrad; hyd->P[k] = 1.0 / hgrad;
sol->Y[k] = hloss / 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 ** Input: k = link index
@@ -739,6 +749,8 @@ void pumpcoeff(EN_Project *pr, int k)
**-------------------------------------------------------------- **--------------------------------------------------------------
*/ */
{ {
Hydraul *hyd = &pr->hydraul;
int p; // Pump index int p; // Pump index
double h0, // Shutoff head double h0, // Shutoff head
q, // Abs. value of flow q, // Abs. value of flow
@@ -748,22 +760,19 @@ void pumpcoeff(EN_Project *pr, int k)
qa, // Flow limit for linear head loss qa, // Flow limit for linear head loss
hloss, // Head loss across pump hloss, // Head loss across pump
hgrad; // Head loss gradient hgrad; // Head loss gradient
hydraulics_t *hyd = &pr->hydraulics;
solver_t *sol = &hyd->solver;
Spump *pump; Spump *pump;
// Use high resistance pipe if pump closed or cannot deliver head // Use high resistance pipe if pump closed or cannot deliver head
setting = hyd->LinkSetting[k]; setting = hyd->LinkSetting[k];
if (hyd->LinkStatus[k] <= CLOSED || setting == 0.0) if (hyd->LinkStatus[k] <= CLOSED || setting == 0.0)
{ {
sol->P[k] = 1.0 / CBIG; hyd->P[k] = 1.0 / CBIG;
sol->Y[k] = hyd->LinkFlows[k]; hyd->Y[k] = hyd->LinkFlow[k];
return; return;
} }
// Obtain reference to pump object & its speed setting // Obtain reference to pump object & its speed setting
q = ABS(hyd->LinkFlows[k]); q = ABS(hyd->LinkFlow[k]);
p = findpump(&pr->network, k); p = findpump(&pr->network, k);
pump = &pr->network.Pump[p]; pump = &pr->network.Pump[p];
@@ -783,7 +792,7 @@ void pumpcoeff(EN_Project *pr, int k)
// Compute head loss and its gradient // Compute head loss and its gradient
hgrad = pump->R * setting ; hgrad = pump->R * setting ;
hloss = pump->H0 * SQR(setting) + hgrad * hyd->LinkFlows[k]; hloss = pump->H0 * SQR(setting) + hgrad * hyd->LinkFlow[k];
} }
else else
{ {
@@ -798,23 +807,23 @@ void pumpcoeff(EN_Project *pr, int k)
if (q <= qa) if (q <= qa)
{ {
hgrad = hyd->RQtol; hgrad = hyd->RQtol;
hloss = h0 + hgrad * hyd->LinkFlows[k]; hloss = h0 + hgrad * hyd->LinkFlow[k];
} }
// ... use original pump curve for normal flows // ... use original pump curve for normal flows
else else
{ {
hgrad = n * r * pow(q, n - 1.0); 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. // P and Y coeffs.
sol->P[k] = 1.0 / hgrad; hyd->P[k] = 1.0 / hgrad;
sol->Y[k] = hloss / 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 ** 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 ** Input: k = link index
@@ -868,8 +877,7 @@ void gpvcoeff(EN_Project *pr, int k)
r, // Slope of head loss curve segment r, // Slope of head loss curve segment
q; // Abs. value of flow q; // Abs. value of flow
hydraulics_t *hyd = &pr->hydraulics; Hydraul *hyd = &pr->hydraul;
solver_t *sol = &hyd->solver;
// Treat as a pipe if valve closed // Treat as a pipe if valve closed
if (hyd->LinkStatus[k] == CLOSED) valvecoeff(pr, k); 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]); i = (int)ROUND(hyd->LinkSetting[k]);
// Adjusted flow rate // Adjusted flow rate
q = ABS(hyd->LinkFlows[k]); q = ABS(hyd->LinkFlow[k]);
q = MAX(q, TINY); q = MAX(q, TINY);
// Intercept and slope of curve segment containing q // Intercept and slope of curve segment containing q
@@ -891,13 +899,13 @@ void gpvcoeff(EN_Project *pr, int k)
r = MAX(r, TINY); r = MAX(r, TINY);
// Resulting P and Y coeffs. // Resulting P and Y coeffs.
sol->P[k] = 1.0 / r; hyd->P[k] = 1.0 / r;
sol->Y[k] = (h0 / r + q) * SGN(hyd->LinkFlows[k]); 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 ** Input: k = link index
@@ -906,8 +914,7 @@ void pbvcoeff(EN_Project *pr, int k)
**-------------------------------------------------------------- **--------------------------------------------------------------
*/ */
{ {
hydraulics_t *hyd = &pr->hydraulics; Hydraul *hyd = &pr->hydraul;
solver_t *sol = &hyd->solver;
Slink *link = &pr->network.Link[k]; Slink *link = &pr->network.Link[k];
// If valve fixed OPEN or CLOSED then treat as a pipe // If valve fixed OPEN or CLOSED then treat as a pipe
@@ -920,21 +927,21 @@ void pbvcoeff(EN_Project *pr, int k)
else else
{ {
// Treat as a pipe if minor loss > valve setting // 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); valvecoeff(pr, k);
} }
// Otherwise force headloss across valve to be equal to setting // Otherwise force headloss across valve to be equal to setting
else else
{ {
sol->P[k] = CBIG; hyd->P[k] = CBIG;
sol->Y[k] = hyd->LinkSetting[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 ** Input: k = link index
@@ -944,7 +951,7 @@ void tcvcoeff(EN_Project *pr, int k)
*/ */
{ {
double km; double km;
hydraulics_t *hyd = &pr->hydraulics; Hydraul *hyd = &pr->hydraul;
Slink *link = &pr->network.Link[k]; Slink *link = &pr->network.Link[k];
// Save original loss coeff. for open valve // 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 ** 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 int i, j; // Rows of solution matrix
double hset; // Valve head setting double hset; // Valve head setting
hydraulics_t *hyd = &pr->hydraulics;
solver_t *sol = &hyd->solver;
i = sol->Row[n1]; // Matrix rows of nodes i = sm->Row[n1]; // Matrix rows of nodes
j = sol->Row[n2]; j = sm->Row[n2];
hset = pr->network.Node[n2].El + hset = pr->network.Node[n2].El +
hyd->LinkSetting[k]; // Valve setting 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 // Set coeffs. to force head at downstream
// node equal to valve setting & force flow // 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; hyd->P[k] = 0.0;
sol->Y[k] = hyd->LinkFlows[k] + hyd->X_tmp[n2]; // Force flow balance hyd->Y[k] = hyd->LinkFlow[k] + hyd->Xflow[n2]; // Force flow balance
sol->F[j] += (hset * CBIG); // Force head = hset sm->F[j] += (hset * CBIG); // Force head = hset
sol->Aii[j] += CBIG; // at downstream node sm->Aii[j] += CBIG; // at downstream node
if (hyd->X_tmp[n2] < 0.0) if (hyd->Xflow[n2] < 0.0)
{ {
sol->F[i] += hyd->X_tmp[n2]; sm->F[i] += hyd->Xflow[n2];
} }
return; return;
} }
@@ -1008,15 +1016,15 @@ void prvcoeff(EN_Project *pr, int k, int n1, int n2)
// compute matrix coeffs. using the valvecoeff() function. // compute matrix coeffs. using the valvecoeff() function.
valvecoeff(pr, k); valvecoeff(pr, k);
sol->Aij[sol->Ndx[k]] -= sol->P[k]; sm->Aij[sm->Ndx[k]] -= hyd->P[k];
sol->Aii[i] += sol->P[k]; sm->Aii[i] += hyd->P[k];
sol->Aii[j] += sol->P[k]; sm->Aii[j] += hyd->P[k];
sol->F[i] += (sol->Y[k] - hyd->LinkFlows[k]); sm->F[i] += (hyd->Y[k] - hyd->LinkFlow[k]);
sol->F[j] -= (sol->Y[k] - hyd->LinkFlows[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 ** 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 int i, j; // Rows of solution matrix
double hset; // Valve head setting double hset; // Valve head setting
hydraulics_t *hyd = &pr->hydraulics;
solver_t *sol = &hyd->solver;
i = sol->Row[n1]; // Matrix rows of nodes i = sm->Row[n1]; // Matrix rows of nodes
j = sol->Row[n2]; j = sm->Row[n2];
hset = pr->network.Node[n1].El + hset = pr->network.Node[n1].El +
hyd->LinkSetting[k]; // Valve setting 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 // Set coeffs. to force head at upstream
// node equal to valve setting & force flow // 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; hyd->P[k] = 0.0;
sol->Y[k] = hyd->LinkFlows[k] - hyd->X_tmp[n1]; // Force flow balance hyd->Y[k] = hyd->LinkFlow[k] - hyd->Xflow[n1]; // Force flow balance
sol->F[i] += (hset * CBIG); // Force head = hset sm->F[i] += (hset * CBIG); // Force head = hset
sol->Aii[i] += CBIG; // at upstream node sm->Aii[i] += CBIG; // at upstream node
if (hyd->X_tmp[n1] > 0.0) if (hyd->Xflow[n1] > 0.0)
{ {
sol->F[j] += hyd->X_tmp[n1]; sm->F[j] += hyd->Xflow[n1];
} }
return; return;
} }
@@ -1059,15 +1068,15 @@ void psvcoeff(EN_Project *pr, int k, int n1, int n2)
// compute matrix coeffs. using the valvecoeff() function. // compute matrix coeffs. using the valvecoeff() function.
valvecoeff(pr, k); valvecoeff(pr, k);
sol->Aij[sol->Ndx[k]] -= sol->P[k]; sm->Aij[sm->Ndx[k]] -= hyd->P[k];
sol->Aii[i] += sol->P[k]; sm->Aii[i] += hyd->P[k];
sol->Aii[j] += sol->P[k]; sm->Aii[j] += hyd->P[k];
sol->F[i] += (sol->Y[k] - hyd->LinkFlows[k]); sm->F[i] += (hyd->Y[k] - hyd->LinkFlow[k]);
sol->F[j] -= (sol->Y[k] - hyd->LinkFlows[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 ** 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 int i, j; // Rows in solution matrix
double q; // Valve flow setting double q; // Valve flow setting
hydraulics_t *hyd = &pr->hydraulics;
solver_t *sol = &hyd->solver;
q = hyd->LinkSetting[k]; q = hyd->LinkSetting[k];
i = hyd->solver.Row[n1]; i = sm->Row[n1];
j = hyd->solver.Row[n2]; j = sm->Row[n2];
// If valve active, break network at valve and treat // If valve active, break network at valve and treat
// flow setting as external demand at upstream node // 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) if (hyd->LinkStatus[k] == ACTIVE)
{ {
hyd->X_tmp[n1] -= q; hyd->Xflow[n1] -= q;
sol->F[i] -= q; hyd->Xflow[n2] += q;
hyd->X_tmp[n2] += q; hyd->Y[k] = hyd->LinkFlow[k] - q;
sol->F[j] += q; sm->F[i] -= q;
sol->P[k] = 1.0 / CBIG; sm->F[j] += q;
sol->Aij[sol->Ndx[k]] -= sol->P[k]; hyd->P[k] = 1.0 / CBIG;
sol->Aii[i] += sol->P[k]; sm->Aij[sm->Ndx[k]] -= hyd->P[k];
sol->Aii[j] += sol->P[k]; sm->Aii[i] += hyd->P[k];
sol->Y[k] = hyd->LinkFlows[k] - q; sm->Aii[j] += hyd->P[k];
} }
// Otherwise treat valve as an open pipe // Otherwise treat valve as an open pipe
@@ -1110,16 +1120,16 @@ void fcvcoeff(EN_Project *pr, int k, int n1, int n2)
else else
{ {
valvecoeff(pr, k); valvecoeff(pr, k);
sol->Aij[sol->Ndx[k]] -= sol->P[k]; sm->Aij[sm->Ndx[k]] -= hyd->P[k];
sol->Aii[i] += sol->P[k]; sm->Aii[i] += hyd->P[k];
sol->Aii[j] += sol->P[k]; sm->Aii[j] += hyd->P[k];
sol->F[i] += (sol->Y[k] - hyd->LinkFlows[k]); sm->F[i] += (hyd->Y[k] - hyd->LinkFlow[k]);
sol->F[j] -= (sol->Y[k] - hyd->LinkFlows[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 ** 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; double flow, q, y, qa, hgrad;
EN_Network *net = &pr->network; flow = hyd->LinkFlow[k];
hydraulics_t *hyd = &pr->hydraulics;
solver_t *sol = &hyd->solver;
Slink *link = &net->Link[k];
flow = hyd->LinkFlows[k];
// Valve is closed. Use a very small matrix coeff. // Valve is closed. Use a very small matrix coeff.
if (hyd->LinkStatus[k] <= CLOSED) if (hyd->LinkStatus[k] <= CLOSED)
{ {
sol->P[k] = 1.0 / CBIG; hyd->P[k] = 1.0 / CBIG;
sol->Y[k] = flow; hyd->Y[k] = flow;
return; return;
} }
@@ -1164,15 +1172,15 @@ void valvecoeff(EN_Project *pr, int k)
} }
// P and Y coeffs. // P and Y coeffs.
sol->P[k] = 1.0 / hgrad; hyd->P[k] = 1.0 / hgrad;
sol->Y[k] = y; hyd->Y[k] = y;
} }
// If no minor loss coeff. specified use a // If no minor loss coeff. specified use a
// low resistance linear head loss relation // low resistance linear head loss relation
else else
{ {
sol->P[k] = 1.0 / CSMALL; hyd->P[k] = 1.0 / CSMALL;
sol->Y[k] = flow; hyd->Y[k] = flow;
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,13 +1,15 @@
/* /*
********************************************************************* ******************************************************************************
Project: OWA EPANET
HYDSOLVER.C -- Equilibrium hydraulic solver for the EPANET Program Version: 2.2
Module: hydsolver.c
This module contains a pipe network hydraulic solver that computes Description: computes flows and pressures throughout a pipe network using
flows and pressures within the network at a specific point in time. Todini's Global Gradient Algorithm
Authors: see AUTHORS
The solver implements Todini's Global Gradient Algorithm. Copyright: see AUTHORS
******************************************************************* License: see LICENSE
Last Updated: 11/27/2018
******************************************************************************
*/ */
#include <stdio.h> #include <stdio.h>
@@ -33,32 +35,29 @@ typedef struct {
int maxflowlink; int maxflowlink;
} Hydbalance; } Hydbalance;
// External functions // Exported functions
//int hydsolve(EN_Project *pr, int *iter, double *relerr); int hydsolve(Project *, int *, double *);
//void headlosscoeffs(EN_Project *pr);
//void matrixcoeffs(EN_Project *pr);
extern int valvestatus(EN_Project *pr); //(see HYDSTATUS.C) // Imported functions
extern int linkstatus(EN_Project *pr); //(see HYDSTATUS.C) extern int linsolve(Smatrix *, int); //(see SMATRIX.C)
extern int valvestatus(Project *); //(see HYDSTATUS.C)
extern int linkstatus(Project *); //(see HYDSTATUS.C)
// Local functions // Local functions
static int badvalve(EN_Project *pr, int); static int badvalve(Project *, int);
static int pswitch(EN_Project *pr); static int pswitch(Project *);
static double newflows(EN_Project *pr, Hydbalance *hbal); static double newflows(Project *, Hydbalance *);
static void newlinkflows(EN_Project *pr, Hydbalance *hbal, double *qsum, static void newlinkflows(Project *, Hydbalance *, double *, double *);
double *dqsum); static void newemitterflows(Project *, Hydbalance *, double *, double *);
static void newemitterflows(EN_Project *pr, Hydbalance *hbal, double *qsum, static void newdemandflows(Project *, Hydbalance *, double *, double *);
double *dqsum);
static void newdemandflows(EN_Project *pr, Hydbalance *hbal, double *qsum,
double *dqsum);
static void checkhydbalance(EN_Project *pr, Hydbalance *hbal); static void checkhydbalance(Project *, Hydbalance *);
static int hasconverged(EN_Project *pr, double *relerr, Hydbalance *hbal); static int hasconverged(Project *, double *, Hydbalance *);
static void reporthydbal(EN_Project *pr, Hydbalance *hbal); static void reporthydbal(Project *, Hydbalance *);
int hydsolve(EN_Project *pr, int *iter, double *relerr) int hydsolve(Project *pr, int *iter, double *relerr)
/* /*
**------------------------------------------------------------------- **-------------------------------------------------------------------
** Input: none ** Input: none
@@ -68,11 +67,8 @@ int hydsolve(EN_Project *pr, int *iter, double *relerr)
** Purpose: solves network nodal equations for heads and flows ** Purpose: solves network nodal equations for heads and flows
** using Todini's Gradient algorithm ** 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 ** 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 ** are reached. Status checks on control valves are made
** every iteration if DampLimit = 0 or only when the ** every iteration if DampLimit = 0 or only when the
** convergence error is at or below DampLimit. If DampLimit ** 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 i; // Node index
int errcode = 0; // Node causing solution error int errcode = 0; // Node causing solution error
int nextcheck; // Next status check trial 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 int statChange; // Non-valve status change flag
Hydbalance hydbal; // Hydraulic balance errors 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 // Initialize status checking & relaxation factor
nextcheck = hyd->CheckFreq; nextcheck = hyd->CheckFreq;
hyd->RelaxFactor = 1.0; hyd->RelaxFactor = 1.0;
// Repeat iterations until convergence or trial limit is exceeded. // Repeat iterations until convergence or trial limit is exceeded.
// (ExtraIter used to increase trials in case of status cycling.) // (ExtraIter used to increase trials in case of status cycling.)
if (pr->report.Statflag == FULL) if (rpt->Statflag == FULL) writerelerr(pr, 0, 0);
{
writerelerr(pr, 0, 0);
}
maxtrials = hyd->MaxIter; maxtrials = hyd->MaxIter;
if (hyd->ExtraIter > 0) if (hyd->ExtraIter > 0) maxtrials += hyd->ExtraIter;
{
maxtrials += hyd->ExtraIter;
}
*iter = 1; *iter = 1;
while (*iter <= maxtrials) while (*iter <= maxtrials)
{ {
/* // Compute coefficient matrices A & F and solve A*H = F
** Compute coefficient matrices A & F and solve A*H = F // where H = heads, A = Jacobian coeffs. derived from
** where H = heads, A = Jacobian coeffs. derived from // head loss gradients, & F = flow correction terms.
** head loss gradients, & F = flow correction terms. // Solution for H is returned in F from call to linsolve().
** Solution for H is returned in F from call to linsolve().
*/
headlosscoeffs(pr); headlosscoeffs(pr);
matrixcoeffs(pr); matrixcoeffs(pr);
errcode = linsolve(pr, net->Njuncs); errcode = linsolve(sm, net->Njuncs);
// Quit if memory allocation error
if (errcode < 0) break;
// Matrix ill-conditioning problem - if control valve causing problem, // Matrix ill-conditioning problem - if control valve causing problem,
// fix its status & continue, otherwise quit with no solution. // fix its status & continue, otherwise quit with no solution.
if (errcode > 0) if (errcode > 0)
{ {
if (badvalve(pr, sol->Order[errcode])) continue; if (badvalve(pr, sm->Order[errcode])) continue;
else break; 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) // (Row[i] = row of solution matrix corresponding to node i)
for (i = 1; i <= net->Njuncs; 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 newerr = newflows(pr, &hydbal); // Update flows
*relerr = newerr; *relerr = newerr;
// Write convergence error to status report if called for // Write convergence error to status report if called for
if (rep->Statflag == FULL) if (rpt->Statflag == FULL)
{ {
writerelerr(pr, *iter, *relerr); writerelerr(pr, *iter, *relerr);
} }
@@ -199,17 +185,16 @@ int hydsolve(EN_Project *pr, int *iter, double *relerr)
} }
// Iterations ended - report any errors. // Iterations ended - report any errors.
if (errcode < 0) errcode = 101; // Memory allocation error if (errcode > 0)
else if (errcode > 0)
{ {
writehyderr(pr, sol->Order[errcode]); // Ill-conditioned matrix error writehyderr(pr, sm->Order[errcode]); // Ill-conditioned matrix error
errcode = 110; errcode = 110;
} }
// Replace junction demands with total outflow values // Replace junction demands with total outflow values
for (i = 1; i <= net->Njuncs; i++) 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 // Save convergence info
@@ -218,11 +203,11 @@ int hydsolve(EN_Project *pr, int *iter, double *relerr)
hyd->MaxFlowChange = hydbal.maxflowchange; hyd->MaxFlowChange = hydbal.maxflowchange;
hyd->Iterations = *iter; hyd->Iterations = *iter;
return(errcode); return errcode;
} }
int badvalve(EN_Project *pr, int n) int badvalve(Project *pr, int n)
/* /*
**----------------------------------------------------------------- **-----------------------------------------------------------------
** Input: n = node index ** 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; int i, k, n1, n2;
hydraulics_t *hyd = &pr->hydraulics;
report_options_t *rep = &pr->report;
time_options_t *time = &pr->time_options;
Slink *link; Slink *link;
LinkType t; LinkType t;
@@ -257,19 +242,14 @@ int badvalve(EN_Project *pr, int n)
{ {
if (hyd->LinkStatus[k] == ACTIVE) 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); writeline(pr, pr->Msg);
} }
if (link->Type == FCV) if (link->Type == FCV) hyd->LinkStatus[k] = XFCV;
{ else hyd->LinkStatus[k] = XPRESSURE;
hyd->LinkStatus[k] = XFCV;
}
else
{
hyd->LinkStatus[k] = XPRESSURE;
}
return 1; return 1;
} }
} }
@@ -280,7 +260,7 @@ int badvalve(EN_Project *pr, int n)
} }
int pswitch(EN_Project *pr) int pswitch(Project *pr)
/* /*
**-------------------------------------------------------------- **--------------------------------------------------------------
** Input: none ** 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 int i, // Control statement index
k, // Index of link being controlled k, // Index of link being controlled
n, // Node controlling link k n, // Node controlling link k
@@ -297,10 +281,6 @@ int pswitch(EN_Project *pr)
change, // Flag for status or setting change change, // Flag for status or setting change
anychange = 0; // Flag for 1 or more control actions anychange = 0; // Flag for 1 or more control actions
char s; // Current link status char s; // Current link status
EN_Network *net = &pr->network;
hydraulics_t *hyd = &pr->hydraulics;
report_options_t *rep = &pr->report;
Slink *link; Slink *link;
// Check each control statement // Check each control statement
@@ -358,7 +338,7 @@ int pswitch(EN_Project *pr)
{ {
hyd->LinkSetting[k] = net->Control[i].Setting; hyd->LinkSetting[k] = net->Control[i].Setting;
} }
if (rep->Statflag == FULL) if (rpt->Statflag == FULL)
{ {
writestatchange(pr, k, s, hyd->LinkStatus[k]); 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 ** 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 double dqsum, // Network flow change
qsum; // Network total flow qsum; // Network total flow
EN_Network *net = &pr->network;
hydraulics_t *hyd = &pr->hydraulics;
// Initialize sum of flows & corrections // Initialize sum of flows & corrections
qsum = 0.0; qsum = 0.0;
dqsum = 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 ** 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 */ double dh, /* Link head loss */
dq; /* Link flow change */ dq; /* Link flow change */
int k, n, n1, n2; int k, n, n1, n2;
EN_Network *net = &pr->network;
hydraulics_t *hyd = &pr->hydraulics;
solver_t *sol = &hyd->solver;
Slink *link; Slink *link;
// Initialize net inflows (i.e., demands) at fixed grade nodes // 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 // where P & Y were computed in hlosscoeff() in hydcoeffs.c
dh = hyd->NodeHead[n1] - hyd->NodeHead[n2]; 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 // Adjust flow change by the relaxation factor
dq *= hyd->RelaxFactor; dq *= hyd->RelaxFactor;
@@ -454,15 +433,15 @@ void newlinkflows(EN_Project *pr, Hydbalance *hbal, double *qsum, double *dqsum
if (link->Type == PUMP) if (link->Type == PUMP)
{ {
n = findpump(net, k); 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 // Update link flow and system flow summation
hyd->LinkFlows[k] -= dq; hyd->LinkFlow[k] -= dq;
*qsum += ABS(hyd->LinkFlows[k]); *qsum += ABS(hyd->LinkFlow[k]);
*dqsum += ABS(dq); *dqsum += ABS(dq);
// Update identity of element with max. flow change // 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 // Update net flows to fixed grade nodes
if (hyd->LinkStatus[k] > CLOSED) if (hyd->LinkStatus[k] > CLOSED)
{ {
if (n1 > net->Njuncs) hyd->NodeDemand[n1] -= hyd->LinkFlows[k]; if (n1 > net->Njuncs) hyd->NodeDemand[n1] -= hyd->LinkFlow[k];
if (n2 > net->Njuncs) hyd->NodeDemand[n2] += hyd->LinkFlows[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) 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; int i;
double hloss, hgrad, dh, dq; double hloss, hgrad, dh, dq;
EN_Network *net = &pr->network;
hydraulics_t *hyd = &pr->hydraulics;
// Examine each network junction // Examine each network junction
for (i = 1; i <= net->Njuncs; i++) for (i = 1; i <= net->Njuncs; i++)
@@ -512,10 +492,10 @@ void newemitterflows(EN_Project *pr, Hydbalance *hbal, double *qsum,
// Find emitter flow change // Find emitter flow change
dh = hyd->NodeHead[i] - net->Node[i].El; dh = hyd->NodeHead[i] - net->Node[i].El;
dq = (hloss - dh) / hgrad; dq = (hloss - dh) / hgrad;
hyd->EmitterFlows[i] -= dq; hyd->EmitterFlow[i] -= dq;
// Update system flow summation // Update system flow summation
*qsum += ABS(hyd->EmitterFlows[i]); *qsum += ABS(hyd->EmitterFlow[i]);
*dqsum += ABS(dq); *dqsum += ABS(dq);
// Update identity of element with max. flow change // 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 ** 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) double dp, // pressure range over which demand can vary (ft)
dq, // change in demand flow (cfs) dq, // change in demand flow (cfs)
n; // exponent in head loss v. demand function n; // exponent in head loss v. demand function
int k; int k;
EN_Network *net = &pr->network;
hydraulics_t *hyd = &pr->hydraulics;
// Get demand function parameters // Get demand function parameters
if (hyd->DemandModel == DDA) return; 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) // Find change in demand flow (see hydcoeffs.c)
dq = demandflowchange(pr, k, dp, n); dq = demandflowchange(pr, k, dp, n);
hyd->DemandFlows[k] -= dq; hyd->DemandFlow[k] -= dq;
// Update system flow summation // Update system flow summation
*qsum += ABS(hyd->DemandFlows[k]); *qsum += ABS(hyd->DemandFlow[k]);
*dqsum += ABS(dq); *dqsum += ABS(dq);
// Update identity of element with max. flow change // 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 ** 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; int k, n1, n2;
double dh, headerror, headloss; double dh, headerror, headloss;
EN_Network *net = &pr->network;
hydraulics_t *hyd = &pr->hydraulics;
solver_t *sol = &hyd->solver;
Slink *link; Slink *link;
hbal->maxheaderror = 0.0; hbal->maxheaderror = 0.0;
hbal->maxheadlink = 1; hbal->maxheadlink = 1;
headlosscoeffs(pr); headlosscoeffs(pr);
for (k = 1; k <= net->Nlinks; k++) for (k = 1; k <= net->Nlinks; k++)
{ {
if (hyd->LinkStatus[k] <= CLOSED) continue; if (hyd->LinkStatus[k] <= CLOSED) continue;
if (sol->P[k] == 0.0) continue; if (hyd->P[k] == 0.0) continue;
link = &net->Link[k]; link = &net->Link[k];
n1 = link->N1; n1 = link->N1;
n2 = link->N2; n2 = link->N2;
dh = hyd->NodeHead[n1] - hyd->NodeHead[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); headerror = ABS(dh - headloss);
if (headerror > hbal->maxheaderror) 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 ** 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; if (*relerr > hyd->Hacc) return 0;
checkhydbalance(pr, hbal); 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 ** Input: hbal = current hydraulic balance errors

View File

@@ -1,29 +1,34 @@
/* /*
********************************************************************* ******************************************************************************
Project: OWA EPANET
HYDSTATUS.C -- Hydraulic status updating for the EPANET Program 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 <stdio.h>
#include "types.h" #include "types.h"
#include "funcs.h" #include "funcs.h"
// External functions // Exported functions
int valvestatus(EN_Project *pr); int valvestatus(Project *);
int linkstatus(EN_Project *pr); int linkstatus(Project *);
// Local functions // Local functions
static StatType cvstatus(EN_Project *pr, StatType, double, double); static StatusType cvstatus(Project *, StatusType, double, double);
static StatType pumpstatus(EN_Project *pr, int, double); static StatusType pumpstatus(Project *, int, double);
static StatType prvstatus(EN_Project *pr, int, StatType, double, double, double); static StatusType prvstatus(Project *, int, StatusType, double, double, double);
static StatType psvstatus(EN_Project *pr, int, StatType, double, double, double); static StatusType psvstatus(Project *, int, StatusType, double, double, double);
static StatType fcvstatus(EN_Project *pr, int, StatType, double, double); static StatusType fcvstatus(Project *, int, StatusType, double, double);
static void tankstatus(EN_Project *pr, int, int, int); static void tankstatus(Project *, int, int, int);
int valvestatus(EN_Project *pr) int valvestatus(Project *pr)
/* /*
**----------------------------------------------------------------- **-----------------------------------------------------------------
** Input: none ** 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 int change = FALSE, // Status change flag
i, k, // Valve & link indexes i, k, // Valve & link indexes
n1, n2; // Start & end nodes n1, n2; // Start & end nodes
StatType status; // Valve status settings
double hset; // Valve head setting double hset; // Valve head setting
StatusType status; // Valve status settings
Slink *link; Slink *link;
EN_Network *net = &pr->network;
hydraulics_t *hyd = &pr->hydraulics;
report_options_t *rep = &pr->report;
// Examine each valve // Examine each valve
for (i = 1; i <= net->Nvalves; i++) for (i = 1; i <= net->Nvalves; i++)
{ {
@@ -80,7 +85,7 @@ int valvestatus(EN_Project *pr)
// Check for a status change // Check for a status change
if (status != hyd->LinkStatus[k]) if (status != hyd->LinkStatus[k])
{ {
if (rep->Statflag == FULL) if (rpt->Statflag == FULL)
{ {
writestatchange(pr, k, status, hyd->LinkStatus[k]); writestatchange(pr, k, status, hyd->LinkStatus[k]);
} }
@@ -88,10 +93,10 @@ int valvestatus(EN_Project *pr)
} }
} }
return change; return change;
} /* End of valvestatus() */ }
int linkstatus(EN_Project *pr) int linkstatus(Project *pr)
/* /*
**-------------------------------------------------------------- **--------------------------------------------------------------
** Input: none ** 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 int change = FALSE, // Status change flag
k, // Link index k, // Link index
n1, // Start node index n1, // Start node index
n2; // End node index n2; // End node index
double dh; // Head difference across link double dh; // Head difference across link
StatType status; // Current status StatusType status; // Current status
EN_Network *net = &pr->network;
hydraulics_t *hyd = &pr->hydraulics;
report_options_t *rep = &pr->report;
Slink *link; Slink *link;
// Examine each link // Examine each link
@@ -132,7 +137,7 @@ int linkstatus(EN_Project *pr)
if (link->Type == CVPIPE) if (link->Type == CVPIPE)
{ {
hyd->LinkStatus[k] = cvstatus(pr, hyd->LinkStatus[k], dh, hyd->LinkStatus[k] = cvstatus(pr, hyd->LinkStatus[k], dh,
hyd->LinkFlows[k]); hyd->LinkFlow[k]);
} }
if (link->Type == PUMP && hyd->LinkStatus[k] >= OPEN && if (link->Type == PUMP && hyd->LinkStatus[k] >= OPEN &&
hyd->LinkSetting[k] > 0.0) hyd->LinkSetting[k] > 0.0)
@@ -157,7 +162,7 @@ int linkstatus(EN_Project *pr)
if (status != hyd->LinkStatus[k]) if (status != hyd->LinkStatus[k])
{ {
change = TRUE; change = TRUE;
if (rep->Statflag == FULL) if (rpt->Statflag == FULL)
{ {
writestatchange(pr, k, status, hyd->LinkStatus[k]); 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 ** 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 // Prevent reverse flow through CVs
if (ABS(dh) > hyd->Htol) 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 ** 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; int p;
double hmax; double hmax;
hydraulics_t *hyd = &pr->hydraulics;
EN_Network *net = &pr->network;
// Find maximum head (hmax) pump can deliver // Find maximum head (hmax) pump can deliver
p = findpump(net, k); 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) 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 Hydraul *hyd = &pr->hydraul;
double hml; // Head loss when fully opened
hydraulics_t *hyd = &pr->hydraulics;
double htol = hyd->Htol; StatusType status; // Valve's new status
Slink *link = &pr->network.Link[k]; double hml; // Head loss when fully opened
double htol;
Slink *link;
htol = hyd->Htol;
link = &pr->network.Link[k];
// Head loss when fully open // 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 // Rules for updating valve's status from current value s
status = s; status = s;
switch (s) switch (s)
{ {
case ACTIVE: 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 if (h1 - hml < hset - htol) status = OPEN;
else status = ACTIVE; else status = ACTIVE;
break; break;
case OPEN: 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 if (h2 >= hset + htol) status = ACTIVE;
else status = OPEN; else status = OPEN;
break; break;
@@ -278,7 +287,7 @@ StatType prvstatus(EN_Project *pr, int k, StatType s, double hset,
break; break;
case XPRESSURE: case XPRESSURE:
if (hyd->LinkFlows[k] < -hyd->Qtol) status = CLOSED; if (hyd->LinkFlow[k] < -hyd->Qtol) status = CLOSED;
break; break;
default: 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) 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 Hydraul *hyd = &pr->hydraul;
double hml; // Head loss when fully opened
hydraulics_t *hyd = &pr->hydraulics;
double htol = hyd->Htol; StatusType status; // Valve's new status
Slink *link = &pr->network.Link[k]; double hml; // Head loss when fully opened
double htol;
Slink *link;
htol = hyd->Htol;
link = &pr->network.Link[k];
// Head loss when fully open // 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 // Rules for updating valve's status from current value s
status = s; status = s;
switch (s) switch (s)
{ {
case ACTIVE: 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 if (h2 + hml > hset + htol) status = OPEN;
else status = ACTIVE; else status = ACTIVE;
break; break;
case OPEN: 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 if (h1 < hset - htol) status = ACTIVE;
else status = OPEN; else status = OPEN;
break; break;
@@ -335,7 +347,7 @@ StatType psvstatus(EN_Project *pr, int k, StatType s, double hset,
break; break;
case XPRESSURE: case XPRESSURE:
if (hyd->LinkFlows[k] < -hyd->Qtol) status = CLOSED; if (hyd->LinkFlow[k] < -hyd->Qtol) status = CLOSED;
break; break;
default: 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 ** 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 Hydraul *hyd = &pr->hydraul;
hydraulics_t *hyd = &pr->hydraulics; StatusType status; // New valve status
status = s; status = s;
if (h1 - h2 < -hyd->Htol) if (h1 - h2 < -hyd->Htol)
{ {
status = XFCV; status = XFCV;
} }
else if (hyd->LinkFlows[k] < -hyd->Qtol) else if (hyd->LinkFlow[k] < -hyd->Qtol)
{ {
status = XFCV; status = XFCV;
} }
else if (s == XFCV && hyd->LinkFlows[k] >= hyd->LinkSetting[k]) else if (s == XFCV && hyd->LinkFlow[k] >= hyd->LinkSetting[k])
{ {
status = ACTIVE; 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 ** 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; int i, n;
double h, q; double h, q;
Stank *tank; Stank *tank;
hydraulics_t *hyd = &pr->hydraulics;
EN_Network *net = &pr->network;
Slink *link = &net->Link[k]; Slink *link = &net->Link[k];
// Return if link is closed // Return if link is closed
if (hyd->LinkStatus[k] <= CLOSED) return; if (hyd->LinkStatus[k] <= CLOSED) return;
// Make node n1 be the tank, reversing flow (q) if need be // Make node n1 be the tank, reversing flow (q) if need be
q = hyd->LinkFlows[k]; q = hyd->LinkFlow[k];
i = n1 - net->Njuncs; i = n1 - net->Njuncs;
if (i <= 0) if (i <= 0)
{ {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,17 @@
/* mempool.c /*
** ******************************************************************************
** A simple fast pooled memory allocation package. Project: OWA EPANET
** Version: 2.2
** Based on code by Steve Hill in Graphics Gems III, Module: mempool.c
** David Kirk (ed.), Academic Press, Boston, MA, 1992 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> #include <stdlib.h>

View File

@@ -1,9 +1,14 @@
/* /*
** mempool.h ******************************************************************************
** Project: OWA EPANET
** Header for mempool.c Version: 2.2
** Module: mempool.h
** A simple pooled memory allocator 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 #ifndef MEMPOOL_H

File diff suppressed because it is too large Load Diff

838
src/project.c Normal file
View 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);
}
}

View File

@@ -1,13 +1,14 @@
/* /*
********************************************************************* ******************************************************************************
Project: OWA EPANET
QUALITY.C -- water quality engine module for the EPANET program Version: 2.2
Module: quality.c
This module works together with QUALROUTE.C and QUALREACT.C to Description: implements EPANET's water quality engine
compute transport and reaction of a water quality constituent within Authors: see AUTHORS
a pipe network over a series of time steps. Copyright: see AUTHORS
License: see LICENSE
********************************************************************* Last Updated: 11/27/2018
******************************************************************************
*/ */
#include <stdio.h> #include <stdio.h>
@@ -24,36 +25,35 @@ a pipe network over a series of time steps.
#include "funcs.h" #include "funcs.h"
// Stagnant flow tolerance // 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) // Exported functions (declared in FUNCS.H)
//int openqual(EN_Project *pr); //int openqual(Project *);
//void initqual(EN_Project *pr); //void initqual(Project *);
//int runqual(EN_Project *pr, long *); //int runqual(Project *, long *);
//int nextqual(EN_Project *pr, long *); //int nextqual(Project *, long *);
//int stepqual(EN_Project *pr, long *); //int stepqual(Project *, long *);
//int closequal(EN_Project *pr); //int closequal(Project *);
//double avgqual(EN_Project *pr, int); //double avgqual(Project *, int);
double findsourcequal(EN_Project *pr, int, double, double, long); double findsourcequal(Project *, int, double, double, long);
// Imported Functions // Imported functions
extern char setreactflag(EN_Project *pr); extern char setreactflag(Project *);
extern double getucf(double); extern double getucf(double);
extern void ratecoeffs(EN_Project *pr); extern void ratecoeffs(Project *);
extern int buildilists(EN_Project *pr); extern void initsegs(Project *);
extern void initsegs(EN_Project *pr); extern void reversesegs(Project *, int);
extern void reversesegs(EN_Project *pr, int); extern int sortnodes(Project *);
extern int sortnodes(EN_Project *pr); extern void transport(Project *, long);
extern void transport(EN_Project *pr, long);
// Local Functions // Local functions
static double sourcequal(EN_Project *pr, Psource); static double sourcequal(Project *, Psource);
static void evalmassbalance(EN_Project *pr); static void evalmassbalance(Project *);
static double findstoredmass(EN_Project *pr); static double findstoredmass(Project *);
static int flowdirchanged(EN_Project *pr); static int flowdirchanged(Project *);
int openqual(EN_Project *pr) int openqual(Project *pr)
/* /*
**-------------------------------------------------------------- **--------------------------------------------------------------
** Input: none ** Input: none
@@ -62,16 +62,23 @@ int openqual(EN_Project *pr)
**-------------------------------------------------------------- **--------------------------------------------------------------
*/ */
{ {
Network *net = &pr->network;
Quality *qual = &pr->quality;
int errcode = 0; int errcode = 0;
int n; int n;
quality_t *qual = &pr->quality; // Build nodal adjacency lists if they don't already exist
EN_Network *net = &pr->network; if (net->Adjlist == NULL)
{
errcode = buildadjlists(net);
if (errcode ) return errcode;
}
// Create a memory pool for water quality segments // Create a memory pool for water quality segments
qual->OutOfMemory = FALSE; qual->OutOfMemory = FALSE;
qual->SegPool = mempool_create(); qual->SegPool = mempool_create();
if (qual->SegPool == NULL) errcode = 101;; if (qual->SegPool == NULL) errcode = 101;
// Allocate arrays for link flow direction & reaction rates // Allocate arrays for link flow direction & reaction rates
n = net->Nlinks + 1; n = net->Nlinks + 1;
@@ -83,34 +90,19 @@ int openqual(EN_Project *pr)
qual->FirstSeg = (Pseg *)calloc(n, sizeof(Pseg)); qual->FirstSeg = (Pseg *)calloc(n, sizeof(Pseg));
qual->LastSeg = (Pseg *)calloc(n, sizeof(Pseg)); qual->LastSeg = (Pseg *)calloc(n, sizeof(Pseg));
// Allocate memory for sorted nodes and link incidence lists // Allocate memory for topologically sorted nodes
// ... 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
qual->SortedNodes = (int *)calloc(n, sizeof(int)); qual->SortedNodes = (int *)calloc(n, sizeof(int));
ERRCODE(MEMCHECK(qual->FlowDir)); ERRCODE(MEMCHECK(qual->FlowDir));
ERRCODE(MEMCHECK(qual->PipeRateCoeff)); ERRCODE(MEMCHECK(qual->PipeRateCoeff));
ERRCODE(MEMCHECK(qual->FirstSeg)); ERRCODE(MEMCHECK(qual->FirstSeg));
ERRCODE(MEMCHECK(qual->LastSeg)); ERRCODE(MEMCHECK(qual->LastSeg));
ERRCODE(MEMCHECK(qual->Ilist));
ERRCODE(MEMCHECK(qual->IlistPtr));
ERRCODE(MEMCHECK(qual->SortedNodes)); ERRCODE(MEMCHECK(qual->SortedNodes));
// Build link incidence lists
if (!errcode) errcode = buildilists(pr);
return errcode; return errcode;
} }
int initqual(EN_Project *pr) int initqual(Project *pr)
/* /*
**-------------------------------------------------------------- **--------------------------------------------------------------
** Input: none ** 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 i;
int errcode = 0; int errcode = 0;
EN_Network *net = &pr->network;
hydraulics_t *hyd = &pr->hydraulics;
quality_t *qual = &pr->quality;
// Re-position hydraulics file // Re-position hydraulics file
if (!hyd->OpenHflag) 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 // Set elapsed times to zero
qual->Qtime = 0; time->Qtime = 0;
pr->time_options.Htime = 0; time->Htime = 0;
pr->time_options.Rtime = pr->time_options.Rstart; time->Rtime = time->Rstart;
pr->report.Nperiods = 0; pr->report.Nperiods = 0;
// Initialize node quality // Initialize node quality
@@ -183,17 +177,17 @@ int initqual(EN_Project *pr)
qual->Wsource = 0.0; qual->Wsource = 0.0;
// Initialize mass balance components // Initialize mass balance components
qual->massbalance.initial = findstoredmass(pr); qual->MassBalance.initial = findstoredmass(pr);
qual->massbalance.inflow = 0.0; qual->MassBalance.inflow = 0.0;
qual->massbalance.outflow = 0.0; qual->MassBalance.outflow = 0.0;
qual->massbalance.reacted = 0.0; qual->MassBalance.reacted = 0.0;
qual->massbalance.final = 0.0; qual->MassBalance.final = 0.0;
qual->massbalance.ratio = 0.0; qual->MassBalance.ratio = 0.0;
return errcode; return errcode;
} }
int runqual(EN_Project *pr, long *t) int runqual(Project *pr, long *t)
/* /*
**-------------------------------------------------------------- **--------------------------------------------------------------
** Input: none ** 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 hydtime; // Hydraulic solution time
long hydstep; // Hydraulic time step long hydstep; // Hydraulic time step
int errcode = 0; int errcode = 0;
hydraulics_t *hyd = &pr->hydraulics;
quality_t *qual = &pr->quality;
time_options_t *time = &pr->time_options;
// Update reported simulation time // Update reported simulation time
*t = qual->Qtime; *t = time->Qtime;
// Read hydraulic solution from hydraulics file // Read hydraulic solution from hydraulics file
if (qual->Qtime == time->Htime) if (time->Qtime == time->Htime)
{ {
// Read hydraulic results from file // Read hydraulic results from file
if (!hyd->OpenHflag) if (!hyd->OpenHflag)
@@ -229,7 +223,7 @@ int runqual(EN_Project *pr, long *t)
// Save current results to output file // Save current results to output file
if (time->Htime >= time->Rtime) if (time->Htime >= time->Rtime)
{ {
if (pr->save_options.Saveflag) if (pr->outfile.Saveflag)
{ {
errcode = saveoutput(pr); errcode = saveoutput(pr);
pr->report.Nperiods++; pr->report.Nperiods++;
@@ -239,7 +233,7 @@ int runqual(EN_Project *pr, long *t)
if (errcode) return errcode; if (errcode) return errcode;
// If simulating water quality // If simulating water quality
if (qual->Qualflag != NONE && qual->Qtime < time->Dur) if (qual->Qualflag != NONE && time->Qtime < time->Dur)
{ {
// ... compute reaction rate coeffs. // ... compute reaction rate coeffs.
if (qual->Reactflag && qual->Qualflag != AGE) ratecoeffs(pr); 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 ** 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 hydstep; // Time step until next hydraulic event
long dt, qtime; long dt, qtime;
int errcode = 0; int errcode = 0;
quality_t *qual = &pr->quality;
time_options_t *time = &pr->time_options;
// Find time step till next hydraulic event // Find time step till next hydraulic event
*tstep = 0; *tstep = 0;
hydstep = 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 // Perform water quality routing over this time step
if (qual->Qualflag != NONE && hydstep > 0) if (qual->Qualflag != NONE && hydstep > 0)
@@ -286,7 +280,7 @@ int nextqual(EN_Project *pr, long *tstep)
qtime = 0; qtime = 0;
while (!qual->OutOfMemory && qtime < hydstep) while (!qual->OutOfMemory && qtime < hydstep)
{ {
dt = MIN(qual->Qstep, hydstep - qtime); dt = MIN(time->Qstep, hydstep - qtime);
qtime += dt; qtime += dt;
transport(pr, dt); transport(pr, dt);
} }
@@ -298,7 +292,7 @@ int nextqual(EN_Project *pr, long *tstep)
// Update current time // Update current time
if (!errcode) *tstep = hydstep; if (!errcode) *tstep = hydstep;
qual->Qtime += hydstep; time->Qtime += hydstep;
// If no more time steps remain // If no more time steps remain
if (!errcode && *tstep == 0) if (!errcode && *tstep == 0)
@@ -310,13 +304,13 @@ int nextqual(EN_Project *pr, long *tstep)
} }
// ... write the final portion of the binary output file // ... 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; return errcode;
} }
int stepqual(EN_Project *pr, long *tleft) int stepqual(Project *pr, long *tleft)
/* /*
**-------------------------------------------------------------- **--------------------------------------------------------------
** Input: none ** 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; long dt, hstep, t, tstep;
int errcode = 0; int errcode = 0;
quality_t *qual = &pr->quality; tstep = time->Qstep;
tstep = qual->Qstep;
do do
{ {
// Set local time step to quality time step // Set local time step to quality time step
dt = tstep; dt = tstep;
// Find time step until next hydraulic event // 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 next hydraulic event occurs before end of local time step
if (hstep < dt) if (hstep < dt)
@@ -349,21 +344,21 @@ int stepqual(EN_Project *pr, long *tleft)
// ... transport quality over local time step // ... transport quality over local time step
if (qual->Qualflag != NONE) transport(pr, dt); if (qual->Qualflag != NONE) transport(pr, dt);
qual->Qtime += dt; time->Qtime += dt;
// ... quit if running quality concurrently with hydraulics // ... quit if running quality concurrently with hydraulics
if (pr->hydraulics.OpenHflag) break; if (pr->hydraul.OpenHflag) break;
// ... otherwise call runqual() to update hydraulics // ... otherwise call runqual() to update hydraulics
errcode = runqual(pr, &t); errcode = runqual(pr, &t);
qual->Qtime = t; time->Qtime = t;
} }
// Otherwise transport quality over current local time step // Otherwise transport quality over current local time step
else else
{ {
if (qual->Qualflag != NONE) transport(pr, dt); if (qual->Qualflag != NONE) transport(pr, dt);
qual->Qtime += dt; time->Qtime += dt;
} }
// Reduce quality time step by local time step // Reduce quality time step by local time step
@@ -376,7 +371,7 @@ int stepqual(EN_Project *pr, long *tleft)
evalmassbalance(pr); evalmassbalance(pr);
// Update total simulation time left // Update total simulation time left
*tleft = pr->time_options.Dur - qual->Qtime; *tleft = time->Dur - time->Qtime;
// If no more time steps remain // If no more time steps remain
if (!errcode && *tleft == 0) if (!errcode && *tleft == 0)
@@ -388,13 +383,13 @@ int stepqual(EN_Project *pr, long *tleft)
} }
// ... write the final portion of the binary output file // ... 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; return errcode;
} }
int closequal(EN_Project *pr) int closequal(Project *pr)
/* /*
**-------------------------------------------------------------- **--------------------------------------------------------------
** Input: none ** Input: none
@@ -403,7 +398,7 @@ int closequal(EN_Project *pr)
**-------------------------------------------------------------- **--------------------------------------------------------------
*/ */
{ {
quality_t *qual = &pr->quality; Quality *qual = &pr->quality;
int errcode = 0; int errcode = 0;
if (qual->SegPool) mempool_delete(qual->SegPool); if (qual->SegPool) mempool_delete(qual->SegPool);
@@ -411,14 +406,12 @@ int closequal(EN_Project *pr)
FREE(qual->LastSeg); FREE(qual->LastSeg);
FREE(qual->PipeRateCoeff); FREE(qual->PipeRateCoeff);
FREE(qual->FlowDir); FREE(qual->FlowDir);
FREE(qual->Ilist);
FREE(qual->IlistPtr);
FREE(qual->SortedNodes); FREE(qual->SortedNodes);
return errcode; return errcode;
} }
double avgqual(EN_Project *pr, int k) double avgqual(Project *pr, int k)
/* /*
**-------------------------------------------------------------- **--------------------------------------------------------------
** Input: k = link index ** 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; double vsum = 0.0, msum = 0.0;
Pseg seg; Pseg seg;
EN_Network *net = &pr->network;
quality_t *qual = &pr->quality;
if (qual->Qualflag == NONE) return 0.0; if (qual->Qualflag == NONE) return 0.0;
// Sum up the quality and volume in each segment of the link // 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 ** 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; double massadded = 0.0, c;
Psource source; 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 // Sources only apply to CHEMICAL analyses
if (qual->Qualflag != CHEM) return 0.0; 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; source = net->Node[n].S;
if (source == NULL) return 0.0; if (source == NULL) return 0.0;
if (source->C0 == 0.0) 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 // Added source concentration depends on source type
c = sourcequal(pr, source); 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 ** 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; int i;
long k; long k;
double c; 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 // Get source concentration (or mass flow) in original units
c = source->C0; c = source->C0;
@@ -568,13 +561,13 @@ double sourcequal(EN_Project *pr, Psource source)
// Apply time pattern if assigned // Apply time pattern if assigned
i = source->Pat; i = source->Pat;
if (i == 0) return c; if (i == 0) return c;
k = ((qual->Qtime + time->Pstart) / time->Pstep) % k = ((time->Qtime + time->Pstart) / time->Pstep) %
(long)net->Pattern[i].Length; (long)net->Pattern[i].Length;
return (c * net->Pattern[i].F[k]); return (c * net->Pattern[i].F[k]);
} }
void evalmassbalance(EN_Project *pr) void evalmassbalance(Project *pr)
/* /*
**-------------------------------------------------------------- **--------------------------------------------------------------
** Input: none ** Input: none
@@ -584,27 +577,28 @@ void evalmassbalance(EN_Project *pr)
**-------------------------------------------------------------- **--------------------------------------------------------------
*/ */
{ {
Quality *qual = &pr->quality;
double massin; double massin;
double massout; double massout;
double massreacted; 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 else
{ {
qual->massbalance.final = findstoredmass(pr); qual->MassBalance.final = findstoredmass(pr);
massin = qual->massbalance.initial + qual->massbalance.inflow; massin = qual->MassBalance.initial + qual->MassBalance.inflow;
massout = qual->massbalance.outflow + qual->massbalance.final; massout = qual->MassBalance.outflow + qual->MassBalance.final;
massreacted = qual->massbalance.reacted; massreacted = qual->MassBalance.reacted;
if (massreacted > 0.0) massout += massreacted; if (massreacted > 0.0) massout += massreacted;
else massin -= massreacted; else massin -= massreacted;
if (massin == 0.0) qual->massbalance.ratio = 1.0; if (massin == 0.0) qual->MassBalance.ratio = 1.0;
else qual->massbalance.ratio = massout / massin; else qual->MassBalance.ratio = massout / massin;
} }
} }
double findstoredmass(EN_Project *pr) double findstoredmass(Project *pr)
/* /*
**-------------------------------------------------------------- **--------------------------------------------------------------
** Input: none ** Input: none
@@ -614,13 +608,13 @@ double findstoredmass(EN_Project *pr)
**-------------------------------------------------------------- **--------------------------------------------------------------
*/ */
{ {
Network *net = &pr->network;
Quality *qual = &pr->quality;
int i, k; int i, k;
double totalmass = 0.0; double totalmass = 0.0;
Pseg seg; Pseg seg;
EN_Network *net = &pr->network;
quality_t *qual = &pr->quality;
// Mass residing in each pipe // Mass residing in each pipe
for (k = 1; k <= net->Nlinks; k++) for (k = 1; k <= net->Nlinks; k++)
{ {
@@ -654,7 +648,7 @@ double findstoredmass(EN_Project *pr)
return totalmass; return totalmass;
} }
int flowdirchanged(EN_Project *pr) int flowdirchanged(Project *pr)
/* /*
**-------------------------------------------------------------- **--------------------------------------------------------------
** Input: none ** Input: none
@@ -663,25 +657,25 @@ int flowdirchanged(EN_Project *pr)
**-------------------------------------------------------------- **--------------------------------------------------------------
*/ */
{ {
Hydraul *hyd = &pr->hydraul;
Quality *qual = &pr->quality;
int k; int k;
int result = FALSE; int result = FALSE;
int newdir; int newdir;
int olddir; int olddir;
double q; double q;
hydraulics_t *hyd = &pr->hydraulics;
quality_t *qual = &pr->quality;
// Examine each network link // Examine each network link
for (k = 1; k <= pr->network.Nlinks; k++) for (k = 1; k <= pr->network.Nlinks; k++)
{ {
// Determine sign (+1 or -1) of new flow rate // Determine sign (+1 or -1) of new flow rate
olddir = qual->FlowDir[k]; 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); newdir = SGN(q);
// Indicate if flow is negligible // 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 // Reverse link's volume segments if flow direction changes sign
if (newdir * olddir < 0) reversesegs(pr, k); if (newdir * olddir < 0) reversesegs(pr, k);
@@ -696,5 +690,3 @@ int flowdirchanged(EN_Project *pr)
} }
return result; return result;
} }
/************************* End of QUALITY.C ***************************/

View File

@@ -1,40 +1,45 @@
/* /*
********************************************************************* ******************************************************************************
Project: OWA EPANET
QUALREACT.C -- water quality reaction module for the EPANET program 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 <stdio.h>
#include <math.h> #include <math.h>
#include "types.h" #include "types.h"
// Exported Functions // Exported functions
char setreactflag(EN_Project *pr); char setreactflag(Project *);
double getucf(double); double getucf(double);
void ratecoeffs(EN_Project *pr); void ratecoeffs(Project *);
void reactpipes(EN_Project *pr, long); void reactpipes(Project *, long);
void reacttanks(EN_Project *pr, long); void reacttanks(Project *, long);
double mixtank(EN_Project *pr, int, double, double ,double); double mixtank(Project *, int, double, double ,double);
// Imported Functions // Imported functions
extern void addseg(EN_Project *pr, int, double, double); extern void addseg(Project *, int, double, double);
// Local Functions // Local functions
static double piperate(EN_Project *pr, int); static double piperate(Project *, int);
static double pipereact(EN_Project *pr, int, double, double, long); static double pipereact(Project *, int, double, double, long);
static double tankreact(EN_Project *pr, double, double, double, long); static double tankreact(Project *, double, double, double, long);
static double bulkrate(EN_Project *pr, double, double, double); static double bulkrate(Project *, double, double, double);
static double wallrate(EN_Project *pr, double, double, double, double); static double wallrate(Project *, double, double, double, double);
static void tankmix1(EN_Project *pr, int, double, double, double); static void tankmix1(Project *, int, double, double, double);
static void tankmix2(EN_Project *pr, int, double, double, double); static void tankmix2(Project *, int, double, double, double);
static void tankmix3(EN_Project *pr, int, double, double, double); static void tankmix3(Project *, int, double, double, double);
static void tankmix4(EN_Project *pr, int, double, double, double); static void tankmix4(Project *, int, double, double, double);
char setreactflag(EN_Project *pr) char setreactflag(Project *pr)
/* /*
**----------------------------------------------------------- **-----------------------------------------------------------
** Input: none ** Input: none
@@ -43,8 +48,8 @@ char setreactflag(EN_Project *pr)
**----------------------------------------------------------- **-----------------------------------------------------------
*/ */
{ {
Network *net = &pr->network;
int i; int i;
EN_Network *net = &pr->network;
if (pr->quality.Qualflag == TRACE) return 0; if (pr->quality.Qualflag == TRACE) return 0;
else if (pr->quality.Qualflag == AGE) return 1; 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 ** Input: none
@@ -91,12 +96,12 @@ void ratecoeffs(EN_Project *pr)
**-------------------------------------------------------------- **--------------------------------------------------------------
*/ */
{ {
Network *net = &pr->network;
Quality *qual = &pr->quality;
int k; int k;
double kw; double kw;
EN_Network *net = &pr->network;
quality_t *qual = &pr->quality;
for (k = 1; k <= net->Nlinks; k++) for (k = 1; k <= net->Nlinks; k++)
{ {
kw = net->Link[k].Kw; 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 ** 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; int k;
Pseg seg; Pseg seg;
double cseg, rsum, vsum; double cseg, rsum, vsum;
EN_Network *net = &pr->network;
quality_t *qual = &pr->quality;
// Examine each link in network // Examine each link in network
for (k = 1; k <= net->Nlinks; k++) 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); seg->c = pipereact(pr, k, seg->c, seg->v, dt);
// Update reaction component of mass balance // 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 // Accumulate volume-weighted reaction rate
if (qual->Qualflag == CHEM) 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 ** 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; int i, k;
double c; double c;
Pseg seg; Pseg seg;
EN_Network *net = &pr->network;
quality_t *qual = &pr->quality;
Stank *tank; Stank *tank;
// Examine each tank in network // Examine each tank in network
@@ -191,14 +196,14 @@ void reacttanks(EN_Project *pr, long dt)
{ {
c = seg->c; c = seg->c;
seg->c = tankreact(pr, seg->c, seg->v, tank->Kb, dt); 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; seg = seg->prev;
} }
} }
} }
double piperate(EN_Project *pr, int k) double piperate(Project *pr, int k)
/* /*
**-------------------------------------------------------------- **--------------------------------------------------------------
** Input: k = link index ** 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; double a, d, u, q, kf, kw, y, Re, Sh;
hydraulics_t *hyd = &pr->hydraulics;
quality_t *qual = &pr->quality;
d = net->Link[k].Diam; // Pipe diameter, ft d = net->Link[k].Diam; // Pipe diameter, ft
@@ -226,7 +231,7 @@ double piperate(EN_Project *pr, int k)
// Compute Reynolds No. // Compute Reynolds No.
// Flow rate made consistent with how its saved to hydraulics file // 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 a = PI * d * d / 4.0; // pipe area
u = fabs(q) / a; // flow velocity u = fabs(q) / a; // flow velocity
Re = u * d / hyd->Viscos; // Reynolds number 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 ** 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; double cnew, dc, dcbulk, dcwall, rbulk, rwall;
quality_t *qual = &pr->quality;
// For water age (hrs), update concentration by timestep // For water age (hrs), update concentration by timestep
if (qual->Qualflag == AGE) 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; dcwall = rwall * (double)dt;
// Update cumulative mass reacted // 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->Wbulk += fabs(dcbulk) * v;
qual->Wwall += fabs(dcwall) * 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 ** 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; double cnew, dc, rbulk;
quality_t *qual = &pr->quality;
// For water age, update concentration by timestep // For water age, update concentration by timestep
if (qual->Qualflag == AGE) 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 // Find concentration change & update quality
dc = rbulk * (double)dt; 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; 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 ** 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; double c1;
quality_t *qual = &pr->quality;
// Find bulk reaction potential taking into account // Find bulk reaction potential taking into account
// limiting potential & reaction order. // 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 ** 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 (kw == 0.0 || d == 0.0) return (0.0);
if (qual->WallOrder == 0.0) // 0-order reaction */ 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 ** 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; int i;
double vnet; double vnet;
EN_Network *net = &pr->network;
quality_t *qual = &pr->quality;
i = n - net->Njuncs; i = n - net->Njuncs;
vnet = volin - volout; vnet = volin - volout;
switch (net->Tank[i].MixModel) 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 ** 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; int k;
double vnew; double vnew;
Pseg seg; Pseg seg;
EN_Network *net = &pr->network;
hydraulics_t *hyd = &pr->hydraulics;
quality_t *qual = &pr->quality;
Stank *tank = &net->Tank[i]; Stank *tank = &net->Tank[i];
k = net->Nlinks + 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 ** 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; int k;
double vt, // Transferred volume double vt, // Transferred volume
vmz; // Full mixing zone volume vmz; // Full mixing zone volume
Pseg mixzone, // Mixing zone segment Pseg mixzone, // Mixing zone segment
stagzone; // Stagnant zone segment stagzone; // Stagnant zone segment
EN_Network *net = &pr->network;
quality_t *qual = &pr->quality;
Stank *tank = &pr->network.Tank[i]; Stank *tank = &pr->network.Tank[i];
// Identify segments for each compartment // 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 ** 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; int k;
double vout, vseg; double vout, vseg;
double cin, vsum, wsum; double cin, vsum, wsum;
Pseg seg; Pseg seg;
EN_Network *net = &pr->network;
hydraulics_t *hyd = &pr->hydraulics;
quality_t *qual = &pr->quality;
Stank *tank = &pr->network.Tank[i]; Stank *tank = &pr->network.Tank[i];
k = net->Nlinks + 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 ** 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; int k, n;
double cin, vsum, wsum, vseg; double cin, vsum, wsum, vseg;
Pseg seg; Pseg seg;
EN_Network *net = &pr->network;
quality_t *qual = &pr->quality;
Stank *tank = &pr->network.Tank[i]; Stank *tank = &pr->network.Tank[i];
k = net->Nlinks + i; k = net->Nlinks + i;

View File

@@ -1,46 +1,55 @@
/* /*
********************************************************************* ******************************************************************************
Project: OWA EPANET
QUALROUTE.C -- water quality routing module for the EPANET program 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 "mempool.h"
#include "types.h" #include "types.h"
// Macro to compute the volume of a link // Macro to compute the volume of a link
#define LINKVOL(k) (0.785398 * net->Link[(k)].Len * SQR(net->Link[(k)].Diam)) #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 // 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 // Exported functions
int buildilists(EN_Project *pr); int sortnodes(Project *);
int sortnodes(EN_Project *pr); void transport(Project *, long);
void transport(EN_Project *pr, long); void initsegs(Project *);
void initsegs(EN_Project *pr); void reversesegs(Project *, int);
void reversesegs(EN_Project *pr, int); void addseg(Project *, int, double, double);
void addseg(EN_Project *pr, int, double, double);
// Imported Functions // Imported functions
extern double findsourcequal(EN_Project *pr, int, double, double, long); extern double findsourcequal(Project *, int, double, double, long);
extern void reactpipes(EN_Project *pr, long); extern void reactpipes(Project *, long);
extern void reacttanks(EN_Project *pr, long); extern void reacttanks(Project *, long);
extern double mixtank(EN_Project *pr, int, double, double, double); extern double mixtank(Project *, int, double, double, double);
// Local Functions // Local functions
static void evalnodeinflow(EN_Project *pr, int, long, double *, double *); static void evalnodeinflow(Project *, int, long, double *, double *);
static void evalnodeoutflow(EN_Project *pr, int, double, long); static void evalnodeoutflow(Project *, int, double, long);
static double findnodequal(EN_Project *pr, int, double, double, double, long); static double findnodequal(Project *, int, double, double, double, long);
static double noflowqual(EN_Project *pr, int); static double noflowqual(Project *, int);
static void updatemassbalance(EN_Project *pr, int, double, double, long); static void updatemassbalance(Project *, int, double, double, long);
static int selectnonstacknode(EN_Project *pr, int, int *); 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 ** Input: tstep = length of current time step
@@ -50,12 +59,13 @@ void transport(EN_Project *pr, long tstep)
**-------------------------------------------------------------- **--------------------------------------------------------------
*/ */
{ {
int i, j, k, m, n; Network *net = &pr->network;
double volin, massin, volout, nodequal; Hydraul *hyd = &pr->hydraul;
Quality *qual = &pr->quality;
hydraulics_t *hyd = &pr->hydraulics; int j, k, m, n;
quality_t *qual = &pr->quality; double volin, massin, volout, nodequal;
EN_Network *net = &pr->network; Padjlist alink;
// React contents of each pipe and tank // React contents of each pipe and tank
if (qual->Reactflag) if (qual->Reactflag)
@@ -76,10 +86,10 @@ void transport(EN_Project *pr, long tstep)
volout = 0.0; volout = 0.0;
// ... examine each link with flow into the node // ... 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 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 // ... link has flow into node - add it to node's inflow
// (m is index of link's downstream node) // (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); nodequal = findnodequal(pr, n, volin, massin, volout, tstep);
// ... examine each link with flow out of the node // ... 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 // ... 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; m = net->Link[k].N1;
if (qual->FlowDir[k] < 0) m = net->Link[k].N2; if (qual->FlowDir[k] < 0) m = net->Link[k].N2;
if (m == n) 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) 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; double q, v, vseg;
Pseg seg; 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 // Get flow rate (q) and flow volume (v) through link
q = LINKFLOW(k); q = LINKFLOW(k);
v = fabs(q) * tstep; 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) double massin, double volout, long tstep)
/* /*
**-------------------------------------------------------------- **--------------------------------------------------------------
@@ -200,9 +210,9 @@ double findnodequal(EN_Project *pr, int n, double volin,
**-------------------------------------------------------------- **--------------------------------------------------------------
*/ */
{ {
EN_Network *net = &pr->network; Network *net = &pr->network;
hydraulics_t *hyd = &pr->hydraulics; Hydraul *hyd = &pr->hydraul;
quality_t *qual = &pr->quality; Quality *qual = &pr->quality;
// Node is a junction - update its water quality // Node is a junction - update its water quality
if (net->Node[n].Type == JUNCTION) 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 ** 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; double c = 0.0;
FlowDirection dir; FlowDirection dir;
Padjlist alink;
EN_Network *net = &pr->network;
hydraulics_t *hyd = &pr->hydraulics;
quality_t *qual = &pr->quality;
// Examine each link incident on the node // 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 // ... index of an incident link
k = qual->Ilist[i]; k = alink->link;
dir = qual->FlowDir[k]; dir = qual->FlowDir[k];
// Node n is link's downstream node - add quality // 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 ** 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; double v;
Pseg seg; Pseg seg;
hydraulics_t *hyd = &pr->hydraulics;
quality_t *qual = &pr->quality;
// Find flow volume (v) released over time step // Find flow volume (v) released over time step
v = fabs(LINKFLOW(k)) * tstep; v = fabs(LINKFLOW(k)) * tstep;
if (v == 0.0) return; 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) 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, double masslost = 0.0,
massadded = 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) switch (net->Node[n].Type)
{ {
// Junctions lose mass from outflow demand & gain it from source inflow // 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; massadded = qual->SourceQual * volout;
break; break;
} }
qual->massbalance.outflow += masslost; qual->MassBalance.outflow += masslost;
qual->massbalance.inflow += massadded; qual->MassBalance.inflow += massadded;
} }
int sortnodes(Project *pr)
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)
/* /*
**-------------------------------------------------------------- **--------------------------------------------------------------
** Input: none ** 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 i, j, k, n;
int *indegree = NULL; int *indegree = NULL;
int *stack = NULL; int *stack = NULL;
@@ -494,10 +438,7 @@ int sortnodes(EN_Project *pr)
int numsorted = 0; int numsorted = 0;
int errcode = 0; int errcode = 0;
FlowDirection dir; FlowDirection dir;
Padjlist alink;
EN_Network *net = &pr->network;
hydraulics_t *hyd = &pr->hydraulics;
quality_t *qual = &pr->quality;
// Allocate an array to count # links with inflow to each node // Allocate an array to count # links with inflow to each node
// and for a stack to hold nodes waiting to be processed // 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 // ... for each outflow link from this node reduce the in-degree
// of its downstream node // 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 is the index of the next link incident on node i
k = qual->Ilist[j]; k = alink->link;
// ... skip link if flow is negligible // ... skip link if flow is negligible
if (qual->FlowDir[k] == 0) continue; if (qual->FlowDir[k] == 0) continue;
@@ -579,25 +520,11 @@ int sortnodes(EN_Project *pr)
if (numsorted < net->Nnodes) errcode = 120; if (numsorted < net->Nnodes) errcode = 120;
FREE(indegree); FREE(indegree);
FREE(stack); 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; 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 ** 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; int i, m, n;
EN_Network *net = &pr->network; Padjlist alink;
// Examine each sorted node in last in - first out order // Examine each sorted node in last in - first out order
for (i = numsorted; i > 0; i--) for (i = numsorted; i > 0; i--)
{ {
// For each link connected to the sorted node // For each link connected to the sorted node
m = qual->SortedNodes[i]; 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 is the node of link k opposite to node m
n = net->Link[k].N2; n = alink->node;
if (n == m) n = net->Link[k].N1;
// ... select node n if it still has inflow links // ... select node n if it still has inflow links
if (indegree[n] > 0) return n; 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 ** 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; int j, k;
double c, v, v1; 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 // Add one segment with assigned downstream node quality to each pipe
for (k = 1; k <= net->Nlinks; k++) 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 ** Input: k = link index
@@ -715,8 +639,8 @@ void reversesegs(EN_Project *pr, int k)
**-------------------------------------------------------------- **--------------------------------------------------------------
*/ */
{ {
Quality *qual = &pr->quality;
Pseg seg, nseg, pseg; Pseg seg, nseg, pseg;
quality_t *qual = &pr->quality;
seg = qual->FirstSeg[k]; seg = qual->FirstSeg[k];
qual->FirstSeg[k] = qual->LastSeg[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 ** 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; Pseg seg;
quality_t *qual = &pr->quality;
// Grab the next free segment from the segment pool if available // Grab the next free segment from the segment pool if available
if (qual->FreeSeg != NULL) if (qual->FreeSeg != NULL)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,22 +1,21 @@
/* /*
**************************************************** ******************************************************************************
Project: OWA EPANET
String Constants for EPANET Program Version: 2.2
Module: text.h
VERSION: 2.00 Description: string constants used throughout EPANET
DATE: 5/8/00 Authors: see AUTHORS
10/25/00 Copyright: see AUTHORS
8/15/07 (2.00.11) License: see LICENSE
2/14/08 (2.00.12) Last Updated: 11/27/2018
AUTHOR: L. Rossman ******************************************************************************
US EPA - NRMRL
****************************************************
*/ */
/* ------------ Keyword Dictionary ---------- */
#ifndef TEXT_H #ifndef TEXT_H
#define TEXT_H #define TEXT_H
//------- Keyword Dictionary ------------------------------
#define w_USE "USE" #define w_USE "USE"
#define w_SAVE "SAVE" #define w_SAVE "SAVE"
@@ -194,7 +193,8 @@ AUTHOR: L. Rossman
#define w_ELSE "ELSE" #define w_ELSE "ELSE"
#define w_PRIORITY "PRIO" #define w_PRIORITY "PRIO"
/* ---------Input Section Names ---------- */ // ------ Input File Section Names ------------------------
#define s_TITLE "[TITLE]" #define s_TITLE "[TITLE]"
#define s_JUNCTIONS "[JUNCTIONS]" #define s_JUNCTIONS "[JUNCTIONS]"
#define s_RESERVOIRS "[RESERVOIRS]" #define s_RESERVOIRS "[RESERVOIRS]"
@@ -225,8 +225,8 @@ AUTHOR: L. Rossman
#define s_TAGS "[TAGS]" #define s_TAGS "[TAGS]"
#define s_END "[END]" #define s_END "[END]"
/* ---------------- Units ---------------- */ //------- Units -------------------------------------------
/*** Limit units to MAXID or less characters ***/
#define u_CFS "cfs" #define u_CFS "cfs"
#define u_GPM "gpm" #define u_GPM "gpm"
#define u_AFD "a-f/d" #define u_AFD "a-f/d"
@@ -257,13 +257,15 @@ AUTHOR: L. Rossman
#define u_per1000FT "/1000ft" #define u_per1000FT "/1000ft"
#define u_HP "hp" #define u_HP "hp"
/* -------------- Curve Types ----------------- */ //------- Curve Types -------------------------------------
#define c_HEADLOSS "HEADLOSS" #define c_HEADLOSS "HEADLOSS"
#define c_PUMP "PUMP" #define c_PUMP "PUMP"
#define c_EFFIC "EFFIC" #define c_EFFIC "EFFIC"
#define c_VOLUME "VOLUME" #define c_VOLUME "VOLUME"
/* ------------------ Text Phrases ------------------- */ //------- Text Phrases ------------------------------------
#define t_ABOVE "above" #define t_ABOVE "above"
#define t_BELOW "below" #define t_BELOW "below"
#define t_HW "Hazen-Williams" #define t_HW "Hazen-Williams"
@@ -334,7 +336,8 @@ AUTHOR: L. Rossman
#define t_ORIFICE "Orifice Flow" #define t_ORIFICE "Orifice Flow"
/* ------------------ Format Messages ------------------*/ //----- Summary Report Format Strings ---------------------
#define LOGO1 \ #define LOGO1 \
"******************************************************************" "******************************************************************"
#define LOGO2 \ #define LOGO2 \
@@ -399,10 +402,9 @@ AUTHOR: L. Rossman
#define FMT47 " with %s below %-.2f %s" #define FMT47 " with %s below %-.2f %s"
#define FMT48 " with %s above %-.2f %s" #define FMT48 " with %s above %-.2f %s"
/* ---------- Status Report Format Strings ------------ */ //----- Status Report Format Strings ----------------------
#define FMT49 "Hydraulic Status:"
/*** Updated 6/24/02 ***/ #define FMT49 "Hydraulic Status:"
#define FMT50 "%10s: Tank %s is %s at %-.2f %s" #define FMT50 "%10s: Tank %s is %s at %-.2f %s"
#define FMT51 "%10s: Reservoir %s is %s" #define FMT51 "%10s: Reservoir %s is %s"
#define FMT52 "%10s: %s %s %s" #define FMT52 "%10s: %s %s %s"
@@ -422,13 +424,12 @@ AUTHOR: L. Rossman
#define FMT63 "%10s: %s %s changed by rule %s" #define FMT63 "%10s: %s %s changed by rule %s"
#define FMT64 "%10s: Balancing the network:\n" #define FMT64 "%10s: Balancing the network:\n"
#define FMT65 " Trial %2d: relative flow change = %-.6f" #define FMT65 " Trial %2d: relative flow change = %-.6f"
/*** End of update ***/
#define FMT66 " maximum flow change = %.4f for Link %s" #define FMT66 " maximum flow change = %.4f for Link %s"
#define FMT67 " maximum flow change = %.4f for Node %s" #define FMT67 " maximum flow change = %.4f for Node %s"
#define FMT68 " maximum head error = %.4f for Link %s\n" #define FMT68 " maximum head error = %.4f for Link %s\n"
/* -------------------- Energy Report Table ------------------- */ //----- Energy Report Table -------------------------------
#define FMT71 "Energy Usage:" #define FMT71 "Energy Usage:"
#define FMT72 \ #define FMT72 \
" Usage Avg. Kw-hr Avg. Peak Cost" " Usage Avg. Kw-hr Avg. Peak Cost"
@@ -437,18 +438,21 @@ AUTHOR: L. Rossman
#define FMT74 "%38s Demand Charge: %9.2f" #define FMT74 "%38s Demand Charge: %9.2f"
#define FMT75 "%38s Total Cost: %9.2f" #define FMT75 "%38s Total Cost: %9.2f"
/* -------------------- Node Report Table --------------------- */ //----- Node Report Table ---------------------------------
#define FMT76 "%s Node Results:" #define FMT76 "%s Node Results:"
#define FMT77 "Node Results:" #define FMT77 "Node Results:"
#define FMT78 "Node Results at %s hrs:" #define FMT78 "Node Results at %s hrs:"
/* -------------------- Link Report Table --------------------- */ //----- Link Report Table ---------------------------------
#define FMT79 "%s Link Results:" #define FMT79 "%s Link Results:"
#define FMT80 "Link Results:" #define FMT80 "Link Results:"
#define FMT81 "Link Results at %s hrs:" #define FMT81 "Link Results at %s hrs:"
#define FMT82 "\n\f\n Page %-d %60.60s\n" #define FMT82 "\n\f\n Page %-d %60.60s\n"
/* ------------------- Progress Messages ---------------------- */ //----- Progress Messages ---------------------------------
#define FMT100 " Retrieving network data ... " #define FMT100 " Retrieving network data ... "
#define FMT101 " Computing hydraulics at hour %-10s " #define FMT101 " Computing hydraulics at hour %-10s "
#define FMT102 " Computing water quality at hour %-10s " #define FMT102 " Computing water quality at hour %-10s "
@@ -457,16 +461,17 @@ AUTHOR: L. Rossman
#define FMT104 "Analysis begun %s" #define FMT104 "Analysis begun %s"
#define FMT105 "Analysis ended %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_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_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_ERR203 "Input Error 203: undefined node in following line of "
#define R_ERR204 "Input Error 204: undefined link 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_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 " #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 WARN01 "WARNING: System unbalanced at %s hrs."
#define WARN02 \ #define WARN02 \
"WARNING: Maximum trials exceeded at %s hrs. System may be unstable." "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 WARN05 "WARNING: %s %s %s at %s hrs."
#define WARN06 "WARNING: Negative pressures at %s hrs." #define WARN06 "WARNING: Negative pressures at %s hrs."
/*-------------------- General Warning Messages -------------------------*/ //----- General Warning Messages --------------------------
#define WARN1 "WARNING: System hydraulically unbalanced." #define WARN1 "WARNING: System hydraulically unbalanced."
#define WARN2 "WARNING: System may be hydraulically unstable." #define WARN2 "WARNING: System may be hydraulically unstable."
#define WARN3 "WARNING: System disconnected." #define WARN3 "WARNING: System disconnected."

File diff suppressed because it is too large Load Diff

View File

@@ -21,9 +21,9 @@ Find /i "x86" < checkOS.tmp > StringCheck.tmp
If %ERRORLEVEL% == 1 ( If %ERRORLEVEL% == 1 (
CALL "%SDK_PATH%bin\"SetEnv.cmd /x64 /release CALL "%SDK_PATH%bin\"SetEnv.cmd /x64 /release
rem : create EPANET2.DLL 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 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 md "%Build_PATH%"\64bit
move /y "%SRC_PATH%"\*.dll "%Build_PATH%"\64bit move /y "%SRC_PATH%"\*.dll "%Build_PATH%"\64bit
move /y "%SRC_PATH%"\*.exe "%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 CALL "%SDK_PATH%bin\"SetEnv.cmd /x86 /release
echo "32 bit with epanet2.def mapping" echo "32 bit with epanet2.def mapping"
rem : create EPANET2.DLL 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 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 md "%Build_PATH%"\32bit
move /y "%SRC_PATH%"\*.dll "%Build_PATH%"\32bit move /y "%SRC_PATH%"\*.dll "%Build_PATH%"\32bit
move /y "%SRC_PATH%"\*.exe "%Build_PATH%"\32bit move /y "%SRC_PATH%"\*.exe "%Build_PATH%"\32bit