github.com/archlabjp/eeslism-go@v0.0.0-20231109122333-4bb7bfcdf292/eeslism/blinit.go (about) 1 //This file is part of EESLISM. 2 // 3 //Foobar is free software : you can redistribute itand /or modify 4 //it under the terms of the GNU General Public License as published by 5 //the Free Software Foundation, either version 3 of the License, or 6 //(at your option) any later version. 7 // 8 //Foobar is distributed in the hope that it will be useful, 9 //but WITHOUT ANY WARRANTY; without even the implied warranty of 10 //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the 11 //GNU General Public License for more details. 12 // 13 //You should have received a copy of the GNU General Public License 14 //along with Foobar.If not, see < https://www.gnu.org/licenses/>. 15 16 /* binit.c */ 17 package eeslism 18 19 import ( 20 "bufio" 21 "fmt" 22 "strconv" 23 "strings" 24 ) 25 26 /* 壁体デ-タの入力 */ 27 28 // WALLデータセットの読み取り 29 func Walldata(section *EeTokens, fbmlist string, Wall *[]*WALL, dfwl *DFWL, pcm []*PCM) { 30 var s string 31 var i = -1 32 var j, jj, jw, Nlyr, k = 0, 0, 0, 0, -1 33 var Nbm, ndiv int // ic 34 var dt float64 35 var W []BMLST 36 var Wl *BMLST 37 38 W = nil 39 // E = fmt.Sprintf(ERRFMT, dsn) 40 41 NwLines := wbmlistcount(fbmlist) 42 43 s = "Walldata wbmlist.efl--" 44 45 k = 0 46 47 for _, line := range NwLines { 48 s := strings.Fields(line) 49 50 Wl = new(BMLST) 51 Wl.Mcode = s[0] 52 53 for j := 0; j < k-1; j++ { 54 Wc := &W[j] 55 if Wl.Mcode == Wc.Mcode { 56 message := fmt.Sprintf("wbmlist.efl duplicate code=<%s>", Wl.Mcode) 57 Eprint("<Walldata>", message) 58 } 59 } 60 61 // Cond:熱伝導率[W/mK]、Cro:容積比熱[kJ/m3K] 62 var err error 63 Wl.Cond, err = strconv.ParseFloat(s[1], 64) 64 if err != nil { 65 Eprint("<Walldata>", "wbmlist.efl Cond error") 66 } 67 68 Wl.Cro, err = strconv.ParseFloat(s[2], 64) 69 if err != nil { 70 Eprint("<Walldata>", "wbmlist.efl Cro error") 71 } 72 73 W = append(W, *Wl) 74 75 for j := 0; j < k+1; j++ { 76 fmt.Printf("k=%d code=%s\n", k, W[j].Mcode) 77 } 78 79 fmt.Printf("Walldata>> name=%s Con=%f Cro=%f\n", W[k].Mcode, W[k].Cond, W[k].Cro) 80 W[k] = *Wl 81 k++ 82 } 83 84 k++ 85 Nbm = k 86 87 //N = Wallcount(fi) 88 89 s = "Walldata --" 90 91 i = 0 92 for section.IsEnd() == false { 93 line := section.GetLogicalLine() 94 if line[0] == "*" { 95 break 96 } 97 98 Wa := NewWall() 99 100 s = line[0] 101 102 // for jj = 0; jj < len(Wa.welm); jj++ { 103 // w = NewWelm() 104 // } 105 106 // for jj = 0; jj < len(Wa.PCM); jj++ { 107 // Wa.PCM[jj] = nil 108 // Wa.PCMrate[jj] = -999.0 109 // } 110 111 // (1) 部位・壁体名の読み取り 112 if strings.HasPrefix(s, "-") { 113 // For `-E` or `-R:ROOF` or ... 114 115 // 部位コードの指定 116 Wa.ble = BLEType(s[1]) 117 118 if len(s) > 2 && s[2] == ':' { 119 // 壁体名の指定(最初の1文字を必ず英字とする) 120 Wa.name = s[3:] 121 } else { 122 // 部位のみ指定(既定値の定義) 123 switch s[1] { 124 case 'E': // 外壁 125 dfwl.E = i 126 case 'R': // 屋根 127 dfwl.R = i 128 case 'F': // 床(外部) 129 dfwl.F = i 130 case 'i': // 内壁 131 dfwl.i = i 132 case 'c': // 天井(内部) 133 dfwl.c = i 134 case 'f': // 床(内部) 135 dfwl.f = i 136 } 137 } 138 } else { 139 // 部位コードの指定なし 140 Wa.name = s 141 } 142 143 j = -1 144 145 // (2) 部位・壁体のパラメータを読み取り 146 // 例) `Eo=0.9 Ei=0.9 as=0.7 type=1 APR-100 APR-100/20 <P:80.3> ;` 147 var layer []string 148 for _, s = range line[1:] { 149 var err error 150 st := strings.IndexRune(s, '=') 151 if st != -1 { 152 dt, err = strconv.ParseFloat(s[st+1:], 64) 153 if err != nil { 154 panic(err) 155 } 156 157 switch strings.TrimSpace(s[:st]) { 158 case "Ei": 159 Wa.Ei = dt // 室内表面放射率 160 case "Eo": 161 Wa.Eo = dt // 外表面放射率 162 case "as": 163 Wa.as = dt // 外表面日射吸収率 164 case "type": 165 Wa.ColType = s[st+1:] // 集熱器のタイプ 166 case "tra": 167 Wa.tra = dt // τα 168 case "Ksu": 169 Wa.Ksu = dt // 通気層内上側から屋外までの熱貫流率 [W/m2K] 170 case "Ksd": 171 Wa.Ksd = dt // 通気層内下側から裏面までの熱貫流率 [W/m2K] 172 case "Ru": 173 Wa.Ru = dt // 通気層から上面までの熱抵抗 [m2K/W] 174 case "Rd": 175 Wa.Rd = dt // 通気層から裏面までの熱抵抗 [m2K/W] 176 case "fcu": 177 Wa.fcu = dt // Kcu / Ksu (太陽光発電設置時のアレイ温度計算のみに使用) 178 case "fcd": 179 Wa.fcd = dt // Kcd / Ksd (太陽光発電設置時のアレイ温度計算のみに使用) 180 case "Kc": 181 Wa.Kc = dt 182 case "Esu": 183 Wa.dblEsu = dt // 通気層内上側の放射率 184 case "Esd": 185 Wa.dblEsd = dt // 通気層内下側の放射率 186 case "Eg": 187 Wa.Eg = dt // 透過体の中空層側表面の放射率 188 case "Eb": 189 Wa.Eb = dt // 集熱板の中空層側表面の放射率 190 case "ag": 191 Wa.ag = dt // 透過体の日射吸収率 192 case "ta": 193 Wa.ta = dt / 1000.0 // 中空層の厚さ [mm] -> [m] 194 case "tnxt": 195 Wa.tnxt = dt 196 case "t": 197 Wa.air_layer_t = dt / 1000.0 198 case "KHD": 199 Wa.PVwallcat.KHD = dt // 日射量年変動補正係数 (集熱板が太陽電池一体型のとき) 200 case "KPD": 201 Wa.PVwallcat.KPD = dt // 経時変化補正係数 (集熱板が太陽電池一体型のとき) 202 case "KPM": 203 Wa.PVwallcat.KPM = dt // アレイ負荷整合補正係数 (集熱板が太陽電池一体型のとき) 204 case "KPA": 205 Wa.PVwallcat.KPA = dt // アレイ回路補正係数 (集熱板が太陽電池一体型のとき) 206 case "EffInv": 207 Wa.PVwallcat.EffINO = dt // インバータ効率 (集熱板が太陽電池一体型のとき) 208 case "apamax": 209 Wa.PVwallcat.Apmax = dt // 最大出力温度係数 (集熱板が太陽電池一体型のとき) 210 case "ap": 211 Wa.PVwallcat.Ap = dt // 太陽電池裏面の対流熱伝達率 212 case "Rcoloff": 213 Wa.PVwallcat.Rcoloff = dt // 太陽電池から集熱器裏面までの熱抵抗 (集熱板が太陽電池一体型のとき) 214 Wa.PVwallcat.Kcoloff = 1. / Wa.PVwallcat.Rcoloff 215 default: 216 Eprint("<Walldata>", s) 217 } 218 } else { 219 layer = append(layer, s) 220 j++ 221 } 222 } 223 224 // 層の数 225 Nlyr = j + 1 226 227 Wa.welm = []WELM{ 228 { 229 Code: "ali", //内表面熱伝達率 230 L: -999.0, 231 ND: 0, 232 Cond: -999.0, 233 Cro: -999.0, 234 }, 235 } 236 237 // (3) 層の読み取り 238 // `APR-100 APR-100/20 <P:80.3>` 239 for j = 1; j <= Nlyr; j++ { 240 if Wa.ble == BLE_Roof || Wa.ble == BLE_Ceil { 241 jj = Nlyr - j 242 } else { 243 jj = j - 1 244 } 245 246 // `APR-100`, `APR-100/20` or `<P>:80.3` or `<C>` 247 var err error 248 st := strings.IndexRune(layer[jj], '-') 249 if st != -1 { 250 // 一般材料のとき または 一般材料で分割層数を指定するとき 251 // For `APR-100` or `APR-100/20` 252 var code string // 材料コード 253 var ND int // 内部分割数 254 var L float64 // 部材厚さ [mm] 255 256 // 1) 材料コード 257 code = layer[jj][:st] 258 259 // 2) 同一層内の内部分割数と部材の厚さ 260 ss := layer[jj][st+1:] 261 st = strings.IndexRune(ss, '/') 262 if st != -1 { 263 // "20.0/2"のように分割数が指定されている場合 264 sss := strings.SplitN(ss, "/", 2) 265 L, err = strconv.ParseFloat(sss[0], 64) 266 if err != nil { 267 panic(err) 268 } 269 270 // 分割数 271 ndiv, err = strconv.Atoi(sss[1]) 272 if err != nil { 273 panic(err) 274 } 275 ND = ndiv - 1 276 } else { 277 // "20.0"のように分割数が指定されていない場合 278 L, err = strconv.ParseFloat(ss, 64) 279 if err != nil { 280 panic(err) 281 } 282 283 if L >= 50. { 284 ND = int((L - 50.) / 50.) 285 } else { 286 // 50mm未満の場合は分割しない 287 ND = 0 288 } 289 } 290 291 Wa.welm = append(Wa.welm, WELM{ 292 Code: code, 293 ND: ND, 294 L: L / 1000.0, // [mm] -> [m] 295 }) 296 297 } else if strings.HasPrefix(layer[jj], "<P") || layer[jj] == "<C>" { 298 // 放射暖冷房パネル発熱面位置の指定の場合 For `<P:80.3>` or `<P>` or `<C>` 299 // ※ `<C>`はマニュアルに記述が見当たらないが、`<P>`と同じ扱いにする 300 Wa.Ip = len(Wa.welm) - 1 301 if layer[jj][2] == ':' { 302 // パネル効率が指定されている場合 `<P:80.3>` 303 Wa.effpnl, err = strconv.ParseFloat(layer[jj][3:], 64) 304 if err != nil { 305 panic(err) 306 } 307 } else { 308 // パネル効率が指定されない場合 `<C>` 309 Wa.effpnl = 0.7 310 } 311 } else if layer[jj] != "alo" && layer[jj] != "ali" { 312 // 表面熱伝達率、中空層熱コンダクタンスのとき、材料コードのみを指定する 313 Wa.welm = append(Wa.welm, WELM{ 314 Code: layer[jj], 315 ND: 0, 316 L: 0.0, 317 }) 318 } 319 } 320 jw = len(Wa.welm) - 1 321 322 // 建材一体型空気集熱器の総合熱貫流率の計算、データ入力状況のチェック 323 if Wa.Ip >= 0 { 324 if Wa.tra > 0. { 325 // 壁種類 -> 建材一体型空気集熱器 326 Wa.WallType = 'C' 327 328 if (Wa.Ksu > 0. && Wa.Ksd > 0.) || (Wa.Rd > 0. && (Wa.Ru >= 0. || Wa.ta > 0.)) { 329 330 if strings.HasPrefix(Wa.ColType, "A") { 331 // 集熱器のタイプ = A1,A2,A2P or A3 332 if Wa.Ksu > 0. { 333 // 熱抵抗が入力されていない 334 Wa.Kcu = Wa.fcu * Wa.Ksu 335 Wa.Kcd = Wa.fcd * Wa.Ksd 336 Wa.Kc = Wa.Kcu + Wa.Kcd 337 Wa.ku = Wa.Kcu / Wa.Kc 338 Wa.kd = Wa.Kcd / Wa.Kc 339 } else { 340 // 熱抵抗が入力されている 341 Wa.chrRinput = true 342 } 343 } else if strings.HasPrefix(Wa.ColType, "W") { 344 // 集熱器のタイプ = W3 345 Wa.Ko = Wa.Ksu + Wa.Ksd 346 Wa.ku = Wa.Ksu / Wa.Ko 347 Wa.kd = Wa.Ksd / Wa.Ko 348 } 349 350 // PVがある場合は事前計算をする 351 if Wa.PVwallcat.KHD > 0. { 352 PVwallPreCalc(&Wa.PVwallcat) 353 } 354 } else { 355 s = fmt.Sprintf("ble=%c name=%s 建築一体型空気集熱の熱貫流率Ku、Kdが未定義です", Wa.ble, Wa.name) 356 Eprint("<Walldata>", s) 357 } 358 359 if Wa.chrRinput == false && (Wa.Kc < 0. || Wa.Ksu < 0. || Wa.Ksd < 0.) { 360 s = fmt.Sprintf("ble=%c name=%s 建築一体型空気集熱の熱貫流率Kc、Kdd、Kudが未定義です", 361 Wa.ble, Wa.name) 362 Eprint("<Walldata>", s) 363 } 364 365 if Wa.Ip == -1 { 366 s = fmt.Sprintf("ble=%c name=%s 建築一体型空気集熱の空気流通層<P>が未定義です", 367 Wa.ble, Wa.name) 368 Eprint("<Walldata>", s) 369 } 370 } else { 371 // 壁種類 -> 床暖房等放射パネル 372 Wa.WallType = WallType_P 373 } 374 } 375 376 Wa.N = jw + 1 377 Walli(Nbm, W, Wa, pcm) 378 379 *Wall = append(*Wall, Wa) 380 i++ 381 } 382 } 383 384 /* ------------------------------------------------ */ 385 386 /* 窓デ-タの入力 */ 387 388 // WINDOWデータセットの読み取り 389 func Windowdata(section *EeTokens, Window *[]*WINDOW) { 390 E := fmt.Sprintf(ERRFMT, "WINDOW") 391 392 var N int 393 for section.IsEnd() == false { 394 line := section.GetLogicalLine() 395 if line[0] != "*" { 396 N++ 397 } 398 } 399 section.Reset() 400 401 if N > 0 { 402 *Window = make([]*WINDOW, N) 403 404 for j := 0; j < N; j++ { 405 (*Window)[j] = NewWINDOW() 406 } 407 } 408 409 i := 0 410 for section.IsEnd() == false { 411 line := section.GetLogicalLine() 412 413 if line[0] == "*" { 414 break 415 } 416 417 W := (*Window)[i] 418 419 // 名称 420 W.Name = line[0] 421 422 // 名前の重複確認 423 for k := 0; k < i; k++ { 424 Wc := (*Window)[k] 425 if W.Name == Wc.Name { 426 ss := fmt.Sprintf("<WINDOW> WindowName Already Defined (%s)", W.Name) 427 Eprint("<Windowdata>", ss) 428 } 429 } 430 431 // プロパティの設定 432 for _, s := range line[1:] { 433 // 室内透過日射が窓室内側への入射日射を屋外に透過する場合'y' 434 if s == "-RStrans" { 435 W.RStrans = true 436 } else { 437 //キー・バリューの分離 438 st := strings.IndexRune(s, '=') 439 if st == -1 { 440 panic("Windowdata: invalid format") 441 } else { 442 st++ 443 } 444 key := s[:st-1] 445 value := s[st:] 446 447 // 小数読み取り 448 var realValue float64 449 var err error 450 switch key { 451 case "t", "B", "R", "Ei", "Eo": 452 realValue, err = strconv.ParseFloat(value, 64) 453 if err != nil { 454 panic(err) 455 } 456 } 457 458 // 値の設定 459 switch key { 460 case "t": 461 W.tgtn = realValue // 日射透過率 462 case "B": 463 W.Bn = realValue // 吸収日射取得率 464 case "R": 465 W.Rwall = realValue // 窓部材熱抵抗 [m2K/W] 466 case "Ei": 467 W.Ei = realValue // 室内表面放射率(0.9) 468 case "Eo": 469 W.Eo = realValue // 外表面放射率(0.9) 470 case "Cidtype": 471 W.Cidtype = strings.Trim(value, "'") // 入射角特性の種類 472 default: 473 Err := fmt.Sprintf("%s %s\n", E, s) 474 Eprint("<Windowdata>", Err) 475 } 476 477 //NOTE: 以下の項目を入力する箇所が不明 478 // 窓ガラス面積 Ag, 開口面積 Ao, 幅 W, 高さ H, ??? K 479 } 480 } 481 482 i++ 483 } 484 } 485 486 /* --------------------------------------------------- */ 487 488 func Snbkdata(section *EeTokens, dsn string, Snbk *[]*SNBK) { 489 // 入力チェック用パターン文字列 490 typstr := []string{ 491 "HWDTLR.", // 庇 492 "HWDTLRB", // 袖壁(その1) (左右) 493 "HWDTL.B", // 袖壁(その2) (左のみ) 494 "HWDT.RB", // 袖壁(その3) (右のみ) 495 "HWDT...", // 長い庇 496 "HWD.LR.", // 長い袖壁(その1) (左右) 497 "HWD.L..", // 長い袖壁(その2) (左のみ) 498 "HWD..R.", // 長い袖壁(その3) (右のみ) 499 "HWDTLRB", // ルーバー 500 } 501 502 Er := fmt.Sprintf(ERRFMT, dsn) 503 Type := 0 504 505 *Snbk = make([]*SNBK, 0) 506 507 for section.IsEnd() == false { 508 509 fields := section.GetLogicalLine() 510 if fields[0] == "*" { 511 break 512 } 513 514 S := NewSNBK() 515 516 // 名前 517 S.Name = fields[0] 518 519 // 入力チェック用 520 code := [7]rune{'.', '.', '.', '.', '.', '.', '.'} 521 522 for _, s := range fields[1:] { 523 // キー・バリューの分離 524 st := strings.IndexRune(s, '=') 525 if st == -1 { 526 panic("Snbkdata: invalid format") 527 } 528 key := s[:st] 529 v := s[st+1:] 530 531 var err error 532 switch key { 533 case "type": 534 var vs string 535 if v[0] == '-' { 536 S.Ksi = 1 537 vs = v[1:] 538 } else { 539 S.Ksi = 0 540 vs = v[0:] 541 } 542 543 if vs == "H" { 544 Type = 1 // 一般の庇 545 } else if vs == "HL" { 546 Type = 5 // 長い庇 547 } else if vs == "S" { 548 Type = 2 // 袖壁 549 } else if vs == "SL" { 550 Type = 6 // 長い袖壁 551 } else if vs == "K" { 552 Type = 9 // 格子ルーバー 553 } else { 554 E := fmt.Sprintf("`%s` is invalid", vs) 555 Eprint("<Snbkdata>", E) 556 } 557 558 case "window": 559 // For `window=HhhhxWwww` 560 hw := strings.Split(v, "x") 561 h, w := hw[0], hw[1] 562 563 if h[0] != 'H' || w[0] != 'W' { 564 panic(fmt.Sprintf("Invaid window format: %s", v)) 565 } 566 567 // 開口部の高さ 568 S.H, err = strconv.ParseFloat(h[1:], 64) 569 if err != nil { 570 panic(err) 571 } 572 code[0] = 'H' 573 574 // 開口部の幅 575 S.W, err = strconv.ParseFloat(w[1:], 64) 576 if err != nil { 577 panic(err) 578 } 579 code[1] = 'W' 580 581 case "D": 582 // 庇の付け根から先端までの長さ 583 S.D, err = strconv.ParseFloat(v, 64) 584 if err != nil { 585 panic(err) 586 } 587 code[2] = 'D' 588 589 case "T": 590 // 開口部の上端から壁の上端までの距離 591 S.H1, err = strconv.ParseFloat(v, 64) 592 if err != nil { 593 panic(err) 594 } 595 code[3] = 'T' 596 597 case "L": 598 // 開口部の左端から壁の左端までの距離 599 S.W1, err = strconv.ParseFloat(v, 64) 600 if err != nil { 601 panic(err) 602 } 603 code[4] = 'L' 604 605 case "R": 606 // 開口部の右端から壁の右端までの距離 607 S.W2, err = strconv.ParseFloat(v, 64) 608 if err != nil { 609 panic(err) 610 } 611 code[5] = 'R' 612 613 case "B": 614 // 地面から開口部の下端までの高さ 615 S.H2, err = strconv.ParseFloat(v, 64) 616 if err != nil { 617 panic(err) 618 } 619 code[6] = 'B' 620 621 default: 622 panic(fmt.Sprintf("Invaid window format: %s", s)) 623 } 624 } 625 626 // 日除けの種類 627 S.Type = Type 628 629 // 日除けの種類ごとに入力チェック 630 switch Type { 631 case 1, 5, 9: 632 // 庇 or ルーバー 633 if string(code[:]) != typstr[Type-1] { 634 E := fmt.Sprintf("%s %s type=%d %s\n", Er, fields[0], Type, string(code[:])) 635 Eprint("<Snbkdata>", E) 636 } 637 case 2, 6: 638 // 袖壁 639 if string(code[:]) != typstr[Type-1] { 640 for j := 1; j < 3; j++ { 641 if string(code[:]) == typstr[Type+j-1] { 642 S.Type = Type + j 643 break 644 } 645 if j == 3 { 646 E := fmt.Sprintf("%s %s type=%d %s\n", Er, fields[0], Type, string(code[:])) 647 Eprint("<Snbkdata>", E) 648 } 649 } 650 } 651 } 652 653 *Snbk = append(*Snbk, S) 654 } 655 } 656 657 func NewSNBK() *SNBK { 658 S := new(SNBK) 659 S.Name = "" 660 S.W = 0.0 661 S.H = 0.0 662 S.D = 0.0 663 S.W1 = 0.0 664 S.W2 = 0.0 665 S.H1 = 0.0 666 S.H2 = 0.0 667 S.Type = 0 668 S.Ksi = 0 669 return S 670 } 671 672 /************************************************************/ 673 674 func wbmlistcount(fi string) []string { 675 N := make([]string, 0) 676 677 reader := strings.NewReader(fi) 678 scanner := bufio.NewScanner(reader) 679 680 for scanner.Scan() { 681 s := scanner.Text() 682 683 if strings.HasPrefix(s, "*") { 684 break 685 } 686 687 //コメントを読み飛ばす 688 st := strings.IndexRune(s, '!') 689 if st != -1 { 690 s = s[:st] 691 } 692 693 //ゴミ除去 694 s = strings.TrimSpace(s) 695 696 if s != "" { 697 N = append(N, s) 698 } 699 } 700 701 return N 702 } 703 704 /************************************************************/ 705 706 func Wallcount(scanner *bufio.Scanner) []string { 707 N := make([]string, 0) 708 709 for scanner.Scan() { 710 s := scanner.Text() 711 712 if strings.HasPrefix(s, "*") { 713 break 714 } 715 716 //コメントを読み飛ばす 717 st := strings.IndexRune(s, '!') 718 if st != -1 { 719 s = s[:st] 720 } 721 722 //ゴミ除去 723 s = strings.TrimSpace(s) 724 725 if s != "" { 726 N = append(N, s) 727 } 728 } 729 730 return N 731 }