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  }