github.com/archlabjp/eeslism-go@v0.0.0-20231109122333-4bb7bfcdf292/eeslism/eecmpdat_s.go (about) 1 package eeslism 2 3 import ( 4 "fmt" 5 "os" 6 "strconv" 7 "strings" 8 ) 9 10 // システム要素の入力 11 // 12 // - SYSCMPを`f`から読み込み、`Cmp`に使用機器情報を登録する.同時に、 `Eqsys`にメモリを確保する。 13 // - `Cmp`に使用機器情報を登録する際に `Eqcat`のカタログデータを参照する。 14 // - `Rmvls`に含まれる室および放射パネルは `Cmp`に使用機器として自動登録される。 15 // 16 // TODO: 17 // - この関数内で Eqsysにメモリを確保すると関数の責務を超えるので、分離独立させたほうが良い。 18 // 19 func Compodata(f *EeTokens, Rmvls *RMVLS, Eqcat *EQCAT, Cmp *[]*COMPNT, Eqsys *EQSYS) { 20 var ( 21 Ni, No int 22 cio ELIOType 23 idi []ELIOType 24 ido []ELIOType 25 ) 26 D := 0 27 errkey := "Compodata" 28 29 Room := Rmvls.Room 30 Rdpnl := Rmvls.Rdpnl 31 32 // Nairflow := Rmvls.Nairflow 33 // var AirFlow *AIRFLOW 34 // if Nairflow > 0 { 35 // AirFlow = Rmvls.airflow 36 // } else { 37 // AirFlow = nil 38 // } 39 40 //コンポーネント数 41 *Cmp = make([]*COMPNT, 0, 100) 42 43 // fmt.Printf("<Compodata> Compnt Alloc=%d\n", Ncmp) 44 //cmp = Cmp 45 46 // if fi, err := os.Open("bdata.ewk"); err != nil { 47 if f == nil { 48 Eprint("bdata.ewk", "<Compodata>") 49 os.Exit(EXIT_BDATA) 50 } 51 52 // ---------------------------------------------------------- 53 // 組込みシステム要素 54 // 給水温度 _CW: -type FLI -V t=Twsup * ; 55 // 外気温度・絶対湿度 _OA: -type FLI -V t=_Ta x=_xa * ; 56 // 室 <室名>: ROOMデータセットの宣言に応じて自動で組み込まれる 57 // 放射パネル <パネル名>: 放射パネルの 58 // ---------------------------------------------------------- 59 60 // 給水温度設定 `_CW` 61 Cmp1 := NewCOMPNT() 62 Cmp1.Name = CITYWATER_NAME 63 Cmp1.Eqptype = FLIN_TYPE 64 Cmp1.Tparm = CITYWATER_PARM 65 Cmp1.Nin = 1 66 Cmp1.Nout = 1 67 Eqsys.Flin = append(Eqsys.Flin, NewFLIN()) 68 D++ 69 70 // 取り入れ外気設定 `_OA` 71 Cmp2 := NewCOMPNT() 72 Cmp2.Name = OUTDRAIR_NAME 73 Cmp2.Eqptype = FLIN_TYPE 74 Cmp2.Tparm = OUTDRAIR_PARM 75 Cmp2.Nin = 2 76 Cmp2.Nout = 2 77 Eqsys.Flin = append(Eqsys.Flin, NewFLIN()) 78 D++ 79 80 *Cmp = append(*Cmp, Cmp1, Cmp2) 81 82 /* 室およびパネル用 */ 83 84 var Ncrm int 85 if SIMUL_BUILDG { 86 87 // 室用 `<室名>` 88 for i := range Rmvls.Room { 89 c := NewCOMPNT() 90 c.Name = Room[i].Name 91 c.Eqptype = ROOM_TYPE 92 c.Neqp = i 93 c.Eqp = Room[i] 94 c.Nout = 2 95 c.Nin = 2*Room[i].Nachr + Room[i].Ntr + Room[i].Nrp 96 c.Nivar = 0 97 c.Ivparm = nil 98 c.Airpathcpy = true 99 *Cmp = append(*Cmp, c) 100 D++ 101 } 102 Ncrm = 2 + len(Rmvls.Room) // 給水温度設定+取り入れ外気設定+室の数 103 104 // パネル用 `<パネル名>` 105 for i := range Rdpnl { 106 c := NewCOMPNT() 107 c.Name = Rdpnl[i].Name 108 c.Eqptype = RDPANEL_TYPE 109 c.Neqp = i 110 c.Eqp = Rdpnl[i] 111 c.Nout = 2 112 c.Nin = 3 + Rdpnl[i].Ntrm[0] + Rdpnl[i].Ntrm[1] + Rdpnl[i].Nrp[0] + Rdpnl[i].Nrp[1] + 1 113 c.Nivar = 0 114 c.Airpathcpy = true 115 *Cmp = append(*Cmp, c) 116 D++ 117 } 118 119 // エアフローウィンドウの機器メモリ 120 // for i := 0; i < Nairflow; i++ { 121 // c := NewCOMPNT() 122 // c.name = AirFlow[i].name 123 // c.eqptype = AIRFLOW_TYPE 124 // c.neqp = i 125 // c.eqp = AirFlow[i] 126 // c.Nout = 2 127 // c.Nin = 3 128 // c.nivar = 0 129 // c.airpathcpy = true 130 // *Cmp = append(*Cmp, *c) 131 // } 132 133 } 134 135 //cp := (*COMPNT)(nil) 136 137 for f.IsEnd() == false { 138 s := f.GetToken() 139 if s == "*" { 140 break 141 } 142 if s == "\n" { 143 continue 144 } 145 cio = ELIO_SPACE 146 147 var comp *COMPNT = NewCOMPNT() 148 var Crm *COMPNT = comp 149 150 // 三方弁(二方弁で連動する弁)を指定するとき 151 // `(<elmname1> <elmname2>)` のように入力する 152 // elmname1とelmname2が三方弁のように、逆作動の連動弁として機能するときの記述方法。 153 // このように書くとelmname1とelmname2はともに2方弁であるが、elmname1が開くとelmname2は閉じる操作が行われる。 154 // 155 // [elm1] --> [elm2] 156 // 157 if strings.HasPrefix(s, "(") { 158 if len(s) == 1 { 159 s = f.GetToken() 160 } else { 161 fmt.Sscanf(s, "(%s", &s) 162 } 163 Crm = nil 164 165 // 1つ目の2方弁 166 vc1 := NewCOMPNT() 167 vc1.Name = s // <compname1> 168 169 s = f.GetToken() 170 if strings.IndexRune(s, ')') != -1 { 171 idx := strings.IndexRune(s, ')') 172 s = s[idx+1:] 173 } 174 175 // 2つ目の2方弁 176 vc2 := NewCOMPNT() 177 vc2.Name = s // <compname2> 178 179 // 1つ目の2方弁から2つ目の2方弁を参照させる 180 vc1.Valvcmp = vc2 181 182 *Cmp = append(*Cmp, vc1, vc2) 183 184 // 2つ目の要素に対して各種設定を反映させる 185 comp = vc2 186 187 // NOTE: ここでVALVを追加する理由が不明 188 Eqsys.Valv = append(Eqsys.Valv, NewVALV()) 189 } 190 191 if Crm != nil { 192 // 組み込みの部屋要素を探す → 該当がなければ初期化 (必要性不明) 193 Crm = FindCOMPNTByName(s, (*Cmp)[:Ncrm]) 194 if Crm == nil { 195 comp.Name = s 196 comp.Ivparm = nil 197 comp.Tparm = "" 198 comp.Envname = "" 199 comp.Roomname = "" 200 comp.Nivar = 0 201 } 202 } 203 204 for f.IsEnd() == false { 205 s = f.GetToken() 206 if s[0] == ';' { 207 break 208 } 209 if strings.HasPrefix(s, "-") { 210 /********************************/ 211 if cio == 'i' { 212 comp.Nin = Ni 213 comp.Idi = make([]ELIOType, Ni) 214 } else if cio == 'o' { 215 comp.Nout = No 216 comp.Ido = make([]ELIOType, No) 217 if comp.Eqptype == DIVERG_TYPE { 218 comp.Nivar = No 219 //comp.Ivparm = new(float64) 220 } 221 } 222 223 /********************************/ 224 225 // ハイフンの後ろに続く文字列を取得 226 ps := s[1:] 227 228 switch ps { 229 case "c": 230 // カタログ名 231 cio = 'c' 232 case "type": 233 // 要素の種類 234 cio = 't' 235 case "Nin": 236 // 合流数 237 cio = 'I' 238 case "Nout": 239 // 分岐数 240 cio = 'O' 241 case "in": 242 cio = 'i' 243 Ni = 0 244 idi = []ELIOType{} 245 case "out": 246 cio = 'o' 247 No = 0 248 ido = []ELIOType{} 249 case "L": 250 // 配管長 [m] 251 cio = 'L' 252 comp.Nivar = 1 253 case "env": 254 // 周囲温度 255 cio = 'e' 256 case "room": 257 // 機器設置空間の室名 258 cio = 'r' 259 case "roomheff": 260 cio = 'R' 261 case "exs": 262 // 太陽熱集熱器の方位・傾斜名(EXSRFデータで入力) 263 cio = 's' 264 case "S": 265 // ??? 266 cio = 'S' 267 case "Tinit": 268 // 蓄熱槽の初期水温 269 cio = 'T' 270 case "V": 271 // ??? 272 cio = 'V' 273 case "hcc": 274 // VWV制御するときの制御対象熱交換器名称 275 cio = 'h' 276 case "pfloor": 277 // VWV制御するときの制御対象床暖房 278 cio = 'f' 279 case "wet": 280 // 冷却コイルで出口相対湿度一定の仮定で除湿の計算を行う。 281 comp.Wetparm = ps 282 283 /*---- Roh Debug for a constant outlet humidity model of wet coil 2003/4/25 ----*/ 284 cio = 'w' 285 comp.Ivparm = CreateConstantValuePointer(90.0) 286 case "control": 287 // 集熱器が直列接続の場合に流れ方向に記載する 288 cio = 'M' 289 case "monitor": 290 // Satoh Debug 291 cio = 'm' 292 case "PCMweight": 293 // 電気蓄熱暖房器の潜熱蓄熱材重量(kg) 294 cio = 'P' 295 default: 296 Eprint(errkey, s) 297 } 298 } else if cio != 'V' && cio != 'S' && strings.IndexRune(s, '-') != -1 { 299 idx := strings.IndexRune(s, '-') 300 st := s[idx+1:] 301 var err error 302 switch { 303 case strings.HasPrefix(s, "Ac"): 304 // 集熱器面積 [m2] 305 comp.Ac, err = readFloat(st) 306 if err != nil { 307 panic(err) 308 } 309 case strings.HasPrefix(s, "PVcap"): 310 // 設置容量 [W] (PV) 311 comp.PVcap, err = readFloat(st) 312 if err != nil { 313 panic(err) 314 } 315 case strings.HasPrefix(s, "Area"): 316 // アレイ面積 [m2](PV) 317 comp.Area, err = readFloat(st) 318 if err != nil { 319 panic(err) 320 } 321 } 322 } else { 323 switch cio { 324 case 'c': 325 // `-c <カタログ名>` 326 if eqpcat(s, comp, Eqcat, Eqsys) { 327 Eprint(errkey, s) 328 } 329 break 330 case 't': 331 // `-type <種類>` 332 comp.Eqptype = EqpType(s) 333 334 // 三方弁(二方弁で連動する弁) 335 if comp.Valvcmp != nil { 336 // 連動する対となる要素にも種類を指定 337 comp.Valvcmp.Eqptype = EqpType(s) 338 } 339 340 comp.Neqp = 0 341 comp.Ncat = 0 342 343 switch s { 344 case CONVRG_TYPE, CVRGAIR_TYPE: 345 // 合流要素 346 Eqsys.Cnvrg = append(Eqsys.Cnvrg, nil) 347 comp.Nout = 1 348 case DIVERG_TYPE, DIVGAIR_TYPE: 349 // 分岐要素 350 comp.Nin = 1 351 case FLIN_TYPE: 352 // 流入境界条件 353 Eqsys.Flin = append(Eqsys.Flin, NewFLIN()) 354 case HCLOAD_TYPE, HCLOADW_TYPE, RMAC_TYPE, RMACD_TYPE: 355 // 空調負荷 356 Eqsys.Hcload = append(Eqsys.Hcload, NewHCLOAD()) 357 358 case VALV_TYPE, TVALV_TYPE: 359 // 弁・ダンパー 360 Eqsys.Valv = append(Eqsys.Valv, NewVALV()) 361 case QMEAS_TYPE: 362 // カロリーメータ 363 //Eqsys.Nqmeas++ 364 default: 365 if s != DIVERG_TYPE && s != DIVGAIR_TYPE { 366 Eprint(errkey, s) 367 } 368 } 369 370 break 371 372 case 'i': 373 // `-in` 374 idi = append(idi, ELIO_None) 375 Ni++ 376 break 377 case 'o': 378 // `-out` 379 ido = append(ido, ELIO_None) 380 No++ 381 break 382 case 'I': 383 // `-Nin <合流数>` 384 // Satoh DEBUG 1998/5/15 385 var err error 386 if Crm != nil && SIMUL_BUILDG { 387 if Crm.Eqptype == ROOM_TYPE { 388 room := Crm.Eqp.(*ROOM) 389 room.Nasup, err = strconv.Atoi(s) 390 if err != nil { 391 panic(err) 392 } 393 394 N := room.Nasup 395 if N > 0 { 396 if room.Arsp == nil { 397 room.Arsp = make([]*AIRSUP, N) 398 for i := 0; i < N; i++ { 399 room.Arsp[i] = new(AIRSUP) 400 } 401 } 402 } 403 404 Crm.Nin += 2 * room.Nasup 405 } 406 } else { 407 comp.Nin, err = strconv.Atoi(s) 408 if err != nil { 409 panic(err) 410 } 411 } 412 413 comp.Idi = make([]ELIOType, comp.Nin) 414 for i := 0; i < comp.Nin; i++ { 415 comp.Idi[i] = ' ' 416 } 417 break 418 case 'O': 419 // `-Nout <分岐数>` 420 var err error 421 comp.Nout, err = strconv.Atoi(s) 422 if err != nil { 423 panic(err) 424 } 425 ido = make([]ELIOType, comp.Nout) 426 for i := 0; i < comp.Nout; i++ { 427 ido[i] = ELIO_SPACE 428 } 429 comp.Ido = ido 430 break 431 432 case 'L': 433 // `-L <配管長>` 434 l, err := readFloat(s) 435 if err != nil { 436 panic(err) 437 } 438 comp.Ivparm = CreateConstantValuePointer(l) 439 break 440 case 'e': 441 // `-env <周囲温度>` 442 comp.Envname = s 443 break 444 case 'r': 445 // `-room <機器設置空間の室名>` 446 comp.Roomname = s 447 break 448 case 'h': 449 // `-hcc <VWV制御するときの制御対象熱交換器名称>` 450 comp.Hccname = s 451 break 452 case 'f': 453 // `-pfloor <VWV制御するときの制御対象床暖房>` 454 comp.Rdpnlname = s 455 break 456 case 'R': 457 // `-roomheff <ボイラ室内置き時の室内供給熱量率>` 458 var err error 459 comp.Roomname = s 460 s = f.GetToken() 461 comp.Eqpeff, err = readFloat(s) 462 if err != nil { 463 panic(err) 464 } 465 break 466 case 's': 467 // `-exs <太陽熱集熱器の方位・傾斜名>` 468 comp.Exsname = s 469 break 470 case 'M': 471 // `-control <集熱器が直列接続の場合に集熱器の要素名を流れ方向に記載する>` 472 comp.Omparm = s 473 break 474 case 'S', 'V': 475 // `-S <????>` or `-V <????>` 476 for { 477 _s := f.GetToken() 478 if _s == "*" { 479 break 480 } 481 s += " " + _s 482 } 483 s += " *" 484 comp.Tparm = s 485 break 486 487 case 'T': 488 // `-Tinit <蓄熱槽の初期水温>` 489 if strings.HasPrefix(s, "(") { 490 s += " " 491 s += strings.Repeat(" ", len(s)) 492 _s := f.GetToken() 493 s += _s 494 comp.Tparm = s 495 } else { 496 comp.Tparm = s 497 } 498 break 499 case 'w': 500 // `-wet` 冷却コイルで出口相対湿度一定の仮定で除湿の計算を行う。 501 wet, err := readFloat(s) 502 if err != nil { 503 panic(err) 504 } 505 comp.Ivparm = CreateConstantValuePointer(wet) 506 break 507 case 'm': 508 // `-monitor` デバッグ用 509 comp.MonPlistName = s 510 comp.Valvcmp.MonPlistName = s 511 break 512 case 'P': 513 // `-PCMweight <電気蓄熱暖房器の潜熱蓄熱材重量(kg)>` 514 var err error 515 comp.MPCM, err = readFloat(s) 516 if err != nil { 517 panic(err) 518 } 519 break 520 } 521 } 522 } 523 524 if Crm == nil { 525 *Cmp = append(*Cmp, comp) 526 D++ 527 } 528 } 529 530 // 空気の分岐要素・合流要素があった場合、内容をコピーして湿度用に分岐要素・合流要素を作成 531 n := len(*Cmp) 532 for i := 0; i < n; i++ { 533 cm := (*Cmp)[i] 534 if cm.Eqptype == DIVGAIR_TYPE { 535 c := NewCOMPNT() 536 c.Name = cm.Name + ".x" 537 c.Eqptype = cm.Eqptype 538 c.Nout = cm.Nout 539 c.Ido = cm.Ido 540 *Cmp = append(*Cmp, c) 541 } else if cm.Eqptype == CVRGAIR_TYPE { 542 c := NewCOMPNT() 543 c.Name = cm.Name + ".x" 544 c.Eqptype = cm.Eqptype 545 c.Nin = cm.Nin 546 c.Idi = cm.Idi 547 // ここで合流要素一覧に追加する理由が不明 548 Eqsys.Cnvrg = append(Eqsys.Cnvrg, nil) 549 *Cmp = append(*Cmp, c) 550 } 551 } 552 553 // for _, c := range *Cmp { 554 // if len(c.Idi) != c.Nin { 555 // panic(c.Name) 556 // } 557 // if len(c.Ido) != c.Nout { 558 // panic(c.Name) 559 // } 560 // } 561 562 //fmt.Printf("<<Compodata>> Ncompnt = %d\n", *Ncompnt) 563 564 //printf("<<Compodata>> end\n"); 565 } 566 567 func FindCOMPNTByName(s string, Compnt []*COMPNT) *COMPNT { 568 cp := (*COMPNT)(nil) 569 for i := range Compnt { 570 if s == Compnt[i].Name { 571 cp = Compnt[i] 572 break 573 } 574 } 575 return cp 576 } 577 578 func NewVALV() *VALV { 579 return &VALV{ 580 Name: "", 581 Cmp: nil, 582 Cmb: nil, 583 Org: 'n', 584 X: -999.0, 585 Xinit: nil, 586 Tin: nil, 587 Tset: nil, 588 Mon: nil, 589 Plist: nil, 590 MGo: nil, 591 Tout: nil, 592 MonPlist: nil, 593 //OMfan : nil, 594 //OMfanName : nil, 595 } 596 } 597 598 func NewHCC() *HCC { 599 return &HCC{ 600 Name: "", 601 Cmp: nil, 602 Cat: nil, 603 Twin: 5.0, 604 Xain: FNXtr(25.0, 50.0), 605 } 606 } 607 608 func NewBOI() *BOI { 609 Boi := &BOI{ 610 Name: "", 611 Cmp: nil, 612 Cat: nil, 613 Load: nil, 614 Mode: 'M', 615 } 616 MtEdayinit(&Boi.MtEdy) 617 MtEdayinit(&Boi.MtPhdy) 618 return Boi 619 } 620 621 func NewCOLL() *COLL { 622 return &COLL{ 623 Name: "", 624 Cmp: nil, 625 Cat: nil, 626 sol: nil, 627 Te: 0.0, 628 Tcb: 0.0, 629 } 630 } 631 632 func NewPV() *PV { 633 PV := &PV{ 634 PVcap: -999., 635 Area: -999., 636 Name: "", 637 Cmp: nil, 638 Cat: nil, 639 Sol: nil, 640 Ta: nil, 641 V: nil, 642 I: nil, 643 } 644 MtEdayinit(&PV.mtEdy) 645 return PV 646 } 647 648 func NewOMVAV() *OMVAV { 649 OMvav := &OMVAV{ 650 Name: "", 651 Cmp: nil, 652 Cat: nil, 653 Omwall: nil, 654 Plist: nil, 655 Nrdpnl: 0, 656 } 657 for j := 0; j < 4; j++ { 658 OMvav.Rdpnl[j] = nil 659 } 660 return OMvav 661 } 662 663 func NewREFA() *REFA { 664 Rf := &REFA{ 665 Name: "", 666 Cmp: nil, 667 Cat: nil, 668 Load: nil, 669 Room: nil, 670 Do: 0.0, 671 D1: 0.0, 672 Tin: 0.0, 673 Te: 0.0, 674 Tc: 0.0, 675 } 676 MtEdayinit(&Rf.mtEdy) 677 MtEdayinit(&Rf.mtPhdy) 678 return Rf 679 } 680 681 func NewPIPE() *PIPE { 682 return &PIPE{ 683 Name: "", 684 Cmp: nil, 685 Cat: nil, 686 Loadt: nil, 687 Loadx: nil, 688 Room: nil, 689 } 690 } 691 692 func NewSTANK() *STANK { 693 return &STANK{ 694 Name: "", 695 Cmp: nil, 696 Cat: nil, 697 Jin: nil, 698 Jout: nil, 699 Batchcon: nil, 700 Ihex: nil, 701 B: nil, 702 R: nil, 703 Fg: nil, 704 D: nil, 705 Tss: nil, 706 DtankF: nil, 707 Tssold: nil, 708 Dvol: nil, 709 Mdt: nil, 710 KS: nil, 711 Ihxeff: nil, 712 KA: nil, 713 KAinput: nil, 714 CGwin: nil, 715 EGwin: nil, 716 Twin: nil, 717 Q: nil, 718 Tenv: nil, 719 Stkdy: nil, 720 Mstkdy: nil, 721 MQlossdy: 0.0, 722 MQstody: 0.0, 723 Ncalcihex: 0, 724 } 725 } 726 727 func NewHEX() *HEX { 728 return &HEX{ 729 Name: "", 730 Cmp: nil, 731 Cat: nil, 732 Id: 0, 733 } 734 } 735 736 func NewPUMP() *PUMP { 737 Pp := &PUMP{ 738 Name: "", 739 Cmp: nil, 740 Cat: nil, 741 Sol: nil, 742 } 743 MtEdayinit(&Pp.MtEdy) 744 return Pp 745 } 746 747 func NewFLIN() *FLIN { 748 return &FLIN{ 749 Name: "", 750 Namet: "", 751 Namex: "", 752 Vart: nil, 753 Varx: nil, 754 Cmp: nil, 755 } 756 } 757 758 func NewHCLOAD() *HCLOAD { 759 Hl := &HCLOAD{ 760 Name: "", 761 Loadt: nil, 762 Loadx: nil, 763 Cmp: nil, 764 RMACFlg: 'N', 765 Ga: 0.0, 766 Gw: 0.0, 767 RHout: 50.0, 768 } 769 MtEdayinit(&Hl.mtEdy) 770 return Hl 771 } 772 773 func NewVAV() *VAV { 774 return &VAV{ 775 Name: "", 776 Cat: nil, 777 Hcc: nil, 778 Hcld: nil, 779 Cmp: nil, 780 } 781 } 782 783 func NewSTHEAT() *STHEAT { 784 st := &STHEAT{ 785 Name: "", 786 Cat: nil, 787 Cmp: nil, 788 Room: nil, 789 Pcm: nil, 790 } 791 MtEdayinit(&st.MtEdy) 792 return st 793 } 794 795 func NewDESI() *DESI { 796 return &DESI{ 797 Name: "", 798 Cat: nil, 799 Cmp: nil, 800 Room: nil, 801 Tenv: nil, 802 } 803 } 804 805 func NewEVAC() *EVAC { 806 return &EVAC{ 807 Name: "", 808 Cat: nil, 809 Cmp: nil, 810 M: nil, 811 Kx: nil, 812 Tdry: nil, 813 Twet: nil, 814 Xdry: nil, 815 Xwet: nil, 816 Ts: nil, 817 Xs: nil, 818 RHdry: nil, 819 RHwet: nil, 820 UXC: nil, 821 UX: nil, 822 //UXdry: nil, 823 //UXwet: nil, 824 } 825 } 826 827 func NewTHEX() *THEX { 828 return &THEX{ 829 Name: "", 830 Cmp: nil, 831 Cat: nil, 832 Type: ' ', 833 CGe: 0.0, 834 Ge: 0.0, 835 Go: 0.0, 836 ET: -999.0, 837 EH: -999.0, 838 } 839 }