github.com/archlabjp/eeslism-go@v0.0.0-20231109122333-4bb7bfcdf292/eeslism/bltcomfrt.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  /*   tcomfrt.c    */
    17  
    18  package eeslism
    19  
    20  import "math"
    21  
    22  /*   作用温度制御時の設定室内空気温度  */
    23  
    24  var __Rmotset_Pint int
    25  
    26  func Rmotset(_Room []*ROOM) {
    27  	Fotinit(_Room)
    28  
    29  	for i := range _Room {
    30  		Room := _Room[i]
    31  
    32  		Eo := Room.cmp.Elouts[0]
    33  		if Eo.Control == LOAD_SW {
    34  			rmld := Room.rmld
    35  
    36  			if rmld.tropt == 'o' {
    37  				Fotf(Room)
    38  
    39  				OT := rmld.Tset
    40  				a := OT - rmld.FOC
    41  
    42  				for j := 0; j < Room.Ntr; j++ {
    43  					trnx := Room.trnx[j]
    44  					a -= rmld.FOTN[j] * trnx.nextroom.Tr
    45  				}
    46  
    47  				for j := 0; j < Room.Nrp; j++ {
    48  					rmpnl := Room.rmpnl[j]
    49  
    50  					var Twi float64
    51  					if __Rmotset_Pint == 0 {
    52  						Twi = rmpnl.sd.mw.Tw[rmpnl.sd.mw.mp]
    53  						__Rmotset_Pint = 1
    54  					} else {
    55  						Twi = rmpnl.pnl.Tpi
    56  					}
    57  
    58  					a -= rmld.FOPL[j] * Twi
    59  				}
    60  
    61  				Trset := a / rmld.FOTr
    62  				Eo.Sysv = Trset
    63  				Room.Tr = Trset
    64  
    65  				if rmld.loadx != nil {
    66  					Eo = Room.cmp.Elouts[1]
    67  					if Eo.Control == LOAD_SW && rmld.hmopt == 'r' {
    68  						Eo.Sysv = FNXtr(Trset, rmld.Xset)
    69  					}
    70  				}
    71  			}
    72  		}
    73  	}
    74  }
    75  
    76  /* -------------------------------------- */
    77  
    78  var __Fotinit_init int = 'i'
    79  
    80  func Fotinit(_Room []*ROOM) {
    81  	if __Fotinit_init == 'i' {
    82  		for i := range _Room {
    83  			Room := _Room[i]
    84  			if Room.rmld != nil {
    85  				Room.rmld.FOTN = nil
    86  				Room.rmld.FOPL = nil
    87  
    88  				Room.rmld.FOTN = make([]float64, Room.Ntr)
    89  				Room.rmld.FOPL = make([]float64, Room.Nrp)
    90  			}
    91  		}
    92  		__Fotinit_init = 'x'
    93  	}
    94  }
    95  
    96  /* -------------------------------------- */
    97  func Fotf(Room *ROOM) {
    98  	var r float64
    99  	if Room.OTsetCwgt == nil || *(Room.OTsetCwgt) < 0.0 || *(Room.OTsetCwgt) > 1.0 {
   100  		r = 0.5
   101  	} else {
   102  		r = *(Room.OTsetCwgt)
   103  	}
   104  
   105  	{
   106  		var a, C float64
   107  		for i := 0; i < Room.N; i++ {
   108  			Sd := Room.rsrf[i]
   109  			a += Sd.A * Sd.WSR
   110  			C += Sd.A * Sd.WSC
   111  		}
   112  		Room.rmld.FOTr = r + (1.0-r)*a/Room.Area
   113  		Room.rmld.FOC = (1.0 - r) * C / Room.Area
   114  	}
   115  
   116  	for k := 0; k < Room.Ntr; k++ {
   117  		ft := &Room.rmld.FOTN[k]
   118  
   119  		var a float64
   120  		for i := 0; i < Room.N; i++ {
   121  			Sd := Room.rsrf[i]
   122  			a += Sd.A * Sd.WSRN[k]
   123  		}
   124  
   125  		*ft = (1.0 - r) * a / Room.Area
   126  	}
   127  
   128  	for k := 0; k < Room.Nrp; k++ {
   129  		ft := &Room.rmld.FOPL[k]
   130  
   131  		var a float64
   132  		for i := 0; i < Room.N; i++ {
   133  			Sd := Room.rsrf[i]
   134  			a += Sd.A * Sd.WSPL[k]
   135  		}
   136  
   137  		*ft = (1.0 - r) * a / Room.Area
   138  	}
   139  }
   140  
   141  /* -------------------------------------- */
   142  
   143  /*   各室の温熱環境指標計算  */
   144  
   145  func Rmcomfrt(_Room []*ROOM) {
   146  	met := 0.0
   147  	Icl := 0.0
   148  	v := 0.0
   149  
   150  	for i := range _Room {
   151  		id := 0
   152  		Room := _Room[i]
   153  		if Room.Metsch != nil && *Room.Metsch > 0.0 {
   154  			met = *Room.Metsch
   155  			id++
   156  		}
   157  		if Room.Closch != nil && *Room.Closch > 0.0 {
   158  			Icl = *Room.Closch
   159  			id++
   160  		}
   161  		if Room.Wvsch != nil && *Room.Wvsch > 0.0 {
   162  			v = *Room.Wvsch
   163  			id++
   164  		}
   165  
   166  		if id == 3 {
   167  			Room.PMV = Pmv0(met, Icl, Room.Tr, Room.xr, Room.Tsav, v)
   168  			Room.SET = SET_star(Room.Tr, Room.Tsav, v, Room.RH, met, Icl, 0.0, 101.3)
   169  		} else {
   170  			Room.PMV = -999.0
   171  		}
   172  		/*******************
   173  		fmt.Printf("**** Rmcomfrt  met=%.1f Icl=%.1f v=%.2f  Tr=%.1f  xr=%.4f Tmrt=%.1f  PMV=%.2f\n",
   174  			met, Icl, v, Room.Tr, Room.xr, Room.Tsav, Room.PMV)
   175  		*******************/
   176  	}
   177  }
   178  
   179  /* ----------------------------------------------------- */
   180  
   181  /*   PMVの計算     */
   182  
   183  func Pmv0(met, Icl, Tr, xr, Tmrt, v float64) float64 {
   184  	/* m [kcal.m2h] */
   185  
   186  	Po := 760.0
   187  	eta := 0.0
   188  
   189  	m := met * 50.0
   190  	Pa := xr * Po / (xr + 0.62198)
   191  	hc := 10.4 * math.Sqrt(v)
   192  	Tm := 0.5*(37.0+0.5*(Tr+Tmrt)) + 273.15
   193  	hr := 13.6e-8 * Tm * Tm * Tm
   194  	fcl := 1.0
   195  	if Icl < 0.5 {
   196  		fcl = 1.0 + 0.2*Icl
   197  	} else {
   198  		fcl = 1.05 + 0.1*Icl
   199  	}
   200  	Ifcl := 0.18 * Icl * fcl
   201  
   202  	tcl := (35.7 - 0.032*m*(1.0-eta) + Ifcl*(hr*Tmrt+hc*Tr)) / (1.0 + Ifcl*(hr+hc))
   203  
   204  	L := m*(0.60135-0.0023*(44.0-Pa)-0.0014*(34.0-Tr)) + 0.35*Pa + 5.95 - 0.6013*eta - fcl*(hr*(tcl-Tmrt)+hc*(tcl-Tr))
   205  
   206  	return (0.352*math.Exp(-0.042*m) + 0.032) * L
   207  }
   208  
   209  //	SET*の計算
   210  func SET_star(TA, TR, VEL, RH, MET, CLO, WME, PATM float64) float64 {
   211  	//Input doubleiables ? TA (air temperature): °C, TR (mean radiant temperature): °C, VEL (air velocity): m/s,
   212  	//RH (relative humidity): %, MET: met unit, CLO: clo unit, WME (external work): W/m2, PATM (atmospheric pressure): kPa
   213  	const KCLO = 0.25
   214  	const BODYWEIGHT = 69.9        //kg
   215  	const BODYSURFACEAREA = 1.8258 //m2
   216  	const METFACTOR = 58.2         //W/m2
   217  	const SBC = 0.000000056697     //Stefan-Boltzmann constant (W/m2K4)
   218  	const CSW = 170.0
   219  	const CDIL = 120.0
   220  	const CSTR = 0.5
   221  	const LTIME = 60
   222  	var PS = FindSaturatedVaporPressureTorr(TA)
   223  	var VaporPressure = RH * PS / 100.0
   224  	var AirVelocity = math.Max(VEL, 0.1)
   225  	const TempSkinNeutral = 33.7
   226  	const TempCoreNeutral = 36.49
   227  	const TempBodyNeutral = 36.49
   228  	const SkinBloodFlowNeutral = 6.3
   229  	var TempSkin = TempSkinNeutral //Initial values
   230  	var TempCore = TempCoreNeutral
   231  	var SkinBloodFlow = SkinBloodFlowNeutral
   232  	var MSHIV = 0.0
   233  	var ALFA = 0.1
   234  	var ESK = 0.1 * MET
   235  	// 桁落ちによる誤差を避けるため換算係数を変更
   236  	//double PressureInAtmospheres = PATM * 0.009869;
   237  	var PressureInAtmospheres = PATM / 101.3
   238  	var RCL = 0.155 * CLO
   239  	var FACL = 1.0 + 0.15*CLO
   240  	var LR = 2.2 / PressureInAtmospheres //Lewis Relation is 2.2 at sea level
   241  	var RM = MET * METFACTOR
   242  	var M = MET * METFACTOR
   243  	var ICL, WCRIT float64
   244  	if CLO <= 0 {
   245  		WCRIT = 0.38 * math.Pow(AirVelocity, -0.29)
   246  		ICL = 1.0
   247  	} else {
   248  		WCRIT = 0.59 * math.Pow(AirVelocity, -0.08)
   249  		ICL = 0.45
   250  	}
   251  	var CHC = 3.0 * math.Pow(PressureInAtmospheres, 0.53)
   252  	var CHCV = 8.600001 * math.Pow((AirVelocity*PressureInAtmospheres), 0.53)
   253  	CHC = math.Max(CHC, CHCV)
   254  	var CHR = 4.7
   255  	var CTC = CHR + CHC
   256  	var RA = 1.0 / (FACL * CTC) //Resistance of air layer to dry heat transfer
   257  	var TOP = (CHR*TR + CHC*TA) / CTC
   258  	var TCL = TOP + (TempSkin-TOP)/(CTC*(RA+RCL))
   259  	//TCL and CHR are solved iteratively using: H(Tsk - TOP) = CTC(TCL - TOP),
   260  	//where H = 1/(RA + RCL) and RA = 1/FACL*CTC
   261  	var TCL_OLD = TCL
   262  	var flag = true
   263  	var DRY, HFCS, ERES, CRES, SCR, SSK, TCSK, TCCR, DTSK, DTCR, TB, SKSIG, WARMS, COLDS, CRSIG, WARMC,
   264  		COLDC, BDSIG, WARMB, REGSW, EMAX float64
   265  	var PWET = 0.0
   266  
   267  	//Begin iteration
   268  	for TIM := 1; TIM <= LTIME; TIM++ {
   269  		for i := 0; i < 100; i++ {
   270  			if flag {
   271  				TCL_OLD = TCL
   272  				CHR = 4.0 * SBC * math.Pow(((TCL+TR)/2.0+273.15), 3.0) * 0.72
   273  				CTC = CHR + CHC
   274  				RA = 1.0 / (FACL * CTC) //Resistance of air layer to dry heat transfer
   275  				TOP = (CHR*TR + CHC*TA) / CTC
   276  			}
   277  			TCL = (RA*TempSkin + RCL*TOP) / (RA + RCL)
   278  			flag = true
   279  			if math.Abs(TCL-TCL_OLD) <= 0.01 {
   280  				break
   281  			}
   282  		}
   283  		flag = false
   284  		DRY = (TempSkin - TOP) / (RA + RCL)
   285  		HFCS = (TempCore - TempSkin) * (5.28 + 1.163*SkinBloodFlow)
   286  		ERES = 0.0023 * M * (44.0 - VaporPressure)
   287  		CRES = 0.0014 * M * (34.0 - TA)
   288  		SCR = M - HFCS - ERES - CRES - WME
   289  		SSK = HFCS - DRY - ESK
   290  		TCSK = 0.97 * ALFA * BODYWEIGHT
   291  		TCCR = 0.97 * (1. - ALFA) * BODYWEIGHT
   292  		DTSK = (SSK * BODYSURFACEAREA) / (TCSK * 60.0) //°C/min
   293  		DTCR = SCR * BODYSURFACEAREA / (TCCR * 60.0)   //°C/min
   294  		TempSkin = TempSkin + DTSK
   295  		TempCore = TempCore + DTCR
   296  		TB = ALFA*TempSkin + (1.-ALFA)*TempCore
   297  		SKSIG = TempSkin - TempSkinNeutral
   298  		if SKSIG > 0 {
   299  			WARMS = SKSIG
   300  		} else {
   301  			WARMS = 0
   302  		}
   303  		if (-1.0 * SKSIG) > 0 {
   304  			COLDS = (-1.0 * SKSIG)
   305  		} else {
   306  			COLDS = 0
   307  		}
   308  		CRSIG = (TempCore - TempCoreNeutral)
   309  		if CRSIG > 0 {
   310  			WARMC = CRSIG
   311  		} else {
   312  			WARMC = 0
   313  		}
   314  		if (-1.0 * CRSIG) > 0 {
   315  			COLDC = (-1.0 * CRSIG)
   316  		} else {
   317  			COLDC = 0
   318  		}
   319  		BDSIG = TB - TempBodyNeutral
   320  		if BDSIG > 0 {
   321  			WARMB = BDSIG
   322  		} else {
   323  			WARMB = 0
   324  		}
   325  		SkinBloodFlow = (SkinBloodFlowNeutral + CDIL*WARMC) / (1. + CSTR*COLDS)
   326  		SkinBloodFlow = math.Max(0.5, math.Min(90.0, SkinBloodFlow))
   327  		REGSW = CSW * WARMB * math.Exp(WARMS/10.7)
   328  		REGSW = math.Min(REGSW, 500.0)
   329  		var ERSW = 0.68 * REGSW
   330  		var REA = 1.0 / (LR * FACL * CHC) //Evaporative resistance of air layer
   331  		var RECL = RCL / (LR * ICL)       //Evaporative resistance of clothing (icl=.45)
   332  		EMAX = (FindSaturatedVaporPressureTorr(TempSkin) - VaporPressure) / (REA + RECL)
   333  		var PRSW = ERSW / EMAX
   334  		PWET = 0.06 + 0.94*PRSW
   335  		var EDIF = PWET*EMAX - ERSW
   336  		ESK = ERSW + EDIF
   337  		//if (TIM == 60)
   338  		//	printf("aqa\n");
   339  		if PWET > WCRIT {
   340  			PWET = WCRIT
   341  			PRSW = WCRIT / 0.94
   342  			ERSW = PRSW * EMAX
   343  			EDIF = 0.06 * (1.0 - PRSW) * EMAX
   344  			ESK = ERSW + EDIF
   345  		}
   346  		if EMAX < 0 {
   347  			EDIF = 0
   348  			ERSW = 0
   349  			PWET = WCRIT
   350  			PRSW = WCRIT
   351  			ESK = EMAX
   352  		}
   353  		ESK = ERSW + EDIF
   354  		//printf("%d\t%f\n", TIM, ESK);
   355  		MSHIV = 19.4 * COLDS * COLDC
   356  		M = RM + MSHIV
   357  		ALFA = 0.0417737 + 0.7451833/(SkinBloodFlow+0.585417)
   358  	} //End iteration
   359  
   360  	var HSK = DRY + ESK //Total heat loss from skin
   361  	var RN = M - WME    //Net metabolic heat production
   362  	var ECOMF = 0.42 * (RN - (1. * METFACTOR))
   363  	if ECOMF < 0.0 {
   364  		ECOMF = 0.0 //From Fanger
   365  	}
   366  	EMAX = EMAX * WCRIT
   367  	var W = PWET
   368  	var PSSK = FindSaturatedVaporPressureTorr(TempSkin)
   369  	var CHRS = CHR //Definition of ASHRAE standard environment
   370  	//... denoted “S”
   371  	var CHCS float64
   372  	if MET < 0.85 {
   373  		CHCS = 3.0
   374  	} else {
   375  		CHCS = 5.66 * math.Pow((MET-0.85), 0.39)
   376  		CHCS = math.Max(CHCS, 3.0)
   377  	}
   378  	var CTCS = CHCS + CHRS
   379  	var RCLOS = 1.52/((MET-WME/METFACTOR)+0.6944) - 0.1835
   380  	var RCLS = 0.155 * RCLOS
   381  	var FACLS = 1.0 + KCLO*RCLOS
   382  	var FCLS = 1.0 / (1.0 + 0.155*FACLS*CTCS*RCLOS)
   383  	const IMS = 0.45
   384  	var ICLS = IMS * CHCS / CTCS * (1. - FCLS) / (CHCS/CTCS - FCLS*IMS)
   385  	var RAS = 1.0 / (FACLS * CTCS)
   386  	var REAS = 1.0 / (LR * FACLS * CHCS)
   387  	var RECLS = RCLS / (LR * ICLS)
   388  	var HD_S = 1.0 / (RAS + RCLS)
   389  	var HE_S = 1.0 / (REAS + RECLS)
   390  	//SET determined using Newton’s iterative solution
   391  	const DELTA = .0001
   392  	var dx = 100.0
   393  	var SET, ERR1, ERR2 float64
   394  	var SET_OLD = TempSkin - HSK/HD_S //Lower bound for SET
   395  	for math.Abs(dx) > .01 {
   396  		ERR1 = (HSK - HD_S*(TempSkin-SET_OLD) - W*HE_S*(PSSK-0.5*
   397  			FindSaturatedVaporPressureTorr(SET_OLD)))
   398  		ERR2 = (HSK - HD_S*(TempSkin-(SET_OLD+DELTA)) - W*HE_S*(PSSK-0.5*
   399  			FindSaturatedVaporPressureTorr((SET_OLD+DELTA))))
   400  		SET = SET_OLD - DELTA*ERR1/(ERR2-ERR1)
   401  		dx = SET - SET_OLD
   402  		SET_OLD = SET
   403  	}
   404  	return SET
   405  }
   406  
   407  func FindSaturatedVaporPressureTorr(T float64) float64 {
   408  	//Helper function for pierceSET calculates Saturated Vapor Pressure (Torr) at Temperature T (°C)
   409  	return math.Exp(18.6686 - 4030.183/(T+235.0))
   410  }