github.com/archlabjp/eeslism-go@v0.0.0-20231109122333-4bb7bfcdf292/eeslism/wdread.go (about)

     1  package eeslism
     2  
     3  import (
     4  	"bufio"
     5  	"fmt"
     6  	"io"
     7  	"math"
     8  	"os"
     9  	"strconv"
    10  	"strings"
    11  )
    12  
    13  /* 月日の設定(翌日の日時を設定する) */
    14  
    15  func monthday(mo int, dayo int) (int, int) {
    16  	var Day = dayo + 1
    17  	var Mon = mo
    18  
    19  	switch mo {
    20  	case 1, 3, 5, 7, 8, 10, 12:
    21  		if dayo == 31 {
    22  			Day = 1
    23  			if mo == 12 {
    24  				Mon = 1
    25  			} else {
    26  				Mon = mo + 1
    27  			}
    28  		}
    29  	case 4, 6, 9, 11:
    30  		if dayo == 30 {
    31  			Day = 1
    32  			Mon = mo + 1
    33  		}
    34  	case 2:
    35  		if dayo == 28 {
    36  			Day = 1
    37  			Mon = mo + 1
    38  		}
    39  	}
    40  
    41  	return Mon, Day
    42  }
    43  
    44  /*  気象デ-タの入力     */
    45  var (
    46  	Lat, Slat, Clat, Tlat, Lon, Ls, Isc float64
    47  )
    48  
    49  var __Weatherdt_ptt int = 25
    50  var __Weatherdt_nc int = 0
    51  var __Weatherdt_decl, __Weatherdt_E, __Weatherdt_tas, __Weatherdt_timedg float64
    52  var __Weatherdt_dt [7][25]float64
    53  var __Weatherdt_dtL [7][25]float64
    54  
    55  func Weatherdt(Simc *SIMCONTL, Daytm *DAYTM, Loc *LOCAT, Wd *WDAT, Exs []*EXSF, EarthSrfFlg bool) {
    56  	var tt, Mon, Day int
    57  
    58  	tt = Daytm.Tt
    59  
    60  	if tt < __Weatherdt_ptt {
    61  		if Simc.Wdtype == 'H' {
    62  			if Simc.DTm < 3600 {
    63  				_, Mon, Day, _ = hspwdread(Simc.Fwdata, Daytm.DayOfYear-1, Loc, &__Weatherdt_dtL)
    64  				fmt.Printf("Mon=%d  Day=%d\n", Mon, Day)
    65  			}
    66  
    67  			_, Mon, Day, _ = hspwdread(Simc.Fwdata, Daytm.DayOfYear, Loc, &__Weatherdt_dt)
    68  			if Daytm.Mon != Mon || Daytm.Day != Day {
    69  				s := fmt.Sprintf("loop Mon/Day=%d/%d - data Mon/Day=%d/%d", Daytm.Mon, Daytm.Day, Mon, Day)
    70  				Eprint("<Weatherdt>", s)
    71  				Preexit()
    72  				os.Exit(EXIT_MOND)
    73  			}
    74  		}
    75  
    76  		if __Weatherdt_nc == 0 {
    77  			Lat = Loc.Lat
    78  			Lon = Loc.Lon
    79  			Ls = Loc.Ls
    80  			Sunint()
    81  			Psyint()
    82  			if Simc.Wdtype == 'H' {
    83  				gtsupw(Simc.Ftsupw, Loc.Name, &(Loc.Daymxert), &(Loc.Tgrav), &(Loc.DTgr), &Loc.Twsup)
    84  
    85  				Intgtsup(1, Loc.Twsup[:])
    86  			}
    87  
    88  			if EarthSrfFlg {
    89  				Wd.EarthSurface = make([]float64, 366*25)
    90  				EarthSrfTempInit(Simc, Loc, Wd)
    91  			}
    92  			__Weatherdt_nc = 1
    93  		}
    94  
    95  		__Weatherdt_decl = FNDecl(Daytm.DayOfYear)
    96  		__Weatherdt_E = FNE(Daytm.DayOfYear)
    97  
    98  		if Wd.Intgtsupw == 'N' {
    99  			Wd.Twsup = Loc.Twsup[Daytm.Mon-1]
   100  		} else {
   101  			Wd.Twsup = Intgtsup(Daytm.DayOfYear, Loc.Twsup[:])
   102  		}
   103  	}
   104  
   105  	Exsfter(Daytm.DayOfYear, Loc.Daymxert, Loc.Tgrav, Loc.DTgr, Exs, Wd, tt)
   106  	__Weatherdt_timedg = float64(Daytm.Tt) + math.Mod(float64(Daytm.Ttmm), 100.0)/60.0
   107  
   108  	__Weatherdt_tas = FNTtas(__Weatherdt_timedg, __Weatherdt_E)
   109  	Wd.Sh, Wd.Sw, Wd.Ss, Wd.Solh, Wd.SolA = Solpos(__Weatherdt_tas, __Weatherdt_decl)
   110  
   111  	if Simc.Wdtype == 'H' {
   112  		// 計算時間間隔が1時間未満の場合には直線補完する
   113  		if Simc.DTm < 3600 {
   114  			wdatadiv(Daytm, Wd, __Weatherdt_dt, __Weatherdt_dtL)
   115  		} else {
   116  			dt2wdata(Wd, tt, __Weatherdt_dt)
   117  		}
   118  	} else {
   119  		// VCFILE形式の気象データの読み込み
   120  		Wdflinput(&Simc.Wdpt, Wd)
   121  	}
   122  
   123  	if DEBUG {
   124  		fmt.Println("\n\n<Weatherdt>  ***** Wdata *****\n\n=================")
   125  		fmt.Printf("\tT=%.1f\n\tx=%.4f\n\tRH=%.0f\n", Wd.T, Wd.X, Wd.RH)
   126  		fmt.Printf("\tIdn=%.0f\n\tIsky=%.0f\n\tIhor=%.0f\n", Wd.Idn, Wd.Isky, Wd.Ihor)
   127  		fmt.Printf("\tRN=%.0f\n\tCC=%.0f\n\tWdre=%.0f\n\tWv=%.1f\n", Wd.RN, Wd.CC, Wd.Wdre, Wd.Wv)
   128  		fmt.Printf("\th=%.0f\n==================\n", Wd.H)
   129  	}
   130  
   131  	if dayprn && Ferr != nil {
   132  		fmt.Fprintln(Ferr, "\n\n<Weatherdt>  ***** Wdata *****\n\n=================")
   133  		fmt.Fprintf(Ferr, "\tT=%.1f\n\tx=%.4f\n\tRH=%.0f\n", Wd.T, Wd.X, Wd.RH)
   134  		fmt.Fprintf(Ferr, "\tIdn=%.0f\n\tIsky=%.0f\n\tIhor=%.0f\n", Wd.Idn, Wd.Isky, Wd.Ihor)
   135  		fmt.Fprintf(Ferr, "\tRN=%.0f\n\tCC=%.0f\n\tWdre=%.0f\n\tWv=%.1f\n", Wd.RN, Wd.CC, Wd.Wdre, Wd.Wv)
   136  		fmt.Fprintf(Ferr, "\th=%.0f\n==================\n", Wd.H)
   137  	}
   138  
   139  	__Weatherdt_ptt = tt
   140  }
   141  
   142  var __gtsupw_ic int
   143  
   144  func gtsupw(fp []byte, loc string, nmx *int, Tgrav, DTgr *float64, Tsupw *[12]float64) {
   145  	var flg int
   146  	var s string
   147  
   148  	if __gtsupw_ic == 0 {
   149  		reader := strings.NewReader(string(fp))
   150  		scanner := bufio.NewScanner(reader)
   151  		scanner.Split(bufio.ScanWords)
   152  
   153  		// Find location
   154  		for scanner.Scan() {
   155  			s = scanner.Text()
   156  			if s == loc {
   157  				flg = 1
   158  				break
   159  			}
   160  		}
   161  
   162  		// Check error
   163  		if scanner.Err() != nil {
   164  			E := fmt.Sprintf("supw.eflに%sが登録されていません。\n", s)
   165  			Eprint("<gtsupw>", E)
   166  			os.Exit(EXIT_GTSUPW)
   167  		}
   168  
   169  		// Read data of 12 months and nmx, Tgrav, DTgr
   170  		var err error
   171  		var values [15]float64
   172  		for i := 0; i < 15; i++ {
   173  			scanner.Scan()
   174  			values[i], err = strconv.ParseFloat(scanner.Text(), 64)
   175  			if err != nil {
   176  				panic(err)
   177  			}
   178  		}
   179  		copy(Tsupw[:], values[:12])
   180  		*nmx = int(values[12])
   181  		*Tgrav = values[13]
   182  		*DTgr = values[14]
   183  
   184  		__gtsupw_ic = 1
   185  
   186  		if flg == 0 {
   187  			E := fmt.Sprintf("supw.eflに%sが登録されていません。\n", s)
   188  			Eprint("<gtsupw>", E)
   189  			os.Exit(1)
   190  		}
   191  	}
   192  }
   193  
   194  /*   HASP標準気象デ-タファイルからの入力   */
   195  
   196  var __hspwdread_ic int
   197  var __hspwdread_recl int
   198  
   199  func hspwdread(fp io.ReadSeeker, nday int, Loc *LOCAT, dt *[7][25]float64) (year int, mon int, day int, wkdy int) {
   200  	var d, a, b, c float64
   201  	var k, t int
   202  	Data := [24][3]byte{}
   203  	Yr, Mon, Day, Wk, Sq := [2]byte{}, [2]byte{}, [2]byte{}, [1]byte{}, [2]byte{}
   204  	var s string
   205  
   206  	if nday > 365 {
   207  		nday = nday - 365
   208  	}
   209  	if nday <= 0 {
   210  		nday = nday + 365
   211  	}
   212  
   213  	if __hspwdread_ic == 0 {
   214  		// NOTE: 独自のHASPフォーマットになっている
   215  		fmt.Fscanf(fp, "%s %f %f %f %f %f %f ", &s, &Loc.Lat, &Loc.Lon, &Loc.Ls, &a, &b, &c)
   216  		Loc.Name = s
   217  
   218  		if Ferr != nil {
   219  			fmt.Fprintf(Ferr, "\n------> <hspwdread> \n")
   220  			fmt.Fprintf(Ferr, "\nName=%s\tLat=%.4g\tLon=%.4g\tLs=%.4g\ta=%.4g\tb=%.4g\tc=%.4g\n",
   221  				Loc.Name, Loc.Lat, Loc.Lon, Loc.Ls, a, b, c)
   222  		}
   223  
   224  		//改行コードの判定
   225  		fp.Seek(0, io.SeekEnd)
   226  		fsize, _ := fp.Seek(0, io.SeekCurrent)
   227  		__hspwdread_recl = int(fsize / 2556)
   228  		//recl=82 -> Windows (CRLF)
   229  		//recl=81 -> Linux/Mac(CR or LF)
   230  	}
   231  
   232  	if __hspwdread_ic != nday {
   233  		fp.Seek(int64(__hspwdread_recl*7*(nday-1)+__hspwdread_recl), 0)
   234  	}
   235  
   236  	if __hspwdread_ic > 0 {
   237  		for k = 0; k < 7; k++ {
   238  			dt[k][0] = dt[k][24]
   239  		}
   240  	}
   241  
   242  	for k = 0; k < 7; k++ {
   243  		for t = 0; t < 24; t++ {
   244  			fp.Read(Data[t][:])
   245  		}
   246  
   247  		fp.Read(Yr[:])
   248  		fp.Read(Mon[:])
   249  		fp.Read(Day[:])
   250  		fp.Read(Wk[:])
   251  		fp.Read(Sq[:])
   252  
   253  		for t = 1; t < 25; t++ {
   254  			var err error
   255  			d, err = strconv.ParseFloat(strings.TrimSpace(string(Data[t-1][:])), 64)
   256  			if err != nil {
   257  				panic(err)
   258  			}
   259  			switch k {
   260  			case 0:
   261  				dt[k][t] = (d - 500.0) * 0.1
   262  			case 1:
   263  				dt[k][t] = 0.0001 * d
   264  			case 6:
   265  				dt[k][t] = 0.1 * d
   266  			default:
   267  				dt[k][t] = d
   268  			}
   269  		}
   270  	}
   271  
   272  	fmt.Printf("C Mon=%s Day=%s\n", Mon, Day)
   273  
   274  	year, _ = strconv.Atoi(strings.TrimSpace(string(Yr[:])))
   275  	mon, _ = strconv.Atoi(strings.TrimSpace(string(Mon[:])))
   276  	day, _ = strconv.Atoi(strings.TrimSpace(string(Day[:])))
   277  	wkdy, _ = strconv.Atoi(strings.TrimSpace(string(Wk[:])))
   278  
   279  	if __hspwdread_ic == 0 {
   280  		for k = 0; k < 7; k++ {
   281  			dt[k][0] = dt[k][1]
   282  		}
   283  	}
   284  	__hspwdread_ic = nday + 1
   285  
   286  	if DEBUG {
   287  		for t = 0; t < 25; t++ {
   288  			fmt.Printf("%2d %5.1f %6.4f %5.0f %5.0f %2.0f %2.0f %5.1f\n", t, dt[0][t], dt[1][t], dt[2][t], dt[3][t], dt[4][t], dt[5][t], dt[6][t])
   289  		}
   290  	}
   291  
   292  	return year, mon, day, wkdy
   293  }
   294  
   295  func dt2wdata(Wd *WDAT, tt int, dt [7][25]float64) {
   296  	Wd.T = dt[0][tt]
   297  	Wd.X = dt[1][tt]
   298  	Wd.Idn = dt[2][tt] / 0.86
   299  	Wd.Isky = dt[3][tt] / 0.86
   300  	Wd.Ihor = Wd.Idn*Wd.Sh + Wd.Isky
   301  
   302  	if Wd.RNtype == 'C' {
   303  		Br := 0.51 + 0.209*math.Sqrt(FNPwx(Wd.X))
   304  		Wd.CC = dt[4][tt]
   305  		Wd.RN = (1.0 - 0.62*Wd.CC/10.0) * (1.0 - Br) * Sgm * math.Pow(Wd.T+273.15, 4.0)
   306  		Wd.Rsky = ((1.0-0.62*Wd.CC/10.0)*Br + 0.62*Wd.CC/10.0) * Sgm * math.Pow(Wd.T+273.15, 4.0)
   307  	} else {
   308  		Wd.CC = -999.0
   309  		Wd.RN = dt[4][tt] / 0.86
   310  		Wd.Rsky = Sgm*math.Pow(Wd.T+273.15, 4.0) - Wd.RN
   311  	}
   312  
   313  	Wd.Wdre = dt[5][tt]
   314  	Wd.Wv = dt[6][tt]
   315  	Wd.RH = FNRhtx(Wd.T, Wd.X)
   316  	Wd.H = FNH(Wd.T, Wd.X)
   317  }
   318  
   319  func wdatadiv(Daytm *DAYTM, Wd *WDAT, dt [7][25]float64, dtL [7][25]float64) {
   320  	var WdF, WdL WDAT
   321  	var r float64
   322  
   323  	WdL.RNtype = Wd.RNtype
   324  	WdF.RNtype = Wd.RNtype
   325  
   326  	r = math.Mod(float64(Daytm.Ttmm), 100.0) / 60.0
   327  
   328  	if Daytm.Ttmm%100 == 0 {
   329  		dt2wdata(Wd, Daytm.Tt, dt)
   330  	} else if Daytm.Ttmm > 100 {
   331  		dt2wdata(&WdL, Daytm.Tt, dt)
   332  		dt2wdata(&WdF, Daytm.Tt+1, dt)
   333  
   334  		WdLineardiv(Wd, &WdL, &WdF, r)
   335  	} else {
   336  		dt2wdata(&WdL, 24, dtL)
   337  		dt2wdata(&WdF, 1, dt)
   338  
   339  		WdLineardiv(Wd, &WdL, &WdF, r)
   340  	}
   341  }
   342  
   343  func WdLineardiv(Wd *WDAT, WdL *WDAT, WdF *WDAT, dt float64) {
   344  	Wd.T = Lineardiv(WdL.T, WdF.T, dt)
   345  	Wd.X = Lineardiv(WdL.X, WdF.X, dt)
   346  	// Wd.RH = Lineardiv(WdL.RH, WdF.RH, dt)
   347  	Wd.RH = FNRhtx(Wd.T, Wd.X)
   348  	// Wd.h = Lineardiv(WdL.h, WdF.h, dt)
   349  	Wd.H = FNH(Wd.T, Wd.X)
   350  	Wd.Idn = Lineardiv(WdL.Idn, WdF.Idn, dt)
   351  	Wd.Isky = Lineardiv(WdL.Isky, WdF.Isky, dt)
   352  	// Wd.Ihor = Lineardiv(WdL.Ihor, WdF.Ihor, dt)
   353  	Wd.Ihor = Wd.Idn*Wd.Sh + Wd.Isky
   354  	Wd.CC = Lineardiv(WdL.CC, WdF.CC, dt)
   355  	Wd.RN = Lineardiv(WdL.RN, WdF.RN, dt)
   356  	Wd.Wv = Lineardiv(WdL.Wv, WdF.Wv, dt)
   357  	Wd.Wdre = Lineardiv(WdL.Wdre, WdF.Wdre, dt)
   358  
   359  	if Wd.Wdre > 16.0 {
   360  		Wd.Wdre -= 16.0
   361  	}
   362  }
   363  
   364  func EarthSrfTempInit(Simc *SIMCONTL, Loc *LOCAT, Wd *WDAT) {
   365  	var decl, E, ac, Te, tas float64
   366  	var year, nday, tt int
   367  	//var wkdy, Year, Mon, Day int
   368  	dt := [7][25]float64{}
   369  	var U, T, oldT []float64
   370  	var i, j int
   371  	var Ihol float64
   372  	var Soic, Soil float64
   373  
   374  	// 地表面温度の計算
   375  	fmt.Println("地表面温度の計算開始")
   376  
   377  	// 土壌の容積比熱[J/m3K]
   378  	Soic = 3.34e6
   379  	// 土壌の熱伝導率[W/mK]
   380  	Soil = 1.047
   381  	// 土壌の熱拡散率
   382  	a := Soil / Soic
   383  	ac = 23.0
   384  	u := float64(Simc.DTm) * a / (0.5 * 0.5)
   385  	U = make([]float64, 20*20)
   386  	T = make([]float64, 20*20)
   387  	oldT = make([]float64, 20*20)
   388  
   389  	// 地中温度の初期温度は平均外気温度
   390  	matinitx(oldT, 20, Loc.Tgrav)
   391  
   392  	// 地中温度計算用の行列の作成
   393  	for i = 0; i < 20; i++ {
   394  		U[i*20+i] = 1.0 + 2.0*u
   395  		if i > 0 {
   396  			U[i*20+i-1] = -u
   397  		}
   398  		if i < 20-1 {
   399  			U[i*20+i+1] = -u
   400  		}
   401  
   402  		if i == 0 {
   403  			U[i*20+i] = 1.0 + float64(Simc.DTm)/(0.5*(0.0+Soic*0.5)*1.0/ac) + float64(Simc.DTm)/(0.5*(0.0+Soic*0.5)*0.5/Soil)
   404  			U[i*20+i+1] = -float64(Simc.DTm) / (0.5 * (0.0 + Soic*0.5) * 0.5 / Soil)
   405  		}
   406  		if i == 19 {
   407  			U[i*20+i] = 1.0 + float64(Simc.DTm)/(0.5*(0.0+Soic*0.5)*0.5/Soil)
   408  			U[i*20+i-1] = -float64(Simc.DTm) / (0.5 * (0.0 + Soic*0.5) * 0.5 / Soil)
   409  		}
   410  	}
   411  
   412  	//matfprint("%.2lf ", 20,U )
   413  	// Uの逆行列の計算
   414  	Matinv(U, 20, 20, "<EarthSrfTempInit>")
   415  
   416  	// 1年目は助走期間
   417  	for year = 0; year < 2; year++ {
   418  		for nday = 1; nday <= 365; nday++ {
   419  			decl = FNDecl(nday)
   420  			E = FNE(nday)
   421  
   422  			hspwdread(Simc.Fwdata2, nday, Loc, &dt)
   423  
   424  			for tt = 1; tt <= 24; tt++ {
   425  				matinit(T, 20)
   426  
   427  				tas = FNTtas(float64(tt), E)
   428  				var Sh float64
   429  				Sh, _, _, Wd.Solh, Wd.Solh = Solpos(tas, decl)
   430  				dt2wdata(Wd, tt, dt)
   431  
   432  				Ihol = Wd.Idn*Sh + Wd.Isky
   433  
   434  				Te = Wd.T + (0.7*Ihol-Wd.RN)/ac
   435  
   436  				oldT[0] += (Te * float64(Simc.DTm) / (0.5 * Soic * 0.5 / ac))
   437  
   438  				Matmalv(U, oldT, 20, 20, T)
   439  
   440  				if year == 1 {
   441  					Wd.EarthSurface[nday*24+tt] = T[0]
   442  				}
   443  
   444  				for j = 0; j < 20; j++ {
   445  					oldT[j] = T[j]
   446  				}
   447  			}
   448  		}
   449  	}
   450  
   451  	fmt.Println("地表面温度の計算終了")
   452  }