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 ************************/