EPANET中读取INPUT文件的函数文件——INPUT3.C

   1 /*
   2 **********************************************************************
   3 
   4 INPUT3.C -- Input data parser for EPANET;
   5 
   6 VERSION:    2.00
   7 DATE:       5/30/00
   8             9/7/00
   9             10/25/00
  10             3/1/01
  11             6/24/02
  12             8/15/07    (2.00.11)
  13             2/14/08    (2.00.12)
  14 AUTHOR:     L. Rossman
  15             US EPA - NRMRL
  16 
  17 This module parses data from each line of input from file InFile.
  18 All functions in this module are called from newline() in INPUT2.C.
  19 该模块逐行解析INPUT文件。
  20 该模块中的所有函数都在INPUT2.C的newline(int sect, char *line)中被调用。
  21 
  22 同时该模块也调用了INPUT2.C中的部分工具函数:addlinkID(int n, char *id)、addnodeID(int n, char *id)、addpattern(char *id)、
  23 addcurve(char *id)、*findID(char *id, STmplist *list)、match(char *str, char *substr)、hour(char *time, char *units)等
  24 
  25 **********************************************************************
  26 */
  27 
  28 #include <stdlib.h>
  29 #include <stdio.h>
  30 #include <string.h>
  31 #include <malloc.h>
  32 #include <math.h>
  33 #include "hash.h"
  34 #include "text.h"
  35 #include "types.h"
  36 #include "funcs.h"
  37 #define  EXTERN  extern
  38 #include "vars.h"
  39 
  40 /* Defined in enumstxt.h in EPANET.C */
  41 extern char *MixTxt[];
  42 extern char *Fldname[];            //字段名称字符串数组
  43 
  44 /* Defined in INPUT2.C */
  45 extern char      *Tok[MAXTOKS];    /* Array of token strings            ;每一输入行的项数组成的字符串数组*/
  46 extern STmplist  *PrevPat;         /* Pointer to pattern list element   ;指向模式的最近一个指针*/
  47 extern STmplist  *PrevCurve;       /* Pointer to curve list element     ;指向曲线的最近一个指针*/
  48 extern int       Ntokens;          /* Number of tokens in input line    ;每一输入行的项数(项与项之间的分隔形式是:)*/
  49 
  50 
  51 int  juncdata()
  52 /*
  53 **--------------------------------------------------------------
  54 **  Input:   none                            ;输入:无                    
  55 **  Output:  returns error code              ;输出:错误编码                    
  56 **  Purpose: processes junction data         ;作用:处理节点数据                    
  57 **  Format:                                  ;格式:                    
  58 **    [JUNCTIONS]                                              
  59 **      id  elev.  (demand)  (demand pattern)            数据项的列表      
  60 **--------------------------------------------------------------
  61 */
  62 {
  63    int      n, p = 0;//n代表待解析行中的数据项的个数;p代表该节点的用水模式链表中的index值;
  64    double    el,y = 0.0;//el表示该节点的高程值;y表示该节点的用水量值
  65    Pdemand  demand;//当该节点存在多个用水量及对应的用水模式曲线时,使用该变量保存
  66    STmplist *pat;
  67 
  68 /* Add new junction to data base ;增加一个新的节点数据*/
  69    n = Ntokens;
  70    if (Nnodes == MaxNodes) return(200);
  71    Njuncs++;
  72    Nnodes++;
  73    if (!addnodeID(Njuncs,Tok[0])) return(215);
  74 
  75 /* Check for valid data ;检查该数据的正确性*/
  76    if (n < 2) return(201);//不存在高程信息
  77    if (!getfloat(Tok[1],&el)) return(202);//高程信息数据类型非法
  78    if (n >= 3  && !getfloat(Tok[2],&y)) return(202);//若需水量存在且需水量数据类型非法
  79    if (n >= 4)
  80    {
  81       pat = findID(Tok[3],Patlist);
  82       if (pat == NULL) return(205);
  83       p = pat->i;
  84    }
  85 
  86 /* Save junction data ;将节点的高程等信息保存下来*/
  87    Node[Njuncs].El  = el;
  88    Node[Njuncs].C0  = 0.0;
  89    Node[Njuncs].S   = NULL;
  90    Node[Njuncs].Ke  = 0.0;
  91    Node[Njuncs].Rpt = 0;
  92 
  93 /* Create a new demand record ;一个节点有一个指向该节点所挂的需水量指针D,将读入的水量及模式挂接到D的链首*/
  94 /*** Updated 6/24/02 ***/
  95    if (n >= 3)
  96    {
  97       demand = (struct Sdemand *) malloc(sizeof(struct Sdemand));
  98       if (demand == NULL) return(101);
  99       demand->Base = y;
 100       demand->Pat = p;
 101       demand->next = Node[Njuncs].D;
 102       Node[Njuncs].D = demand;
 103       D[Njuncs] = y;//全局变量中的节点实际需水量
 104    }
 105    else D[Njuncs] = MISSING;   //标记该节点暂无以Junction节点中分配水量,如果Demand中有对该节点分水量,那么也标记为MISSING
 106 /*** end of update ***/
 107    return(0);
 108 }                        /* end of juncdata */
 109 
 110 
 111 int  tankdata()
 112 /*
 113 **--------------------------------------------------------------
 114 **  Input:   none                                              ;输入:无
 115 **  Output:  returns error code                                ;输出:错误代码
 116 **  Purpose: processes tank & reservoir data                   ;作用:处理水塔和水池(水库)数据
 117 **  Format:                                                    ;格式:
 118 **   [RESERVOIRS]                                              
 119 **     id elev (pattern)                                     
 120 **   [TANKS]                                                 
 121 **     id elev (pattern)                                     
 122 **     id elev initlevel minlevel maxlevel diam (minvol vcurve)         
 123 **--------------------------------------------------------------
 124 */
 125 {
 126    int   i,               /* Node index Node中的索引值*/
 127          n,               /* # data items 该数据行的数据项数 */
 128          p = 0,           /* Fixed grade time pattern index 时间模式中的索引值 */
 129          vcurve = 0;      /* Volume curve index 容积曲线的索引值*/
 130    double el        = 0.0, /* Elevation 高程值*/
 131          initlevel = 0.0, /* Initial level 初始水面高程*/
 132          minlevel  = 0.0, /* Minimum level 最小水池高程*/
 133          maxlevel  = 0.0, /* Maximum level 最大水池高程*/
 134          minvol    = 0.0, /* Minimum volume 最小容积*/
 135          diam      = 0.0, /* Diameter 口径*/
 136          area;            /* X-sect. area 横截面面积*/
 137    STmplist *t;
 138 
 139 /* Add new tank to data base 添加新的水塔数据*/
 140    n = Ntokens;
 141    if (Ntanks == MaxTanks
 142    ||  Nnodes == MaxNodes) return(200);
 143    Ntanks++;
 144    Nnodes++;
 145    i = MaxJuncs + Ntanks;                    /* i = node index.   i是水塔在Node中的索引  */
 146    if (!addnodeID(i,Tok[0])) return(215);    /* Add ID to database. 将"ID标识"及其Node的索引值添加到节点哈希表中*/
 147 
 148 /* Check for valid data 检查数据的合法性*/
 149    if (n < 2) return(201);                   /* Too few fields.   字段个数过少,至少包含id与高程值*/
 150    if (!getfloat(Tok[1],&el)) return(202);   /* Read elevation    高程值无法转成数值型*/
 151    if (n <= 3)                               /* Tank is reservoir.水池是特殊的水塔,如果数据项小于3项,则将水塔认为为水库*/
 152    {
 153       if (n == 3)                            /* Pattern supplied  找到指定时间模式值的索引值*/
 154       {
 155          t = findID(Tok[2],Patlist);
 156          if (t == NULL) return(205);
 157          p = t->i;
 158       }
 159    }
 160    else if (n < 6) return(201);              /* Too few fields for tank.水塔需要的字段数不能少于6个*/
 161    else
 162    {
 163       /* Check for valid input data 检查水塔数据的正确性,进行类型检查*/
 164       if (!getfloat(Tok[2],&initlevel)) return(202);
 165       if (!getfloat(Tok[3],&minlevel))  return(202);
 166       if (!getfloat(Tok[4],&maxlevel))  return(202);
 167       if (!getfloat(Tok[5],&diam))      return(202);
 168       if (diam < 0.0)                   return(202);//口径非负检查
 169       if (n >= 7
 170       && !getfloat(Tok[6],&minvol))     return(202);
 171 
 172       /* If volume curve supplied check it exists 如果容积曲线存在,则对容积曲线进行存在性检查,若存在返回索引值*/
 173       if (n == 8)
 174       {                           
 175          t = findID(Tok[7],Curvelist);
 176          if (t == NULL) return(202);
 177          vcurve = t->i;
 178       }
 179    }
 180 
 181    Node[i].Rpt           = 0;
 182    Node[i].El            = el;               /* Elevation.           */
 183    Node[i].C0            = 0.0;              /* Init. quality.       */
 184    Node[i].S             = NULL;             /* WQ source data       */     
 185    Node[i].Ke            = 0.0;              /* Emitter coeff.       */
 186    Tank[Ntanks].Node     = i;                /* Node index.          */
 187    Tank[Ntanks].H0       = initlevel;        /* Init. level.         */
 188    Tank[Ntanks].Hmin     = minlevel;         /* Min. level.          */
 189    Tank[Ntanks].Hmax     = maxlevel;         /* Max level.           */
 190    Tank[Ntanks].A        = diam;             /* Diameter.            */
 191    Tank[Ntanks].Pat      = p;                /* Fixed grade pattern. */
 192    Tank[Ntanks].Kb       = MISSING;          /* Reaction coeff.      */
 193    /*
 194    *******************************************************************
 195     NOTE: The min, max, & initial volumes set here are based on a     
 196        nominal tank diameter. They will be modified in INPUT1.C if    
 197        a volume curve is supplied for this tank. 
 198        这里的最小、最大和初始容积的计算是基于水塔的口径来的。
 199        它们会在INPUT1.C文件中被修改,如果这个水塔存在一个容积曲线。
 200    *******************************************************************
 201    */
 202    area = PI*SQR(diam)/4.0;//横截面积
 203    Tank[Ntanks].Vmin = area*minlevel;//最小容积
 204    if (minvol > 0.0) Tank[Ntanks].Vmin = minvol;
 205    Tank[Ntanks].V0 = Tank[Ntanks].Vmin + area*(initlevel - minlevel);
 206    Tank[Ntanks].Vmax = Tank[Ntanks].Vmin + area*(maxlevel - minlevel);//最大容积
 207 
 208    Tank[Ntanks].Vcurve   = vcurve;           /* Volume curve         容积曲线索引值*/
 209    Tank[Ntanks].MixModel = MIX1;             /* Completely mixed     水池出水模式*/
 210    Tank[Ntanks].V1max    = 1.0;              /* Compart. size ratio  */
 211    return(0);
 212 }                        /* end of tankdata */
 213 
 214 
 215 int  pipedata()
 216 /*
 217 **--------------------------------------------------------------
 218 **  Input:   none                                              ;输入:无
 219 **  Output:  returns error code                                ;输出:错误代码
 220 **  Purpose: processes pipe data                               :作用:处理管段数据
 221 **  Format:                                                    ;格式:状态可以不需要,默认都是OPEN
 222 **    [PIPE]                                                
 223 **    id  node1  node2  length  diam  rcoeff (lcoeff) (status)          
 224 **--------------------------------------------------------------
 225 */
 226 {
 227    int   j1,                     /* Start-node index  起始junction在Node链表中的索引值*/
 228          j2,                     /* End-node index    终点junction在Node链表中的索引值*/
 229          n;                      /* # data items      当前行数据项个数*/
 230    char  type = PIPE,            /* Link type         管段类型,默认为Pipe*/
 231          status = OPEN;          /* Link status       管段状态(OPEN, CLOSED或CV),默认是开启状态*/
 232    double length,                /* Link length       管长*/
 233          diam,                   /* Link diameter     管径*/
 234          rcoeff,                 /* Roughness coeff.  粗糙系数*/
 235          lcoeff = 0.0;           /* Minor loss coeff. 局部损失系数*/
 236 
 237 /* Add new pipe to data base 将新管段添加进来*/
 238    n = Ntokens;
 239    if (Nlinks == MaxLinks) return(200);
 240    Npipes++;
 241    Nlinks++;
 242    if (!addlinkID(Nlinks,Tok[0])) return(215);
 243 
 244 /* Check for valid data 检查管段数据的正确性*/
 245    if (n < 6) return(201);              //数据项个数至少有6个
 246    if ((j1 = findnode(Tok[1])) == 0 ||  //获取始末点的索引值   
 247        (j2 = findnode(Tok[2])) == 0
 248       ) return(203);
 249 
 250 /*** Updated 10/25/00 ***/
 251    if (j1 == j2) return(222);           //如果起点与终点相同则返回出错信息
 252 
 253    if (!getfloat(Tok[3],&length) ||     //进行长度、口径、粗糙系数的数据类型检查
 254        !getfloat(Tok[4],&diam)   ||     
 255        !getfloat(Tok[5],&rcoeff)        
 256       ) return(202);
 257 
 258    if (length <= 0.0 ||                 //进行长度、口径、粗糙系数的数据的非负检查
 259        diam   <= 0.0 ||
 260        rcoeff <= 0.0
 261       ) return(202);
 262 
 263    /* Case where either loss coeff. or status supplied 获取局部损失系数或者状态*/
 264    if (n == 7)
 265    {
 266       if      (match(Tok[6],w_CV))        type = CV;
 267       else if (match(Tok[6],w_CLOSED))    status = CLOSED;
 268       else if (match(Tok[6],w_OPEN))      status = OPEN;
 269       else if (!getfloat(Tok[6],&lcoeff)) return(202);
 270    }
 271 
 272    /* Case where both loss coeff. and status supplied 获取局部损失系数和状态*/
 273    if (n == 8)
 274    {
 275       if (!getfloat(Tok[6],&lcoeff))   return(202);
 276       if      (match(Tok[7],w_CV))     type = CV;
 277       else if (match(Tok[7],w_CLOSED)) status = CLOSED;
 278       else if (match(Tok[7],w_OPEN))   status = OPEN;
 279       else return(202);
 280    }
 281    if (lcoeff < 0.0) return(202);
 282 
 283 /* Save pipe data 保存该管段的数据*/
 284    Link[Nlinks].N1    = j1;                  /* Start-node index */
 285    Link[Nlinks].N2    = j2;                  /* End-node index   */
 286    Link[Nlinks].Len   = length;              /* Length           */
 287    Link[Nlinks].Diam  = diam;                /* Diameter         */
 288    Link[Nlinks].Kc    = rcoeff;              /* Rough. coeff     */
 289    Link[Nlinks].Km    = lcoeff;              /* Loss coeff       */
 290    Link[Nlinks].Kb    = MISSING;             /* Bulk coeff       */
 291    Link[Nlinks].Kw    = MISSING;             /* Wall coeff       */
 292    Link[Nlinks].Type  = type;                /* Link type        */
 293    Link[Nlinks].Stat  = status;              /* Link status      */
 294    Link[Nlinks].Rpt   = 0;                   /* Report flag      */
 295    return(0);
 296 }                        /* end of pipedata */
 297 
 298 
 299 int  pumpdata()
 300 /*
 301 **--------------------------------------------------------------;备注:水泵被认为是特殊的管段数据
 302 ** Input:   none                                                ;输入:无 
 303 ** Output:  returns error code                                  ;输出:错误代码
 304 ** Purpose: processes pump data                                 ;目的:处理水泵数据
 305 ** Formats:                                                     ;格式:
 306 **  [PUMP]                                                     
 307 **   (Version 1.x Format):                                              
 308 **   id  node1  node2  power                                   
 309 **   id  node1  node2  h1    q1                                
 310 **   id  node1  node2  h0    h1   q1   h2   q2                 
 311 **   (Version 2 Format):                                              
 312 **   id  node1  node2  KEYWORD value {KEYWORD value ...}       
 313 **   where KEYWORD = [POWER,HEAD,PATTERN,SPEED]            
 314 ;ID                  Node1               Node2               Parameters
 315  9                   9                   10                  HEAD 1    ;
 316 **--------------------------------------------------------------
 317 */
 318 {
 319    int   j,
 320          j1,                    /* Start-node index 起始junction在Node链表中的索引值*/
 321          j2,                    /* End-node index   终点junction在Node链表中的索引值*/
 322          m, n;                  /* # data items     当前行数据项个数*/
 323    double y;
 324    STmplist *t;                 /* Pattern record   */
 325 
 326 /* Add new pump to data base 将新水泵数据添加进来*/
 327    n = Ntokens;
 328    if (Nlinks == MaxLinks ||
 329        Npumps == MaxPumps
 330       ) return(200);
 331    Nlinks++;
 332    Npumps++;
 333    if (!addlinkID(Nlinks,Tok[0])) return(215);
 334 
 335 /* Check for valid data 检查数据合法性*/
 336    if (n < 4) return(201);                    //字段个数至少4个
 337    if ((j1 = findnode(Tok[1])) == 0 ||        //获取始末junction在Node链表中的索引值
 338        (j2 = findnode(Tok[2])) == 0
 339       ) return(203);
 340 
 341 /*** Updated 10/25/00 ***/
 342    if (j1 == j2) return(222);                 //如果起点与终点相同则返回出错信息
 343 
 344 /* Save pump data 保存水泵数据*/
 345    Link[Nlinks].N1    = j1;               /* Start-node index.  */
 346    Link[Nlinks].N2    = j2;               /* End-node index.    */
 347    Link[Nlinks].Diam  = Npumps;           /* Pump index.        */
 348    Link[Nlinks].Len   = 0.0;              /* Link length.       */
 349    Link[Nlinks].Kc    = 1.0;              /* Speed factor.      */
 350    Link[Nlinks].Km    = 0.0;              /* Horsepower.        */
 351    Link[Nlinks].Kb    = 0.0;
 352    Link[Nlinks].Kw    = 0.0;
 353    Link[Nlinks].Type  = PUMP;             /* Link type.         */
 354    Link[Nlinks].Stat  = OPEN;             /* Link status.       */
 355    Link[Nlinks].Rpt   = 0;                /* Report flag.       */
 356    Pump[Npumps].Link = Nlinks;            /* Link index.        */
 357    Pump[Npumps].Ptype = NOCURVE;          /* Type of pump curve 默认无水泵曲线*/
 358    Pump[Npumps].Hcurve = 0;               /* Pump curve index   */
 359    Pump[Npumps].Ecurve = 0;               /* Effic. curve index */
 360    Pump[Npumps].Upat   = 0;               /* Utilization pattern*/
 361    Pump[Npumps].Ecost  = 0.0;             /* Unit energy cost   */
 362    Pump[Npumps].Epat   = 0;               /* Energy cost pattern*/
 363 
 364 /* If 4-th token is a number then input follows Version 1.x format 若第4个数据项是一个数字则按版本1.x来解读水泵曲线*/
 365 /* so retrieve pump curve parameters 获取水泵参数曲线;一般现在都是按2.x版本,所以可以跳过不做细究*/
 366    if (getfloat(Tok[3],&X[0]))
 367    {
 368       m = 1;
 369       for (j=4; j<n; j++)
 370       {
 371          if (!getfloat(Tok[j],&X[m])) return(202);
 372          m++;
 373       }
 374       return(getpumpcurve(m));          /* Get pump curve params */
 375    }
 376 
 377 /* Otherwise input follows Version 2 format */
 378 /* so retrieve keyword/value pairs.         版本2是采用键值对的方式来定义水泵曲线*/
 379 /*
 380     关键词和数值(可以重复)
 381 a.  关键词包括: 
 382 * POWER——定速能量水泵的功率数值,hp (kW) 
 383 * HEAD——描述了水泵扬程与流量关系的曲线ID 
 384 * SPEED——相对速度设置(额定速度为1.0 ,0意味着水泵关闭) 
 385 * PATTERN——时间模式的ID,描述了速度设置怎样随时间变化 
 386 b.  对于每一台水泵,必须提供POWER 或者HEAD。其它关键词是可选的。 
 387 */
 388    m = 4;
 389    while (m < n)
 390    {
 391       if (match(Tok[m-1],w_POWER))          /* Const. HP curve       定速能量水泵的功率数值,hp (kW)*/
 392       {
 393          y = atof(Tok[m]);
 394          if (y <= 0.0) return(202);
 395          Pump[Npumps].Ptype = CONST_HP;    //水泵曲线类型
 396          Link[Nlinks].Km = y;              //Minor loss coeff. 局部损失系数
 397       }
 398       else if (match(Tok[m-1],w_HEAD))      /* Custom pump curve      描述了水泵扬程与流量关系的曲线ID*/
 399       {
 400          t = findID(Tok[m],Curvelist);
 401          if (t == NULL) return(206);
 402          Pump[Npumps].Hcurve = t->i;
 403       }
 404       else if (match(Tok[m-1],w_PATTERN))   /* Speed/status pattern 时间模式的ID,描述了速度设置怎样随时间变化 */
 405       {
 406          t = findID(Tok[m],Patlist);
 407          if (t == NULL) return(205);
 408          Pump[Npumps].Upat = t->i;
 409       }
 410       else if (match(Tok[m-1],w_SPEED))     /* Speed setting 相对速度设置(额定速度为1.0 ,0意味着水泵关闭)*/
 411       {
 412          if (!getfloat(Tok[m],&y)) return(202);
 413          if (y < 0.0) return(202); 
 414          Link[Nlinks].Kc = y;
 415       }
 416       else return(201);
 417       m = m + 2;                          /* Skip to next keyword token 键值对都是2个一组的,可以重复*/
 418    }
 419    return(0);
 420 }                        /* end of pumpdata */
 421 
 422 
 423 int  valvedata()
 424 /*
 425 **--------------------------------------------------------------
 426 **  Input:   none                                                ;输入:无 
 427 **  Output:  returns error code                                  ;输出:错误代码
 428 **  Purpose: processes valve data                                ;作用:处理阀门数据
 429 **  Format:                                                      ;格式:
 430 **     [VALVE]                                                   
 431 **        id  node1  node2  diam  type  setting (lcoeff)       
 432 **--------------------------------------------------------------
 433 */
 434 {
 435    int   j1,                    /* Start-node index   起始junction在Node链表中的索引值*/
 436          j2,                    /* End-node index     终点junction在Node链表中的索引值*/
 437          n;                     /* # data items       当前行数据项个数*/
 438    char  status = ACTIVE,       /* Valve status       阀门状态*/
 439          type;                  /* Valve type         阀门类型*/
 440    double diam = 0.0,           /* Valve diameter     阀门口径*/
 441          setting,               /* Valve setting      阀门设置*/
 442          lcoeff = 0.0;          /* Minor loss coeff.  局部损失系数*/
 443    STmplist *t;                 /* Curve record       阀门曲线*/
 444 
 445 /* Add new valve to data base 添加阀门数据*/
 446    n = Ntokens;
 447    if (Nlinks == MaxLinks ||
 448        Nvalves == MaxValves
 449       ) return(200);
 450    Nvalves++;
 451    Nlinks++;
 452    if (!addlinkID(Nlinks,Tok[0])) return(215);
 453 
 454 /* Check for valid data 检查阀门数据的合法性*/
 455    if (n < 6) return(201);                            //至少需要6个字段,第7个字段"局部损失系数"可选
 456    if ((j1 = findnode(Tok[1])) == 0 ||                
 457        (j2 = findnode(Tok[2])) == 0
 458       ) return(203);
 459 
 460 /*** Updated 10/25/00 ***/
 461    if (j1 == j2) return(222);                    //起点与终点相同,返回错误代码
 462 //获取阀门类型                              阀门                              设置
 463    if      (match(Tok[4],w_PRV)) type = PRV;//PRV (减压阀)                    压力,m(psi) 
 464    else if (match(Tok[4],w_PSV)) type = PSV;//PSV  (稳压阀)                        压力,m(psi)
 465    else if (match(Tok[4],w_PBV)) type = PBV;//PBV (压力制动阀)                压力,m(psi)
 466    else if (match(Tok[4],w_FCV)) type = FCV;//FCV (流量控制阀)                流量(流量单位)
 467    else if (match(Tok[4],w_TCV)) type = TCV;//TCV (节流控制阀)                损失系数
 468    else if (match(Tok[4],w_GPV)) type = GPV;//GPV (常规阀门)                  水头损失曲线的ID 
 469    else    return(201);                      /* Illegal valve type.*/
 470    if (!getfloat(Tok[3],&diam)) return(202);
 471    if (diam <= 0.0) return(202);             /* Illegal diameter.*/
 472    if (type == GPV)                          /* Headloss curve for GPV 获取水头损失曲线ID在曲线表中的索引值*/
 473    {
 474       t = findID(Tok[5],Curvelist);
 475       if (t == NULL) return(206);
 476       setting = t->i;
 477 
 478 /*** Updated 9/7/00 ***/
 479       status = OPEN;                        //阀门状态设置为开启
 480 
 481    }
 482    else if (!getfloat(Tok[5],&setting)) return(202);
 483    if (n >= 7 &&                           //获取
 484        !getfloat(Tok[6],&lcoeff)
 485       ) return(202);
 486 
 487 /* Check that PRV, PSV, or FCV not connected to a tank & */
 488 /* check for illegal connections between pairs of valves.*/
 489    if ((j1 > Njuncs || j2 > Njuncs) &&
 490        (type == PRV || type == PSV || type == FCV)
 491       ) return(219);
 492    if (!valvecheck(type,j1,j2)) return(220);
 493 
 494 /* Save valve data 设置阀门数据,注意阀门是特殊的管段数据*/
 495    Link[Nlinks].N1     = j1;                 /* Start-node index. 设置起始节点索引值*/
 496    Link[Nlinks].N2     = j2;                 /* End-node index.   设置终点节点索引值*/
 497    Link[Nlinks].Diam   = diam;               /* Valve diameter.   阀门口径*/
 498    Link[Nlinks].Len    = 0.0;                /* Link length.      */
 499    Link[Nlinks].Kc     = setting;            /* Valve setting.    */
 500    Link[Nlinks].Km     = lcoeff;             /* Loss coeff        */
 501    Link[Nlinks].Kb     = 0.0;
 502    Link[Nlinks].Kw     = 0.0;
 503    Link[Nlinks].Type   = type;               /* Valve type.       */
 504    Link[Nlinks].Stat   = status;             /* Valve status.     */
 505    Link[Nlinks].Rpt    = 0;                  /* Report flag.      */
 506    Valve[Nvalves].Link = Nlinks;             /* Link index.       */
 507    return(0);
 508 }                        /* end of valvedata */
 509 
 510 
 511 int  patterndata()
 512 /*
 513 **--------------------------------------------------------------
 514 **  Input:   none                                                ;输入:无 
 515 **  Output:  returns error code                                  ;输出:错误代码
 516 **  Purpose: processes time pattern data                         ;作用:处理时间模式数据
 517 **  Format:                                                      ;格式:
 518 **     [PATTERNS]                                                这让我回想起当时Hammer中导出的INP文件解算时只有前面几个时段的数据,很可能的一个原因就是EPANET对INP文件的规范是每行最多40项,而Hammer的Pattern格式长度过长导致的。
 519 **        id  mult1  mult2 .....                               
 520 **--------------------------------------------------------------
 521 */
 522 {
 523    int  i,n;                       /*n表示 当前行数据项个数*/
 524    double x;
 525    SFloatlist *f;                  //f:一个包含浮点数的单向链表                        
 526    STmplist   *p;                  //p:当前的用水模式
 527    n = Ntokens - 1;
 528    if (n < 1) return(201);            /* Too few values        当前行数据项个数过少*/
 529    if (                               /* Check for new pattern 查看当前行的ID是否存在于PrevPat链表中*/
 530           PrevPat != NULL &&          /*这里的if语句的作用在于一个时间模式可能是连接多行,那么这样就能提高效率*/
 531           strcmp(Tok[0],PrevPat->ID) == 0
 532       ) p = PrevPat;
 533    else p = findID(Tok[0],Patlist);
 534    if (p == NULL) return(205);
 535    for (i=1; i<=n; i++)               /* Add multipliers to list 添加用水模式系数,添加至链首*/
 536    {
 537        if (!getfloat(Tok[i],&x)) return(202);
 538        f = (SFloatlist *) malloc(sizeof(SFloatlist));
 539        if (f == NULL) return(101);
 540        f->value = x;
 541        f->next = p->x;               //将当前系数挂在该模式p的系数链首
 542        p->x = f;
 543    }
 544    Pattern[p->i].Length += n;         /* Save # multipliers for pattern 维护当前模式的长度*/
 545    PrevPat = p;                       /* Set previous pattern pointer 临时的模式对象,因模式可能是连着多行而提高效率*/
 546    return(0);
 547 }                        /* end of patterndata */
 548 
 549 
 550 int  curvedata()
 551 /*
 552 **------------------------------------------------------
 553 **  Input:   none                                       ;输入:无
 554 **  Output:  returns error code                         ;输出:错误代码
 555 **  Purpose: processes curve data                       ;作用:处理曲线数据 
 556 **  Format:                                             ;格式: 
 557 **     [CURVES]                                        
 558 **      CurveID   x-value  y-value                    
 559 **------------------------------------------------------
 560 */
 561 {
 562    double      x,y;
 563    SFloatlist *fx, *fy;
 564    STmplist   *c;
 565 
 566    /* Check for valid curve ID */
 567    if (Ntokens < 3) return(201);
 568    if (
 569           PrevCurve != NULL &&
 570           strcmp(Tok[0],PrevCurve->ID) == 0
 571       ) c = PrevCurve;
 572    else c = findID(Tok[0],Curvelist);
 573    if (c == NULL) return(205);
 574 
 575    /* Check for valid data */
 576    if (!getfloat(Tok[1],&x)) return(202);
 577    if (!getfloat(Tok[2],&y)) return(202);
 578 
 579    /* Add new data point to curve's linked list */
 580    fx = (SFloatlist *) malloc(sizeof(SFloatlist));
 581    fy = (SFloatlist *) malloc(sizeof(SFloatlist));
 582    if (fx == NULL || fy == NULL) return(101);
 583    fx->value = x;
 584    fx->next = c->x;
 585    c->x = fx;
 586    fy->value = y;
 587    fy->next = c->y;
 588    c->y = fy;
 589    Curve[c->i].Npts++;
 590 
 591    /* Save the pointer to this curve */
 592    PrevCurve = c;
 593    return(0);
 594 }
 595 
 596 
 597 int  demanddata()
 598 /*
 599 **--------------------------------------------------------------
 600 **  Input:   none                                                ;输入:无 
 601 **  Output:  returns error code                                  ;输出:错误代码
 602 **  Purpose: processes node demand data                          ;作用:定义连接节点的多模式需水,是对[JUNCTIONS]的补充。 
 603 **  Format:                                                      ;格式:
 604 **     [DEMANDS]                                               
 605 **        MULTIPLY  factor                                     
 606 **        node  base_demand  (pattern)                         
 607 **
 608 **  NOTE: Demands entered in this section replace those          ;注意:这部分的需水量将替换[JUNCTIONS]部分录入的需水量
 609 **        entered in the [JUNCTIONS] section
 610 **--------------------------------------------------------------
 611 */
 612 {                                       //j:表示节点在Node中的索引值
 613    int  j,n,p = 0;                      //p:当前的用水模式在Pattern中的索引  /*n表示 当前行数据项个数*/
 614    double y;         
 615    Pdemand demand;
 616    STmplist *pat;
 617 
 618 /* Extract data from tokens 从当前行中提取需水量数据*/
 619    n = Ntokens;
 620    if (n < 2) return(201); 
 621    if (!getfloat(Tok[1],&y)) return(202);
 622 
 623 /* If MULTIPLY command, save multiplier */
 624    if (match(Tok[0],w_MULTIPLY))
 625    {
 626       if (y <= 0.0) return(202);
 627       else Dmult = y;
 628       return(0);
 629    }
 630 
 631 /* Otherwise find node (and pattern) being referenced 找到节点所引用的用水模式的索引值*/
 632    if ((j = findnode(Tok[0])) == 0) return(208);
 633    if (j > Njuncs) return(208);
 634    if (n >= 3)
 635    {
 636       pat = findID(Tok[2],Patlist);
 637       if (pat == NULL)  return(205);
 638       p = pat->i;
 639    }
 640 
 641 /* Replace any demand entered in [JUNCTIONS] section */
 642 /* (Such demand was temporarily stored in D[]) */
 643 
 644 /*** Updated 6/24/02 ***/
 645    demand = Node[j].D;
 646    if (demand && D[j] != MISSING)
 647    {
 648       demand->Base = y;
 649       demand->Pat  = p;
 650       D[j] = MISSING;//通过这个MISSING来做替换标记
 651    }
 652 /*** End of update ***/
 653 
 654 /* Otherwise add a new demand to this junction */
 655    else
 656    {
 657       demand = (struct Sdemand *) malloc(sizeof(struct Sdemand));
 658       if (demand == NULL) return(101);
 659       demand->Base = y;
 660       demand->Pat = p;
 661       demand->next = Node[j].D;
 662       Node[j].D = demand;
 663    }
 664    return(0);
 665 }                        /* end of demanddata */
 666 
 667 
 668 int  controldata()
 669 /*
 670 **--------------------------------------------------------------
 671 **  Input:   none                                                ;输入:无
 672 **  Output:  returns error code                                  ;输出:错误代码
 673 **  Purpose: processes simple controls                           ;作用:处理简单控制规则
 674 **  Formats:                                                     ;格式:
 675 **  [CONTROLS]                                                 
 676 **  LINK  linkID  setting IF NODE      nodeID {BELOW/ABOVE}  value 
 677 **  LINK  linkID  setting AT TIME      time  (units)               
 678 **  LINK  linkID  setting AT CLOCKTIME clocktime  (units)           
 679 **   (0)   (1)      (2)   (3) (4)       (5)     (6)          (7)
 680 其中: 
 681 linkID——管段ID标签; 
 682 setting——OPEN或者CLOSED,水泵速度设置或者控制阀门设置 
 683 nodeID——节点ID标签; 
 684 value ——连接节点压力或者水池水位; 
 685 time——从模拟开始起算的时间,以小数或者小时:分钟计; 
 686 clocktime——24小时的钟表时间(小时:分钟)。 
 687 备注: 
 688 a.  简单控制将根据水池水位、节点压强、进入模拟时间或者一日中的时间,改变管
 689 段状态或者设置。 
 690 b.  对于用在指定管段状态和设置的常规情况,尤其阀门控制,参见[STATUS] 节的
 691 备注。
 692 示例: 
 693 [CONTROLS] 
 694 ;如果Tank 23的水位超过20 ft ,关闭Link 
 695 LINK 12 CLOSED IF NODE 23 ABOVE 20 
 696  
 697 ;如果Node 130 的压力低于30 psi,开启Link 12 
 698 LINK 12 OPEN IF NODE 130 BELOW 30 
 699  
 700 ;在进入模拟16小时后水泵PUMP02的转速比设置为1.5 
 701 LINK PUMP02 1.5 AT TIME 16 
 702  
 703 ;整个模拟过程中Lin 12在上午10时关闭,下午8时开启 
 704 LINK 12 CLOSED AT CLOCKTIME 10 AM 
 705 LINK 12 OPEN AT CLOCKTIME 8 PM
 706 **--------------------------------------------------------------
 707 */
 708 {
 709    int   i = 0,                /* Node index             Node中的索引值*/
 710          k,                    /* Link index             Link中的索引值*/
 711          n;                    /* # data items           当前行数据项个数*/
 712    char  status = ACTIVE,      /* Link status            管段状态*/
 713          type;                 /* Link or control type   管段类型*/
 714    double setting = MISSING,    /* Link setting           */
 715          time = 0.0,           /* Simulation time        从模拟开始起算的时间*/
 716          level = 0.0;          /* Pressure or tank level 水池水位或节点压强*/
 717 
 718 /* Check for sufficient number of input tokens 检查字段个数是否合法,不小于6个*/
 719    n = Ntokens;
 720    if (n < 6) return(201);
 721 
 722 /* Check that controlled link exists 判断控制的管段是否存在*/
 723    k = findlink(Tok[1]);
 724    if (k == 0) return(204);
 725    type = Link[k].Type;
 726    if (type == CV) return(207);         /* Cannot control check valve. 不能够控制检查阀*/
 727 
 728 /*** Updated 9/7/00 ***/
 729 /* Parse control setting into a status level or numerical setting. 获取并设置控制管段的状态*/
 730    if (match(Tok[2],w_OPEN))
 731    {
 732       status = OPEN;
 733       if (type == PUMP) setting = 1.0;
 734       if (type == GPV)  setting = Link[k].Kc;
 735    }
 736    else if (match(Tok[2],w_CLOSED))
 737    {
 738       status = CLOSED;
 739       if (type == PUMP) setting = 0.0;
 740       if (type == GPV)  setting = Link[k].Kc;
 741    }
 742    else if (type == GPV) return(206);
 743    else if (!getfloat(Tok[2],&setting)) return(202);
 744 
 745 /*** Updated 3/1/01 ***/
 746 /* Set status for pump in case speed setting was supplied 根据setting来设置水泵或者管段的status*/
 747 /* or for pipe if numerical setting was supplied */
 748 
 749    if (type == PUMP || type == PIPE)
 750    {
 751       if (setting != MISSING)
 752       {
 753          if (setting < 0.0)       return(202);
 754          else if (setting == 0.0) status = CLOSED;
 755          else                     status = OPEN;
 756       }
 757    }
 758 
 759 /* Determine type of control 获取该条控制规则的类型*/
 760    if      (match(Tok[4],w_TIME))      type = TIMER;
 761    else if (match(Tok[4],w_CLOCKTIME)) type = TIMEOFDAY;
 762    else
 763    {//对节点或者水池的控制
 764       if (n < 8) return(201);
 765       if ((i = findnode(Tok[5])) == 0) return(203);
 766       if      (match(Tok[6],w_BELOW)) type = LOWLEVEL;
 767       else if (match(Tok[6],w_ABOVE)) type = HILEVEL;
 768       else return(201);
 769    }
 770 
 771 /* Parse control level or time 获取控制的时间或者水位*/
 772    switch (type)
 773    {
 774       case TIMER:
 775       case TIMEOFDAY:
 776          if (n == 6) time = hour(Tok[5],"");
 777          if (n == 7) time = hour(Tok[5],Tok[6]);
 778          if (time < 0.0) return(201);
 779          break;
 780       case LOWLEVEL:
 781       case HILEVEL:   
 782          if (!getfloat(Tok[7],&level)) return(202);
 783          break;
 784    }
 785 
 786 /* Fill in fields of control data structure 将上述获取到的值填充到控制规则线性链表中*/
 787    Ncontrols++;
 788    if (Ncontrols > MaxControls) return(200);
 789    Control[Ncontrols].Link     = k;
 790    Control[Ncontrols].Node     = i;
 791    Control[Ncontrols].Type     = type;
 792    Control[Ncontrols].Status   = status;
 793    Control[Ncontrols].Setting  = setting;
 794    Control[Ncontrols].Time     = (long)(3600.0*time);
 795    if (type == TIMEOFDAY)
 796       Control[Ncontrols].Time %= SECperDAY;
 797    Control[Ncontrols].Grade    = level;
 798    return(0);
 799 }                        /* end of controldata */
 800 
 801 
 802 int  sourcedata()
 803 /*
 804 **--------------------------------------------------------------
 805 **  Input:   none                                                ;输入:无
 806 **  Output:  returns error code                                  ;输出:错误代码
 807 **  Purpose: processes water quality source data                 ;目的:定义水质源头的位置。     
 808 **  Formats:                                                     ;格式:
 809 **     [SOURCE]                                                
 810 **        node  sourcetype  quality  (pattern start stop)
 811 **                                            
 812 格式: 
 813 每一水质源头为一输入行,包括: 
 814 node  节点ID标签 
 815 sourcetype  源头类型(CONCEN, MASS, FLOWPACED 或SETPOINT )
 816 quality  基准源头强度 
 817 pattern  时间模式ID(可选) 
 818   
 819 **  NOTE: units of mass-based source are mass/min  
 820 备注: 
 821 a.  MASS类型源头的强度以质量流量每分钟计。所有其它类型以浓度单位来计量源头强度。 
 822 b.  源头强度可以指定时间模式,使其随时间变化。 
 823 c.  CONCEN源头为: 
 824    表示节点的任何外部源头进流浓度 
 825    仅仅在节点具有净负需水量时使用(水从节点进入管网) 
 826    如果节点为连接节点,报告浓度时混合了源流量和从管网其它部分的进流 
 827    如果节点为水库,报告的浓度为源头浓度 
 828    如果节点为水池,报告的浓度为水池的内部浓度 
 829    用于节点,表示了源水供应或者处理厂(例如,水库或者节点具有负的需水量) 
 830    不可用于同时具有进流/出流的蓄水池。 
 831 d. MASS, FLOWPACED 或SETPOINT 源头: 
 832    表示了增强源头,这里物质被直接注射到管网,不考虑节点的需水量怎样 
 833    以下方式影响了离开节点到管网的其它部分的水: 
 834     - MASS 注入,增加了固定的质量流量到节点的进流 
 835     - FLOWPACED 注入,增加了固定浓度到节点的进流浓度 
 836     - SETPOINT 注入,固定了任何离开节点的浓度(只要进流带来的浓度低于设置值) 
 837    连接节点或者水库注入源头报告的浓度,是在注入之后的浓度;报告具有注入源头的水
 838 池的浓度,为水池的内部浓度 
 839    适合于模拟示踪剂或者消毒剂直接注入到管网,或者为了模拟污染物的入侵。 
 840 e.对于模拟水龄或者源头跟踪,[SOURCES]节是不需要的。
 841 **--------------------------------------------------------------
 842 */
 843 {
 844    int   i,                  /* Token with quality value 水质值这列所在的当前行的数据项列表中的索引值*/
 845          j,                  /* Node index    Node中的索引值*/
 846          n,                  /* # data items  行的数据项数*/
 847          p = 0;              /* Time pattern  模式*/
 848    char  type = CONCEN;      /* Source type   源头类型*/
 849    double c0 = 0;             /* Init. quality 初始水质*/
 850    STmplist *pat;
 851    Psource  source;
 852 
 853    n = Ntokens;
 854    if (n < 2) return(201);
 855    if ((j = findnode(Tok[0])) == 0) return(203);
 856    /* NOTE: Under old format, SourceType not supplied so let  如果是老版本那么i=1,因为源头类型不存在*/
 857    /*       i = index of token that contains quality value.   水质值这列所在的当前行的数据项列表中的索引值*/
 858    i = 2;
 859    if      (match(Tok[1],w_CONCEN))    type = CONCEN;
 860    else if (match(Tok[1],w_MASS))      type = MASS;
 861    else if (match(Tok[1],w_SETPOINT))  type = SETPOINT;
 862    else if (match(Tok[1],w_FLOWPACED)) type = FLOWPACED;
 863    else i = 1;
 864    if (!getfloat(Tok[i],&c0)) return(202);      /* Illegal WQ value 检查水质数据类型*/
 865 
 866    if (n > i+1 && strlen(Tok[i+1]) > 0 && strcmp(Tok[i+1], "*") != 0 )         //(2.00.11 - LR)
 867    {
 868        pat = findID(Tok[i+1],Patlist);
 869        if (pat == NULL) return(205);            /* Illegal pattern. 找不到指定模式*/
 870        p = pat->i;                              //返回该模式在Pattern中的索引值
 871    }
 872 
 873    source = (struct Ssource *) malloc(sizeof(struct Ssource));
 874    if (source == NULL) return(101);
 875    source->C0 = c0;
 876    source->Pat = p;
 877    source->Type = type;
 878    Node[j].S = source;
 879    return(0);
 880 }                        /* end of sourcedata */
 881 
 882 
 883 int  emitterdata()
 884 /*
 885 **--------------------------------------------------------------
 886 **  Input:   none                                                ;输入:无
 887 **  Output:  returns error code                                  ;输出:错误代码
 888 **  Purpose: processes junction emitter data                     ;目的:将模拟节点定义为扩散器(喷嘴或者孔口)。 
 889 **  Formats:                                                     ;格式:
 890 **     [EMITTER]                                               
 891 **        node   K       
 892 备注: 
 893 a.  扩散器用于模拟通过喷水或者管道渗漏的流量。 
 894 b.  扩散器的出流等于流量系数与提升的连接节点压力乘积。 
 895 c.  功率可以利用[OPTIONS]节的EMITTER EXPONENT选项指定。缺省功率为0.5 ,通常用于喷嘴。 
 896 d.  程序结果中报告的实际需水量,包括节点的常规需水量加上通过扩散器的流量。 
 897 e.  [EMITTERS] 节是可选的。 
 898 **--------------------------------------------------------------
 899 */
 900 {
 901    int   j,                  /* Node index    Node中的索引值*/
 902          n,                  /* # data items  行的数据项数*/
 903    double k;                  /* Flow coeff,   流量系数,在1米(1 psi )压降下的流量单位。*/
 904 
 905    n = Ntokens;
 906    if (n < 2) return(201); 
 907    if ((j = findnode(Tok[0])) == 0) return(203);
 908    if (j > Njuncs) return(209);                 /* Not a junction.*/
 909    if (!getfloat(Tok[1],&k)) return(202);
 910    if (k < 0.0) return(202);
 911    Node[j].Ke = k;
 912    return(0);
 913 }
 914 
 915 
 916 int  qualdata()
 917 /*
 918 **--------------------------------------------------------------
 919 **  Input:   none                                                ;输入:无
 920 **  Output:  returns error code                                  ;输出:错误代码                               
 921 **  Purpose: processes initial water quality data                ;目的:定义节点的初始水质。 
 922 **  Formats:
 923 **     [QUALITY]                                               
 924 **        node   initqual
 925 **        node1  node2    initqual
 926 每一节点为一输入行,包括: 
 927 node  节点ID标签 
 928 initqual  初始水质
 929 
 930 备注: 
 931 a.  对于没有列入的节点,水质假设为零。 
 932 b.  水质表示了化学成分的浓度、水龄的小时或源头跟踪的百分比。 
 933 c.  [QUALITY]节是可选的。
 934 **--------------------------------------------------------------
 935 */
 936 {
 937    int   j,n;
 938    long  i,i0,i1;
 939    double c0;
 940 
 941    if (Nnodes == 0) return(208);        /* No nodes defined yet */
 942    n = Ntokens;
 943    if (n < 2) return(0);
 944    if (n == 2)                          /* Single node entered  单个节点*/
 945    {
 946       if ( (j = findnode(Tok[0])) == 0) return(0);
 947       if (!getfloat(Tok[1],&c0)) return(209);
 948       Node[j].C0 = c0;
 949    }
 950    else                                 /* Node range entered    批量节点*/
 951    {
 952       if (!getfloat(Tok[2],&c0)) return(209);
 953    
 954       /* If numerical range supplied, then use numerical comparison 这块代码有些奇怪,不过一般没有这种输入格式的*/
 955       if ((i0 = atol(Tok[0])) > 0 && (i1 = atol(Tok[1])) > 0)
 956       {
 957          for (j=1; j<=Nnodes; j++)
 958          {
 959             i = atol(Node[j].ID);
 960             if (i >= i0 && i <= i1) Node[j].C0 = c0;
 961          }
 962       }
 963       else
 964       {
 965          for (j=1; j<=Nnodes; j++)
 966             if ((strcmp(Tok[0],Node[j].ID) <= 0) &&
 967                 (strcmp(Tok[1],Node[j].ID) >= 0)
 968                ) Node[j].C0 = c0;
 969       }
 970    }
 971    return(0);
 972 }                        /* end of qualdata */
 973 
 974 
 975 int  reactdata()
 976 /*
 977 **--------------------------------------------------------------
 978 **  Input:   none                                                ;输入:无
 979 **  Output:  returns error code                                  ;输出:错误代码                                
 980 **  Purpose: processes reaction coeff. data                      ;目的:定义对应于管网中与化学成分反应的参数。 
 981 **  Formats:                                                     ;格式:
 982 **     [REACTIONS]
 983 **        ORDER     {BULK/WALL/TANK} value                       
 984 **        GLOBAL    {BULK/WALL}      coeff                                                                  
 985 **        BULK      link1  (link2)   coeff                          
 986 **        WALL      link1  (link2)   coeff                          
 987 **        TANK      node1  (node2)   coeff                          
 988 **        LIMITING  POTENTIAL        value                          
 989 **        ROUGHNESS CORRELATION      value
 990 格式: 
 991 ORDER BULK/WALL/TANK value 
 992 GLOBAL BULK/WALL value 
 993 BULK/WALL/TANK  pipeID value 
 994 LIMITING POTENTIAL value 
 995 ROUGHNESS CORRELATION value 
 996 定义: 
 997 ORDER 用于设置分别发生在主流水体、管壁或者水池中的反应级数。管壁反应的数值必须
 998 为0或者1。如果没有提供,缺省反应级数为1.0 。 
 999 GLOBAL用于设置所有主流水体反应系数(管道和水池)或者所有管壁系数的全局数值。缺
1000 省值为零。 
1001 BULK, WALL 和TANK用于对指定管道和水池重新设置全局反应系数。 
1002 LIMITING POTENTIAL 指定了反应速率正比于当前浓度和一些限制值之间的差异。 
1003 ROUGHNESS CORRELATION将使所有缺省管壁反应系数,以以下方式,相关于管道粗糙系
1004 数: 
1005 水头损失公式    粗糙相关性 
1006 Hazen-Williams F/C 
1007 Darcy-Weisbach F/log(e/D) 
1008 Chezy-Manning   F*n 
1009  105
1010 式中F——粗糙系数相关性; 
1011 C——Hazen-Williams C因子; 
1012 e——Darcy-Weisbach粗糙系数; 
1013 D——管道直径; 
1014 n——Chezy-Manning 粗糙系数。 
1015 这种方式计算的缺省值能够通过利用WALL格式,对于任何使用特定数值管道重载。 
1016 备注: 
1017 a.  注意增长反应系数采用正值,衰减反应系数为负值。 
1018 b.  所有反应系数的时间单位为1/日。 
1019 c.  本节所有输入为可选的,反斜杠(/)之后的事项说明了允许选项。
1020 **--------------------------------------------------------------
1021 */
1022 {
1023    int   item,j,n;
1024    long  i,i1,i2;
1025    double y;
1026 
1027 /* Skip line if insufficient data */
1028    n = Ntokens;
1029    if (n < 3) return(0);
1030 
1031 /* Process input depending on keyword */
1032    if (match(Tok[0],w_ORDER))                    /* Reaction order */
1033    {
1034       if (!getfloat(Tok[n-1],&y)) return(213);
1035       if      (match(Tok[1],w_BULK)) BulkOrder = y;
1036       else if (match(Tok[1],w_TANK)) TankOrder = y;
1037       else if (match(Tok[1],w_WALL))
1038       {
1039          if (y == 0.0) WallOrder = 0.0;
1040          else if (y == 1.0) WallOrder = 1.0;
1041          else return(213);
1042       }
1043       else return(213);
1044       return(0);
1045    }
1046    if (match(Tok[0],w_ROUGHNESS))                /* Roughness factor */
1047    {
1048       if (!getfloat(Tok[n-1],&y)) return(213);
1049       Rfactor = y;
1050       return(0);
1051    }
1052    if (match(Tok[0],w_LIMITING))                 /* Limiting potential */
1053    {
1054       if (!getfloat(Tok[n-1],&y)) return(213);
1055       /*if (y < 0.0) return(213);*/
1056       Climit = y;
1057       return(0);
1058    }
1059    if (match(Tok[0],w_GLOBAL))                   /* Global rates */
1060    {
1061       if (!getfloat(Tok[n-1],&y)) return(213);
1062       if      (match(Tok[1],w_BULK)) Kbulk = y;
1063       else if (match(Tok[1],w_WALL)) Kwall = y;
1064       else return(201);
1065       return(0);
1066    }
1067    if      (match(Tok[0],w_BULK)) item = 1;      /* Individual rates */
1068    else if (match(Tok[0],w_WALL)) item = 2;
1069    else if (match(Tok[0],w_TANK)) item = 3;
1070    else return(201);
1071    strcpy(Tok[0],Tok[1]);                        /* Save id in Tok[0] */
1072    if (item == 3)                                /* Tank rates */
1073    {
1074       if (!getfloat(Tok[n-1],&y)) return(209);   /* Rate coeff. */
1075       if (n == 3)
1076       {
1077           if ( (j = findnode(Tok[1])) <= Njuncs) return(0);
1078           Tank[j-Njuncs].Kb = y;
1079       }
1080       else
1081       {
1082        /* If numerical range supplied, then use numerical comparison */
1083          if ((i1 = atol(Tok[1])) > 0 && (i2 = atol(Tok[2])) > 0)
1084          {
1085             for (j=Njuncs+1; j<=Nnodes; j++)
1086             {
1087                i = atol(Node[j].ID);
1088                if (i >= i1 && i <= i2) Tank[j-Njuncs].Kb = y;
1089             }
1090          }
1091          else for (j=Njuncs+1; j<=Nnodes; j++)
1092             if ((strcmp(Tok[1],Node[j].ID) <= 0) &&
1093                 (strcmp(Tok[2],Node[j].ID) >= 0)
1094                ) Tank[j-Njuncs].Kb = y;
1095       }
1096    }
1097    else                                          /* Link rates */
1098    {
1099       if (!getfloat(Tok[n-1],&y)) return(211);   /* Rate coeff. */
1100       if (Nlinks == 0) return(0);
1101       if (n == 3)                                /* Single link */
1102       {
1103          if ( (j = findlink(Tok[1])) == 0) return(0);
1104          if (item == 1) Link[j].Kb = y;
1105          else           Link[j].Kw = y;
1106       }
1107       else                                       /* Range of links */
1108       {
1109        /* If numerical range supplied, then use numerical comparison */
1110          if ((i1 = atol(Tok[1])) > 0 && (i2 = atol(Tok[2])) > 0)
1111          {
1112             for (j=1; j<=Nlinks; j++)
1113             {
1114                i = atol(Link[j].ID);
1115                if (i >= i1 && i <= i2)
1116                {
1117                   if (item == 1) Link[j].Kb = y;
1118                   else           Link[j].Kw = y;
1119                }
1120             }
1121          }
1122          else for (j=1; j<=Nlinks; j++)
1123             if ((strcmp(Tok[1],Link[j].ID) <= 0) &&
1124                 (strcmp(Tok[2],Link[j].ID) >= 0) )
1125             {
1126                if (item == 1) Link[j].Kb = y;
1127                else           Link[j].Kw = y;
1128             }
1129       }
1130    }
1131    return(0);
1132 }                        /* end of reactdata */
1133 
1134 
1135 int  mixingdata()
1136 /*
1137 **-------------------------------------------------------------
1138 **  Input:   none                                                ;输入:无
1139 **  Output:  returns error code                                  ;输出:错误代码                                
1140 **  Purpose: processes tank mixing data                          ;目的:确定控制蓄水池混合的模型。
1141 **  Format:                                                     
1142 **    [MIXING]                                                   
1143 **     TankID  MixModel  FractVolume
1144 格式: 
1145 一个水池占一输入行,包括: 
1146 z  水池ID标签 
1147 z  混合模型(MIXED, 2COMP, FIFO 或LIFO) 
1148 z  室的容积(小数) 
1149 备注: 
1150 a.  混合模型包括: 
1151 z  完全混合(MIXED ) 
1152 z  双室混合(2COMP ) 
1153 z  先进先出(FIFO) 
1154 z  后进先出(LIFO) 
1155 b.  室容积参数仅仅用于双室模型,代表了总水池容积贡献于进水/出水室的部分。 
1156 c. [MIXING]节是可选的。不在本节描述的水池假设为完全混合。 
1157 **-------------------------------------------------------------
1158 */
1159 {
1160    int   i,j,n;
1161    double v;
1162 
1163    if (Nnodes == 0) return(208);        /* No nodes defined yet */
1164    n = Ntokens;
1165    if (n < 2) return(0);
1166    if ( (j = findnode(Tok[0])) <= Njuncs) return(0);
1167    if ( (i = findmatch(Tok[1],MixTxt)) < 0) return(201);
1168    v = 1.0;
1169    if ( (i == MIX2) &&
1170         (n == 3) &&
1171         (!getfloat(Tok[2],&v))          /* Get frac. vol. for 2COMP model */
1172       ) return(209);
1173    if (v == 0.0) v = 1.0;               /* v can't be zero */
1174    n = j - Njuncs;
1175    if (Tank[n].A == 0.0) return(0);     /* Tank is a reservoir */
1176    Tank[n].MixModel = (char)i;
1177    Tank[n].V1max = v;
1178    return(0);
1179 }
1180 
1181 
1182 int  statusdata()
1183 /*
1184 **--------------------------------------------------------------
1185 **  Input:   none                                                ;输入:无
1186 **  Output:  returns error code                                  ;输出:错误代码                                
1187 **  Purpose: processes link initial status data                  ;目的:定义模拟开始时被选管段的初始状态。       
1188 **  Formats:                                                     
1189 **    [STATUS]
1190 **       link   value
1191 **       link1  (link2)  value
1192 格式: 
1193 每一控制管段占一输入行,包括: 
1194 z  管段ID标签 
1195 z  状态或者设置 
1196 备注: 
1197 a.  该部分没有列出的管段,缺省状态为OPEN(对于管道和水泵)或者ACTIVE(对于阀门)。 
1198 b.  状态值可以为OPEN或者CLOSED。对于控制阀(例如PRV, FCV 等),意味着阀门是全开或
1199 者全闭,在其控制点不是活动的。 
1200 c.  设置数值可以是水泵的转速设置,或者阀门的开启度设置。 
1201 d.  管道的初始状态也可以在[PIPES]节设置。 
1202 e.  止回阀不能够预先设置它们的状态。 
1203 **--------------------------------------------------------------
1204 */
1205 {
1206    int   j,n;                        //j:Link中的索引值;n:行数据项个数
1207    long  i,i0,i1;
1208    double y = 0.0;
1209    char  status = ACTIVE;
1210 
1211    if (Nlinks == 0) return(210);
1212    n = Ntokens - 1;
1213    if (n < 1) return(201);
1214 
1215 /* Check for legal status setting 检查状态数据的合法性*/
1216    if      (match(Tok[n],w_OPEN))    status = OPEN;
1217    else if (match(Tok[n],w_CLOSED))  status = CLOSED;
1218    else if (!getfloat(Tok[n],&y))    return(211);
1219    if (y < 0.0)                      return(211);
1220 
1221 /* Single link ID supplied */
1222    if (n == 1)
1223    {
1224       if ( (j = findlink(Tok[0])) == 0) return(0);
1225       /* Cannot change status of a Check Valve */
1226       if (Link[j].Type == CV) return(211);
1227 
1228 /*** Updated 9/7/00 ***/      
1229       /* Cannot change setting for a GPV */
1230       if (Link[j].Type == GPV
1231       &&  status == ACTIVE)   return(211);
1232 
1233       changestatus(j,status,y);
1234    }
1235 
1236 /* Range of ID's supplied 对间与某2个ID之间的管段的状态的批量设置*/
1237    else
1238    {
1239       /* Numerical range supplied */
1240       if ((i0 = atol(Tok[0])) > 0 && (i1 = atol(Tok[1])) > 0)
1241       {
1242          for (j=1; j<=Nlinks; j++)
1243          {
1244             i = atol(Link[j].ID);
1245             if (i >= i0 && i <= i1) changestatus(j,status,y);
1246          }
1247       }
1248       else
1249          for (j=1; j<=Nlinks; j++)
1250             if ( (strcmp(Tok[0],Link[j].ID) <= 0) &&
1251                  (strcmp(Tok[1],Link[j].ID) >= 0)
1252                ) changestatus(j,status,y);
1253    }
1254    return(0);
1255 }              /* end of statusdata */
1256 
1257 
1258 int  energydata()
1259 /*
1260 **--------------------------------------------------------------
1261 **  Input:   none                                                ;输入:无
1262 **  Output:  returns error code                                  ;输出:错误代码                              
1263 **  Purpose: processes pump energy data                          ;目的:定义计算水泵提升能量和成本的参数。
1264 **  Formats:                                                     ;格式:
1265 **    [ENERGY]                                                   
1266 **       GLOBAL         {PRICE/PATTERN/EFFIC}  value                 
1267 **       PUMP   id      {PRICE/PATTERN/EFFIC}  value                 
1268 **       DEMAND CHARGE  value  
1269 格式: 
1270 GLOBAL PRICE/PATTERN/EFFIC value 
1271 PUMP  PumpID PRICE/PATTERN/EFFIC  value 
1272 DEMAND CHARGE value 
1273 备注: 
1274 a.  以关键词GLOBAL为开头的行,用于设置所有水泵的能量价格、价格模式和水泵效
1275 率的全局缺省。 
1276 b.  以关键词PUMP为开头的行,用于对特定水泵重新设置全局缺省。 
1277 c.  参数定义如下: 
1278 z  PRICE ——每千瓦时的平均成本, 
1279 z  PATTERN——描述能量价格怎样变化的时间模式ID标签, 
1280 z  EFFIC ——对于全局设置的单一百分比效率,或者指定水泵的效率曲线ID标
1281 签, 
1282 z  DEMAND CHARGE ——模拟时段每最大kW用量增加的成本。 
1283 d.  缺省全局水泵效率为75% ,缺省全局能量价格为0。
1284 e.  本节的所有输入是可选的。反斜杠(/)后的项说明允许选项。 
1285 示例: 
1286 [ENERGY] 
1287 GLOBAL PRICE 0.05 ;设置全局能量价格 
1288 GLOBAL PATTERN PAT1 ;和一日内时间模式 
1289 PUMP 23 PRICE 0.10 ; 重载Pump 23的价格 
1290 PUMP 23 EFFIC E23 ;将效率曲线赋给Pump 23 
1291 **--------------------------------------------------------------
1292 */
1293 {
1294    int j,k,n;
1295    double y;
1296    STmplist *t;
1297 
1298 /* Check for sufficient data */
1299    n = Ntokens;
1300    if (n < 3) return(201);
1301 
1302 /* Check first keyword */
1303    if (match(Tok[0],w_DMNDCHARGE))               /* Demand charge */
1304    {
1305       if (!getfloat(Tok[2], &y)) return(213);
1306       Dcost = y;
1307       return(0);
1308    }
1309    if (match(Tok[0],w_GLOBAL))                   /* Global parameter */
1310    {
1311       j = 0;
1312    }
1313    else if (match(Tok[0],w_PUMP))                /* Pump-specific parameter */
1314    {
1315       if (n < 4) return(201);
1316       k = findlink(Tok[1]);                      /* Check that pump exists */
1317       if (k == 0) return(216);
1318       if (Link[k].Type != PUMP) return(216);
1319       j = PUMPINDEX(k);
1320    }
1321    else return(201);
1322 
1323 /* Find type of energy parameter */      
1324    if (match(Tok[n-2],w_PRICE))                  /* Energy price */
1325    {
1326       if (!getfloat(Tok[n-1],&y))
1327       {
1328          if (j == 0) return(213);
1329          else return(217);
1330       }
1331       if (j == 0) Ecost = y;
1332       else Pump[j].Ecost = y;
1333       return(0);
1334    }    
1335    else if (match(Tok[n-2],w_PATTERN))           /* Price pattern */
1336    {
1337       t = findID(Tok[n-1],Patlist);              /* Check if pattern exists */
1338       if (t == NULL)
1339       {
1340          if (j == 0) return(213);
1341          else return(217);
1342       }
1343       if (j == 0) Epat = t->i;
1344       else Pump[j].Epat = t->i;
1345       return(0);
1346    }
1347    else if (match(Tok[n-2],w_EFFIC))             /* Pump efficiency */
1348    {
1349       if (j == 0)
1350       {
1351          if (!getfloat(Tok[n-1], &y)) return(213);
1352          if (y <= 0.0) return(213);
1353          Epump = y;
1354       }
1355       else
1356       {
1357          t = findID(Tok[n-1],Curvelist);         /* Check if curve exists */ 
1358          if (t == NULL) return(217);
1359          Pump[j].Ecurve = t->i;
1360       }
1361       return(0);
1362    }
1363    return(201);
1364 }
1365 
1366 
1367 int  reportdata()
1368 /*
1369 **--------------------------------------------------------------
1370 **  Input:   none                                                ;输入:无
1371 **  Output:  returns error code                                  ;输出:错误代码                                 
1372 **  Purpose: processes report options data                       ;目的:描述模拟生成的输出报表内容。 
1373 **  Formats:                                                     
1374 **    PAGE     linesperpage                                      
1375 **    STATUS   {NONE/YES/FULL}
1376 **    SUMMARY  {YES/NO}
1377 **    MESSAGES {YES/NO}
1378 **    ENERGY   {NO/YES}                                   
1379 **    NODES    {NONE/ALL}                                        
1380 **    NODES    node1  node2 ...                                  
1381 **    LINKS    {NONE/ALL}                                        
1382 **    LINKS    link1  link2 ...                                  
1383 **    FILE     filename
1384 **    variable {YES/NO}                                          
1385 **    variable {BELOW/ABOVE/PRECISION}  value 
1386 格式: 
1387 PAGESIZE value 
1388 FILE  filename 
1389 STATUS YES/NO/FULL 
1390 SUMMARY YES/NO 
1391 ENERGY YES/NO 
1392 NODES NONE/ALL/ node1 node2 ... 
1393 LINKS NONE/ALL/ link1 link2 ... 
1394 parameter  YES/NO 
1395 parameter  BELOW/ABOVE/PRECISION value 
1396 定义: 
1397 PAGESIZES设置了输出报表中每一页中的行数。缺省为0,意味着事实上每一页没有行数限
1398 制。 
1399 对于将要写入的输出报告(在EPANETH的Windows版本中忽略),FILE提供了文件的名字。 
1400 STATUS确定了应怎样生成水力状态报告。如果YES 被选择,在模拟的每一时间步长中改变
1401 状态的所有管网组件将输出到报告。如果FULL被选择,那么也将包括每一水力分析的每一试算
1402 中的信息输出到报告。详细水平仅仅对于调试管网是有用的,这时水力不平衡。缺省为NO。 
1403 SUMMARY确定了管网组件数量的总结表,以及产生的关键分析选项。缺省为YES 。 
1404 ENERGY确定是否提供表格报告平均能量使用和每一台水泵的成本。缺省为NO。 
1405 NODES 确定了哪些节点将被报告。可以列出单个节点ID标签,或者利用关键词NONE或者
1406 ALL 。额外NODES 行可用于继续该表。缺省为NONE。 
1407 LINKS 确定了哪些管段将被报告。可以列出单个管段ID标签,或者使用关键词NONE或者
1408  106
1409 ALL 。额外LINKS 行可用于继续该表。缺省为NONE。 
1410 “参数”报告选项,用于确定报告哪些量,多少小数位被显示,哪种类型的过滤用于限制输
1411 出报告。可以被报告的节点参数包括: 
1412 z  标高; 
1413 z  需水量; 
1414 z  水头; 
1415 z  压强; 
1416 z  水质。 
1417 管段参数包括: 
1418 z  长度; 
1419 z  直径; 
1420 z  流量; 
1421 z  流速; 
1422 z  水头损失; 
1423 z  位置(与状态相同-开启、活动、关闭); 
1424 z  设置(对应于管道的粗糙系数、水泵的转速、阀门的压力/流量设置); 
1425 z  反应(反应速率); 
1426 z  F-因子(摩擦因子)。 
1427 报告的缺省量对于节点的需水量、水头、压强和水质,以及管段的流量、流速和水头损失。
1428 缺省精度为两个小数位。 
1429 备注: 
1430 a.  如果在本节没有明确指出,所有选项假设为它们的缺省数值。 
1431 b.  反斜杠(/)后的项为可选项。 
1432 c.  缺省值对应于任何节点或者管段没有报告,因此如果希望报告这些事项的结果,
1433 必须提供NODES 或者LINKS 选项。 
1434 d.  对于EPANETH的Windows版本,仅仅意识到的[REPORT] 选项为STATUS。所 有 其
1435 它被忽略。 
1436 示例: 
1437 以下示例报告了节点N1, N2, N3 和N17 ,以及所有流速大于3.0 的管段。标准节点参数(需水
1438 量、水头、压强和水质)被报告,同时仅仅管段的流量、流速和F因子(摩擦因子)被报告。 
1439 [REPORT] 
1440 NODES N1 N2 N3 N17 
1441 LINKS ALL 
1442 FLOW YES 
1443 VELOCITY PRECISION 4 
1444 F-FACTOR PRECISION 4 
1445 VELOCITY ABOVE 3.0
1446 **--------------------------------------------------------------
1447 */
1448 {
1449    int    i,j,n;
1450    double  y;
1451 
1452    n = Ntokens - 1;
1453    if (n < 1) return(201);
1454 
1455 /* Value for page size */
1456    if (match(Tok[0],w_PAGE))
1457    {
1458       if (!getfloat(Tok[n],&y))   return(213);
1459       if (y < 0.0 || y > 255.0) return(213);
1460       PageSize = (int) y;
1461       return(0);
1462    }
1463 
1464 /* Request that status reports be written */
1465    if (match(Tok[0],w_STATUS))
1466    {
1467       if (match(Tok[n],w_NO))   Statflag = FALSE;
1468       if (match(Tok[n],w_YES))  Statflag = TRUE;
1469       if (match(Tok[n],w_FULL)) Statflag = FULL;
1470       return(0);
1471    }
1472 
1473 /* Request summary report */
1474    if (match(Tok[0],w_SUMMARY))
1475    {
1476       if (match(Tok[n],w_NO))  Summaryflag = FALSE;
1477       if (match(Tok[n],w_YES)) Summaryflag = TRUE;
1478       return(0);
1479    }
1480 
1481 /* Request error/warning message reporting */
1482    if (match(Tok[0],w_MESSAGES))
1483    {
1484       if (match(Tok[n],w_NO))  Messageflag = FALSE;
1485       if (match(Tok[n],w_YES)) Messageflag = TRUE;
1486       return(0);
1487    }
1488    
1489 
1490 /* Request an energy usage report */
1491    if (match(Tok[0],w_ENERGY))
1492    {
1493       if (match(Tok[n],w_NO))  Energyflag = FALSE;
1494       if (match(Tok[n],w_YES)) Energyflag = TRUE;
1495       return(0);
1496    }
1497 
1498 /* Particular reporting nodes specified */
1499    if (match(Tok[0],w_NODE))
1500    {
1501       if      (match(Tok[n],w_NONE)) Nodeflag = 0;  /* No nodes */
1502       else if (match(Tok[n],w_ALL))  Nodeflag = 1;  /* All nodes */
1503       else
1504       {
1505          if (Nnodes == 0) return(208);
1506          for (i=1; i<=n; i++)
1507          {
1508             if ( (j = findnode(Tok[i])) == 0) return(208);
1509             Node[j].Rpt = 1;
1510          }
1511          Nodeflag = 2;
1512       }
1513       return(0);
1514    }
1515 
1516 /* Particular reporting links specified */
1517    if (match(Tok[0],w_LINK))
1518    {
1519       if      (match(Tok[n],w_NONE)) Linkflag = 0;
1520       else if (match(Tok[n],w_ALL))  Linkflag = 1;
1521       else
1522       {
1523          if (Nlinks == 0) return(210);
1524          for (i=1; i<=n; i++)
1525          {
1526             if ( (j = findlink(Tok[i])) == 0) return(210);
1527             Link[j].Rpt = 1;
1528          }
1529          Linkflag = 2;
1530       }
1531       return(0);
1532    }
1533 
1534 /* Check if input is a reporting criterion. */
1535 
1536 /*** Special case needed to distinguish "HEAD" from "HEADLOSS" ***/            //(2.00.11 - LR)
1537    if (strcomp(Tok[0], w_HEADLOSS)) i = HEADLOSS;                              //(2.00.11 - LR)
1538    else i = findmatch(Tok[0],Fldname);                                         //(2.00.11 - LR)
1539    if (i >= 0)                                                                 //(2.00.11 - LR)
1540 /*****************************************************************/            //(2.00.11 - LR)
1541    {
1542       if (i > FRICTION) return(201);
1543       if (Ntokens == 1 || match(Tok[1],w_YES))
1544       {
1545          Field[i].Enabled = TRUE;
1546          return(0);
1547       }
1548       if (match(Tok[1],w_NO))
1549       {
1550          Field[i].Enabled = FALSE;
1551          return(0);
1552       }
1553       if (Ntokens < 3) return(201);
1554       if      (match(Tok[1],w_BELOW))  j = LOW;   /* Get relation operator */
1555       else if (match(Tok[1],w_ABOVE))  j = HI;    /* or precision keyword  */
1556       else if (match(Tok[1],w_PRECISION)) j = PREC;
1557       else return(201);
1558       if (!getfloat(Tok[2],&y)) return(201);
1559       if (j == PREC)
1560       {
1561          Field[i].Enabled = TRUE;
1562          Field[i].Precision = ROUND(y);
1563       }
1564       else Field[i].RptLim[j] = y;                /* Report limit value */
1565       return(0);
1566    }
1567 
1568 /* Name of external report file */
1569    if (match(Tok[0],w_FILE))
1570    {
1571       strncpy(Rpt2Fname,Tok[1],MAXFNAME);
1572       return(0);
1573    }
1574 
1575 /* If get to here then return error condition */
1576    return(201);
1577 }                        /* end of reportdata */
1578 
1579 
1580 int  timedata()
1581 /*
1582 **--------------------------------------------------------------
1583 **  Input:   none                                                ;输入:无
1584 **  Output:  returns error code                                  ;输出:错误代码                                  
1585 **  Purpose: processes time options data                         ;目的:定义模拟中的各种事件时间步长参数。
1586 **  Formats:                                                     
1587 **    STATISTIC                  {NONE/AVERAGE/MIN/MAX/RANGE}                                          
1588 **    DURATION                   value   (units)                 
1589 **    HYDRAULIC TIMESTEP         value   (units)                 
1590 **    QUALITY TIMESTEP           value   (units)                 
1591 **    MINIMUM TRAVELTIME         value   (units)
1592 **    RULE TIMESTEP              value   (units)                 
1593 **    PATTERN TIMESTEP           value   (units)
1594 **    PATTERN START              value   (units)              
1595 **    REPORT TIMESTEP            value   (units)                 
1596 **    REPORT START               value   (units)                 
1597 **    START CLOCKTIME            value   (AM PM)
1598 定义: 
1599 DURATION 是模拟的历时。设为0来运行简单的瞬时分析。缺省为0。 
1600 HYDRAULIC TIMESTEP 定义了管网新的水力状态计算频率。如果它大于PATTERN或者
1601 REPORT时间步长,将自动降低。缺省为1小时。 
1602 QUALITY TIMESTEP用于跟踪水质通过管网变化的时间步长。缺省为水力时间步长的1/10。
1603 RULE TIMESTEP 用于检查水力时间步长之间,基于规则控制引起的系统状态变化的时间步长。
1604 缺省为1/10的水力时间步长。 
1605 PATTERN TIMESTEP是所有事件模式中时段之间的间隔。缺省为1小时。 
1606 PATTERN START 是所有模式开始时的时间分量。例如,6小时的数值将开始模拟,在时段
1607 中的每一模式,对应于6小时。缺省为0。 
1608 REPORT TIMESTEP 设置了输出结果被报告的时间间隔。缺省为1小时。 
1609 REPORT START是进入模拟的时间长度,此时输出结果开始报告。缺省为0。 
1610 START CLOCKTIME 是模拟开始的钟表时间(例如3:00 PM)。缺省为子夜12:00 AM 。 
1611 STATISTICS 确定了在产生模拟结果的时间序列中,统计后处理的类型。AVERAGED 报告了
1612 时间平均结果集合,MINIMUM仅仅报告最小值,MAXIMUM为最大值,以及RANGE 报告了最大值
1613 和最小值之间的差异。NONE报告了所有节点和管段量的完整时间序列,它为缺省的。 
1614 备注: 
1615 a.  单位应为SECONDS(SEC), MINUTES(MIN), HOURS 或DAYS。缺省为小时。 
1616 b.  如果没有提供计量单位,该时间数值可能输入为小数小时或者为小时:分钟。 
1617 c.  所有在[TIMES]节的输入是可选的。在反斜杠(/)后的事项说明了可选情况。
1618 **-------------------------------------------------------------
1619 */
1620 {
1621    int    n;
1622    long   t;
1623    double  y;
1624 
1625    n = Ntokens - 1;
1626    if (n < 1) return(201);
1627 
1628 /* Check if setting time statistic flag */
1629    if (match(Tok[0],w_STATISTIC))
1630    {
1631       if      (match(Tok[n],w_NONE))  Tstatflag = SERIES;
1632       else if (match(Tok[n],w_NO))    Tstatflag = SERIES;
1633       else if (match(Tok[n],w_AVG))   Tstatflag = AVG;
1634       else if (match(Tok[n],w_MIN))   Tstatflag = MIN;
1635       else if (match(Tok[n],w_MAX))   Tstatflag = MAX;
1636       else if (match(Tok[n],w_RANGE)) Tstatflag = RANGE;
1637       else return(201);
1638       return(0);
1639    }
1640 
1641 /* Convert text time value to numerical value in seconds 将文本时间值转换为数值时间值单位为秒*/
1642 /* Examples:
1643 **    5           = 5 * 3600 sec
1644 **    5 MINUTES   = 5 * 60   sec
1645 **    13:50       = 13*3600 + 50*60 sec
1646 **    1:50 pm     = (12+1)*3600 + 50*60 sec
1647 */
1648      
1649    if (!getfloat(Tok[n],&y))
1650    {
1651       if ( (y = hour(Tok[n],"")) < 0.0)
1652       {
1653          if ( (y = hour(Tok[n-1],Tok[n])) < 0.0) return(213);
1654       }
1655    }
1656    t = (long)(3600.0*y);
1657 
1658 /* Process the value assigned to the matched parameter */
1659    if      (match(Tok[0],w_DURATION))  Dur = t;      /* Simulation duration */
1660    else if (match(Tok[0],w_HYDRAULIC)) Hstep = t;    /* Hydraulic time step */
1661    else if (match(Tok[0],w_QUALITY))   Qstep = t;    /* Quality time step   */
1662    else if (match(Tok[0],w_RULE))      Rulestep = t; /* Rule time step      */
1663    else if (match(Tok[0],w_MINIMUM))   return(0);    /* Not used anymore    */
1664    else if (match(Tok[0],w_PATTERN))
1665    {
1666       if (match(Tok[1],w_TIME))       Pstep = t;     /* Pattern time step   */
1667       else if (match(Tok[1],w_START)) Pstart = t;    /* Pattern start time  */
1668       else return(201);
1669    }
1670    else if (match(Tok[0],w_REPORT))
1671    {
1672       if      (match(Tok[1],w_TIME))  Rstep = t;     /* Reporting time step  */
1673       else if (match(Tok[1],w_START)) Rstart = t;    /* Reporting start time */
1674       else return(201);
1675    }                                                 /* Simulation start time*/
1676    else if (match(Tok[0],w_START))    Tstart = t % SECperDAY; 
1677    else return(201);
1678    return(0);
1679 }                        /* end of timedata */
1680 
1681 
1682 int  optiondata()
1683 /*
1684 **--------------------------------------------------------------
1685 **  Input:   none                                                ;输入:无
1686 **  Output:  returns error code                                  ;输出:错误代码                                 
1687 **  Purpose: processes [OPTIONS] data                            ;目的:定义不同的模拟选项。 
1688 **--------------------------------------------------------------
1689 */
1690 {
1691    int i,n;
1692 
1693    n = Ntokens - 1;
1694    i = optionchoice(n);         /* Option is a named choice    */
1695    if (i >= 0) return(i);
1696    return(optionvalue(n));      /* Option is a numerical value */
1697 }                        /* end of optiondata */
1698 
1699 
1700 int  optionchoice(int n)
1701 /*
1702 **--------------------------------------------------------------
1703 **  Input:   n = index of last input token saved in Tok[]          
1704 **  Output:  returns error code or 0 if option belongs to        
1705 **           those listed below, or -1 otherwise                 
1706 **  Purpose: processes fixed choice [OPTIONS] data               
1707 **  Formats:                                                     
1708 **    UNITS               CFS/GPM/MGD/IMGD/AFD/LPS/LPM/MLD/CMH/CMD/SI
1709 **    PRESSURE            PSI/KPA/M                          
1710 **    HEADLOSS            H-W/D-W/C-M                        
1711 **    HYDRAULICS          USE/SAVE  filename                  
1712 **    QUALITY             NONE/AGE/TRACE/CHEMICAL  (TraceNode) 
1713 **    MAP                 filename                               
1714 **    VERIFY              filename                               
1715 **    UNBALANCED          STOP/CONTINUE {Niter}
1716 **    PATTERN             id
1717 **--------------------------------------------------------------
1718 */
1719 {
1720   /* Check if 1st token matches a parameter name and */
1721   /* process the input for the matched parameter     */
1722    if (n < 0) return(201);
1723    if (match(Tok[0],w_UNITS))  
1724    {
1725       if (n < 1) return(0);
1726       else if (match(Tok[1],w_CFS))  Flowflag = CFS;
1727       else if (match(Tok[1],w_GPM))  Flowflag = GPM;
1728       else if (match(Tok[1],w_AFD))  Flowflag = AFD;
1729       else if (match(Tok[1],w_MGD))  Flowflag = MGD;
1730       else if (match(Tok[1],w_IMGD)) Flowflag = IMGD;
1731       else if (match(Tok[1],w_LPS))  Flowflag = LPS;
1732       else if (match(Tok[1],w_LPM))  Flowflag = LPM;
1733       else if (match(Tok[1],w_CMH))  Flowflag = CMH;
1734       else if (match(Tok[1],w_CMD))  Flowflag = CMD;
1735       else if (match(Tok[1],w_MLD))  Flowflag = MLD;
1736       else if (match(Tok[1],w_SI))   Flowflag = LPS;
1737       else return(201);
1738    }
1739    else if (match(Tok[0],w_PRESSURE))
1740    {
1741       if (n < 1) return(0);
1742       else if (match(Tok[1],w_PSI))    Pressflag = PSI;
1743       else if (match(Tok[1],w_KPA))    Pressflag = KPA;
1744       else if (match(Tok[1],w_METERS)) Pressflag = METERS;
1745       else return(201);
1746    }
1747    else if (match(Tok[0],w_HEADLOSS))
1748    {
1749       if (n < 1) return(0);
1750       else if (match(Tok[1],w_HW)) Formflag = HW;
1751       else if (match(Tok[1],w_DW)) Formflag = DW;
1752       else if (match(Tok[1],w_CM)) Formflag = CM;
1753       else return(201);
1754    }
1755    else if (match(Tok[0],w_HYDRAULIC))
1756    {
1757       if (n < 2) return(0);
1758       else if (match(Tok[1],w_USE))  Hydflag = USE;
1759       else if (match(Tok[1],w_SAVE)) Hydflag = SAVE;
1760       else return(201);
1761       strncpy(HydFname,Tok[2],MAXFNAME);
1762    }
1763    else if (match(Tok[0],w_QUALITY))
1764    {
1765       if (n < 1) return(0);
1766       else if (match(Tok[1],w_NONE))  Qualflag = NONE;
1767       else if (match(Tok[1],w_CHEM))  Qualflag = CHEM;
1768       else if (match(Tok[1],w_AGE))   Qualflag = AGE;
1769       else if (match(Tok[1],w_TRACE)) Qualflag = TRACE;
1770       else
1771       {
1772          Qualflag = CHEM;
1773          strncpy(ChemName,Tok[1],MAXID);
1774          if (n >= 2) strncpy(ChemUnits,Tok[2],MAXID);
1775       }
1776       if (Qualflag == TRACE)                  /* Source tracing option */
1777       {
1778       /* Copy Trace Node ID to Tok[0] for error reporting */
1779          strcpy(Tok[0],"");
1780          if (n < 2) return(212);
1781          strcpy(Tok[0],Tok[2]);
1782          TraceNode = findnode(Tok[2]);
1783          if (TraceNode == 0) return(212);
1784          strncpy(ChemName,u_PERCENT,MAXID);
1785          strncpy(ChemUnits,Tok[2],MAXID);
1786       }
1787       if (Qualflag == AGE)
1788       {
1789          strncpy(ChemName,w_AGE,MAXID);
1790          strncpy(ChemUnits,u_HOURS,MAXID);
1791       }
1792    }
1793    else if (match(Tok[0],w_MAP))
1794    {
1795       if (n < 1) return(0);
1796       strncpy(MapFname,Tok[1],MAXFNAME);        /* Map file name */
1797    }
1798    else if (match(Tok[0],w_VERIFY))
1799    {
1800       /* Backward compatibility for verification file */
1801    }
1802    else if (match(Tok[0],w_UNBALANCED))         /* Unbalanced option */
1803    {
1804       if (n < 1) return(0);
1805       if (match(Tok[1],w_STOP)) ExtraIter = -1;
1806       else if (match(Tok[1],w_CONTINUE))
1807       {
1808          if (n >= 2) ExtraIter = atoi(Tok[2]);
1809          else ExtraIter = 0;
1810       }
1811       else return(201);
1812    }
1813    else if (match(Tok[0],w_PATTERN))            /* Pattern option */
1814    {
1815       if (n < 1) return(0);
1816       strncpy(DefPatID,Tok[1],MAXID);
1817    }
1818    else return(-1);
1819    return(0);
1820 }                        /* end of optionchoice */
1821 
1822 
1823 int  optionvalue(int n)
1824 /*
1825 **------------------------------------------------------------- 
1826 **  Input:   *line = line read from input file                   
1827 **  Output:  returns error code                                  
1828 **  Purpose: processes numerical value [OPTIONS] data            
1829 **  Formats:
1830 **    DEMAND MULTIPLIER   value
1831 **    EMITTER EXPONENT    value                                                     
1832 **    VISCOSITY           value                                  
1833 **    DIFFUSIVITY         value                                  
1834 **    SPECIFIC GRAVITY    value                                  
1835 **    TRIALS              value                                  
1836 **    ACCURACY            value                                  
1837 **    TOLERANCE           value                                  
1838 **    SEGMENTS            value  (not used)                                 
1839 **  ------ Undocumented Options -----                            
1840 **    HTOL                value                                  
1841 **    QTOL                value                                  
1842 **    RQTOL               value                                  
1843 **    CHECKFREQ           value                                  
1844 **    MAXCHECK            value
1845 **    DAMPLIMIT           value                                                //(2.00.12 - LR)                                  
1846 **--------------------------------------------------------------
1847 UNITS 设置了流量被表达的单位: 
1848     LPS ——升/秒 
1849     LPM ——升/分 
1850     MLD ——百万升/日 
1851     CMH ——立方米/小时 
1852     CMG ——立方米/日 
1853     CFS ——立方英尺/秒 
1854     GPM ——加仑/分 
1855     MGD ——百万加仑/日 
1856     IMGD——英制MGD 
1857     AFD ——英亩-英尺/日 
1858 如果流量单位为升或者立方米,那么公制单位也必须用于所有其它输入量。对于CFS, GPM, 
1859 MGD, IMGD和AFD ,其它输入量表达为美制单位。(计量单位参见附录A)。缺省流量单位为GPM 。 
1860 HEADLOSS 选择了用于计算通过管道水流的水头损失公式。包括Hazen-Williams(H-W ),
1861 Darcy-Weisbach(D-W)或Chezy-Manning (C-M)公式。缺省为H-W 。 
1862 HYDRAULICS 选项允许将当前水力结果SAVE(保存)到文件,或者USE (利用)以前保存的
1863 水力结果。当研究仅仅影响水质行为的因子时,很有用。 
1864 QUALITY选择了执行水质分析的类型。选择包括NONE(无), CHEMICAL(化学药剂), AGE
1865 (水龄)和TRACE (跟踪)。在CHEMI CAL 情况中,化合物的实际名称之后为其浓度单位(例如
1866 CHLORINE mg/L )。如果TRACE 被选择,必须跟踪节点的ID标签。缺省选项为NONE(没有水
1867 质分析)。 
1868 VISCOSITY是被模拟流体的运动粘度,相对于20摄氏度时的情况(1.0 厘斯)。缺省值为
1869 1.0 。 
1870 DIFFUSIVITY是化合物的分析扩散系数,相对于水中的氯情况。缺省值为1.0 。扩散系数
1871 仅仅适用于管壁反应中考虑质量转换限制时。数值0将造成EPANETH忽略质量转换限制。 
1872 SPECIFIC GRAVITY是被模拟流体密度与4摄氏度水的密度之比(无量纲)。 
1873 TRIALS是在每一模拟水力时间步长中,求解管网水力特性使用的最大试算次数。缺省为40。 
1874 ACCURACY 指定了确定何时达到水力结果的收敛准则。当所有流量总和改变,来自原先求解
1875 除以所有管段的总流量低于该数值时,试算中止。缺省为0.001 。 
1876 UNBALANCED 确定了何时进行,如果水力结果在指定的TRIAL 数值内不能够达到,对于水力
1877 时间步长来模拟。“STOP”将在该点终止整个分析。“CONTINUE ”将在公布警告消息的情况
1878 下继续分析。“CONTINUE n ”将在另外“n”次试算中搜索结果,所有管线状态保持它们的当
1879 前设置。模拟将在该点继续,关于收敛是否达到,具有消息公布。缺省选项为“STOP”。 
1880 PATTERN提供了用于没有指定需水量模式的所有节点缺省需水量模式的ID标签。如果没有
1881 这样的模式在[PATTERNS] 节中存在,那么通过缺省的模式,包含一个等于1.0 的单一乘子。如
1882 果没有使用该选项,总体缺省需水量模式具有标签“1”。 
1883 DEMAND MULTIPLIER用于调整所有连接节点的基本需水量数值,以及所有需水量的类型。
1884 例如,数值2为两倍的基准需水量,而数值0.5 将为它们的一半。缺省值为1.0 。 
1885 EMITTER EXPONENT指定了当计算扩散器的流量时,节点压力上升的幂指数。缺省为0.5 。 
1886 MAP 用于提供包含了管网节点坐标的文件名称,以便绘制管网地图。对于任何水力或者水质
1887 计算这是无用的。 
1888 TOLERANCE是水质水平精度。对于所有水质分析(化合物、水龄(以小时度量),或者源
1889 头跟踪(以百分比度量)),缺省值为0.01。 
1890 备注: 
1891 a.  如果在本节没有明确指定,所有选项假设为缺省数值。 
1892 b.  反斜杠(/)后的项说明为允许选项。 
1893 */
1894 {
1895    int    nvalue = 1;   /* Index of token with numerical value */
1896    double  y;
1897 
1898 /* Check for obsolete SEGMENTS keyword */
1899    if (match(Tok[0],w_SEGMENTS)) return(0);
1900 
1901 /* Check for missing value (which is permissible) */
1902    if (match(Tok[0],w_SPECGRAV) || match(Tok[0],w_EMITTER)
1903    || match(Tok[0],w_DEMAND)) nvalue = 2;
1904    if (n < nvalue) return(0);
1905 
1906 /* Check for valid numerical input */
1907    if (!getfloat(Tok[nvalue],&y)) return(213);
1908 
1909 /* Check for WQ tolerance option (which can be 0) */
1910    if (match(Tok[0],w_TOLERANCE))
1911    {
1912       if (y < 0.0) return(213);
1913       Ctol = y;         /* Quality tolerance*/
1914       return(0);
1915    }
1916 
1917 /* Check for Diffusivity option */
1918    if (match(Tok[0],w_DIFFUSIVITY))
1919    {
1920       if (y < 0.0) return(213);
1921       Diffus = y;
1922       return(0);
1923    }
1924 
1925 /* Check for Damping Limit option */                                           //(2.00.12 - LR)
1926    if (match(Tok[0],w_DAMPLIMIT))
1927    {
1928       DampLimit = y;
1929       return(0);
1930    }
1931 
1932 /* All other options must be > 0 */
1933    if (y <= 0.0) return(213);
1934 
1935 /* Assign value to specified option */
1936    if      (match(Tok[0],w_VISCOSITY))   Viscos = y;       /* Viscosity */
1937    else if (match(Tok[0],w_SPECGRAV))    SpGrav = y;       /* Spec. gravity */
1938    else if (match(Tok[0],w_TRIALS))      MaxIter = (int)y; /* Max. trials */
1939    else if (match(Tok[0],w_ACCURACY))                      /* Accuracy */
1940    {
1941       y = MAX(y,1.e-5);                                  
1942       y = MIN(y,1.e-1);
1943       Hacc = y;
1944    }
1945    else if (match(Tok[0],w_HTOL))        Htol = y;
1946    else if (match(Tok[0],w_QTOL))        Qtol = y;
1947    else if (match(Tok[0],w_RQTOL))
1948    {
1949       if (y >= 1.0) return(213);
1950       RQtol = y;
1951    }
1952    else if (match(Tok[0],w_CHECKFREQ))   CheckFreq = (int)y;
1953    else if (match(Tok[0],w_MAXCHECK))    MaxCheck = (int)y;
1954    else if (match(Tok[0],w_EMITTER))     Qexp = 1.0/y;
1955    else if (match(Tok[0],w_DEMAND))      Dmult = y;
1956    else return(201);
1957    return(0);
1958 }                        /* end of optionvalue */
1959 
1960 
1961 int  getpumpcurve(int n)
1962 /*
1963 **--------------------------------------------------------
1964 **  Input:   n = number of parameters for pump curve
1965 **  Output:  returns error code
1966 **  Purpose: processes pump curve data for Version 1.1-
1967 **           style input data
1968 **  Notes:
1969 **    1. Called by pumpdata() in INPUT3.C
1970 **    2. Current link index & pump index of pump being
1971 **       processed is found in global variables Nlinks
1972 **       and Npumps, respectively
1973 **    3. Curve data read from input line is found in
1974 **       global variables X[0],...X[n-1]
1975 **---------------------------------------------------------
1976 */
1977 {
1978    double a,b,c,h0,h1,h2,q1,q2;
1979 
1980    if (n == 1)                /* Const. HP curve       */
1981    {
1982       if (X[0] <= 0.0) return(202);
1983       Pump[Npumps].Ptype = CONST_HP;
1984       Link[Nlinks].Km = X[0];
1985    }
1986    else
1987    {
1988       if (n == 2)             /* Generic power curve   */
1989       {
1990          q1 = X[1];
1991          h1 = X[0];
1992          h0 = 1.33334*h1;
1993          q2 = 2.0*q1;
1994          h2 = 0.0;
1995       }
1996       else if (n >= 5)        /* 3-pt. power curve     */
1997       {
1998          h0 = X[0];
1999          h1 = X[1];
2000          q1 = X[2];
2001          h2 = X[3];
2002          q2 = X[4];
2003       }
2004       else return(202);
2005       Pump[Npumps].Ptype = POWER_FUNC;
2006       if (!powercurve(h0,h1,h2,q1,q2,&a,&b,&c)) return(206);
2007       Pump[Npumps].H0 = -a;
2008       Pump[Npumps].R  = -b;
2009       Pump[Npumps].N  = c;
2010       Pump[Npumps].Q0 = q1;
2011       Pump[Npumps].Qmax  = pow((-a/b),(1.0/c));
2012       Pump[Npumps].Hmax  = h0;
2013    }
2014    return(0);
2015 }
2016 
2017 
2018 int  powercurve(double h0, double h1, double h2, double q1,
2019                 double q2, double *a, double *b, double *c)
2020 /*
2021 **---------------------------------------------------------
2022 **  Input:   h0 = shutoff head                            输入:h0 =最大水头
2023 **           h1 = design head                                    h1 =设计水头 
2024 **           h2 = head at max. flow                              h2 =最大流量时的水头
2025 **           q1 = design flow                                    q1 =设计流量
2026 **           q2 = max. flow                                      q2 =最大流量
2027 **  Output:  *a, *b, *c = pump curve coeffs. (H = a-bQ^c),输出:返回水泵扬程-流量公式中的3参数
2028 **           Returns 1 if sucessful, 0 otherwise.
2029 **  Purpose: computes coeffs. for pump curve              目的:计算水泵曲线的方程系数
2030 **----------------------------------------------------------
2031 */
2032 {
2033     double h4,h5;
2034     if (
2035           h0      < TINY ||
2036           h0 - h1 < TINY ||
2037           h1 - h2 < TINY ||
2038           q1      < TINY ||
2039           q2 - q1 < TINY
2040                            ) return(0);
2041     *a = h0;
2042     h4 = h0 - h1;
2043     h5 = h0 - h2;
2044     *c = log(h5/h4)/log(q2/q1);
2045     if (*c <= 0.0 || *c > 20.0) return(0);
2046     *b = -h4/pow(q1,*c);
2047 
2048     /*** Updated 6/24/02 ***/
2049     if (*b >= 0.0) return(0);
2050 
2051     return(1);
2052 }
2053 
2054 
2055 int  valvecheck(int type, int j1, int j2)
2056 /*
2057 **--------------------------------------------------------------
2058 **  Input:   type = valve type 阀门类型                                  
2059 **           j1   = index of upstream node   上游节点索引值                    
2060 **           j2   = index of downstream node 下游节点索引值                   
2061 **  Output:  returns 1 for legal connection, 0 otherwise   返回1为合法阀门情况      
2062 **  Purpose: checks for legal connections between PRVs & PSVs    作用:检查多个阀门之间共享节点等非法情况
2063 **--------------------------------------------------------------
2064 */
2065 {
2066    int  k, vk, vj1, vj2, vtype;
2067 
2068    /* Examine each existing valve */
2069    for (k=1; k<=Nvalves; k++)
2070    {
2071       vk = Valve[k].Link;
2072       vj1 = Link[vk].N1;
2073       vj2 = Link[vk].N2;
2074       vtype = Link[vk].Type;
2075 
2076       /* Cannot have two PRVs sharing downstream nodes or in series */
2077       if (vtype == PRV && type == PRV)
2078       {
2079          if (vj2 == j2 ||
2080              vj2 == j1 ||
2081              vj1 == j2   ) return(0);
2082       }
2083 
2084       /* Cannot have two PSVs sharing upstream nodes or in series */
2085       if (vtype == PSV && type == PSV)
2086       {
2087          if (vj1 == j1 ||
2088              vj1 == j2 ||
2089              vj2 == j1   ) return(0);
2090       }
2091 
2092       /* Cannot have PSV connected to downstream node of PRV */
2093       if (vtype == PSV && type == PRV && vj1 == j2) return(0);
2094       if (vtype == PRV && type == PSV && vj2 == j1) return(0);
2095 
2096 /*** Updated 3/1/01 ***/
2097       /* Cannot have PSV connected to downstream node of FCV */
2098       /* nor have PRV connected to upstream node of FCV */
2099       if (vtype == FCV && type == PSV && vj2 == j1) return(0);
2100       if (vtype == FCV && type == PRV && vj1 == j2) return(0);
2101 
2102 /*** Updated 4/14/05 ***/
2103       if (vtype == PSV && type == FCV && vj1 == j2) return (0);
2104       if (vtype == PRV && type == FCV && vj2 == j1) return (0);
2105    }
2106    return(1);
2107 }                   /* End of valvecheck */
2108 
2109 
2110 void  changestatus(int j, char status, double y)
2111 /*
2112 **--------------------------------------------------------------
2113 **  Input:   j      = link index                                   
2114 **           status = status setting (OPEN, CLOSED)             //这里就阐释了status与setting的关系                
2115 **           y      = numerical setting (pump speed, valve
2116 **                    setting)
2117 **  Output:  none
2118 **  Purpose: changes status or setting of a link
2119 **
2120 **  NOTE: If status = ACTIVE, then a numerical setting (y) was  //如果status = ACTIVE,那么一个数值设定y将提供用于表示水泵的转速,或者阀门的开度等
2121 **        supplied. If status = OPEN/CLOSED, then numerical
2122 **        setting is 0.
2123 **--------------------------------------------------------------
2124 */
2125 {
2126    if (Link[j].Type == PIPE || Link[j].Type == GPV)
2127    {
2128       if (status != ACTIVE) Link[j].Stat = status;
2129    }
2130    else if (Link[j].Type == PUMP)
2131    {
2132       if (status == ACTIVE)
2133       {
2134          Link[j].Kc = y;
2135          status = OPEN;
2136          if (y == 0.0) status = CLOSED;
2137       }
2138       else if (status == OPEN) Link[j].Kc = 1.0;
2139       Link[j].Stat = status;
2140    }
2141    else if (Link[j].Type >= PRV)
2142    {
2143       Link[j].Kc = y;
2144       Link[j].Stat = status;
2145       if (status != ACTIVE) Link[j].Kc = MISSING;
2146    }
2147 }                        /* end of changestatus */
2148 
2149 /********************** END OF INPUT3.C ************************/

 

你可能感兴趣的:(input)