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

     1  package eeslism
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"regexp"
     7  	"strings"
     8  )
     9  
    10  /* システム要素の接続経路の入力 */
    11  
    12  func Pathdata(
    13  	f *EeTokens,
    14  	Simc *SIMCONTL,
    15  	Wd *WDAT,
    16  	Compnt []*COMPNT,
    17  	Schdl *SCHDL,
    18  	M *[]*MPATH,
    19  	Plst *[]*PLIST,
    20  	Plm *[]*PELM,
    21  	Eqsys *EQSYS,
    22  	Elout *[]*ELOUT,
    23  	Elin *[]*ELIN,
    24  ) {
    25  	var C *COMPNT
    26  	var stank *STANK
    27  	var Qmeas *QMEAS
    28  	var s, ss string
    29  	var elm string
    30  	var id int
    31  
    32  	var i, j, m, ncv, iswc int
    33  
    34  	errkey := "Pathdata"
    35  	if DEBUG {
    36  		fmt.Printf("\n")
    37  		for i := range Compnt {
    38  
    39  			C = Compnt[i]
    40  			fmt.Printf("name=%s Nin=%d  Nout=%d\n", C.Name, C.Nin, C.Nout)
    41  		}
    42  	}
    43  
    44  	// 最外ループ: MPATHの読み込み 開始
    45  	for f.IsEnd() == false {
    46  		ss = f.GetToken()
    47  		if ss[0] == '*' {
    48  			break
    49  		}
    50  		if ss[0] == '\n' {
    51  			continue
    52  		}
    53  
    54  		if DEBUG {
    55  			fmt.Printf("eepathdat.c  ss=%s\n", ss)
    56  		}
    57  
    58  		Mpath := NewMPATH()
    59  
    60  		// if *Nplst > 0 {
    61  		// 	// 経路系統 -> 末端経路 への参照ポインタの確保
    62  		// 	Mpath.Pl = make([]*PLIST, *Nplst)
    63  		// 	for i := 0; i < *Nplst; i++ {
    64  		// 		Mpath.Pl[i] = nil
    65  		// 	}
    66  		// }
    67  
    68  		// if *Nplst > 0 {
    69  		// 	// 流量連立方程式を解くときに使用する分岐・合流機器 への参照ポインタの確保
    70  		// 	Mpath.Cbcmp = make([]*COMPNT, *Nplst*2)
    71  		// 	for i := 0; i < *Nplst*2; i++ {
    72  		// 		Mpath.Cbcmp[i] = nil
    73  		// 	}
    74  		// }
    75  
    76  		// SYSPTHにおける';'で区切られる経路の基本設定
    77  		// 入力例: `LDAC -sys A -f A`
    78  		Mpath.Name = ss                 // 経路名称
    79  		Mpath.NGv = 0                   // ガス導管数
    80  		Mpath.NGv2 = 0                  // 開口率が2%未満のガス導管数
    81  		Mpath.Ncv = 0                   // 制御弁数
    82  		Mpath.Plist = make([]*PLIST, 0) // 末端経路
    83  		//Pelmpre = nil
    84  
    85  		// PLIST読み込み用ループ 開始
    86  		iPlist := 0 //デフォルト名の設定用カウンタ
    87  		for f.IsEnd() == false {
    88  			s = f.GetToken()
    89  			if s[0] == ';' {
    90  				break
    91  			}
    92  
    93  			if DEBUG {
    94  				fmt.Printf("eepathdat.c  s=%s\n", s)
    95  			}
    96  
    97  			if s[0] == '-' {
    98  				//
    99  				// MPATH用の属性を読み込む -sys or -f
   100  				//
   101  				ss = f.GetToken()
   102  
   103  				if s[1:] == "sys" {
   104  					// システムの分類(A:空調・暖房システム、D:給湯システム)
   105  					Mpath.Sys = ss[0]
   106  				} else if s[1:] == "f" {
   107  					// 循環、通過流体の種類(水系統、空気系統の別)
   108  					//(W:水系統、A:空気系統で温・湿度とも計算、a:空気系統で温度のみ計算。
   109  					Mpath.Fluid = FliudType(ss[0])
   110  				} else {
   111  					Errprint(1, errkey, s)
   112  				}
   113  			} else if s == ">" {
   114  				//
   115  				// PLIST用の作成 ">"から">"の塊を読みとる
   116  				//
   117  				Plist := NewPLIST()
   118  				Plist.Plistname = fmt.Sprintf("Path%d", iPlist) // 末端経路名
   119  				Plist.Pelm = make([]*PELM, 0, 10)               // 機器のリスト
   120  				iPlist++
   121  
   122  				// PELM読み込み用ループ 開始
   123  				for f.IsEnd() == false {
   124  					s = f.GetToken()
   125  
   126  					// ">" が来ると終了
   127  					if s == ">" {
   128  						break
   129  					}
   130  
   131  					if DEBUG {
   132  						fmt.Printf("eepathdat.c  s=%s\n", s)
   133  					}
   134  
   135  					if s[0] == '(' {
   136  						//
   137  						// 流量の計算に使用される係数を読み取る - `(<flwvol>)` のような文字列で定義される
   138  						//
   139  
   140  						// "(value)" のような文字列から vaue を取り出す正規表現
   141  						re := regexp.MustCompile(`\((.*?)\)`)
   142  						matches := re.FindStringSubmatch(s)
   143  
   144  						if len(matches) >= 2 {
   145  							ss := matches[1]
   146  
   147  							if Go, err := readFloat(ss); err == nil {
   148  								Plist.Go = CreateConstantValuePointer(Go)
   149  								if DEBUG {
   150  									fmt.Printf("Go=%f\n", *Plist.Go)
   151  								}
   152  							} else {
   153  								if DEBUG {
   154  									fmt.Printf("s=%s ss=%s\n", s, ss)
   155  								}
   156  
   157  								if j, err = idsch(ss, Schdl.Sch, ""); err == nil {
   158  									Plist.Go = &Schdl.Val[j]
   159  								} else {
   160  									Plist.Go = envptr(ss, Simc, Compnt, Wd, nil)
   161  								}
   162  
   163  								if DEBUG {
   164  									fmt.Printf("Go=%f\n", *Plist.Go)
   165  								}
   166  							}
   167  						}
   168  					} else if s[0] == '[' {
   169  						//
   170  						// 流量比率を読み取る - `[<flwrate>]` のような文字列で定義される
   171  						//
   172  
   173  						// 流量比率設定フラグのセット
   174  						Mpath.Rate = true
   175  
   176  						var Go float64
   177  						i, err := fmt.Scanf(s[1:], "%f", &Go)
   178  						if err != nil {
   179  							panic(err)
   180  						}
   181  						if i == 1 {
   182  							// 指定されていたのが数値なので、流量比率に入力された固定値を設定する
   183  							Plist.Rate = CreateConstantValuePointer(Go)
   184  							if DEBUG {
   185  								fmt.Printf("rate=%f\n", *Plist.Rate)
   186  							}
   187  						} else {
   188  							// 指定されたいたのは数値ではなかったので、設定値スケジュール名である。
   189  							// 、) 文字が見つかるまでの全ての文字を読み取ります.
   190  							_, err := fmt.Sscanf(s[1:], "%[^]]", &ss)
   191  							if err != nil {
   192  								panic(err)
   193  							}
   194  
   195  							if DEBUG {
   196  								fmt.Printf("s=%s ss=%s\n", s, ss)
   197  							}
   198  
   199  							// 設定値スケジュールの検索
   200  							if j, err := idsch(ss, Schdl.Sch, ""); err == nil {
   201  								// 設定値スケジュールが見つかったので、スケジュール設定値へのポインタを指定
   202  								Plist.Rate = &Schdl.Val[j]
   203  							} else {
   204  								Plist.Rate = envptr(ss, Simc, Compnt, Wd, nil)
   205  							}
   206  
   207  							if DEBUG {
   208  								fmt.Printf("rate=%f\n", *Plist.Rate)
   209  							}
   210  						}
   211  					} else if strings.HasPrefix(s, "name=") {
   212  						// 末端経路名称の指定
   213  						// デフォルトでは、 "Path<No.>"のような名前で指定されるので、これを上書きする
   214  						_, err := fmt.Sscanf(s, "%*[^=]=%s", &ss)
   215  						if err != nil {
   216  							panic(err)
   217  						}
   218  						Plist.Plistname = ss
   219  					} else {
   220  
   221  						// 要素名を読み取る 4パターンある. 読み取った要素名は elm に格納する。
   222  						//
   223  						var stv string = "" // stv=蓄熱槽のスケジュール
   224  						var ci ELIOType = ELIO_SPACE
   225  						var co ELIOType = ELIO_SPACE
   226  
   227  						if idx := strings.IndexRune(s, '/'); idx >= 0 {
   228  							// ex: `xxx/LD`
   229  							s = s[idx+1:] // 蓄熱槽の機器名
   230  							stv = s[:idx] // stv=蓄熱槽のスケジュール
   231  						}
   232  						if idx := strings.IndexRune(s, ':'); idx >= 0 {
   233  							// ex: `LD:xxx`
   234  							Plist.Name = s
   235  							s = s[:idx]
   236  							elm = s
   237  						} else {
   238  							if idx := strings.IndexRune(s, '['); idx >= 0 {
   239  								// ex: `LD[r]`
   240  								// rは経路識別子
   241  								// 2流体式熱交換器や蓄熱槽のように構成要素が複数の経路にまたがる場合の書式
   242  								co, ci = ELIOType(s[idx+1]), ELIOType(s[idx+1])
   243  								s = s[:idx]
   244  								elm = s
   245  							} else {
   246  								// ex: `LD`
   247  								elm = s
   248  								co = ELIOType(0)
   249  								ci = ELIOType(0)
   250  							}
   251  						}
   252  
   253  						// SYSCMPで定義したシステム要素名から elm を探す
   254  						err := 1
   255  						_, cmp, er := FindComponent(elm, Compnt)
   256  						if er != nil {
   257  							panic(er)
   258  						}
   259  						err = 0
   260  
   261  						// 機器の種類に応じた処理分け
   262  						//
   263  						if cmp.Eqptype == FLIN_TYPE && len(Plist.Pelm) == 0 {
   264  							// 経路の先頭が流入境界条件である場合、経路の種類は流入境界条件である。
   265  							Plist.Type = IN_LPTP
   266  						} else if cmp.Eqptype == VALV_TYPE || cmp.Eqptype == TVALV_TYPE {
   267  							// バルブが見つかったので、後の処理のために経路と機器に相互参照を付与する
   268  							Plist.Nvalv++
   269  							Plist.Valv = cmp.Eqp.(*VALV)
   270  							Plist.Valv.Plist = Plist // 逆参照
   271  						} else if cmp.Eqptype == OMVAV_TYPE {
   272  							// OMバルブが見つかったので、後の処理のために経路と機器に相互参照を付与する
   273  							// Satoh OMVAV 2010/12/16
   274  							Plist.NOMVAV++
   275  							Plist.OMvav = cmp.Eqp.(*OMVAV)
   276  							Plist.OMvav.Plist = Plist // 逆参照
   277  						} else if cmp.Eqptype == VAV_TYPE || cmp.Eqptype == VWV_TYPE {
   278  							/*---- Satoh Debug VAV  2000/12/6 ----*/
   279  							// VAVユニットが見つかったが、見つかった数だけ記録する。
   280  							Plist.Nvav++
   281  						} else if cmp.Eqptype == QMEAS_TYPE {
   282  							/*---- Satoh Debug QMEAS  2003/6/2 ----*/
   283  							// カロリーメータが見つかったので、後の処理のために経路と機器に相互参照を付与する
   284  							// ただし、単一のカロリーメータは、3種類の値を同時に参照できるため注意する。
   285  							Qmeas = cmp.Eqp.(*QMEAS)
   286  							if co == ELIO_G {
   287  								Qmeas.G = &Plist.G
   288  								Qmeas.PlistG = Plist
   289  								Qmeas.Fluid = Mpath.Fluid
   290  							} else if co == ELIO_H {
   291  								Qmeas.PlistTh = Plist
   292  								Qmeas.Nelmh = id
   293  							} else if co == ELIO_C {
   294  								Qmeas.PlistTc = Plist
   295  								Qmeas.Nelmc = id
   296  							} else {
   297  								// NOTE: オリジナルコードではこのelseはない。念のため導入してみた。
   298  								panic(co)
   299  							}
   300  						} else if cmp.Eqptype == STANK_TYPE {
   301  							// 蓄熱槽が見つかった
   302  							if stv != "" {
   303  								Plist.Batch = true
   304  								stank = cmp.Eqp.(*STANK)
   305  								for i := 0; i < stank.Nin; i++ {
   306  									if stank.Pthcon[i] == co {
   307  										var err error
   308  										if iswc, err = idscw(stv, Schdl.Scw, ""); err == nil {
   309  											stank.Batchcon[i] = Schdl.Isw[iswc]
   310  										}
   311  									}
   312  								}
   313  							}
   314  						}
   315  
   316  						// バルブ、カロリーメータは末端経路ごとに1つまでのようだ
   317  						// その他の要素は複数存在しても良い。
   318  						if cmp.Eqptype != VALV_TYPE && cmp.Eqptype != TVALV_TYPE &&
   319  							cmp.Eqptype != QMEAS_TYPE && cmp.Eqptype != OMVAV_TYPE {
   320  
   321  							Pelm := NewPELM()
   322  							Pelm.Out = nil
   323  							Pelm.Cmp = cmp
   324  							Pelm.Ci = ci
   325  							Pelm.Co = co
   326  							//Pelmpre = Pelm
   327  
   328  							Plist.Pelm = append(Plist.Pelm, Pelm)
   329  							*Plm = append(*Plm, Pelm)
   330  						}
   331  
   332  						if cmp.Eqptype != VALV_TYPE && cmp.Eqptype != TVALV_TYPE &&
   333  							cmp.Eqptype != QMEAS_TYPE && cmp.Eqptype != DIVERG_TYPE &&
   334  
   335  							cmp.Eqptype != CONVRG_TYPE && cmp.Eqptype != DIVGAIR_TYPE &&
   336  							cmp.Eqptype != CVRGAIR_TYPE && cmp.Eqptype != OMVAV_TYPE {
   337  							id++
   338  						}
   339  
   340  						Errprint(err, errkey, elm)
   341  
   342  						if DEBUG {
   343  							fmt.Printf("<<Pathdata>> Mp=%s  elm=%s Npelm=%d\n", Mpath.Name, elm, len(*Plm))
   344  						}
   345  					}
   346  				}
   347  				// PELM読み込み用ループ 終了
   348  
   349  				*Plst = append(*Plst, Plist)
   350  				Mpath.Plist = append(Mpath.Plist, Plist)
   351  
   352  				Plist.Mpath = Mpath // 子→親の逆参照
   353  				//Pelmpre = nil
   354  				id = 0
   355  			} else {
   356  				Errprint(1, errkey, s)
   357  			}
   358  		}
   359  		// PLIST読み込み用ループ 終了
   360  
   361  		if DEBUG {
   362  			// 読み取ったMPATHの順番と流体種別を表示
   363  			fmt.Printf("<<Pathdata>>  Mpath=%d fliud=%c\n", len(*M), Mpath.Fluid)
   364  		}
   365  
   366  		// 流体種別が空気の場合: 空気系統用の絶対湿度経路へのコピーを行う必要がある
   367  		if Mpath.Fluid == AIR_FLD {
   368  			if DEBUG {
   369  				fmt.Printf("<<Pathdata  a>> Mp=%s  Npelm=%d\n", Mpath.Name, len(*Plm))
   370  			}
   371  
   372  			// 空気温度用の経路を追加
   373  			*M = append(*M, Mpath)
   374  
   375  			// if *Nplst > 0 {
   376  			// 	Mpath.Pl = make([]*PLIST, *Nplst)
   377  			// 	for k := 0; k < *Nplst; k++ {
   378  			// 		Mpath.Pl[k] = nil
   379  			// 	}
   380  			// }
   381  
   382  			// if *Nplst > 0 {
   383  			// 	Mpath.Cbcmp = make([]*COMPNT, *Nplst*2)
   384  			// 	for k := 0; k < *Nplst*2; k++ {
   385  			// 		Mpath.Cbcmp[k] = nil
   386  			// 	}
   387  			// }
   388  
   389  			// 空気系統用の絶対湿度経路へのコピー
   390  			Mpath_x := plistcpy(Mpath, Plm, Plst, Compnt)
   391  			*M = append(*M, Mpath_x)
   392  		} else {
   393  			*M = append(*M, Mpath)
   394  		}
   395  	}
   396  	// 最外ループ: MPATHの読み込み 完了
   397  
   398  	if DEBUG {
   399  		if len(*M) > 0 {
   400  			plistprint(*M, *Plm, *Elout, *Elin)
   401  		}
   402  
   403  		fmt.Printf("SYSPTH  Data Read end\n")
   404  		fmt.Printf("Nmpath=%d\n", len(*M))
   405  	}
   406  
   407  	/* ============================================================================ */
   408  
   409  	// すべてのMPATHについてのループ
   410  	for i, Mpath := range *M {
   411  		if DEBUG {
   412  			fmt.Printf("1----- MAX=%d  i=%d\n", len(*M), i)
   413  		}
   414  
   415  		ncv = 0
   416  
   417  		//
   418  		// --- pelmci or pelmco を呼び出す----
   419  		//
   420  		for j, Plist := range Mpath.Plist {
   421  
   422  			if DEBUG {
   423  				fmt.Printf("eepath.c  Mpath->Nlpath=%d\n", len(Mpath.Plist))
   424  				fmt.Printf("<<Pathdata>>  i=%d Mpath=%d  j=%d Plist=%d\n", i, i, j, j)
   425  			}
   426  
   427  			for m, Pelm := range Plist.Pelm {
   428  
   429  				if DEBUG {
   430  					fmt.Printf("<<Pathdata>>  m=%d  pelm=%d  %s\n", m, m, Pelm.Cmp.Name)
   431  					fmt.Printf("MAX=%d  m=%d\n", len(Plist.Pelm), m)
   432  				}
   433  
   434  				//
   435  				// --- システム要素入出力端割当 ---
   436  				//
   437  
   438  				idci := true // システム要素入力端割当を行うか?
   439  				idco := true // システム要素出力端割当を行うか?
   440  				etyp := Pelm.Cmp.Eqptype
   441  
   442  				if m == 0 && etyp == FLIN_TYPE {
   443  					// 末端経路の先頭要素が*流入境界条件*である場合
   444  					idci = false // 流入境界条件
   445  				}
   446  
   447  				if m == 0 && (etyp == CONVRG_TYPE || etyp == DIVERG_TYPE) {
   448  					// 末端経路の先頭要素が*水*の合流または分岐である場合
   449  					idci = false
   450  				} else if m == 0 && (etyp == CVRGAIR_TYPE || etyp == DIVGAIR_TYPE) {
   451  					// 末端経路の先頭要素が*空気*の合流または分岐である場合
   452  					idci = false
   453  				}
   454  
   455  				if m == len(Plist.Pelm)-1 && (etyp == CONVRG_TYPE || etyp == DIVERG_TYPE) {
   456  					// 末端経路の最後尾要素が*水*の合流または分岐である場合
   457  					idco = false
   458  				} else if m == len(Plist.Pelm)-1 && (etyp == CVRGAIR_TYPE || etyp == DIVGAIR_TYPE) {
   459  					// 末端経路の最後尾要素が*空気*の合流または分岐である場合
   460  					idco = false
   461  				}
   462  
   463  				if idci {
   464  					// システム要素入力端割当
   465  					pelmci(Mpath.Fluid, Pelm, errkey)
   466  					Pelm.In.Lpath = Plist
   467  				}
   468  
   469  				if idco {
   470  					// システム要素出力端割当
   471  					pelmco(Mpath.Fluid, Pelm, errkey)
   472  
   473  					Pelm.Out.Lpath = Plist
   474  					Pelm.Out.Fluid = Mpath.Fluid
   475  				}
   476  			}
   477  		}
   478  
   479  		if DEBUG {
   480  			plistprint((*M)[i:i+1], *Plm, *Elout, *Elin)
   481  			fmt.Printf("i=%d\n", i)
   482  		}
   483  
   484  		//
   485  		// --- 貫流経路か循環経路かの判定 + 要素間の接続 ---
   486  		//
   487  		if len(Mpath.Plist) == 1 {
   488  			//
   489  			// 末端経路の数が1の場合
   490  			//
   491  
   492  			Plist := Mpath.Plist[0]
   493  
   494  			if DEBUG {
   495  				fmt.Printf("<<Pathdata>>   Plist->type=%c\n", Plist.Type)
   496  			}
   497  
   498  			if Plist.Type == IN_LPTP {
   499  				Mpath.Type = THR_PTYP
   500  
   501  				if DEBUG {
   502  					fmt.Printf("<<Pathdata>>   Mpath->type=%c\n", Mpath.Type)
   503  				}
   504  			} else {
   505  				Mpath.Type = CIR_PTYP
   506  				Plist.Type = CIR_PTYP
   507  				Plist.Pelm[0].In.Upo = Plist.Pelm[len(Plist.Pelm)-1].Out
   508  			}
   509  
   510  			if DEBUG {
   511  				fmt.Printf("<<Pathdata>> test end\n")
   512  			}
   513  
   514  			// 2番目以降の要素について
   515  			for m = 1; m < len(Plist.Pelm); m++ {
   516  				Pelm := Plist.Pelm[m]
   517  				PelmPrev := Plist.Pelm[m-1]
   518  
   519  				// 要素間の接続: 1つ前の要素の出力への参照を設定
   520  				Pelm.In.Upo = PelmPrev.Out
   521  			}
   522  		} else {
   523  			//
   524  			// 末端経路の数が2以上の場合
   525  			//
   526  
   527  			Mpath.Type = BRC_PTYP
   528  
   529  			if DEBUG {
   530  				fmt.Printf("<<Pathdata>> Mpath i=%d  type=%c\n", i, Mpath.Type)
   531  			}
   532  
   533  			for j, Plist := range Mpath.Plist {
   534  				// 1. 先頭要素による判定
   535  				//
   536  				Pelm_0 := Plist.Pelm[0]
   537  				etyp_0 := Pelm_0.Cmp.Eqptype
   538  
   539  				if DEBUG {
   540  					fmt.Printf("<<Pathdata>> Plist j=%d name=%s eqptype=%s\n", j, Pelm_0.Cmp.Name, etyp_0)
   541  				}
   542  
   543  				if etyp_0 == DIVERG_TYPE || etyp_0 == DIVGAIR_TYPE {
   544  					// 先頭要素が水または空気の*分岐*である場合
   545  					Plist.Type = DIVERG_LPTP
   546  				}
   547  
   548  				if etyp_0 == CONVRG_TYPE || etyp_0 == CVRGAIR_TYPE {
   549  					// 先頭要素が水または空気の*合流*である場合
   550  					Plist.Type = CONVRG_LPTP
   551  					ncv++
   552  				}
   553  
   554  				// 2. 最後尾要素による判定
   555  				//
   556  				etyp_fin := Plist.Pelm[len(Plist.Pelm)-1].Cmp.Eqptype
   557  				if etyp_fin != DIVERG_TYPE && etyp_fin != CONVRG_TYPE &&
   558  					etyp_fin != DIVGAIR_TYPE && etyp_fin != CVRGAIR_TYPE {
   559  					// 最後尾要素が水または空気の分岐または合流である場合
   560  					Plist.Type = OUT_LPTP
   561  				}
   562  
   563  				// 2番目以降の要素について
   564  				for m := 1; m < len(Plist.Pelm); m++ {
   565  					Pelm := Plist.Pelm[m]
   566  					PelmPrev := Plist.Pelm[m-1]
   567  
   568  					// 要素間の接続: 1つ前の要素の出力への参照を設定
   569  					Pelm.In.Upo = PelmPrev.Out
   570  				}
   571  
   572  				if DEBUG {
   573  					fmt.Printf("<<Pathdata>> Plist MAX=%d  j=%d  type=%c\n", len(Mpath.Plist), j, Plist.Type)
   574  				}
   575  			}
   576  		}
   577  		Mpath.Ncv = ncv
   578  
   579  		if DEBUG {
   580  			fmt.Printf("2----- MAX=%d  i=%d\n", len(*M), i)
   581  		}
   582  	}
   583  
   584  	if DEBUG {
   585  		if len(*M) > 0 {
   586  			mpi := *M
   587  			plistprint(mpi, *Plm, *Elout, *Elin)
   588  		}
   589  	}
   590  
   591  	// バルブがモニターするPlistの検索
   592  	Valvinit(Eqsys.Valv, *M)
   593  
   594  	// 未知流量等の構造解析
   595  	pflowstrct(*M)
   596  
   597  	if DEBUG {
   598  		if len(*M) > 0 {
   599  			plistprint(*M, *Plm, *Elout, *Elin)
   600  		}
   601  	}
   602  
   603  	if DEBUG {
   604  		fmt.Printf("\n")
   605  		for i = range Compnt {
   606  			C := Compnt[i]
   607  			fmt.Printf("name=%s Nin=%d  Nout=%d\n", C.Name, C.Nin, C.Nout)
   608  		}
   609  	}
   610  }
   611  
   612  /***********************************************************************/
   613  
   614  func Mpathcount(fi *EeTokens, Pl *int) int {
   615  	var N int
   616  	var ad int
   617  	var s string
   618  
   619  	ad = fi.GetPos()
   620  	*Pl = 0
   621  
   622  	for fi.IsEnd() == false {
   623  		s = fi.GetToken()
   624  
   625  		if s == "*" {
   626  			break
   627  		}
   628  
   629  		if s == ";" {
   630  			N++
   631  		}
   632  
   633  		if s == ">" {
   634  			*Pl++
   635  		}
   636  	}
   637  
   638  	*Pl /= 2
   639  
   640  	fi.RestorePos(ad)
   641  
   642  	return N
   643  }
   644  
   645  /***********************************************************************/
   646  
   647  func Plcount(fi *EeTokens, N []int) {
   648  	i := 0
   649  	M := 0
   650  	ad := fi.GetPos()
   651  
   652  	for fi.IsEnd() == false {
   653  		s := fi.GetToken()
   654  
   655  		if s == "*" {
   656  			break
   657  		}
   658  
   659  		if s == ";" {
   660  			N[M] = i
   661  			M++
   662  			i = 0
   663  		}
   664  
   665  		if s == ">" {
   666  			i++
   667  			fi.GetToken() // skip next token
   668  		}
   669  	}
   670  
   671  	// Print the contents of the N slice for debugging purposes
   672  	// for i := 0; i < len(*N); i++ {
   673  	// 	fmt.Printf("i=%d pl=%d\n", i, (*N)[i])
   674  	// }
   675  
   676  	fi.RestorePos(ad)
   677  }
   678  
   679  /***********************************************************************/
   680  
   681  // 末端経路のシステム要素数を数える。
   682  // 流体が空気であって温・湿度の両方を計算する場合には、経路を複製して1経路を2経路分としてカウントする
   683  func Pelmcount(fi *EeTokens) int {
   684  	ad := fi.GetPos()
   685  	i := 1
   686  	N := 0
   687  
   688  	for fi.IsEnd() == false {
   689  		s := fi.GetToken()
   690  		i = 1
   691  
   692  		if s == "*" {
   693  			break
   694  		}
   695  
   696  		for fi.IsEnd() == false {
   697  			s = fi.GetToken()
   698  
   699  			if s == ";" {
   700  				break
   701  			}
   702  
   703  			if s == "-f" {
   704  				// 循環、通過流体の種類(水系統、空気系統の別)
   705  				t := fi.GetToken()
   706  
   707  				if t == "W" || t == "a" {
   708  					// W:水系統、a:空気系統で温度のみ計算
   709  					i = 1
   710  				} else {
   711  					// A:空気系統で温・湿度とも計算
   712  					i = 2 // 温・湿度に分けるので2経路としてカウントする
   713  				}
   714  			}
   715  
   716  			if s == "-sys" {
   717  				// `A` or `D`. システムの分類(A:空調・暖房システム、D:給湯システム)
   718  				fi.GetToken()
   719  			}
   720  
   721  			if s != ">" && s[:1] != "(" && s[:1] != "-" && s[:1] != ";" {
   722  				N += i
   723  			}
   724  		}
   725  	}
   726  
   727  	fi.RestorePos(ad)
   728  	return N
   729  }
   730  
   731  /***********************************************************************/
   732  
   733  func Elcount(C []*COMPNT) (int, int) {
   734  	var Nelout, Nelin int = 0, 0
   735  
   736  	for i := range C {
   737  		e := C[i].Eqptype
   738  		Nelout += C[i].Nout
   739  		Nelin += C[i].Nin
   740  
   741  		if e == HCLOADW_TYPE {
   742  			Nelin += 8
   743  		} else if e == THEX_TYPE {
   744  			Nelout += 4
   745  			Nelin += 14
   746  		}
   747  	}
   748  
   749  	Nelout *= 4
   750  	Nelin *= 4
   751  
   752  	return Nelout, Nelin
   753  }
   754  
   755  func FindComponent(name string, Compnt []*COMPNT) (int, *COMPNT, error) {
   756  	for i := range Compnt {
   757  		cmp := Compnt[i]
   758  		if cmp.Name == name {
   759  			return i, cmp, nil
   760  		}
   761  	}
   762  	return -1, nil, errors.New(fmt.Sprintf("Component %s not found", name))
   763  }
   764  
   765  // 定数ポインタの作成する。初期値は constValue とする。
   766  func CreateConstantValuePointer(constValue float64) *float64 {
   767  	val := new(float64)
   768  	*val = constValue
   769  	return val
   770  }