github.com/archlabjp/eeslism-go@v0.0.0-20231109122333-4bb7bfcdf292/eeslism/blwall.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 /* bl_wall.c */ 17 package eeslism 18 19 import ( 20 "fmt" 21 "strconv" 22 "strings" 23 ) 24 25 /* ------------------------------------------ */ 26 27 /* 壁体後退差分計算準備 */ 28 29 func Walli(Nbm int, W []BMLST, Wl *WALL, pcm []*PCM) { 30 // int i, j, k, m, N, M; 31 // double Rwall, *C, *Rw, CAPwall; 32 var BM *BMLST 33 var err error 34 // WELM *Welm; 35 // PCM *PCMcat = nil; 36 // char E[SCHAR], *st, *s, *PCMcode; 37 // double *PCMrate; 38 39 Wl.R = nil 40 Wl.CAP = nil 41 BM = nil 42 43 Rwall := 0.0 44 CAPwall := 0.0 45 46 Wl.R = make([]float64, Wl.N) 47 Wl.CAP = make([]float64, Wl.N) 48 Wl.PCM = make([]*PCM, Wl.N) 49 Wl.PCMrate = make([]float64, Wl.N) 50 51 for jj := 0; jj < Wl.N; jj++ { 52 Wl.PCM[jj] = nil 53 Wl.PCMrate[jj] = -999.0 54 } 55 56 var i int 57 for i = 0; i < Wl.N; i++ { 58 Welm := &Wl.welm[i] 59 Rw := &Wl.R[i] 60 C := &Wl.CAP[i] 61 PCMrate := &Wl.PCMrate[i] 62 63 // PCM内蔵建材かどうかをチェックする 64 st := strings.IndexRune(Welm.Code, '(') 65 if st != -1 { 66 // フォーマット code(PCMcode_VolRate) 67 code := Welm.Code[:st] 68 PCMcode := Welm.Code[st+1:] 69 st = strings.IndexRune(PCMcode, '_') 70 if st == -1 { 71 panic("PCMの含有率が指定されていません。") 72 } 73 PCMname := PCMcode[:st] // PCM名称 74 *PCMrate, err = strconv.ParseFloat(PCMcode[st+1:len(PCMcode)-1], 64) // PCM含有率(Vol) 75 if err != nil { 76 panic(err) 77 } 78 79 // PCMフラグ 80 Wl.PCMflg = true 81 82 // codeのコピー 83 Welm.Code = code // 基材のコード名のコピー 84 85 // PCMの検索 86 for k := range pcm { 87 PCMcat := pcm[k] 88 if PCMname == PCMcat.Name { 89 Wl.PCM[i] = PCMcat 90 break 91 } 92 } 93 } 94 95 var k int 96 for k = 0; k < Nbm; k++ { 97 BM = &W[k] 98 if Welm.Code == BM.Mcode { 99 break 100 } 101 } 102 103 if k == Nbm { 104 E := fmt.Sprintf("%s", Welm.Code) 105 Eprint("<Walli>", E) 106 } 107 108 // 熱伝導率、容積比熱のコピー 109 Welm.Cond = BM.Cond // 熱伝導率[W/mK] 110 Welm.Cro = BM.Cro * 1000. // 容積比熱[J/m3K] 111 if Welm.L > 0.0 { 112 *Rw = Welm.L / BM.Cond // Rw:熱抵抗[m2K/W]、L:厚さ[m] 113 } else { 114 *Rw = 1.0 / BM.Cond 115 } 116 117 // 熱容量[J/m2K 118 *C = BM.Cro * 1000. * Welm.L 119 120 if BM.Mcode != "ali" && BM.Mcode != "alo" { 121 Rwall += *Rw 122 CAPwall += *C 123 } 124 } 125 126 N := i 127 Wl.Rwall = Rwall 128 Wl.CAPwall = CAPwall 129 130 m := 0 131 M := 0 132 133 for i := 0; i < N; i++ { 134 Welm := &Wl.welm[i] 135 for j := 0; j <= Welm.ND; j++ { 136 M++ 137 } 138 } 139 140 Wl.res = make([]float64, M+2) 141 Wl.cap = make([]float64, M+2) 142 Wl.L = make([]float64, M+2) 143 144 // PCM構造体へのポインタのメモリ確保 145 Wl.PCMLyr = make([]*PCM, M+2) 146 Wl.PCMrateLyr = make([]float64, M+2) 147 148 for i := 0; i < N; i++ { 149 C := &Wl.CAP[i] 150 Rw := &Wl.R[i] 151 Welm := &Wl.welm[i] 152 PCMrate := &Wl.PCMrate[i] 153 154 for j := 0; j <= Welm.ND; j++ { 155 Wl.res[m] = *Rw / (float64(Welm.ND) + 1.) 156 Wl.cap[m] = *C / (float64(Welm.ND) + 1.) 157 if Welm.L > 0.0 { 158 Wl.L[m] = Welm.L / (float64(Welm.ND) + 1.) 159 } 160 if Wl.PCM[i] != nil { 161 Wl.PCMLyr[m] = Wl.PCM[i] 162 Wl.PCMrateLyr[m] = *PCMrate 163 } 164 165 m++ 166 } 167 } 168 Wl.M = m - 1 169 170 if Wl.Ip > 0 { 171 Wl.mp = Wl.Ip 172 for i := 1; i <= Wl.Ip; i++ { 173 Welm := &Wl.welm[i] 174 Wl.mp += Welm.ND 175 } 176 } else { 177 Wl.mp = -1 178 } 179 } 180 181 /* ------------------------------------------------- */ 182 183 /* 壁体後退差分計算用係数 */ 184 185 func Wallfdc(M int, mp int, res []float64, cap []float64, 186 Wp float64, UX []float64, 187 uo *float64, um *float64, Pc *float64, WallType WALLType, 188 Sd *RMSRF, Wd *WDAT, 189 Exsf *EXSFS, Wall *WALL, Told []float64, Twd []float64, _pcmstate []*PCMSTATE) { 190 var PCMf = 0 191 // double Croa; // 見かけの比熱 192 var ToldPCMave, ToldPCMNodeL, ToldPCMNodeR float64 193 194 Ul := make([]float64, M) 195 Ur := make([]float64, M) 196 captempL := make([]float64, M+1) 197 captempR := make([]float64, M+1) 198 199 // 層構成 200 for m := 0; m < M; m++ { 201 // PCM内蔵床暖房の計算に活用するためcapをコピーして保持 202 captempL[m] = cap[m] 203 captempR[m] = cap[m+1] 204 } 205 206 for m := 0; m < M; m++ { 207 PCMrate := Wall.PCMrateLyr[m] // PCM体積含有率 208 //Welm := &Wall.welm[m] 209 pcmstate := _pcmstate[m] 210 211 capm, capm1, resm, resm1 := 0.0, 0.0, 0.0, 0.0 212 PCM := Wall.PCMLyr[m] 213 PCM1 := Wall.PCMLyr[m+1] 214 215 if PCM == nil && PCM1 == nil { 216 // PCMなしの層 217 C := 0.5 * (cap[m] + cap[m+1]) 218 Ul[m] = DTM / (C * res[m]) 219 Ur[m] = DTM / (C * res[m+1]) 220 } else { 221 // どちらかにPCMがある場合 222 PCMf = 1 223 224 // 相変化温度を考慮した物性値の計算 225 226 // m点の左にPCMがある場合 227 if PCM != nil { 228 pcmstate.TempPCMave = (Twd[m-1] + Twd[m]) * 0.5 229 pcmstate.TempPCMNodeL = Twd[m-1] 230 pcmstate.TempPCMNodeR = Twd[m] 231 232 // PCM温度 233 var T, Toldn float64 234 if PCM.AveTemp == 'y' { 235 T = pcmstate.TempPCMave 236 Toldn = ToldPCMave 237 } else { 238 T = pcmstate.TempPCMNodeR 239 Toldn = ToldPCMNodeR 240 } 241 //pcmstate.tempPCM = T; 242 // m層の見かけの比熱 243 244 var Croa float64 245 if PCM.Spctype == 'm' { 246 Croa = FNPCMStatefun(PCM.Ctype, PCM.Cros, PCM.Crol, PCM.Ql, PCM.Ts, PCM.Tl, PCM.Tp, Toldn, T, PCM.DivTemp, &PCM.PCMp) 247 } else { 248 Croa = FNPCMstate_table(&PCM.Chartable[0], Toldn, T, PCM.DivTemp) 249 } 250 if Croa < 0.0 { 251 fmt.Printf("Croa=%f\n", Croa) 252 } 253 254 pcmstate.CapmR = Croa 255 capm = Croa * Wall.L[m] 256 257 // m層の熱抵抗(見かけの比熱特性Typeはダミー値0) 258 var lamda float64 259 if PCM.Condtype == 'm' { 260 lamda = FNPCMStatefun(0, PCM.Conds, PCM.Condl, 0., PCM.Ts, PCM.Tl, PCM.Tp, Toldn, T, PCM.DivTemp, &PCM.PCMp) 261 } else { 262 lamda = FNPCMstate_table(&PCM.Chartable[1], Toldn, T, PCM.DivTemp) 263 } 264 pcmstate.OldLamdaR = lamda 265 pcmstate.LamdaR = lamda 266 resm = Wall.L[m] / lamda 267 } 268 269 // m点の右にPCMがある場合 270 if PCM1 != nil { 271 pcmstate1 := _pcmstate[m+1] 272 pcmstate1.TempPCMave = (Twd[m] + Twd[m+1]) * 0.5 273 pcmstate1.TempPCMNodeL = Twd[m] 274 pcmstate1.TempPCMNodeR = Twd[m+1] 275 ToldPCMave = (Told[m-1] + Told[m]) * 0.5 276 ToldPCMNodeL = Told[m] 277 //ToldPCMNodeR := Told[m+1] 278 279 // PCM温度 280 var T, Toldn float64 281 if PCM1.AveTemp == 'y' { 282 T = pcmstate1.TempPCMave 283 Toldn = ToldPCMave 284 } else { 285 T = pcmstate1.TempPCMNodeL 286 Toldn = ToldPCMNodeL 287 } 288 289 // m層の見かけの比熱 290 var Croa float64 291 if PCM1.Spctype == 'm' { 292 Croa = FNPCMStatefun(PCM1.Ctype, PCM1.Cros, PCM1.Crol, PCM1.Ql, PCM1.Ts, PCM1.Tl, PCM1.Tp, Toldn, T, PCM1.DivTemp, &PCM1.PCMp) 293 } else { 294 Croa = FNPCMstate_table(&PCM1.Chartable[0], Toldn, T, PCM1.DivTemp) 295 } 296 if Croa < 0. { 297 fmt.Printf("Croa=%f\n", Croa) 298 } 299 300 pcmstate1.CapmL = Croa 301 capm1 = Croa * Wall.L[m+1] 302 303 // m層の熱抵抗(見かけの比熱特性Typeはダミー値0) 304 var lamda float64 305 if PCM1.Condtype == 'm' { 306 lamda = FNPCMStatefun(0, PCM1.Conds, PCM1.Condl, 0., PCM1.Ts, PCM1.Tl, PCM1.Tp, Toldn, T, PCM1.DivTemp, &PCM1.PCMp) 307 } else { 308 lamda = FNPCMstate_table(&PCM1.Chartable[1], Toldn, T, PCM1.DivTemp) 309 } 310 pcmstate1.OldLamdaL = lamda 311 pcmstate1.LamdaL = lamda 312 resm1 = Wall.L[m+1] / lamda 313 } 314 315 // PCMと基材との含有率による重みづけ平均 316 PCMrate1 := Wall.PCMrateLyr[m+1] // PCM体積含有率 317 318 captempL[m] = cap[m]*(1.-PCMrate) + capm*PCMrate 319 captempR[m] = cap[m+1]*(1.-PCMrate1) + capm1*PCMrate1 320 C := 0.5 * (captempL[m] + captempR[m]) 321 Ul[m] = DTM / (C * (res[m]*(1.-PCMrate) + resm*PCMrate)) 322 Ur[m] = DTM / (C * (res[m+1]*(1.-PCMrate1) + resm1*PCMrate1)) 323 } 324 } 325 326 for m := 0; m < M; m++ { 327 for j := 0; j < M; j++ { 328 UX[m*M+j] = 0. 329 } 330 } 331 332 UX[0] = 1.0 + Ul[0] + Ur[0] 333 for m := 1; m < M; m++ { 334 UX[m*M+m] = 1.0 + Ul[m] + Ur[m] // 対角要素 335 UX[m*M+m-1] = -Ul[m] // 対角要素の下 336 UX[(m-1)*M+m] = -Ur[m-1] // 対角要素の右 337 } 338 339 if Wp > 0.0 { 340 if WallType == 'P' { 341 // 床暖房等放射パネル 342 *Pc = DTM / (0.5 * (captempL[mp] + captempR[mp])) 343 UX[mp*M+mp] += Wp * *Pc 344 } else { 345 // 建材一体型空気集熱器の場合 346 //double ECG, ECt, CFc; 347 //WALL *Wall; 348 //Wall := Sd.mw.wall 349 350 *Pc = DTM / (0.5 * captempL[mp]) 351 352 // 境界条件の計算 353 ECG, ECt, CFc := 0.0, 0.0, 0.0 354 FNBoundarySolarWall(Sd, &ECG, &ECt, &CFc) 355 356 UX[mp*M+mp] = 1. - *Pc*ECt + Ul[mp] 357 358 Sd.ColCoeff = *Pc * CFc 359 } 360 } else { 361 if WallType == 'C' { 362 // double ECG, ECt, CFc; 363 // WALL *Wall; 364 365 //Wall := Sd.mw.wall 366 *Pc = DTM / (0.5 * captempL[mp]) 367 368 // 境界条件の計算 369 ECG, ECt, CFc := 0.0, 0.0, 0.0 370 FNBoundarySolarWall(Sd, &ECG, &ECt, &CFc) 371 UX[mp*M+mp] = 1. - *Pc*ECt + Ul[mp] 372 Sd.ColCoeff = *Pc * CFc 373 } 374 375 *Pc = 0.0 376 } 377 378 *uo = Ul[0] 379 *um = Ur[M-1] 380 381 if PCMf == 5 { 382 /*************/ 383 fmt.Printf(" Wallfdc -- U --\n") 384 Matprint(" %12.8f", M, UX) 385 fmt.Printf("\nuo=%f um=%f\n", *uo, *um) 386 fmt.Printf("mp=%d Pc=%f\n", mp, *Pc) 387 /***********/ 388 } 389 390 Matinv(UX, M, M, "<Wallfdc>") 391 392 /*********************/ 393 if PCMf == 5 { 394 fmt.Printf("\n Wallfdc-- inv(U) --\n") 395 Matprint("%12.8f", M, UX) 396 } 397 /*********************/ 398 } 399 400 /* --------------------------------------------- */ 401 402 /* 後退差分による壁体表面、内部温度の計算 */ 403 func Twall(M, mp int, UX []float64, uo, um, Pc, Ti, To, WpT float64, Told, Tw []float64, Sd *RMSRF, pcm []*PCM) { 404 // 前時刻の壁体内部温度のコピー 405 Ttemp := make([]float64, M) 406 Toldcalc := make([]float64, M) 407 copy(Ttemp, Told) 408 copy(Toldcalc, Told) 409 410 Toldcalc[0] += uo * Ti 411 412 if Sd.mw.wall.WallType != WallType_C { 413 Toldcalc[M-1] += um * To 414 } else { 415 Toldcalc[M-1] += Sd.ColCoeff * To 416 } 417 418 if Pc > 0.0 { 419 Toldcalc[mp] += Pc * WpT 420 } 421 422 for m := 0; m < M; m++ { 423 Tw[m] = 0.0 424 for j := 0; j < M; j++ { 425 Tw[m] += UX[m*M+j] * Toldcalc[j] 426 } 427 } 428 429 // 建材一体型集熱器の集熱器と建材の境界温度 430 if Sd.mw.wall.WallType == WallType_C { 431 Sd.oldTx = Tw[mp] 432 } 433 434 // PCMの温度飛び越えのチェック 435 for m := 0; m < M; m++ { 436 PCMLyr := pcm[m] 437 if PCMLyr != nil { 438 // 現在時刻のPCM温度 439 Tpcm := (Tw[m-1] + Tw[m]) * 0.5 440 441 // 前時刻のPCM温度 442 Tpcmold := (Ttemp[m-1] + Ttemp[m]) * 0.5 443 444 // 壁体温度が潜熱領域をまたいだかチェック 445 if PCMLyr.Iterate == false && ((PCMLyr.Ts > Tpcmold && PCMLyr.Tl < Tpcm) || (PCMLyr.Tl < Tpcmold && PCMLyr.Ts > Tpcm)) { 446 fmt.Printf("xxxx 壁体温度が潜熱領域をまたぎました Tpcm=%.1f Tpcmold=%.1f\n", Tpcm, Tpcmold) 447 } 448 } 449 } 450 } 451 452 /* --------------------------------------------- */ 453 454 /* 後退差分による壁体表面、内部温度の計算 */ 455 // PCM収束計算過程のチェック用 456 457 func Twalld(M, mp int, UX []float64, uo, um, Pc, Ti, To, WpT float64, Told, Twd []float64, Sd *RMSRF) { 458 // 収束計算過程なので、前時刻の計算結果が変わらないようにバックアップ 459 Toldtemp := make([]float64, M) 460 copy(Toldtemp, Told) 461 462 Toldtemp[0] += uo * Ti 463 464 if Sd.mw.wall.WallType != WallType_C { 465 Toldtemp[M-1] += um * To 466 } else { 467 Toldtemp[M-1] += Sd.ColCoeff * To 468 } 469 470 if Pc > 0.0 { 471 Toldtemp[mp] += Pc * WpT 472 } 473 474 for m := 0; m < M; m++ { 475 Twd[m] = 0.0 476 for j := 0; j < M; j++ { 477 Twd[m] += UX[m*M+j] * Toldtemp[j] 478 } 479 } 480 }