github.com/archlabjp/eeslism-go@v0.0.0-20231109122333-4bb7bfcdf292/eeslism/blpcm.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 "fmt" 21 "math" 22 "os" 23 "strconv" 24 "strings" 25 ) 26 27 /* 壁体デ-タの入力 */ 28 29 func PCMdata(fi *EeTokens, dsn string, pcm *[]*PCM, pcmiterate *rune) { 30 N := PCMcount(fi) 31 32 s := "PCMdata --" 33 34 if N > 0 { 35 *pcm = make([]*PCM, N) 36 37 for j := 0; j < N; j++ { 38 var PCMa = new(PCM) 39 40 PCMa.Name = "" 41 PCMa.Condl = -999.0 42 PCMa.Conds = -999.0 43 PCMa.Crol = -999.0 44 PCMa.Cros = -999.0 45 PCMa.Ql = -999.0 46 PCMa.Tl = -999.0 47 PCMa.Ts = -999.0 48 PCMa.Tp = -999.0 49 50 PCMa.Iterate = false // 収束なしがデフォルト 51 //PCMa.iterateTemp = false // デフォルトは見かけの比熱だけで収束 52 PCMa.IterateTemp = true 53 PCMa.NWeight = 0.5 // 収束計算時の現在ステップ温度の重み係数 54 PCMa.AveTemp = 'y' 55 PCMa.DivTemp = 1 56 PCMa.Ctype = 2 // 二等辺三角形がデフォルト 57 // パラメータの初期化 58 PCMa.PCMp.a = -999.0 59 PCMa.PCMp.B = -999.0 60 PCMa.PCMp.b = -999.0 61 PCMa.PCMp.bl = -999.0 62 PCMa.PCMp.bs = -999.0 63 PCMa.PCMp.c = -999.0 64 PCMa.PCMp.d = -999.0 65 PCMa.PCMp.e = -999.0 66 PCMa.PCMp.f = -999.0 67 PCMa.PCMp.omega = -999.0 68 PCMa.PCMp.skew = -999.0 69 PCMa.PCMp.T = -999.0 70 PCMa.IterateJudge = 0.05 // 収束判定条件は前ステップ見かけの比熱の5% 71 PCMa.Spctype = 'm' // モデル形式をデフォルトとする 72 PCMa.Condtype = 'm' 73 74 ct := &PCMa.Chartable 75 ct[0].PCMchar = 'E' // 引数0はエンタルピー 76 ct[1].PCMchar = 'C' // 引数1は熱伝導率 77 for i := 0; i < 2; i++ { 78 ct[i].itablerow = 0 79 ct[i].T = nil 80 ct[i].Chara = nil 81 ct[i].filename = "" 82 ct[i].tabletype = 'e' 83 ct[i].fp = nil 84 ct[i].lowA = 0.0 85 ct[i].lowB = 0.0 86 ct[i].upA = 0.0 87 ct[i].upB = 0.0 88 ct[i].minTempChng = 0.5 // 最低温度変動幅 89 } 90 91 (*pcm)[j] = PCMa 92 } 93 } 94 95 for i := 0; i < N; i++ { 96 97 PCMa := (*pcm)[i] 98 99 s = fi.GetToken() 100 101 if s[0] == '*' { 102 break 103 } 104 105 PCMa.Name = s // PCM名称 106 107 for { 108 s = fi.GetToken() 109 110 ce := strings.IndexByte(s, ';') 111 if ce >= 0 { 112 s = s[:ce] 113 } 114 if st := strings.IndexByte(s, '='); st >= 0 { 115 dt, _ := strconv.ParseFloat(s[st+1:], 64) 116 if strings.HasPrefix(s, "Ql") { // 潜熱量[J/m3] 117 PCMa.Ql = dt 118 } else if strings.HasPrefix(s, "spcheattable") { 119 PCMa.Chartable[0].filename = s[st+1:] 120 PCMa.Spctype = 't' 121 } else if strings.HasPrefix(s, "table") { 122 if s[st+1] == 'e' { 123 PCMa.Chartable[0].tabletype = 'e' 124 } else if s[st+1] == 'h' { 125 PCMa.Chartable[0].tabletype = 'h' 126 } 127 } else if strings.HasPrefix(s, "conducttable") { 128 PCMa.Chartable[1].filename = s[st+1:] 129 PCMa.Condtype = 't' 130 } else if strings.HasPrefix(s, "minTempChange") { 131 PCMa.Chartable[0].minTempChng = dt 132 PCMa.Chartable[1].minTemp = dt 133 } else if strings.HasPrefix(s, "Condl") { // 液相熱伝導率[W/mK] 134 PCMa.Condl = dt 135 } else if strings.HasPrefix(s, "Conds") { // 固相熱伝導率[W/mK] 136 PCMa.Conds = dt 137 } else if strings.HasPrefix(s, "Crol") { // 液相容積比熱[J/m3K] 138 PCMa.Crol = dt 139 } else if strings.HasPrefix(s, "Cros") { // 固相容積比熱[J/m3K] 140 PCMa.Cros = dt 141 } else if strings.HasPrefix(s, "Tl") { // 液体から凝固が始まる温度[℃] 142 PCMa.Tl = dt 143 } else if strings.HasPrefix(s, "Ts") { // 固体から融解が始まる温度[℃] 144 PCMa.Ts = dt 145 } else if strings.HasPrefix(s, "Tp") { // 見かけの比熱のピーク温度[℃] 146 PCMa.Tp = dt 147 } else if strings.HasPrefix(s, "DivTemp") { // 比熱数値積分時の温度分割数 148 PCMa.DivTemp = int(dt) 149 } else if strings.HasPrefix(s, "Ctype") { // 見かけの比熱の特性曲線番号 150 PCMa.Ctype = int(dt) 151 } else if strings.HasPrefix(s, "a") { // これ以降は見かけの比熱計算のためのパラメータ 152 PCMa.PCMp.a = dt 153 } else if strings.HasPrefix(s, "b=") { 154 PCMa.PCMp.b = dt 155 } else if strings.HasPrefix(s, "c") { 156 PCMa.PCMp.c = dt 157 } else if strings.HasPrefix(s, "d") { 158 PCMa.PCMp.d = dt 159 } else if strings.HasPrefix(s, "e") { 160 PCMa.PCMp.e = dt 161 } else if strings.HasPrefix(s, "f") { 162 PCMa.PCMp.f = dt 163 } else if strings.HasPrefix(s, "B") { 164 PCMa.PCMp.B = dt 165 } else if strings.HasPrefix(s, "T") { 166 PCMa.PCMp.T = dt 167 } else if strings.HasPrefix(s, "bs") { 168 PCMa.PCMp.bs = dt 169 } else if strings.HasPrefix(s, "bl") { 170 PCMa.PCMp.bl = dt 171 } else if strings.HasPrefix(s, "skew") { 172 PCMa.PCMp.skew = dt 173 } else if strings.HasPrefix(s, "omega") { 174 PCMa.PCMp.omega = dt 175 } else if strings.HasPrefix(s, "nWieght") { 176 PCMa.NWeight = dt 177 } else if strings.HasPrefix(s, "IterateJudge") { 178 PCMa.IterateJudge = dt 179 } else { 180 Eprint("<PCMdata>", s) 181 } 182 } else { 183 if s == "-iterate" { 184 PCMa.Iterate = true 185 *pcmiterate = 'y' 186 } else if s == "-pcmnode" { 187 PCMa.AveTemp = 'n' 188 } else { 189 Eprint("<PCMdata>", s) 190 } 191 } 192 193 if ce != -1 { 194 break 195 } 196 } 197 198 // テーブルの読み込み(見かけの比熱) 199 if PCMa.Spctype == 't' { 200 TableRead(&PCMa.Chartable[0]) 201 } 202 203 // テーブルの読み込み(熱伝導率) 204 if PCMa.Condtype == 't' { 205 TableRead(&PCMa.Chartable[1]) 206 } 207 208 // 入力情報のチェック 209 if PCMa.Spctype == 'm' { 210 var Tin, Bin, bsin, blin, skewin, omegain, ain, bin, cin, din, ein, fin int 211 var Qlin, Condlin, Condsin, Crolin, Crosin, Tlin, Tsin, Tpin int 212 213 Tin = dparaminit(PCMa.PCMp.T) 214 Bin = dparaminit(PCMa.PCMp.B) 215 bsin = dparaminit(PCMa.PCMp.bs) 216 blin = dparaminit(PCMa.PCMp.bl) 217 skewin = dparaminit(PCMa.PCMp.skew) 218 omegain = dparaminit(PCMa.PCMp.omega) 219 ain = dparaminit(PCMa.PCMp.a) 220 bin = dparaminit(PCMa.PCMp.b) 221 cin = dparaminit(PCMa.PCMp.c) 222 din = dparaminit(PCMa.PCMp.d) 223 ein = dparaminit(PCMa.PCMp.e) 224 fin = dparaminit(PCMa.PCMp.f) 225 Qlin = dparaminit(PCMa.Ql) 226 Condlin = dparaminit(PCMa.Condl) 227 Condsin = dparaminit(PCMa.Conds) 228 Crolin = dparaminit(PCMa.Crol) 229 Crosin = dparaminit(PCMa.Cros) 230 Tlin = dparaminit(PCMa.Tl) 231 Tsin = dparaminit(PCMa.Ts) 232 Tpin = dparaminit(PCMa.Tp) 233 234 // 必須入力項目のチェック 235 if Condlin+Condsin+Crolin+Crosin+Tlin+Tsin != 0 { 236 fmt.Printf("<PCMdata> name=%s Condl=%f Conds=%f Crol=%f Cros=%f Tl=%f Ts=%f\n", 237 PCMa.Name, PCMa.Condl, PCMa.Conds, PCMa.Crol, PCMa.Cros, PCMa.Tl, PCMa.Ts) 238 } 239 240 // モデルごとに入力値をチェックする 241 if PCMa.Ctype == 1 || PCMa.Ctype == 2 { 242 if Qlin+Tsin+Tlin != 0 { 243 fmt.Printf("<PCMdata> name=%s Ql=%f Ts=%f Tl=%f\n", 244 PCMa.Name, PCMa.Ql, PCMa.Ts, PCMa.Tl) 245 } 246 } else if PCMa.Ctype == 3 { 247 if Qlin+Tpin+Tin+Bin != 0 { 248 fmt.Printf("<PCMdata> name=%s Ql=%f Tp=%f T=%f B=%f\n", 249 PCMa.Name, PCMa.Ql, PCMa.Tp, PCMa.PCMp.T, PCMa.PCMp.B) 250 } 251 } else if PCMa.Ctype == 4 { 252 if Tpin+ain+bin != 0 { 253 fmt.Printf("<PCMdata> name=%s Tp=%f a=%f b=%f\n", 254 PCMa.Name, PCMa.Tp, PCMa.PCMp.a, PCMa.PCMp.b) 255 } 256 } else if PCMa.Ctype == 5 { 257 if Tpin+bsin+blin+ain != 0 { 258 fmt.Printf("<PCMdata> name=%s Tp=%f bs=%f bl=%f a=%f\n", 259 PCMa.Name, PCMa.Tp, PCMa.PCMp.bs, PCMa.PCMp.bl, PCMa.PCMp.a) 260 } 261 } else if PCMa.Ctype == 6 { 262 if Qlin+Tpin+skewin+omegain != 0 { 263 fmt.Printf("<PCMdata> name=%s Ql=%f Tp=%f skew=%f omega=%f\n", 264 PCMa.Name, PCMa.Ql, PCMa.Tp, PCMa.PCMp.skew, PCMa.PCMp.omega) 265 } 266 } else if PCMa.Ctype == 7 { 267 if ain+bin+cin+din+ein+fin != 0 { 268 fmt.Printf("<PCMdata> name=%s a=%f b=%f c=%f d=%f e=%f f=%f\n", 269 PCMa.Name, PCMa.PCMp.a, PCMa.PCMp.b, PCMa.PCMp.c, PCMa.PCMp.d, PCMa.PCMp.e, PCMa.PCMp.f) 270 } 271 } 272 } 273 } 274 } 275 276 // PCMの物性値テーブルの読み込み 277 func TableRead(ct *CHARTABLE) { 278 if ct.filename == "" { 279 return 280 } 281 282 fp, err := os.Open(ct.filename) 283 if err != nil { 284 fmt.Printf("<PCMdata> xxxx file not found %s xxxx\n", ct.filename) 285 return 286 } 287 ct.fp = fp 288 289 // 設定されている行数を数える 290 var c byte 291 var row int 292 row = 0 293 294 // Count the number of rows 295 for { 296 _, err := fmt.Fscanf(ct.fp, "%c", &c) 297 if err != nil { 298 break 299 } 300 if c == '\n' { 301 row++ 302 } 303 } 304 305 // Close the file temporarily 306 err = ct.fp.Close() 307 if err != nil { 308 fmt.Println("<PCMdata> ファイルのクローズに失敗") 309 return 310 } 311 312 // Allocate memory 313 ct.T = make([]float64, row) 314 ct.Chara = make([]float64, row) 315 if ct.T == nil || ct.Chara == nil { 316 fmt.Println("<PCMdata> メモリの確保に失敗") 317 } 318 319 // Reopen the file 320 fp, err = os.Open(ct.filename) 321 if err != nil { 322 fmt.Println("<PCMdata> ファイルのオープンに失敗") 323 return 324 } 325 ct.fp = fp 326 327 var st, tt int 328 var spheat, prevheat, prevTemp float64 329 prevheat = 0.0 330 prevTemp = -999.0 331 spheat = 0.0 332 333 for i := 0; i < row; i++ { 334 T := &ct.T[i] 335 Char := &ct.Chara[i] 336 337 // 温度の読み込み 338 _, err := fmt.Fscanf(ct.fp, " %f ", T) 339 if err != nil { 340 fmt.Println("<PCMdata> 温度の読み込みに失敗") 341 break 342 } 343 // テーブルの下限温度 344 if st == 0 { 345 ct.minTemp = *T 346 prevTemp = *T 347 st = 1 348 } 349 // 昇順に並んでいないときのエラー表示 350 if *T <= prevTemp && tt == 1 { 351 fmt.Printf("i=%d 温度データが昇順に並んでいません T=%f preT=%f\n", i, *T, prevTemp) 352 } 353 var dblTemp float64 354 // 特性値の読み込み 355 _, err = fmt.Fscanf(ct.fp, " %f ", &dblTemp) 356 if err != nil { 357 fmt.Println("<PCMdata> 特性値の読み込みに失敗") 358 break 359 } 360 *Char = dblTemp 361 // 見かけの比熱の場合 362 if ct.tabletype == 'h' { 363 *Char = prevheat + spheat*(*T-prevTemp) 364 } 365 prevheat = *Char 366 prevTemp = *T 367 spheat = dblTemp 368 // テーブルの上限温度 369 ct.maxTemp = *T 370 ct.itablerow++ 371 tt = 1 372 } 373 374 // Close the file 375 err = ct.fp.Close() 376 if err != nil { 377 fmt.Println("<PCMdata> ファイルのクローズに失敗") 378 } 379 380 // 上下限温度範囲以外の線形回帰式を作成 381 // 下限以下 382 ct.lowA = (ct.Chara[0] - ct.Chara[1]) / (ct.T[0] - ct.T[1]) 383 ct.lowB = ct.Chara[0] - ct.lowA*ct.T[0] 384 // 上限以上 385 ct.upA = (ct.Chara[ct.itablerow-1] - ct.Chara[ct.itablerow-2]) / (ct.T[ct.itablerow-1] - ct.T[ct.itablerow-2]) 386 ct.upB = ct.Chara[ct.itablerow-1] - ct.upA*ct.T[ct.itablerow-1] 387 } 388 389 // 初期化されているかをチェックする 390 func dparaminit(A float64) int { 391 if math.Abs(A-(-999.0)) < 1e-5 { 392 return 1 393 } else { 394 return 0 395 } 396 } 397 398 func PCMcount(fi *EeTokens) int { 399 N := 0 400 add := fi.GetPos() 401 402 for fi.IsEnd() == false { 403 s := fi.GetToken() 404 if strings.HasPrefix(s, "*") { 405 break 406 } 407 if strings.HasPrefix(s, ";") { 408 N++ 409 } 410 } 411 412 fi.RestorePos(add) 413 return N 414 } 415 416 // 固相、液相物性値と潜熱量からPCM温度の物性値を計算する(比熱、熱伝導率共通) 417 // 熱伝導率の計算時はQl=0とする 418 func FNPCMState(Ctype int, Ss, Sl, Ql, Ts, Tl, Tp, T float64, PCMp *PCMPARAM) float64 { 419 var Qse, Qla, Tls float64 420 421 Tls = Tl - Ts 422 // 顕熱分の補間 423 if T > Ts && T < Tl { 424 Qse = Ss + (Sl-Ss)/Tls*(T-Ts) 425 } else if T <= Ts { 426 Qse = Ss 427 } else { 428 Qse = Sl 429 } 430 431 // 潜熱分の補間 432 Qla = 0.0 433 434 Ql = 0.0 435 436 // 熱伝導率計算の場合は潜熱ゼロ 437 if Ctype == 0 { 438 Qla = 0.0 439 } else if Ctype == 1 { // 潜熱変化域潜熱比熱一定 440 if T > Ts && T < Tl { 441 Qla = Ql / (Tl - Ts) 442 } 443 } else if Ctype == 2 { // 二等辺三角形 444 if T > Ts && T < Tl { 445 if T < (Tl+Ts)/2.0 { 446 Qla = 4.0 * Ql / (Tls * Tls) * (T - Ts) 447 } else { 448 Qla = 4.0 * Ql / (Tls * Tls) * (Tl - T) 449 } 450 } 451 } else if Ctype == 3 { // 双曲線関数 452 Temp := math.Cosh((2.0 * PCMp.B / PCMp.T) * (T - Tp)) 453 Qla = 0.5 * Ql * (2.0 * PCMp.B / PCMp.T) / (Temp * Temp) 454 } else if Ctype == 4 { // ガウス関数(対象) 455 Temp := (T - Tp) / PCMp.B 456 Qla = PCMp.a * math.Exp(-0.5*Temp*Temp) 457 } else if Ctype == 5 { // ガウス関数(非対称) 458 Temp := (T - Tp) / PCMp.B 459 if T <= Tp { 460 Temp = PCMp.bs 461 } else { 462 Temp = PCMp.bl 463 } 464 Qla = PCMp.a * math.Exp(-((T-Tp)/Temp)*((T-Tp)/Temp)) 465 } else if Ctype == 6 { // 誤差関数歪度 466 //Temp := math.Exp(-(T - Tp) * (T - Tp) / ((2.0 * PCMp.omega) * PCMp.omega)) 467 Qla = Ql / math.Sqrt(2.0*math.Pi) * math.Exp(-(T-Tp)*(T-Tp)/((2.0*PCMp.omega)*PCMp.omega)) * (1.0 + math.Erf(PCMp.skew*(T-Tp)/(math.Sqrt(2.0)*PCMp.omega))) 468 } else if Ctype == 7 { // 有理関数 469 if T < 0 { 470 Qla = 0.0 471 } else { 472 Qla = math.Pow(T, PCMp.f) * (PCMp.a*T*T + PCMp.B*T + PCMp.c) / (PCMp.d*T*T + PCMp.e*T + 1.0) 473 } 474 } 475 476 return (Qse + Qla) 477 } 478 479 /* ------------------------------------------------------ */ 480 481 // PCMの状態値計算(家具用) 482 483 func FNPCMStatefun(Ctype int, Ss, Sl, Ql, Ts, Tl, Tp, oldT, T float64, DivTemp int, PCMp *PCMPARAM) float64 { 484 var dblTemp, dTemp, TPCM, Qld, Qllst float64 485 dTemp = (T - oldT) / float64(DivTemp) 486 487 Qllst = 0.0 488 // 前時刻からの温度変化が小さい場合は時間積分はしない 489 if math.Abs(T-oldT) < 1e-4 { 490 Qllst = FNPCMState(Ctype, Ss, Sl, Ql, Ts, Tl, Tp, (T+oldT)*0.5, PCMp) 491 } else { 492 // 見かけの比熱の時間積分 493 for i := 0; i < DivTemp+1; i++ { 494 TPCM = oldT + dTemp*float64(i) 495 Qld = FNPCMState(Ctype, Ss, Sl, Ql, Ts, Tl, Tp, TPCM, PCMp) 496 dblTemp += Qld 497 } 498 499 Qllst = dblTemp / float64(DivTemp+1) 500 } 501 502 return Qllst 503 } 504 505 // PCMの温度から見かけの比熱を求める(テーブル形式) 506 // Told:前時刻のPCM温度、T:暫定現在時刻PCM温度 507 func FNPCMstate_table(ct *CHARTABLE, Told, T float64, Ndiv int) float64 { 508 var oldEn, En, Chara float64 509 510 // 前時刻と暫定現在時刻のPCM温度が同温の場合 511 if math.Abs(T-Told) < ct.minTempChng { 512 Tave := 0.5 * (T + Told) 513 // 見かけの比熱の計算 514 if ct.PCMchar == 'E' { 515 oldEn = FNPCMenthalpy_table_lib(ct, Tave-0.5*ct.minTempChng) 516 En = FNPCMenthalpy_table_lib(ct, Tave+0.5*ct.minTempChng) 517 // 見かけの比熱の計算 518 Chara = (En - oldEn) / ct.minTempChng 519 } else { 520 // 熱伝導率の計算 521 Chara = FNPCMenthalpy_table_lib(ct, Tave) 522 } 523 } else { 524 if ct.PCMchar == 'E' { 525 oldEn = FNPCMenthalpy_table_lib(ct, Told) 526 En = FNPCMenthalpy_table_lib(ct, T) 527 // 見かけの比熱の計算 528 Chara = (En - oldEn) / (T - Told) 529 } else { 530 // 熱伝導率の計算 531 var dblTemp, Tpcm, dTemp float64 532 dblTemp = 0.0 533 dTemp = (T - Told) / float64(Ndiv) 534 // ToldからTまでを積分する 535 for i := 0; i < Ndiv; i++ { 536 Tpcm = Told + dTemp*float64(i) 537 dblTemp += FNPCMenthalpy_table_lib(ct, Tpcm) 538 } 539 Chara = dblTemp / float64(Ndiv+1) 540 } 541 } 542 543 return Chara 544 } 545 546 func FNPCMenthalpy_table_lib(ct *CHARTABLE, T float64) float64 { 547 var prevTpcm, Tpcm, enthalpy, preventhalpy *float64 548 var retVal float64 549 550 if T < ct.minTemp { 551 // テーブルの最低温度よりPCM温度が低い場合は端部の特性値を線形で外挿 552 retVal = ct.lowA*T + ct.lowB 553 } else if T > ct.maxTemp { 554 //テーブルの最高温度よりPCM温度が高い場合は端部の特性値を線形で外挿 555 retVal = ct.upA*T + ct.upB 556 } else { 557 for i := 0; i < ct.itablerow; i++ { 558 559 Tpcm := &ct.T[i] 560 enthalpy := &ct.Chara[i] 561 562 if *Tpcm > T { 563 break 564 } 565 prevTpcm = Tpcm 566 preventhalpy = enthalpy 567 } 568 // 線形補間 569 retVal = *preventhalpy + (*enthalpy-*preventhalpy)*(T-*prevTpcm)/(*Tpcm-*prevTpcm) 570 } 571 572 return retVal 573 }