EPANET中读取INPUT文件的函数文件——INPUT3.C
/*
********************************************************************** INPUT3.C -- Input data parser for EPANET; VERSION: 2.00
DATE: 5/30/00
9/7/00
10/25/00
3/1/01
6/24/02
8/15/07 (2.00.11)
2/14/08 (2.00.12)
AUTHOR: L. Rossman
US EPA - NRMRL This module parses data from each line of input from file InFile.
All functions in this module are called from newline() in INPUT2.C.
该模块逐行解析INPUT文件。
该模块中的所有函数都在INPUT2.C的newline(int sect, char *line)中被调用。 同时该模块也调用了INPUT2.C中的部分工具函数:addlinkID(int n, char *id)、addnodeID(int n, char *id)、addpattern(char *id)、
addcurve(char *id)、*findID(char *id, STmplist *list)、match(char *str, char *substr)、hour(char *time, char *units)等 **********************************************************************
*/ #include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <math.h>
#include "hash.h"
#include "text.h"
#include "types.h"
#include "funcs.h"
#define EXTERN extern
#include "vars.h" /* Defined in enumstxt.h in EPANET.C */
extern char *MixTxt[];
extern char *Fldname[]; //字段名称字符串数组 /* Defined in INPUT2.C */
extern char *Tok[MAXTOKS]; /* Array of token strings ;每一输入行的项数组成的字符串数组*/
extern STmplist *PrevPat; /* Pointer to pattern list element ;指向模式的最近一个指针*/
extern STmplist *PrevCurve; /* Pointer to curve list element ;指向曲线的最近一个指针*/
extern int Ntokens; /* Number of tokens in input line ;每一输入行的项数(项与项之间的分隔形式是:)*/ int juncdata()
/*
**--------------------------------------------------------------
** Input: none ;输入:无
** Output: returns error code ;输出:错误编码
** Purpose: processes junction data ;作用:处理节点数据
** Format: ;格式:
** [JUNCTIONS]
** id elev. (demand) (demand pattern) 数据项的列表
**--------------------------------------------------------------
*/
{
int n, p = ;//n代表待解析行中的数据项的个数;p代表该节点的用水模式链表中的index值;
double el,y = 0.0;//el表示该节点的高程值;y表示该节点的用水量值
Pdemand demand;//当该节点存在多个用水量及对应的用水模式曲线时,使用该变量保存
STmplist *pat; /* Add new junction to data base ;增加一个新的节点数据*/
n = Ntokens;
if (Nnodes == MaxNodes) return();
Njuncs++;
Nnodes++;
if (!addnodeID(Njuncs,Tok[])) return(); /* Check for valid data ;检查该数据的正确性*/
if (n < ) return();//不存在高程信息
if (!getfloat(Tok[],&el)) return();//高程信息数据类型非法
if (n >= && !getfloat(Tok[],&y)) return();//若需水量存在且需水量数据类型非法
if (n >= )
{
pat = findID(Tok[],Patlist);
if (pat == NULL) return();
p = pat->i;
} /* Save junction data ;将节点的高程等信息保存下来*/
Node[Njuncs].El = el;
Node[Njuncs].C0 = 0.0;
Node[Njuncs].S = NULL;
Node[Njuncs].Ke = 0.0;
Node[Njuncs].Rpt = ; /* Create a new demand record ;一个节点有一个指向该节点所挂的需水量指针D,将读入的水量及模式挂接到D的链首*/
/*** Updated 6/24/02 ***/
if (n >= )
{
demand = (struct Sdemand *) malloc(sizeof(struct Sdemand));
if (demand == NULL) return();
demand->Base = y;
demand->Pat = p;
demand->next = Node[Njuncs].D;
Node[Njuncs].D = demand;
D[Njuncs] = y;//全局变量中的节点实际需水量
}
else D[Njuncs] = MISSING; //标记该节点暂无以Junction节点中分配水量,如果Demand中有对该节点分水量,那么也标记为MISSING
/*** end of update ***/
return();
} /* end of juncdata */ int tankdata()
/*
**--------------------------------------------------------------
** Input: none ;输入:无
** Output: returns error code ;输出:错误代码
** Purpose: processes tank & reservoir data ;作用:处理水塔和水池(水库)数据
** Format: ;格式:
** [RESERVOIRS]
** id elev (pattern)
** [TANKS]
** id elev (pattern)
** id elev initlevel minlevel maxlevel diam (minvol vcurve)
**--------------------------------------------------------------
*/
{
int i, /* Node index Node中的索引值*/
n, /* # data items 该数据行的数据项数 */
p = , /* Fixed grade time pattern index 时间模式中的索引值 */
vcurve = ; /* Volume curve index 容积曲线的索引值*/
double el = 0.0, /* Elevation 高程值*/
initlevel = 0.0, /* Initial level 初始水面高程*/
minlevel = 0.0, /* Minimum level 最小水池高程*/
maxlevel = 0.0, /* Maximum level 最大水池高程*/
minvol = 0.0, /* Minimum volume 最小容积*/
diam = 0.0, /* Diameter 口径*/
area; /* X-sect. area 横截面面积*/
STmplist *t; /* Add new tank to data base 添加新的水塔数据*/
n = Ntokens;
if (Ntanks == MaxTanks
|| Nnodes == MaxNodes) return();
Ntanks++;
Nnodes++;
i = MaxJuncs + Ntanks; /* i = node index. i是水塔在Node中的索引 */
if (!addnodeID(i,Tok[])) return(); /* Add ID to database. 将"ID标识"及其Node的索引值添加到节点哈希表中*/ /* Check for valid data 检查数据的合法性*/
if (n < ) return(); /* Too few fields. 字段个数过少,至少包含id与高程值*/
if (!getfloat(Tok[],&el)) return(); /* Read elevation 高程值无法转成数值型*/
if (n <= ) /* Tank is reservoir.水池是特殊的水塔,如果数据项小于3项,则将水塔认为为水库*/
{
if (n == ) /* Pattern supplied 找到指定时间模式值的索引值*/
{
t = findID(Tok[],Patlist);
if (t == NULL) return();
p = t->i;
}
}
else if (n < ) return(); /* Too few fields for tank.水塔需要的字段数不能少于6个*/
else
{
/* Check for valid input data 检查水塔数据的正确性,进行类型检查*/
if (!getfloat(Tok[],&initlevel)) return();
if (!getfloat(Tok[],&minlevel)) return();
if (!getfloat(Tok[],&maxlevel)) return();
if (!getfloat(Tok[],&diam)) return();
if (diam < 0.0) return();//口径非负检查
if (n >=
&& !getfloat(Tok[],&minvol)) return(); /* If volume curve supplied check it exists 如果容积曲线存在,则对容积曲线进行存在性检查,若存在返回索引值*/
if (n == )
{
t = findID(Tok[],Curvelist);
if (t == NULL) return();
vcurve = t->i;
}
} Node[i].Rpt = ;
Node[i].El = el; /* Elevation. */
Node[i].C0 = 0.0; /* Init. quality. */
Node[i].S = NULL; /* WQ source data */
Node[i].Ke = 0.0; /* Emitter coeff. */
Tank[Ntanks].Node = i; /* Node index. */
Tank[Ntanks].H0 = initlevel; /* Init. level. */
Tank[Ntanks].Hmin = minlevel; /* Min. level. */
Tank[Ntanks].Hmax = maxlevel; /* Max level. */
Tank[Ntanks].A = diam; /* Diameter. */
Tank[Ntanks].Pat = p; /* Fixed grade pattern. */
Tank[Ntanks].Kb = MISSING; /* Reaction coeff. */
/*
*******************************************************************
NOTE: The min, max, & initial volumes set here are based on a
nominal tank diameter. They will be modified in INPUT1.C if
a volume curve is supplied for this tank.
这里的最小、最大和初始容积的计算是基于水塔的口径来的。
它们会在INPUT1.C文件中被修改,如果这个水塔存在一个容积曲线。
*******************************************************************
*/
area = PI*SQR(diam)/4.0;//横截面积
Tank[Ntanks].Vmin = area*minlevel;//最小容积
if (minvol > 0.0) Tank[Ntanks].Vmin = minvol;
Tank[Ntanks].V0 = Tank[Ntanks].Vmin + area*(initlevel - minlevel);
Tank[Ntanks].Vmax = Tank[Ntanks].Vmin + area*(maxlevel - minlevel);//最大容积 Tank[Ntanks].Vcurve = vcurve; /* Volume curve 容积曲线索引值*/
Tank[Ntanks].MixModel = MIX1; /* Completely mixed 水池出水模式*/
Tank[Ntanks].V1max = 1.0; /* Compart. size ratio */
return();
} /* end of tankdata */ int pipedata()
/*
**--------------------------------------------------------------
** Input: none ;输入:无
** Output: returns error code ;输出:错误代码
** Purpose: processes pipe data :作用:处理管段数据
** Format: ;格式:状态可以不需要,默认都是OPEN
** [PIPE]
** id node1 node2 length diam rcoeff (lcoeff) (status)
**--------------------------------------------------------------
*/
{
int j1, /* Start-node index 起始junction在Node链表中的索引值*/
j2, /* End-node index 终点junction在Node链表中的索引值*/
n; /* # data items 当前行数据项个数*/
char type = PIPE, /* Link type 管段类型,默认为Pipe*/
status = OPEN; /* Link status 管段状态(OPEN, CLOSED或CV),默认是开启状态*/
double length, /* Link length 管长*/
diam, /* Link diameter 管径*/
rcoeff, /* Roughness coeff. 粗糙系数*/
lcoeff = 0.0; /* Minor loss coeff. 局部损失系数*/ /* Add new pipe to data base 将新管段添加进来*/
n = Ntokens;
if (Nlinks == MaxLinks) return();
Npipes++;
Nlinks++;
if (!addlinkID(Nlinks,Tok[])) return(); /* Check for valid data 检查管段数据的正确性*/
if (n < ) return(); //数据项个数至少有6个
if ((j1 = findnode(Tok[])) == || //获取始末点的索引值
(j2 = findnode(Tok[])) ==
) return(); /*** Updated 10/25/00 ***/
if (j1 == j2) return(); //如果起点与终点相同则返回出错信息 if (!getfloat(Tok[],&length) || //进行长度、口径、粗糙系数的数据类型检查
!getfloat(Tok[],&diam) ||
!getfloat(Tok[],&rcoeff)
) return(); if (length <= 0.0 || //进行长度、口径、粗糙系数的数据的非负检查
diam <= 0.0 ||
rcoeff <= 0.0
) return(); /* Case where either loss coeff. or status supplied 获取局部损失系数或者状态*/
if (n == )
{
if (match(Tok[],w_CV)) type = CV;
else if (match(Tok[],w_CLOSED)) status = CLOSED;
else if (match(Tok[],w_OPEN)) status = OPEN;
else if (!getfloat(Tok[],&lcoeff)) return();
} /* Case where both loss coeff. and status supplied 获取局部损失系数和状态*/
if (n == )
{
if (!getfloat(Tok[],&lcoeff)) return();
if (match(Tok[],w_CV)) type = CV;
else if (match(Tok[],w_CLOSED)) status = CLOSED;
else if (match(Tok[],w_OPEN)) status = OPEN;
else return();
}
if (lcoeff < 0.0) return(); /* Save pipe data 保存该管段的数据*/
Link[Nlinks].N1 = j1; /* Start-node index */
Link[Nlinks].N2 = j2; /* End-node index */
Link[Nlinks].Len = length; /* Length */
Link[Nlinks].Diam = diam; /* Diameter */
Link[Nlinks].Kc = rcoeff; /* Rough. coeff */
Link[Nlinks].Km = lcoeff; /* Loss coeff */
Link[Nlinks].Kb = MISSING; /* Bulk coeff */
Link[Nlinks].Kw = MISSING; /* Wall coeff */
Link[Nlinks].Type = type; /* Link type */
Link[Nlinks].Stat = status; /* Link status */
Link[Nlinks].Rpt = ; /* Report flag */
return();
} /* end of pipedata */ int pumpdata()
/*
**--------------------------------------------------------------;备注:水泵被认为是特殊的管段数据
** Input: none ;输入:无
** Output: returns error code ;输出:错误代码
** Purpose: processes pump data ;目的:处理水泵数据
** Formats: ;格式:
** [PUMP]
** (Version 1.x Format):
** id node1 node2 power
** id node1 node2 h1 q1
** id node1 node2 h0 h1 q1 h2 q2
** (Version 2 Format):
** id node1 node2 KEYWORD value {KEYWORD value ...}
** where KEYWORD = [POWER,HEAD,PATTERN,SPEED]
;ID Node1 Node2 Parameters
9 9 10 HEAD 1 ;
**--------------------------------------------------------------
*/
{
int j,
j1, /* Start-node index 起始junction在Node链表中的索引值*/
j2, /* End-node index 终点junction在Node链表中的索引值*/
m, n; /* # data items 当前行数据项个数*/
double y;
STmplist *t; /* Pattern record */ /* Add new pump to data base 将新水泵数据添加进来*/
n = Ntokens;
if (Nlinks == MaxLinks ||
Npumps == MaxPumps
) return();
Nlinks++;
Npumps++;
if (!addlinkID(Nlinks,Tok[])) return(); /* Check for valid data 检查数据合法性*/
if (n < ) return(); //字段个数至少4个
if ((j1 = findnode(Tok[])) == || //获取始末junction在Node链表中的索引值
(j2 = findnode(Tok[])) ==
) return(); /*** Updated 10/25/00 ***/
if (j1 == j2) return(); //如果起点与终点相同则返回出错信息 /* Save pump data 保存水泵数据*/
Link[Nlinks].N1 = j1; /* Start-node index. */
Link[Nlinks].N2 = j2; /* End-node index. */
Link[Nlinks].Diam = Npumps; /* Pump index. */
Link[Nlinks].Len = 0.0; /* Link length. */
Link[Nlinks].Kc = 1.0; /* Speed factor. */
Link[Nlinks].Km = 0.0; /* Horsepower. */
Link[Nlinks].Kb = 0.0;
Link[Nlinks].Kw = 0.0;
Link[Nlinks].Type = PUMP; /* Link type. */
Link[Nlinks].Stat = OPEN; /* Link status. */
Link[Nlinks].Rpt = ; /* Report flag. */
Pump[Npumps].Link = Nlinks; /* Link index. */
Pump[Npumps].Ptype = NOCURVE; /* Type of pump curve 默认无水泵曲线*/
Pump[Npumps].Hcurve = ; /* Pump curve index */
Pump[Npumps].Ecurve = ; /* Effic. curve index */
Pump[Npumps].Upat = ; /* Utilization pattern*/
Pump[Npumps].Ecost = 0.0; /* Unit energy cost */
Pump[Npumps].Epat = ; /* Energy cost pattern*/ /* If 4-th token is a number then input follows Version 1.x format 若第4个数据项是一个数字则按版本1.x来解读水泵曲线*/
/* so retrieve pump curve parameters 获取水泵参数曲线;一般现在都是按2.x版本,所以可以跳过不做细究*/
if (getfloat(Tok[],&X[]))
{
m = ;
for (j=; j<n; j++)
{
if (!getfloat(Tok[j],&X[m])) return();
m++;
}
return(getpumpcurve(m)); /* Get pump curve params */
} /* Otherwise input follows Version 2 format */
/* so retrieve keyword/value pairs. 版本2是采用键值对的方式来定义水泵曲线*/
/*
关键词和数值(可以重复)
a. 关键词包括:
* POWER——定速能量水泵的功率数值,hp (kW)
* HEAD——描述了水泵扬程与流量关系的曲线ID
* SPEED——相对速度设置(额定速度为1.0 ,0意味着水泵关闭)
* PATTERN——时间模式的ID,描述了速度设置怎样随时间变化
b. 对于每一台水泵,必须提供POWER 或者HEAD。其它关键词是可选的。
*/
m = ;
while (m < n)
{
if (match(Tok[m-],w_POWER)) /* Const. HP curve 定速能量水泵的功率数值,hp (kW)*/
{
y = atof(Tok[m]);
if (y <= 0.0) return();
Pump[Npumps].Ptype = CONST_HP; //水泵曲线类型
Link[Nlinks].Km = y; //Minor loss coeff. 局部损失系数
}
else if (match(Tok[m-],w_HEAD)) /* Custom pump curve 描述了水泵扬程与流量关系的曲线ID*/
{
t = findID(Tok[m],Curvelist);
if (t == NULL) return();
Pump[Npumps].Hcurve = t->i;
}
else if (match(Tok[m-],w_PATTERN)) /* Speed/status pattern 时间模式的ID,描述了速度设置怎样随时间变化 */
{
t = findID(Tok[m],Patlist);
if (t == NULL) return();
Pump[Npumps].Upat = t->i;
}
else if (match(Tok[m-],w_SPEED)) /* Speed setting 相对速度设置(额定速度为1.0 ,0意味着水泵关闭)*/
{
if (!getfloat(Tok[m],&y)) return();
if (y < 0.0) return();
Link[Nlinks].Kc = y;
}
else return();
m = m + ; /* Skip to next keyword token 键值对都是2个一组的,可以重复*/
}
return();
} /* end of pumpdata */ int valvedata()
/*
**--------------------------------------------------------------
** Input: none ;输入:无
** Output: returns error code ;输出:错误代码
** Purpose: processes valve data ;作用:处理阀门数据
** Format: ;格式:
** [VALVE]
** id node1 node2 diam type setting (lcoeff)
**--------------------------------------------------------------
*/
{
int j1, /* Start-node index 起始junction在Node链表中的索引值*/
j2, /* End-node index 终点junction在Node链表中的索引值*/
n; /* # data items 当前行数据项个数*/
char status = ACTIVE, /* Valve status 阀门状态*/
type; /* Valve type 阀门类型*/
double diam = 0.0, /* Valve diameter 阀门口径*/
setting, /* Valve setting 阀门设置*/
lcoeff = 0.0; /* Minor loss coeff. 局部损失系数*/
STmplist *t; /* Curve record 阀门曲线*/ /* Add new valve to data base 添加阀门数据*/
n = Ntokens;
if (Nlinks == MaxLinks ||
Nvalves == MaxValves
) return();
Nvalves++;
Nlinks++;
if (!addlinkID(Nlinks,Tok[])) return(); /* Check for valid data 检查阀门数据的合法性*/
if (n < ) return(); //至少需要6个字段,第7个字段"局部损失系数"可选
if ((j1 = findnode(Tok[])) == ||
(j2 = findnode(Tok[])) ==
) return(); /*** Updated 10/25/00 ***/
if (j1 == j2) return(); //起点与终点相同,返回错误代码
//获取阀门类型 阀门 设置
if (match(Tok[],w_PRV)) type = PRV;//PRV (减压阀) 压力,m(psi)
else if (match(Tok[],w_PSV)) type = PSV;//PSV (稳压阀) 压力,m(psi)
else if (match(Tok[],w_PBV)) type = PBV;//PBV (压力制动阀) 压力,m(psi)
else if (match(Tok[],w_FCV)) type = FCV;//FCV (流量控制阀) 流量(流量单位)
else if (match(Tok[],w_TCV)) type = TCV;//TCV (节流控制阀) 损失系数
else if (match(Tok[],w_GPV)) type = GPV;//GPV (常规阀门) 水头损失曲线的ID
else return(); /* Illegal valve type.*/
if (!getfloat(Tok[],&diam)) return();
if (diam <= 0.0) return(); /* Illegal diameter.*/
if (type == GPV) /* Headloss curve for GPV 获取水头损失曲线ID在曲线表中的索引值*/
{
t = findID(Tok[],Curvelist);
if (t == NULL) return();
setting = t->i; /*** Updated 9/7/00 ***/
status = OPEN; //阀门状态设置为开启 }
else if (!getfloat(Tok[],&setting)) return();
if (n >= && //获取
!getfloat(Tok[],&lcoeff)
) return(); /* Check that PRV, PSV, or FCV not connected to a tank & */
/* check for illegal connections between pairs of valves.*/
if ((j1 > Njuncs || j2 > Njuncs) &&
(type == PRV || type == PSV || type == FCV)
) return();
if (!valvecheck(type,j1,j2)) return(); /* Save valve data 设置阀门数据,注意阀门是特殊的管段数据*/
Link[Nlinks].N1 = j1; /* Start-node index. 设置起始节点索引值*/
Link[Nlinks].N2 = j2; /* End-node index. 设置终点节点索引值*/
Link[Nlinks].Diam = diam; /* Valve diameter. 阀门口径*/
Link[Nlinks].Len = 0.0; /* Link length. */
Link[Nlinks].Kc = setting; /* Valve setting. */
Link[Nlinks].Km = lcoeff; /* Loss coeff */
Link[Nlinks].Kb = 0.0;
Link[Nlinks].Kw = 0.0;
Link[Nlinks].Type = type; /* Valve type. */
Link[Nlinks].Stat = status; /* Valve status. */
Link[Nlinks].Rpt = ; /* Report flag. */
Valve[Nvalves].Link = Nlinks; /* Link index. */
return();
} /* end of valvedata */ int patterndata()
/*
**--------------------------------------------------------------
** Input: none ;输入:无
** Output: returns error code ;输出:错误代码
** Purpose: processes time pattern data ;作用:处理时间模式数据
** Format: ;格式:
** [PATTERNS] 这让我回想起当时Hammer中导出的INP文件解算时只有前面几个时段的数据,很可能的一个原因就是EPANET对INP文件的规范是每行最多40项,而Hammer的Pattern格式长度过长导致的。
** id mult1 mult2 .....
**--------------------------------------------------------------
*/
{
int i,n; /*n表示 当前行数据项个数*/
double x;
SFloatlist *f; //f:一个包含浮点数的单向链表
STmplist *p; //p:当前的用水模式
n = Ntokens - ;
if (n < ) return(); /* Too few values 当前行数据项个数过少*/
if ( /* Check for new pattern 查看当前行的ID是否存在于PrevPat链表中*/
PrevPat != NULL && /*这里的if语句的作用在于一个时间模式可能是连接多行,那么这样就能提高效率*/
strcmp(Tok[],PrevPat->ID) ==
) p = PrevPat;
else p = findID(Tok[],Patlist);
if (p == NULL) return();
for (i=; i<=n; i++) /* Add multipliers to list 添加用水模式系数,添加至链首*/
{
if (!getfloat(Tok[i],&x)) return();
f = (SFloatlist *) malloc(sizeof(SFloatlist));
if (f == NULL) return();
f->value = x;
f->next = p->x; //将当前系数挂在该模式p的系数链首
p->x = f;
}
Pattern[p->i].Length += n; /* Save # multipliers for pattern 维护当前模式的长度*/
PrevPat = p; /* Set previous pattern pointer 临时的模式对象,因模式可能是连着多行而提高效率*/
return();
} /* end of patterndata */ int curvedata()
/*
**------------------------------------------------------
** Input: none ;输入:无
** Output: returns error code ;输出:错误代码
** Purpose: processes curve data ;作用:处理曲线数据
** Format: ;格式:
** [CURVES]
** CurveID x-value y-value
**------------------------------------------------------
*/
{
double x,y;
SFloatlist *fx, *fy;
STmplist *c; /* Check for valid curve ID */
if (Ntokens < ) return();
if (
PrevCurve != NULL &&
strcmp(Tok[],PrevCurve->ID) ==
) c = PrevCurve;
else c = findID(Tok[],Curvelist);
if (c == NULL) return(); /* Check for valid data */
if (!getfloat(Tok[],&x)) return();
if (!getfloat(Tok[],&y)) return(); /* Add new data point to curve's linked list */
fx = (SFloatlist *) malloc(sizeof(SFloatlist));
fy = (SFloatlist *) malloc(sizeof(SFloatlist));
if (fx == NULL || fy == NULL) return();
fx->value = x;
fx->next = c->x;
c->x = fx;
fy->value = y;
fy->next = c->y;
c->y = fy;
Curve[c->i].Npts++; /* Save the pointer to this curve */
PrevCurve = c;
return();
} int demanddata()
/*
**--------------------------------------------------------------
** Input: none ;输入:无
** Output: returns error code ;输出:错误代码
** Purpose: processes node demand data ;作用:定义连接节点的多模式需水,是对[JUNCTIONS]的补充。
** Format: ;格式:
** [DEMANDS]
** MULTIPLY factor
** node base_demand (pattern)
**
** NOTE: Demands entered in this section replace those ;注意:这部分的需水量将替换[JUNCTIONS]部分录入的需水量
** entered in the [JUNCTIONS] section
**--------------------------------------------------------------
*/
{ //j:表示节点在Node中的索引值
int j,n,p = ; //p:当前的用水模式在Pattern中的索引 /*n表示 当前行数据项个数*/
double y;
Pdemand demand;
STmplist *pat; /* Extract data from tokens 从当前行中提取需水量数据*/
n = Ntokens;
if (n < ) return();
if (!getfloat(Tok[],&y)) return(); /* If MULTIPLY command, save multiplier */
if (match(Tok[],w_MULTIPLY))
{
if (y <= 0.0) return();
else Dmult = y;
return();
} /* Otherwise find node (and pattern) being referenced 找到节点所引用的用水模式的索引值*/
if ((j = findnode(Tok[])) == ) return();
if (j > Njuncs) return();
if (n >= )
{
pat = findID(Tok[],Patlist);
if (pat == NULL) return();
p = pat->i;
} /* Replace any demand entered in [JUNCTIONS] section */
/* (Such demand was temporarily stored in D[]) */ /*** Updated 6/24/02 ***/
demand = Node[j].D;
if (demand && D[j] != MISSING)
{
demand->Base = y;
demand->Pat = p;
D[j] = MISSING;//通过这个MISSING来做替换标记
}
/*** End of update ***/ /* Otherwise add a new demand to this junction */
else
{
demand = (struct Sdemand *) malloc(sizeof(struct Sdemand));
if (demand == NULL) return();
demand->Base = y;
demand->Pat = p;
demand->next = Node[j].D;
Node[j].D = demand;
}
return();
} /* end of demanddata */ int controldata()
/*
**--------------------------------------------------------------
** Input: none ;输入:无
** Output: returns error code ;输出:错误代码
** Purpose: processes simple controls ;作用:处理简单控制规则
** Formats: ;格式:
** [CONTROLS]
** LINK linkID setting IF NODE nodeID {BELOW/ABOVE} value
** LINK linkID setting AT TIME time (units)
** LINK linkID setting AT CLOCKTIME clocktime (units)
** (0) (1) (2) (3) (4) (5) (6) (7)
其中:
linkID——管段ID标签;
setting——OPEN或者CLOSED,水泵速度设置或者控制阀门设置
nodeID——节点ID标签;
value ——连接节点压力或者水池水位;
time——从模拟开始起算的时间,以小数或者小时:分钟计;
clocktime——24小时的钟表时间(小时:分钟)。
备注:
a. 简单控制将根据水池水位、节点压强、进入模拟时间或者一日中的时间,改变管
段状态或者设置。
b. 对于用在指定管段状态和设置的常规情况,尤其阀门控制,参见[STATUS] 节的
备注。
示例:
[CONTROLS]
;如果Tank 23的水位超过20 ft ,关闭Link
LINK 12 CLOSED IF NODE 23 ABOVE 20 ;如果Node 130 的压力低于30 psi,开启Link 12
LINK 12 OPEN IF NODE 130 BELOW 30 ;在进入模拟16小时后水泵PUMP02的转速比设置为1.5
LINK PUMP02 1.5 AT TIME 16 ;整个模拟过程中Lin 12在上午10时关闭,下午8时开启
LINK 12 CLOSED AT CLOCKTIME 10 AM
LINK 12 OPEN AT CLOCKTIME 8 PM
**--------------------------------------------------------------
*/
{
int i = , /* Node index Node中的索引值*/
k, /* Link index Link中的索引值*/
n; /* # data items 当前行数据项个数*/
char status = ACTIVE, /* Link status 管段状态*/
type; /* Link or control type 管段类型*/
double setting = MISSING, /* Link setting */
time = 0.0, /* Simulation time 从模拟开始起算的时间*/
level = 0.0; /* Pressure or tank level 水池水位或节点压强*/ /* Check for sufficient number of input tokens 检查字段个数是否合法,不小于6个*/
n = Ntokens;
if (n < ) return(); /* Check that controlled link exists 判断控制的管段是否存在*/
k = findlink(Tok[]);
if (k == ) return();
type = Link[k].Type;
if (type == CV) return(); /* Cannot control check valve. 不能够控制检查阀*/ /*** Updated 9/7/00 ***/
/* Parse control setting into a status level or numerical setting. 获取并设置控制管段的状态*/
if (match(Tok[],w_OPEN))
{
status = OPEN;
if (type == PUMP) setting = 1.0;
if (type == GPV) setting = Link[k].Kc;
}
else if (match(Tok[],w_CLOSED))
{
status = CLOSED;
if (type == PUMP) setting = 0.0;
if (type == GPV) setting = Link[k].Kc;
}
else if (type == GPV) return();
else if (!getfloat(Tok[],&setting)) return(); /*** Updated 3/1/01 ***/
/* Set status for pump in case speed setting was supplied 根据setting来设置水泵或者管段的status*/
/* or for pipe if numerical setting was supplied */ if (type == PUMP || type == PIPE)
{
if (setting != MISSING)
{
if (setting < 0.0) return();
else if (setting == 0.0) status = CLOSED;
else status = OPEN;
}
} /* Determine type of control 获取该条控制规则的类型*/
if (match(Tok[],w_TIME)) type = TIMER;
else if (match(Tok[],w_CLOCKTIME)) type = TIMEOFDAY;
else
{//对节点或者水池的控制
if (n < ) return();
if ((i = findnode(Tok[])) == ) return();
if (match(Tok[],w_BELOW)) type = LOWLEVEL;
else if (match(Tok[],w_ABOVE)) type = HILEVEL;
else return();
} /* Parse control level or time 获取控制的时间或者水位*/
switch (type)
{
case TIMER:
case TIMEOFDAY:
if (n == ) time = hour(Tok[],"");
if (n == ) time = hour(Tok[],Tok[]);
if (time < 0.0) return();
break;
case LOWLEVEL:
case HILEVEL:
if (!getfloat(Tok[],&level)) return();
break;
} /* Fill in fields of control data structure 将上述获取到的值填充到控制规则线性链表中*/
Ncontrols++;
if (Ncontrols > MaxControls) return();
Control[Ncontrols].Link = k;
Control[Ncontrols].Node = i;
Control[Ncontrols].Type = type;
Control[Ncontrols].Status = status;
Control[Ncontrols].Setting = setting;
Control[Ncontrols].Time = (long)(3600.0*time);
if (type == TIMEOFDAY)
Control[Ncontrols].Time %= SECperDAY;
Control[Ncontrols].Grade = level;
return();
} /* end of controldata */ int sourcedata()
/*
**--------------------------------------------------------------
** Input: none ;输入:无
** Output: returns error code ;输出:错误代码
** Purpose: processes water quality source data ;目的:定义水质源头的位置。
** Formats: ;格式:
** [SOURCE]
** node sourcetype quality (pattern start stop)
**
格式:
每一水质源头为一输入行,包括:
node 节点ID标签
sourcetype 源头类型(CONCEN, MASS, FLOWPACED 或SETPOINT )
quality 基准源头强度
pattern 时间模式ID(可选) ** NOTE: units of mass-based source are mass/min
备注:
a. MASS类型源头的强度以质量流量每分钟计。所有其它类型以浓度单位来计量源头强度。
b. 源头强度可以指定时间模式,使其随时间变化。
c. CONCEN源头为:
表示节点的任何外部源头进流浓度
仅仅在节点具有净负需水量时使用(水从节点进入管网)
如果节点为连接节点,报告浓度时混合了源流量和从管网其它部分的进流
如果节点为水库,报告的浓度为源头浓度
如果节点为水池,报告的浓度为水池的内部浓度
用于节点,表示了源水供应或者处理厂(例如,水库或者节点具有负的需水量)
不可用于同时具有进流/出流的蓄水池。
d. MASS, FLOWPACED 或SETPOINT 源头:
表示了增强源头,这里物质被直接注射到管网,不考虑节点的需水量怎样
以下方式影响了离开节点到管网的其它部分的水:
- MASS 注入,增加了固定的质量流量到节点的进流
- FLOWPACED 注入,增加了固定浓度到节点的进流浓度
- SETPOINT 注入,固定了任何离开节点的浓度(只要进流带来的浓度低于设置值)
连接节点或者水库注入源头报告的浓度,是在注入之后的浓度;报告具有注入源头的水
池的浓度,为水池的内部浓度
适合于模拟示踪剂或者消毒剂直接注入到管网,或者为了模拟污染物的入侵。
e.对于模拟水龄或者源头跟踪,[SOURCES]节是不需要的。
**--------------------------------------------------------------
*/
{
int i, /* Token with quality value 水质值这列所在的当前行的数据项列表中的索引值*/
j, /* Node index Node中的索引值*/
n, /* # data items 行的数据项数*/
p = ; /* Time pattern 模式*/
char type = CONCEN; /* Source type 源头类型*/
double c0 = ; /* Init. quality 初始水质*/
STmplist *pat;
Psource source; n = Ntokens;
if (n < ) return();
if ((j = findnode(Tok[])) == ) return();
/* NOTE: Under old format, SourceType not supplied so let 如果是老版本那么i=1,因为源头类型不存在*/
/* i = index of token that contains quality value. 水质值这列所在的当前行的数据项列表中的索引值*/
i = ;
if (match(Tok[],w_CONCEN)) type = CONCEN;
else if (match(Tok[],w_MASS)) type = MASS;
else if (match(Tok[],w_SETPOINT)) type = SETPOINT;
else if (match(Tok[],w_FLOWPACED)) type = FLOWPACED;
else i = ;
if (!getfloat(Tok[i],&c0)) return(); /* Illegal WQ value 检查水质数据类型*/ if (n > i+ && strlen(Tok[i+]) > && strcmp(Tok[i+], "*") != ) //(2.00.11 - LR)
{
pat = findID(Tok[i+],Patlist);
if (pat == NULL) return(); /* Illegal pattern. 找不到指定模式*/
p = pat->i; //返回该模式在Pattern中的索引值
} source = (struct Ssource *) malloc(sizeof(struct Ssource));
if (source == NULL) return();
source->C0 = c0;
source->Pat = p;
source->Type = type;
Node[j].S = source;
return();
} /* end of sourcedata */ int emitterdata()
/*
**--------------------------------------------------------------
** Input: none ;输入:无
** Output: returns error code ;输出:错误代码
** Purpose: processes junction emitter data ;目的:将模拟节点定义为扩散器(喷嘴或者孔口)。
** Formats: ;格式:
** [EMITTER]
** node K
备注:
a. 扩散器用于模拟通过喷水或者管道渗漏的流量。
b. 扩散器的出流等于流量系数与提升的连接节点压力乘积。
c. 功率可以利用[OPTIONS]节的EMITTER EXPONENT选项指定。缺省功率为0.5 ,通常用于喷嘴。
d. 程序结果中报告的实际需水量,包括节点的常规需水量加上通过扩散器的流量。
e. [EMITTERS] 节是可选的。
**--------------------------------------------------------------
*/
{
int j, /* Node index Node中的索引值*/
n, /* # data items 行的数据项数*/
double k; /* Flow coeff, 流量系数,在1米(1 psi )压降下的流量单位。*/ n = Ntokens;
if (n < ) return();
if ((j = findnode(Tok[])) == ) return();
if (j > Njuncs) return(); /* Not a junction.*/
if (!getfloat(Tok[],&k)) return();
if (k < 0.0) return();
Node[j].Ke = k;
return();
} int qualdata()
/*
**--------------------------------------------------------------
** Input: none ;输入:无
** Output: returns error code ;输出:错误代码
** Purpose: processes initial water quality data ;目的:定义节点的初始水质。
** Formats:
** [QUALITY]
** node initqual
** node1 node2 initqual
每一节点为一输入行,包括:
node 节点ID标签
initqual 初始水质 备注:
a. 对于没有列入的节点,水质假设为零。
b. 水质表示了化学成分的浓度、水龄的小时或源头跟踪的百分比。
c. [QUALITY]节是可选的。
**--------------------------------------------------------------
*/
{
int j,n;
long i,i0,i1;
double c0; if (Nnodes == ) return(); /* No nodes defined yet */
n = Ntokens;
if (n < ) return();
if (n == ) /* Single node entered 单个节点*/
{
if ( (j = findnode(Tok[])) == ) return();
if (!getfloat(Tok[],&c0)) return();
Node[j].C0 = c0;
}
else /* Node range entered 批量节点*/
{
if (!getfloat(Tok[],&c0)) return(); /* If numerical range supplied, then use numerical comparison 这块代码有些奇怪,不过一般没有这种输入格式的*/
if ((i0 = atol(Tok[])) > && (i1 = atol(Tok[])) > )
{
for (j=; j<=Nnodes; j++)
{
i = atol(Node[j].ID);
if (i >= i0 && i <= i1) Node[j].C0 = c0;
}
}
else
{
for (j=; j<=Nnodes; j++)
if ((strcmp(Tok[],Node[j].ID) <= ) &&
(strcmp(Tok[],Node[j].ID) >= )
) Node[j].C0 = c0;
}
}
return();
} /* end of qualdata */ int reactdata()
/*
**--------------------------------------------------------------
** Input: none ;输入:无
** Output: returns error code ;输出:错误代码
** Purpose: processes reaction coeff. data ;目的:定义对应于管网中与化学成分反应的参数。
** Formats: ;格式:
** [REACTIONS]
** ORDER {BULK/WALL/TANK} value
** GLOBAL {BULK/WALL} coeff
** BULK link1 (link2) coeff
** WALL link1 (link2) coeff
** TANK node1 (node2) coeff
** LIMITING POTENTIAL value
** ROUGHNESS CORRELATION value
格式:
ORDER BULK/WALL/TANK value
GLOBAL BULK/WALL value
BULK/WALL/TANK pipeID value
LIMITING POTENTIAL value
ROUGHNESS CORRELATION value
定义:
ORDER 用于设置分别发生在主流水体、管壁或者水池中的反应级数。管壁反应的数值必须
为0或者1。如果没有提供,缺省反应级数为1.0 。
GLOBAL用于设置所有主流水体反应系数(管道和水池)或者所有管壁系数的全局数值。缺
省值为零。
BULK, WALL 和TANK用于对指定管道和水池重新设置全局反应系数。
LIMITING POTENTIAL 指定了反应速率正比于当前浓度和一些限制值之间的差异。
ROUGHNESS CORRELATION将使所有缺省管壁反应系数,以以下方式,相关于管道粗糙系
数:
水头损失公式 粗糙相关性
Hazen-Williams F/C
Darcy-Weisbach F/log(e/D)
Chezy-Manning F*n
105
式中F——粗糙系数相关性;
C——Hazen-Williams C因子;
e——Darcy-Weisbach粗糙系数;
D——管道直径;
n——Chezy-Manning 粗糙系数。
这种方式计算的缺省值能够通过利用WALL格式,对于任何使用特定数值管道重载。
备注:
a. 注意增长反应系数采用正值,衰减反应系数为负值。
b. 所有反应系数的时间单位为1/日。
c. 本节所有输入为可选的,反斜杠(/)之后的事项说明了允许选项。
**--------------------------------------------------------------
*/
{
int item,j,n;
long i,i1,i2;
double y; /* Skip line if insufficient data */
n = Ntokens;
if (n < ) return(); /* Process input depending on keyword */
if (match(Tok[],w_ORDER)) /* Reaction order */
{
if (!getfloat(Tok[n-],&y)) return();
if (match(Tok[],w_BULK)) BulkOrder = y;
else if (match(Tok[],w_TANK)) TankOrder = y;
else if (match(Tok[],w_WALL))
{
if (y == 0.0) WallOrder = 0.0;
else if (y == 1.0) WallOrder = 1.0;
else return();
}
else return();
return();
}
if (match(Tok[],w_ROUGHNESS)) /* Roughness factor */
{
if (!getfloat(Tok[n-],&y)) return();
Rfactor = y;
return();
}
if (match(Tok[],w_LIMITING)) /* Limiting potential */
{
if (!getfloat(Tok[n-],&y)) return();
/*if (y < 0.0) return(213);*/
Climit = y;
return();
}
if (match(Tok[],w_GLOBAL)) /* Global rates */
{
if (!getfloat(Tok[n-],&y)) return();
if (match(Tok[],w_BULK)) Kbulk = y;
else if (match(Tok[],w_WALL)) Kwall = y;
else return();
return();
}
if (match(Tok[],w_BULK)) item = ; /* Individual rates */
else if (match(Tok[],w_WALL)) item = ;
else if (match(Tok[],w_TANK)) item = ;
else return();
strcpy(Tok[],Tok[]); /* Save id in Tok[0] */
if (item == ) /* Tank rates */
{
if (!getfloat(Tok[n-],&y)) return(); /* Rate coeff. */
if (n == )
{
if ( (j = findnode(Tok[])) <= Njuncs) return();
Tank[j-Njuncs].Kb = y;
}
else
{
/* If numerical range supplied, then use numerical comparison */
if ((i1 = atol(Tok[])) > && (i2 = atol(Tok[])) > )
{
for (j=Njuncs+; j<=Nnodes; j++)
{
i = atol(Node[j].ID);
if (i >= i1 && i <= i2) Tank[j-Njuncs].Kb = y;
}
}
else for (j=Njuncs+; j<=Nnodes; j++)
if ((strcmp(Tok[],Node[j].ID) <= ) &&
(strcmp(Tok[],Node[j].ID) >= )
) Tank[j-Njuncs].Kb = y;
}
}
else /* Link rates */
{
if (!getfloat(Tok[n-],&y)) return(); /* Rate coeff. */
if (Nlinks == ) return();
if (n == ) /* Single link */
{
if ( (j = findlink(Tok[])) == ) return();
if (item == ) Link[j].Kb = y;
else Link[j].Kw = y;
}
else /* Range of links */
{
/* If numerical range supplied, then use numerical comparison */
if ((i1 = atol(Tok[])) > && (i2 = atol(Tok[])) > )
{
for (j=; j<=Nlinks; j++)
{
i = atol(Link[j].ID);
if (i >= i1 && i <= i2)
{
if (item == ) Link[j].Kb = y;
else Link[j].Kw = y;
}
}
}
else for (j=; j<=Nlinks; j++)
if ((strcmp(Tok[],Link[j].ID) <= ) &&
(strcmp(Tok[],Link[j].ID) >= ) )
{
if (item == ) Link[j].Kb = y;
else Link[j].Kw = y;
}
}
}
return();
} /* end of reactdata */ int mixingdata()
/*
**-------------------------------------------------------------
** Input: none ;输入:无
** Output: returns error code ;输出:错误代码
** Purpose: processes tank mixing data ;目的:确定控制蓄水池混合的模型。
** Format:
** [MIXING]
** TankID MixModel FractVolume
格式:
一个水池占一输入行,包括:
z 水池ID标签
z 混合模型(MIXED, 2COMP, FIFO 或LIFO)
z 室的容积(小数)
备注:
a. 混合模型包括:
z 完全混合(MIXED )
z 双室混合(2COMP )
z 先进先出(FIFO)
z 后进先出(LIFO)
b. 室容积参数仅仅用于双室模型,代表了总水池容积贡献于进水/出水室的部分。
c. [MIXING]节是可选的。不在本节描述的水池假设为完全混合。
**-------------------------------------------------------------
*/
{
int i,j,n;
double v; if (Nnodes == ) return(); /* No nodes defined yet */
n = Ntokens;
if (n < ) return();
if ( (j = findnode(Tok[])) <= Njuncs) return();
if ( (i = findmatch(Tok[],MixTxt)) < ) return();
v = 1.0;
if ( (i == MIX2) &&
(n == ) &&
(!getfloat(Tok[],&v)) /* Get frac. vol. for 2COMP model */
) return();
if (v == 0.0) v = 1.0; /* v can't be zero */
n = j - Njuncs;
if (Tank[n].A == 0.0) return(); /* Tank is a reservoir */
Tank[n].MixModel = (char)i;
Tank[n].V1max = v;
return();
} int statusdata()
/*
**--------------------------------------------------------------
** Input: none ;输入:无
** Output: returns error code ;输出:错误代码
** Purpose: processes link initial status data ;目的:定义模拟开始时被选管段的初始状态。
** Formats:
** [STATUS]
** link value
** link1 (link2) value
格式:
每一控制管段占一输入行,包括:
z 管段ID标签
z 状态或者设置
备注:
a. 该部分没有列出的管段,缺省状态为OPEN(对于管道和水泵)或者ACTIVE(对于阀门)。
b. 状态值可以为OPEN或者CLOSED。对于控制阀(例如PRV, FCV 等),意味着阀门是全开或
者全闭,在其控制点不是活动的。
c. 设置数值可以是水泵的转速设置,或者阀门的开启度设置。
d. 管道的初始状态也可以在[PIPES]节设置。
e. 止回阀不能够预先设置它们的状态。
**--------------------------------------------------------------
*/
{
int j,n; //j:Link中的索引值;n:行数据项个数
long i,i0,i1;
double y = 0.0;
char status = ACTIVE; if (Nlinks == ) return();
n = Ntokens - ;
if (n < ) return(); /* Check for legal status setting 检查状态数据的合法性*/
if (match(Tok[n],w_OPEN)) status = OPEN;
else if (match(Tok[n],w_CLOSED)) status = CLOSED;
else if (!getfloat(Tok[n],&y)) return();
if (y < 0.0) return(); /* Single link ID supplied */
if (n == )
{
if ( (j = findlink(Tok[])) == ) return();
/* Cannot change status of a Check Valve */
if (Link[j].Type == CV) return(); /*** Updated 9/7/00 ***/
/* Cannot change setting for a GPV */
if (Link[j].Type == GPV
&& status == ACTIVE) return(); changestatus(j,status,y);
} /* Range of ID's supplied 对间与某2个ID之间的管段的状态的批量设置*/
else
{
/* Numerical range supplied */
if ((i0 = atol(Tok[])) > && (i1 = atol(Tok[])) > )
{
for (j=; j<=Nlinks; j++)
{
i = atol(Link[j].ID);
if (i >= i0 && i <= i1) changestatus(j,status,y);
}
}
else
for (j=; j<=Nlinks; j++)
if ( (strcmp(Tok[],Link[j].ID) <= ) &&
(strcmp(Tok[],Link[j].ID) >= )
) changestatus(j,status,y);
}
return();
} /* end of statusdata */ int energydata()
/*
**--------------------------------------------------------------
** Input: none ;输入:无
** Output: returns error code ;输出:错误代码
** Purpose: processes pump energy data ;目的:定义计算水泵提升能量和成本的参数。
** Formats: ;格式:
** [ENERGY]
** GLOBAL {PRICE/PATTERN/EFFIC} value
** PUMP id {PRICE/PATTERN/EFFIC} value
** DEMAND CHARGE value
格式:
GLOBAL PRICE/PATTERN/EFFIC value
PUMP PumpID PRICE/PATTERN/EFFIC value
DEMAND CHARGE value
备注:
a. 以关键词GLOBAL为开头的行,用于设置所有水泵的能量价格、价格模式和水泵效
率的全局缺省。
b. 以关键词PUMP为开头的行,用于对特定水泵重新设置全局缺省。
c. 参数定义如下:
z PRICE ——每千瓦时的平均成本,
z PATTERN——描述能量价格怎样变化的时间模式ID标签,
z EFFIC ——对于全局设置的单一百分比效率,或者指定水泵的效率曲线ID标
签,
z DEMAND CHARGE ——模拟时段每最大kW用量增加的成本。
d. 缺省全局水泵效率为75% ,缺省全局能量价格为0。
e. 本节的所有输入是可选的。反斜杠(/)后的项说明允许选项。
示例:
[ENERGY]
GLOBAL PRICE 0.05 ;设置全局能量价格
GLOBAL PATTERN PAT1 ;和一日内时间模式
PUMP 23 PRICE 0.10 ; 重载Pump 23的价格
PUMP 23 EFFIC E23 ;将效率曲线赋给Pump 23
**--------------------------------------------------------------
*/
{
int j,k,n;
double y;
STmplist *t; /* Check for sufficient data */
n = Ntokens;
if (n < ) return(); /* Check first keyword */
if (match(Tok[],w_DMNDCHARGE)) /* Demand charge */
{
if (!getfloat(Tok[], &y)) return();
Dcost = y;
return();
}
if (match(Tok[],w_GLOBAL)) /* Global parameter */
{
j = ;
}
else if (match(Tok[],w_PUMP)) /* Pump-specific parameter */
{
if (n < ) return();
k = findlink(Tok[]); /* Check that pump exists */
if (k == ) return();
if (Link[k].Type != PUMP) return();
j = PUMPINDEX(k);
}
else return(); /* Find type of energy parameter */
if (match(Tok[n-],w_PRICE)) /* Energy price */
{
if (!getfloat(Tok[n-],&y))
{
if (j == ) return();
else return();
}
if (j == ) Ecost = y;
else Pump[j].Ecost = y;
return();
}
else if (match(Tok[n-],w_PATTERN)) /* Price pattern */
{
t = findID(Tok[n-],Patlist); /* Check if pattern exists */
if (t == NULL)
{
if (j == ) return();
else return();
}
if (j == ) Epat = t->i;
else Pump[j].Epat = t->i;
return();
}
else if (match(Tok[n-],w_EFFIC)) /* Pump efficiency */
{
if (j == )
{
if (!getfloat(Tok[n-], &y)) return();
if (y <= 0.0) return();
Epump = y;
}
else
{
t = findID(Tok[n-],Curvelist); /* Check if curve exists */
if (t == NULL) return();
Pump[j].Ecurve = t->i;
}
return();
}
return();
} int reportdata()
/*
**--------------------------------------------------------------
** Input: none ;输入:无
** Output: returns error code ;输出:错误代码
** Purpose: processes report options data ;目的:描述模拟生成的输出报表内容。
** Formats:
** PAGE linesperpage
** STATUS {NONE/YES/FULL}
** SUMMARY {YES/NO}
** MESSAGES {YES/NO}
** ENERGY {NO/YES}
** NODES {NONE/ALL}
** NODES node1 node2 ...
** LINKS {NONE/ALL}
** LINKS link1 link2 ...
** FILE filename
** variable {YES/NO}
** variable {BELOW/ABOVE/PRECISION} value
格式:
PAGESIZE value
FILE filename
STATUS YES/NO/FULL
SUMMARY YES/NO
ENERGY YES/NO
NODES NONE/ALL/ node1 node2 ...
LINKS NONE/ALL/ link1 link2 ...
parameter YES/NO
parameter BELOW/ABOVE/PRECISION value
定义:
PAGESIZES设置了输出报表中每一页中的行数。缺省为0,意味着事实上每一页没有行数限
制。
对于将要写入的输出报告(在EPANETH的Windows版本中忽略),FILE提供了文件的名字。
STATUS确定了应怎样生成水力状态报告。如果YES 被选择,在模拟的每一时间步长中改变
状态的所有管网组件将输出到报告。如果FULL被选择,那么也将包括每一水力分析的每一试算
中的信息输出到报告。详细水平仅仅对于调试管网是有用的,这时水力不平衡。缺省为NO。
SUMMARY确定了管网组件数量的总结表,以及产生的关键分析选项。缺省为YES 。
ENERGY确定是否提供表格报告平均能量使用和每一台水泵的成本。缺省为NO。
NODES 确定了哪些节点将被报告。可以列出单个节点ID标签,或者利用关键词NONE或者
ALL 。额外NODES 行可用于继续该表。缺省为NONE。
LINKS 确定了哪些管段将被报告。可以列出单个管段ID标签,或者使用关键词NONE或者
106
ALL 。额外LINKS 行可用于继续该表。缺省为NONE。
“参数”报告选项,用于确定报告哪些量,多少小数位被显示,哪种类型的过滤用于限制输
出报告。可以被报告的节点参数包括:
z 标高;
z 需水量;
z 水头;
z 压强;
z 水质。
管段参数包括:
z 长度;
z 直径;
z 流量;
z 流速;
z 水头损失;
z 位置(与状态相同-开启、活动、关闭);
z 设置(对应于管道的粗糙系数、水泵的转速、阀门的压力/流量设置);
z 反应(反应速率);
z F-因子(摩擦因子)。
报告的缺省量对于节点的需水量、水头、压强和水质,以及管段的流量、流速和水头损失。
缺省精度为两个小数位。
备注:
a. 如果在本节没有明确指出,所有选项假设为它们的缺省数值。
b. 反斜杠(/)后的项为可选项。
c. 缺省值对应于任何节点或者管段没有报告,因此如果希望报告这些事项的结果,
必须提供NODES 或者LINKS 选项。
d. 对于EPANETH的Windows版本,仅仅意识到的[REPORT] 选项为STATUS。所 有 其
它被忽略。
示例:
以下示例报告了节点N1, N2, N3 和N17 ,以及所有流速大于3.0 的管段。标准节点参数(需水
量、水头、压强和水质)被报告,同时仅仅管段的流量、流速和F因子(摩擦因子)被报告。
[REPORT]
NODES N1 N2 N3 N17
LINKS ALL
FLOW YES
VELOCITY PRECISION 4
F-FACTOR PRECISION 4
VELOCITY ABOVE 3.0
**--------------------------------------------------------------
*/
{
int i,j,n;
double y; n = Ntokens - ;
if (n < ) return(); /* Value for page size */
if (match(Tok[],w_PAGE))
{
if (!getfloat(Tok[n],&y)) return();
if (y < 0.0 || y > 255.0) return();
PageSize = (int) y;
return();
} /* Request that status reports be written */
if (match(Tok[],w_STATUS))
{
if (match(Tok[n],w_NO)) Statflag = FALSE;
if (match(Tok[n],w_YES)) Statflag = TRUE;
if (match(Tok[n],w_FULL)) Statflag = FULL;
return();
} /* Request summary report */
if (match(Tok[],w_SUMMARY))
{
if (match(Tok[n],w_NO)) Summaryflag = FALSE;
if (match(Tok[n],w_YES)) Summaryflag = TRUE;
return();
} /* Request error/warning message reporting */
if (match(Tok[],w_MESSAGES))
{
if (match(Tok[n],w_NO)) Messageflag = FALSE;
if (match(Tok[n],w_YES)) Messageflag = TRUE;
return();
} /* Request an energy usage report */
if (match(Tok[],w_ENERGY))
{
if (match(Tok[n],w_NO)) Energyflag = FALSE;
if (match(Tok[n],w_YES)) Energyflag = TRUE;
return();
} /* Particular reporting nodes specified */
if (match(Tok[],w_NODE))
{
if (match(Tok[n],w_NONE)) Nodeflag = ; /* No nodes */
else if (match(Tok[n],w_ALL)) Nodeflag = ; /* All nodes */
else
{
if (Nnodes == ) return();
for (i=; i<=n; i++)
{
if ( (j = findnode(Tok[i])) == ) return();
Node[j].Rpt = ;
}
Nodeflag = ;
}
return();
} /* Particular reporting links specified */
if (match(Tok[],w_LINK))
{
if (match(Tok[n],w_NONE)) Linkflag = ;
else if (match(Tok[n],w_ALL)) Linkflag = ;
else
{
if (Nlinks == ) return();
for (i=; i<=n; i++)
{
if ( (j = findlink(Tok[i])) == ) return();
Link[j].Rpt = ;
}
Linkflag = ;
}
return();
} /* Check if input is a reporting criterion. */ /*** Special case needed to distinguish "HEAD" from "HEADLOSS" ***/ //(2.00.11 - LR)
if (strcomp(Tok[], w_HEADLOSS)) i = HEADLOSS; //(2.00.11 - LR)
else i = findmatch(Tok[],Fldname); //(2.00.11 - LR)
if (i >= ) //(2.00.11 - LR)
/*****************************************************************/ //(2.00.11 - LR)
{
if (i > FRICTION) return();
if (Ntokens == || match(Tok[],w_YES))
{
Field[i].Enabled = TRUE;
return();
}
if (match(Tok[],w_NO))
{
Field[i].Enabled = FALSE;
return();
}
if (Ntokens < ) return();
if (match(Tok[],w_BELOW)) j = LOW; /* Get relation operator */
else if (match(Tok[],w_ABOVE)) j = HI; /* or precision keyword */
else if (match(Tok[],w_PRECISION)) j = PREC;
else return();
if (!getfloat(Tok[],&y)) return();
if (j == PREC)
{
Field[i].Enabled = TRUE;
Field[i].Precision = ROUND(y);
}
else Field[i].RptLim[j] = y; /* Report limit value */
return();
} /* Name of external report file */
if (match(Tok[],w_FILE))
{
strncpy(Rpt2Fname,Tok[],MAXFNAME);
return();
} /* If get to here then return error condition */
return();
} /* end of reportdata */ int timedata()
/*
**--------------------------------------------------------------
** Input: none ;输入:无
** Output: returns error code ;输出:错误代码
** Purpose: processes time options data ;目的:定义模拟中的各种事件时间步长参数。
** Formats:
** STATISTIC {NONE/AVERAGE/MIN/MAX/RANGE}
** DURATION value (units)
** HYDRAULIC TIMESTEP value (units)
** QUALITY TIMESTEP value (units)
** MINIMUM TRAVELTIME value (units)
** RULE TIMESTEP value (units)
** PATTERN TIMESTEP value (units)
** PATTERN START value (units)
** REPORT TIMESTEP value (units)
** REPORT START value (units)
** START CLOCKTIME value (AM PM)
定义:
DURATION 是模拟的历时。设为0来运行简单的瞬时分析。缺省为0。
HYDRAULIC TIMESTEP 定义了管网新的水力状态计算频率。如果它大于PATTERN或者
REPORT时间步长,将自动降低。缺省为1小时。
QUALITY TIMESTEP用于跟踪水质通过管网变化的时间步长。缺省为水力时间步长的1/10。
RULE TIMESTEP 用于检查水力时间步长之间,基于规则控制引起的系统状态变化的时间步长。
缺省为1/10的水力时间步长。
PATTERN TIMESTEP是所有事件模式中时段之间的间隔。缺省为1小时。
PATTERN START 是所有模式开始时的时间分量。例如,6小时的数值将开始模拟,在时段
中的每一模式,对应于6小时。缺省为0。
REPORT TIMESTEP 设置了输出结果被报告的时间间隔。缺省为1小时。
REPORT START是进入模拟的时间长度,此时输出结果开始报告。缺省为0。
START CLOCKTIME 是模拟开始的钟表时间(例如3:00 PM)。缺省为子夜12:00 AM 。
STATISTICS 确定了在产生模拟结果的时间序列中,统计后处理的类型。AVERAGED 报告了
时间平均结果集合,MINIMUM仅仅报告最小值,MAXIMUM为最大值,以及RANGE 报告了最大值
和最小值之间的差异。NONE报告了所有节点和管段量的完整时间序列,它为缺省的。
备注:
a. 单位应为SECONDS(SEC), MINUTES(MIN), HOURS 或DAYS。缺省为小时。
b. 如果没有提供计量单位,该时间数值可能输入为小数小时或者为小时:分钟。
c. 所有在[TIMES]节的输入是可选的。在反斜杠(/)后的事项说明了可选情况。
**-------------------------------------------------------------
*/
{
int n;
long t;
double y; n = Ntokens - ;
if (n < ) return(); /* Check if setting time statistic flag */
if (match(Tok[],w_STATISTIC))
{
if (match(Tok[n],w_NONE)) Tstatflag = SERIES;
else if (match(Tok[n],w_NO)) Tstatflag = SERIES;
else if (match(Tok[n],w_AVG)) Tstatflag = AVG;
else if (match(Tok[n],w_MIN)) Tstatflag = MIN;
else if (match(Tok[n],w_MAX)) Tstatflag = MAX;
else if (match(Tok[n],w_RANGE)) Tstatflag = RANGE;
else return();
return();
} /* Convert text time value to numerical value in seconds 将文本时间值转换为数值时间值单位为秒*/
/* Examples:
** 5 = 5 * 3600 sec
** 5 MINUTES = 5 * 60 sec
** 13:50 = 13*3600 + 50*60 sec
** 1:50 pm = (12+1)*3600 + 50*60 sec
*/ if (!getfloat(Tok[n],&y))
{
if ( (y = hour(Tok[n],"")) < 0.0)
{
if ( (y = hour(Tok[n-],Tok[n])) < 0.0) return();
}
}
t = (long)(3600.0*y); /* Process the value assigned to the matched parameter */
if (match(Tok[],w_DURATION)) Dur = t; /* Simulation duration */
else if (match(Tok[],w_HYDRAULIC)) Hstep = t; /* Hydraulic time step */
else if (match(Tok[],w_QUALITY)) Qstep = t; /* Quality time step */
else if (match(Tok[],w_RULE)) Rulestep = t; /* Rule time step */
else if (match(Tok[],w_MINIMUM)) return(); /* Not used anymore */
else if (match(Tok[],w_PATTERN))
{
if (match(Tok[],w_TIME)) Pstep = t; /* Pattern time step */
else if (match(Tok[],w_START)) Pstart = t; /* Pattern start time */
else return();
}
else if (match(Tok[],w_REPORT))
{
if (match(Tok[],w_TIME)) Rstep = t; /* Reporting time step */
else if (match(Tok[],w_START)) Rstart = t; /* Reporting start time */
else return();
} /* Simulation start time*/
else if (match(Tok[],w_START)) Tstart = t % SECperDAY;
else return();
return();
} /* end of timedata */ int optiondata()
/*
**--------------------------------------------------------------
** Input: none ;输入:无
** Output: returns error code ;输出:错误代码
** Purpose: processes [OPTIONS] data ;目的:定义不同的模拟选项。
**--------------------------------------------------------------
*/
{
int i,n; n = Ntokens - ;
i = optionchoice(n); /* Option is a named choice */
if (i >= ) return(i);
return(optionvalue(n)); /* Option is a numerical value */
} /* end of optiondata */ int optionchoice(int n)
/*
**--------------------------------------------------------------
** Input: n = index of last input token saved in Tok[]
** Output: returns error code or 0 if option belongs to
** those listed below, or -1 otherwise
** Purpose: processes fixed choice [OPTIONS] data
** Formats:
** UNITS CFS/GPM/MGD/IMGD/AFD/LPS/LPM/MLD/CMH/CMD/SI
** PRESSURE PSI/KPA/M
** HEADLOSS H-W/D-W/C-M
** HYDRAULICS USE/SAVE filename
** QUALITY NONE/AGE/TRACE/CHEMICAL (TraceNode)
** MAP filename
** VERIFY filename
** UNBALANCED STOP/CONTINUE {Niter}
** PATTERN id
**--------------------------------------------------------------
*/
{
/* Check if 1st token matches a parameter name and */
/* process the input for the matched parameter */
if (n < ) return();
if (match(Tok[],w_UNITS))
{
if (n < ) return();
else if (match(Tok[],w_CFS)) Flowflag = CFS;
else if (match(Tok[],w_GPM)) Flowflag = GPM;
else if (match(Tok[],w_AFD)) Flowflag = AFD;
else if (match(Tok[],w_MGD)) Flowflag = MGD;
else if (match(Tok[],w_IMGD)) Flowflag = IMGD;
else if (match(Tok[],w_LPS)) Flowflag = LPS;
else if (match(Tok[],w_LPM)) Flowflag = LPM;
else if (match(Tok[],w_CMH)) Flowflag = CMH;
else if (match(Tok[],w_CMD)) Flowflag = CMD;
else if (match(Tok[],w_MLD)) Flowflag = MLD;
else if (match(Tok[],w_SI)) Flowflag = LPS;
else return();
}
else if (match(Tok[],w_PRESSURE))
{
if (n < ) return();
else if (match(Tok[],w_PSI)) Pressflag = PSI;
else if (match(Tok[],w_KPA)) Pressflag = KPA;
else if (match(Tok[],w_METERS)) Pressflag = METERS;
else return();
}
else if (match(Tok[],w_HEADLOSS))
{
if (n < ) return();
else if (match(Tok[],w_HW)) Formflag = HW;
else if (match(Tok[],w_DW)) Formflag = DW;
else if (match(Tok[],w_CM)) Formflag = CM;
else return();
}
else if (match(Tok[],w_HYDRAULIC))
{
if (n < ) return();
else if (match(Tok[],w_USE)) Hydflag = USE;
else if (match(Tok[],w_SAVE)) Hydflag = SAVE;
else return();
strncpy(HydFname,Tok[],MAXFNAME);
}
else if (match(Tok[],w_QUALITY))
{
if (n < ) return();
else if (match(Tok[],w_NONE)) Qualflag = NONE;
else if (match(Tok[],w_CHEM)) Qualflag = CHEM;
else if (match(Tok[],w_AGE)) Qualflag = AGE;
else if (match(Tok[],w_TRACE)) Qualflag = TRACE;
else
{
Qualflag = CHEM;
strncpy(ChemName,Tok[],MAXID);
if (n >= ) strncpy(ChemUnits,Tok[],MAXID);
}
if (Qualflag == TRACE) /* Source tracing option */
{
/* Copy Trace Node ID to Tok[0] for error reporting */
strcpy(Tok[],"");
if (n < ) return();
strcpy(Tok[],Tok[]);
TraceNode = findnode(Tok[]);
if (TraceNode == ) return();
strncpy(ChemName,u_PERCENT,MAXID);
strncpy(ChemUnits,Tok[],MAXID);
}
if (Qualflag == AGE)
{
strncpy(ChemName,w_AGE,MAXID);
strncpy(ChemUnits,u_HOURS,MAXID);
}
}
else if (match(Tok[],w_MAP))
{
if (n < ) return();
strncpy(MapFname,Tok[],MAXFNAME); /* Map file name */
}
else if (match(Tok[],w_VERIFY))
{
/* Backward compatibility for verification file */
}
else if (match(Tok[],w_UNBALANCED)) /* Unbalanced option */
{
if (n < ) return();
if (match(Tok[],w_STOP)) ExtraIter = -;
else if (match(Tok[],w_CONTINUE))
{
if (n >= ) ExtraIter = atoi(Tok[]);
else ExtraIter = ;
}
else return();
}
else if (match(Tok[],w_PATTERN)) /* Pattern option */
{
if (n < ) return();
strncpy(DefPatID,Tok[],MAXID);
}
else return(-);
return();
} /* end of optionchoice */ int optionvalue(int n)
/*
**-------------------------------------------------------------
** Input: *line = line read from input file
** Output: returns error code
** Purpose: processes numerical value [OPTIONS] data
** Formats:
** DEMAND MULTIPLIER value
** EMITTER EXPONENT value
** VISCOSITY value
** DIFFUSIVITY value
** SPECIFIC GRAVITY value
** TRIALS value
** ACCURACY value
** TOLERANCE value
** SEGMENTS value (not used)
** ------ Undocumented Options -----
** HTOL value
** QTOL value
** RQTOL value
** CHECKFREQ value
** MAXCHECK value
** DAMPLIMIT value //(2.00.12 - LR)
**--------------------------------------------------------------
UNITS 设置了流量被表达的单位:
LPS ——升/秒
LPM ——升/分
MLD ——百万升/日
CMH ——立方米/小时
CMG ——立方米/日
CFS ——立方英尺/秒
GPM ——加仑/分
MGD ——百万加仑/日
IMGD——英制MGD
AFD ——英亩-英尺/日
如果流量单位为升或者立方米,那么公制单位也必须用于所有其它输入量。对于CFS, GPM,
MGD, IMGD和AFD ,其它输入量表达为美制单位。(计量单位参见附录A)。缺省流量单位为GPM 。
HEADLOSS 选择了用于计算通过管道水流的水头损失公式。包括Hazen-Williams(H-W ),
Darcy-Weisbach(D-W)或Chezy-Manning (C-M)公式。缺省为H-W 。
HYDRAULICS 选项允许将当前水力结果SAVE(保存)到文件,或者USE (利用)以前保存的
水力结果。当研究仅仅影响水质行为的因子时,很有用。
QUALITY选择了执行水质分析的类型。选择包括NONE(无), CHEMICAL(化学药剂), AGE
(水龄)和TRACE (跟踪)。在CHEMI CAL 情况中,化合物的实际名称之后为其浓度单位(例如
CHLORINE mg/L )。如果TRACE 被选择,必须跟踪节点的ID标签。缺省选项为NONE(没有水
质分析)。
VISCOSITY是被模拟流体的运动粘度,相对于20摄氏度时的情况(1.0 厘斯)。缺省值为
1.0 。
DIFFUSIVITY是化合物的分析扩散系数,相对于水中的氯情况。缺省值为1.0 。扩散系数
仅仅适用于管壁反应中考虑质量转换限制时。数值0将造成EPANETH忽略质量转换限制。
SPECIFIC GRAVITY是被模拟流体密度与4摄氏度水的密度之比(无量纲)。
TRIALS是在每一模拟水力时间步长中,求解管网水力特性使用的最大试算次数。缺省为40。
ACCURACY 指定了确定何时达到水力结果的收敛准则。当所有流量总和改变,来自原先求解
除以所有管段的总流量低于该数值时,试算中止。缺省为0.001 。
UNBALANCED 确定了何时进行,如果水力结果在指定的TRIAL 数值内不能够达到,对于水力
时间步长来模拟。“STOP”将在该点终止整个分析。“CONTINUE ”将在公布警告消息的情况
下继续分析。“CONTINUE n ”将在另外“n”次试算中搜索结果,所有管线状态保持它们的当
前设置。模拟将在该点继续,关于收敛是否达到,具有消息公布。缺省选项为“STOP”。
PATTERN提供了用于没有指定需水量模式的所有节点缺省需水量模式的ID标签。如果没有
这样的模式在[PATTERNS] 节中存在,那么通过缺省的模式,包含一个等于1.0 的单一乘子。如
果没有使用该选项,总体缺省需水量模式具有标签“1”。
DEMAND MULTIPLIER用于调整所有连接节点的基本需水量数值,以及所有需水量的类型。
例如,数值2为两倍的基准需水量,而数值0.5 将为它们的一半。缺省值为1.0 。
EMITTER EXPONENT指定了当计算扩散器的流量时,节点压力上升的幂指数。缺省为0.5 。
MAP 用于提供包含了管网节点坐标的文件名称,以便绘制管网地图。对于任何水力或者水质
计算这是无用的。
TOLERANCE是水质水平精度。对于所有水质分析(化合物、水龄(以小时度量),或者源
头跟踪(以百分比度量)),缺省值为0.01。
备注:
a. 如果在本节没有明确指定,所有选项假设为缺省数值。
b. 反斜杠(/)后的项说明为允许选项。
*/
{
int nvalue = ; /* Index of token with numerical value */
double y; /* Check for obsolete SEGMENTS keyword */
if (match(Tok[],w_SEGMENTS)) return(); /* Check for missing value (which is permissible) */
if (match(Tok[],w_SPECGRAV) || match(Tok[],w_EMITTER)
|| match(Tok[],w_DEMAND)) nvalue = ;
if (n < nvalue) return(); /* Check for valid numerical input */
if (!getfloat(Tok[nvalue],&y)) return(); /* Check for WQ tolerance option (which can be 0) */
if (match(Tok[],w_TOLERANCE))
{
if (y < 0.0) return();
Ctol = y; /* Quality tolerance*/
return();
} /* Check for Diffusivity option */
if (match(Tok[],w_DIFFUSIVITY))
{
if (y < 0.0) return();
Diffus = y;
return();
} /* Check for Damping Limit option */ //(2.00.12 - LR)
if (match(Tok[],w_DAMPLIMIT))
{
DampLimit = y;
return();
} /* All other options must be > 0 */
if (y <= 0.0) return(); /* Assign value to specified option */
if (match(Tok[],w_VISCOSITY)) Viscos = y; /* Viscosity */
else if (match(Tok[],w_SPECGRAV)) SpGrav = y; /* Spec. gravity */
else if (match(Tok[],w_TRIALS)) MaxIter = (int)y; /* Max. trials */
else if (match(Tok[],w_ACCURACY)) /* Accuracy */
{
y = MAX(y,.e-);
y = MIN(y,.e-);
Hacc = y;
}
else if (match(Tok[],w_HTOL)) Htol = y;
else if (match(Tok[],w_QTOL)) Qtol = y;
else if (match(Tok[],w_RQTOL))
{
if (y >= 1.0) return();
RQtol = y;
}
else if (match(Tok[],w_CHECKFREQ)) CheckFreq = (int)y;
else if (match(Tok[],w_MAXCHECK)) MaxCheck = (int)y;
else if (match(Tok[],w_EMITTER)) Qexp = 1.0/y;
else if (match(Tok[],w_DEMAND)) Dmult = y;
else return();
return();
} /* end of optionvalue */ int getpumpcurve(int n)
/*
**--------------------------------------------------------
** Input: n = number of parameters for pump curve
** Output: returns error code
** Purpose: processes pump curve data for Version 1.1-
** style input data
** Notes:
** 1. Called by pumpdata() in INPUT3.C
** 2. Current link index & pump index of pump being
** processed is found in global variables Nlinks
** and Npumps, respectively
** 3. Curve data read from input line is found in
** global variables X[0],...X[n-1]
**---------------------------------------------------------
*/
{
double a,b,c,h0,h1,h2,q1,q2; if (n == ) /* Const. HP curve */
{
if (X[] <= 0.0) return();
Pump[Npumps].Ptype = CONST_HP;
Link[Nlinks].Km = X[];
}
else
{
if (n == ) /* Generic power curve */
{
q1 = X[];
h1 = X[];
h0 = 1.33334*h1;
q2 = 2.0*q1;
h2 = 0.0;
}
else if (n >= ) /* 3-pt. power curve */
{
h0 = X[];
h1 = X[];
q1 = X[];
h2 = X[];
q2 = X[];
}
else return();
Pump[Npumps].Ptype = POWER_FUNC;
if (!powercurve(h0,h1,h2,q1,q2,&a,&b,&c)) return();
Pump[Npumps].H0 = -a;
Pump[Npumps].R = -b;
Pump[Npumps].N = c;
Pump[Npumps].Q0 = q1;
Pump[Npumps].Qmax = pow((-a/b),(1.0/c));
Pump[Npumps].Hmax = h0;
}
return();
} int powercurve(double h0, double h1, double h2, double q1,
double q2, double *a, double *b, double *c)
/*
**---------------------------------------------------------
** Input: h0 = shutoff head 输入:h0 =最大水头
** h1 = design head h1 =设计水头
** h2 = head at max. flow h2 =最大流量时的水头
** q1 = design flow q1 =设计流量
** q2 = max. flow q2 =最大流量
** Output: *a, *b, *c = pump curve coeffs. (H = a-bQ^c),输出:返回水泵扬程-流量公式中的3参数
** Returns 1 if sucessful, 0 otherwise.
** Purpose: computes coeffs. for pump curve 目的:计算水泵曲线的方程系数
**----------------------------------------------------------
*/
{
double h4,h5;
if (
h0 < TINY ||
h0 - h1 < TINY ||
h1 - h2 < TINY ||
q1 < TINY ||
q2 - q1 < TINY
) return();
*a = h0;
h4 = h0 - h1;
h5 = h0 - h2;
*c = log(h5/h4)/log(q2/q1);
if (*c <= 0.0 || *c > 20.0) return();
*b = -h4/pow(q1,*c); /*** Updated 6/24/02 ***/
if (*b >= 0.0) return(); return();
} int valvecheck(int type, int j1, int j2)
/*
**--------------------------------------------------------------
** Input: type = valve type 阀门类型
** j1 = index of upstream node 上游节点索引值
** j2 = index of downstream node 下游节点索引值
** Output: returns 1 for legal connection, 0 otherwise 返回1为合法阀门情况
** Purpose: checks for legal connections between PRVs & PSVs 作用:检查多个阀门之间共享节点等非法情况
**--------------------------------------------------------------
*/
{
int k, vk, vj1, vj2, vtype; /* Examine each existing valve */
for (k=; k<=Nvalves; k++)
{
vk = Valve[k].Link;
vj1 = Link[vk].N1;
vj2 = Link[vk].N2;
vtype = Link[vk].Type; /* Cannot have two PRVs sharing downstream nodes or in series */
if (vtype == PRV && type == PRV)
{
if (vj2 == j2 ||
vj2 == j1 ||
vj1 == j2 ) return();
} /* Cannot have two PSVs sharing upstream nodes or in series */
if (vtype == PSV && type == PSV)
{
if (vj1 == j1 ||
vj1 == j2 ||
vj2 == j1 ) return();
} /* Cannot have PSV connected to downstream node of PRV */
if (vtype == PSV && type == PRV && vj1 == j2) return();
if (vtype == PRV && type == PSV && vj2 == j1) return(); /*** Updated 3/1/01 ***/
/* Cannot have PSV connected to downstream node of FCV */
/* nor have PRV connected to upstream node of FCV */
if (vtype == FCV && type == PSV && vj2 == j1) return();
if (vtype == FCV && type == PRV && vj1 == j2) return(); /*** Updated 4/14/05 ***/
if (vtype == PSV && type == FCV && vj1 == j2) return ();
if (vtype == PRV && type == FCV && vj2 == j1) return ();
}
return();
} /* End of valvecheck */ void changestatus(int j, char status, double y)
/*
**--------------------------------------------------------------
** Input: j = link index
** status = status setting (OPEN, CLOSED) //这里就阐释了status与setting的关系
** y = numerical setting (pump speed, valve
** setting)
** Output: none
** Purpose: changes status or setting of a link
**
** NOTE: If status = ACTIVE, then a numerical setting (y) was //如果status = ACTIVE,那么一个数值设定y将提供用于表示水泵的转速,或者阀门的开度等
** supplied. If status = OPEN/CLOSED, then numerical
** setting is 0.
**--------------------------------------------------------------
*/
{
if (Link[j].Type == PIPE || Link[j].Type == GPV)
{
if (status != ACTIVE) Link[j].Stat = status;
}
else if (Link[j].Type == PUMP)
{
if (status == ACTIVE)
{
Link[j].Kc = y;
status = OPEN;
if (y == 0.0) status = CLOSED;
}
else if (status == OPEN) Link[j].Kc = 1.0;
Link[j].Stat = status;
}
else if (Link[j].Type >= PRV)
{
Link[j].Kc = y;
Link[j].Stat = status;
if (status != ACTIVE) Link[j].Kc = MISSING;
}
} /* end of changestatus */ /********************** END OF INPUT3.C ************************/
EPANET中读取INPUT文件的函数文件——INPUT3.C的更多相关文章
- EPANET中读取INPUT文件的函数文件——INPUT1.C/INPUT2.C/INPUT3.C
首先介绍下这3个文件的关系:可以说INPUT1.C的函数粒度最大,它的函数getdata()就完成了整个INPUT文件数据的读入,该函数又调用了INPUT2.C中的部分函数,INPUT2.C文件中的函 ...
- C#项目实例中读取并修改App.config文件
C#项目是指一系列独特的.复杂的并相互关联的活动,这些活动有着一个明确的目标或目的,必须在特定的时间.预算.资源限定内,依据规范完成.项目参数包括项目范围.质量.成本.时间.资源. 1. 向C#项目实 ...
- 在.NET中读取嵌入和使用资源文件的方法
转http://www.jb51.net/article/84660.htm 本文分别介绍了使用GetManifestResourceStream读取嵌入资源,和使用. resx资源文件嵌入资源,希望 ...
- 总结文件操作函数-文件夹(三)-C语言
获取.改变当前文件夹: 原型为: #include <unistd.h> //头文件 char *getcwd(char *buf, size_t size); //获取当前文件夹.相 ...
- 第3章 Python基础-文件操作&函数 文件操作 练习题
一.利用b模式,编写一个cp工具,要求如下: 1. 既可以拷贝文本又可以拷贝视频,图片等文件 2. 用户一旦参数错误,打印命令的正确使用方法,如usage: cp source_file target ...
- matlab初学者_脚本文件调用函数文件
问题: matlab里面有两种文件,一种是脚本文件,一种是函数文件,为了模块化程序,我们需要把专门的功能写成一个函数封装到某个函数文件里面. 那么来看如何在脚本文件里调用函数文件中的函数. 注意点: ...
- java项目中读取src目录下的文件
private void getUser(String tmpfile){ Properties props = new Properties(); props.load(DbTask.class.g ...
- 通过纯Java代码从excle中读取数据(为.xlsx文件)
参考链接: 程序代码: package demo; import java.io.File; import java.io.IOException; import java.io.InputStrea ...
- [Java] 在 jar 文件中读取 resources 目录下的文件
注意两点: 1. 将资源目录添加到 build path,确保该目录下的文件被拷贝到 jar 文件中. 2. jar 内部的东西,可以当作 stream 来读取,但不应该当作 file 来读取. 例子 ...
随机推荐
- [轉]redis;mongodb;memcache三者的性能比較
先说我自己用的情况: 最先用的memcache ,用于键值对关系的服务器端缓存,用于存储一些常用的不是很大,但需要快速反应的数据 然后,在另一个地方,要用到redis,然后就去研究了下redis. 一 ...
- Splunk - 如何在WebFramework之CORS模式下你的网站和splunk web进行交互
1. 修改配置文件以支持CORS 进入/Applications/Splunk/etc/system/local 修改server.conf 在最后加入如下: [httpServer]crossOri ...
- python 与数据结构
在上面的文章中,我写了python中的一些特性,主要是简单为主,主要是因为一些其他复杂的东西可以通过简单的知识演变而来,比如装饰器还可以带参数,可以使用装饰类,在类中不同的方法中调用,不想写的太复杂, ...
- 删除数据报ORA-00600: internal error code, arguments: [ktbesc_plugged]
Oracle在删除数据是以下错误: ORA-00600: internal error code, arguments: [ktbesc_plugged], [], [], [], [], [], [ ...
- Navi.Soft30.开放平台.百度.开发手册
1系统简介 1.1功能简述 现在是一个信息时代,并且正在高速发展.以前获取信息的途径非常少,可能只有电视台,收音机等有限的来源,而现在的途径数不胜数,如:QQ,微信,官方网站,个人网站等等 本开发手册 ...
- EF OnModelCreating
http://www.cnblogs.com/libingql/p/3353112.html protected override void OnModelCreating(DbModel ...
- LR6 碱性电池才能带动微软鼠标
LR6 碱性电池才能带动微软鼠标 好前一段买个一个微软无线鼠标后来动弹不得,更换电池也不行,本来lp说为什么不扔掉,但因为实在做得很漂亮一直带在身边.改用雷柏的普通无线鼠标后也很是好用.不过要经常 ...
- 3.C#中的多重委托
阅读目录 一:多重委托概述 二:多重委托实例 一:多重委托概述 1.委托的调用其实是一个调用列表,可以同时调用多个不同的方法 2.第1个委托加上第2个委托赋予第3个委托,相当于把两个方法按顺 ...
- Linux环境的PHP执行
/usr/local/php5/bin/php -c /var/spool/php.ini -q /var/spool/auto.php
- iOS 日期处理 (Swift3.0 NSDate)
处理日期的常见情景 NSDate -> String & String -> NSDate 日期比较 日期计算(基于参考日期 +/- 一定时间) 计算日期间的差异 拆解NSDate ...