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 }