====== mac1d_uns_v_1_0_0 ====== mac1d_uns_v_1_0_0.lzhをダウンロードして解凍すると、「**mac1d_uns_v_1_0_0.xls**」ができます。 この「**mac1d_uns_v_1_0_0.xls**」の使用方法を説明します。 ダウンロードについては、[[http://www.disaster-software.net|水理水文ソフトウェア]]のHPを参照してください。 ===== マクロの説明 ===== 本マクロは、各条件シートに条件を入力するだけで、**Maccormack法による1次元不定流計算**が行えます。 ==== 計算条件とデータの入力 ==== === 計算条件 === 「計算条件」シートに計算パラメータを入力します。また、Maccormack法の基本式と差分化について「計算条件」シートに書いていますので、参考資料とともに参照して下さい。 {{ :河川不定流計算:1次元不定流:image01.jpg?650|計算条件シート}} ;#; 計算条件シート ;#; * Δt : 計算刻み時間 * 計算時間 * 出力間隔 * EPS(乱流粘性係数) * 人工粘性係数 : 1.0から5.0の値経験的に決定する * 初期水深をデータで与えるか否か : True or Flase * 断面数 \\ 再度計算実行した場合は、計算結果シート(複数)の値がすべて上書きされます。 === 河道データ === {{ :河川不定流計算:1次元不定流:image02.jpg?650|河道シート}} ;#; 河道シート ;#; \\ * 距離 * 断面間距離 * 河床高 * 粗度係数 * 川幅 * 初期水位 * 初期水深 : 初期水深をデータで与える場合に必要となる。 === 流量データ === {{ :河川不定流計算:1次元不定流:image03.jpg?650|流量シート}} ;#; 流量シート ;#; \\ * データ数 * 経過時間 : 必ず0から始まる。 * 流量 ==== 計算結果 ====  計算結果は、以下の6つのシートに書き出されます。 グラフについては、使用者各自に作成して下さい。 * 結果シート : 出力間隔毎の計算結果 * 最終結果シート * 水深結果シート * 水位結果シート * 流速結果シート * 流量結果シート {{ :河川不定流計算:1次元不定流:image04.jpg?650|結果シート}} ;#; 結果シート ;#; \\ {{ :河川不定流計算:1次元不定流:image05.jpg?650|最終結果シート}} ;#; 最終結果シート ;#; \\ {{ :河川不定流計算:1次元不定流:image06.jpg?650|水深結果シート}} ;#; 水深結果シート ;#; \\ {{ :河川不定流計算:1次元不定流:image07.jpg?650|水位結果シート}} ;#; 水位結果シート ;#; \\ {{ :河川不定流計算:1次元不定流:image08.jpg?650|流速結果シート}} ;#; 流速結果シート ;#; \\ {{ :河川不定流計算:1次元不定流:image09.jpg?650|流量結果シート}} ;#; 流量結果シート ;#; \\ ===== VBAソースファイル =====  Maccromack法に1次元不定流計算の計算部分のソースコードを公開します。このマクロについては、ソースファイルはすべて公開しています。 Option Explicit Option Base 1 '計算キャンセルのフラグ Public windowflag As Boolean '最大配列数の宣言 Public Const ih As Long = 100 '流量データ最大数 'ベクトル式 Type vector2d x As Double y As Double End Type '変数の宣言 Private ied As Long '外部境界を含む断面分割数 +2 Private ndata As Long '外部境界を含む断面分割数 +2 Private dt As Double '計算刻み時間 Private dtdx As Double Private q As Double '流量 Private eps As Double '乱流粘性係数 Private kv As Double '人工粘性係数 Private istep As Long '繰り返し計算回数 Private otime As Double '出力時間間隔 Private nq As Long Private qinput As Double Public etime As Double Public time As Double '配列の宣言 Private z0() As Double '河床高 Private hinit() As Double '水深 Private level() As Double '水位 Private s0x() As Double '河床勾配ib Private totalx() As Double '累積距離 Private manning() As Double 'マニングの粗度係数 Private b0() As Double '川幅 Private dx() As Double '断面間距離 '流量関連の配列宣言 Public thyd(ih) As Double '流量データの時間 Public qhyd(ih) As Double '流量データ Public hhyd(ih) As Double '最下流端の水深 'ベクトルの定義 Private U() As vector2d Private preU() As vector2d Private E() As vector2d Private preE() As vector2d Private C() As vector2d Private preC() As vector2d Private V() As vector2d Private preV() As vector2d Private Const ist As Long = 2 '計算開始メッシュ Private Const g As Double = 9.8 '重力加速度 '************************************************ ' MacCormak法による1次元非定常流の計算 ' ' 人工粘性項としては、拡散法を適用 ' ' 合同会社TYS ' 技術開発部 ' 11/08/2011 ' ' 参考図書 エクセル河川数値解析入門 山海堂 ' 河村哲也 著 ISBN4-381-01696-3 ' '************************************************ Public Sub macRiver1d() Dim i As Long Dim j As Long Dim k As Long Dim n As Long Dim itout As Long Dim itt As Long Dim ncount As Long Dim mcount As Long Dim sst As Double '初期水深の与えた方のフラグ Dim hflag As Boolean 'ture:シートのデータ false:等流計算 '計算条件の読み込み Dim ws_jk As Worksheet Set ws_jk = Sheets("計算条件") dt = ws_jk.Range("_dt") etime = ws_jk.Range("_istep") otime = ws_jk.Range("_otime") 'q = ws_jk.Range("_q") eps = ws_jk.Range("_eps") kv = ws_jk.Range("_kv") hflag = ws_jk.Range("_hflag") itout = Int(otime / dt) itt = itout ied = ist + ws_jk.Range("_xdata") ndata = ied + 1 '配列の再宣言 ReDim z0(ndata) As Double ReDim hinit(ndata) As Double ReDim level(ndata) As Double ReDim s0x(ndata) As Double ReDim totalx(ndata) As Double ReDim manning(ndata) As Double ReDim b0(ndata) As Double ReDim dx(ndata) As Double ReDim U(ndata) As vector2d 'U(x,y) ReDim preU(ndata) As vector2d ReDim E(ndata) As vector2d 'E(x,y) ReDim preE(ndata) As vector2d ReDim C(ndata) As vector2d 'C(x,y) ReDim preC(ndata) As vector2d ReDim V(ndata) As vector2d 'V(x,y) ReDim preV(ndata) As vector2d '配列の初期化 For i = 1 To ndata z0(i) = 0# hinit(i) = 0# level(i) = 0# s0x(i) = 0# totalx(i) = 0# manning(i) = 0# b0(i) = 0# dx(i) = 0# Next i '計算結果シート内のデータ削除 Call SheetDataDel '計算データの読み込み Call readData '流量データの読み込み Dim ws_thq As Worksheet Set ws_thq = Sheets("流量データ") nq = ws_thq.Range("_nq") '流量データ数 For i = 1 To nq thyd(i) = ws_thq.Range("_time").Offset(i, 0) '時間 qhyd(i) = ws_thq.Range("_q").Offset(i, 0) '流量 hhyd(i) = ws_thq.Range("_h").Offset(i, 0) '水深 'Debug.Print i, thyd(i), qhyd(i) Next i '河床勾配の計算 Call setS0x '++++++++++++++++++++++++++++++++++++++++++++++++++++++ '初期水深を等流あるいは不等流計算で求める場合 'サブルーチンを用意しいますが、チェックしていませんので '利用者各自でテストして下さい。 If hflag = False Then Call Uniformflow 'Call non_Uniformflow End If '++++++++++++++++++++++++++++++++++++++++++++++++++++++ '初期条件の設定 Call setUInit Call setEInit Call setCInit time = 0 ncount = 0 mcount = 3 '初期状態の出力 'Call output(ncount) 'Call outputm(mcount) '定常計算を行い各段面の初期値を作成する '流量データのはじめの1ステップを定常計算とする。 For n = 1 To 50000 Call setDT Call predict Call correct '最上流端で同じqを与える U(ist).y = qhyd(1) preU(ist).y = qhyd(1) U(1).y = qhyd(1) preU(1).y = qhyd(1) 'Debug.Print "n="; n Next n '-------------------------------------------------- ' 非定常計算開始 '-------------------------------------------------- mstart: Application.StatusBar = "Calculate Step = " & CStr(time) & " / " & CStr(etime) '流量データの作成 For i = 2 To nq If (time >= thyd(i - 1)) And (time <= thyd(i)) Then '線形で流量を増減させる場合 'sst = (time - thyd(i - 1)) / (thyd(i) - thyd(i - 1)) 'qinput = qhyd(i - 1) + (qhyd(i) - qhyd(i - 1)) * sst 'ステップで流量を増減させる場合 qinput = qhyd(i - 1) End If Next i If windowflag = True Then GoTo mend: Call setDT Call predict Call correct '計算途中の出力 If (itt = itout) Then itt = 0 Call output(ncount) Call outputm(mcount) Debug.Print time End If itt = itt + 1 '定常計算の場合、最上流端で同じqを与える U(ist).y = qinput preU(ist).y = qinput U(1).y = qinput preU(1).y = qinput If (time > etime) Then GoTo mend: time = time + dt GoTo mstart: mend: '-------------------------------------------------- ' 計算終了 '-------------------------------------------------- '計算結果出力(最終の計算結果) Dim ws_o As Worksheet Set ws_o = Sheets("最終結果") For i = 1 To ied ws_o.Range("_X").Offset(i) = totalx(i) ws_o.Range("_I").Offset(i) = i ws_o.Range("_OB").Offset(i) = z0(i) ws_o.Range("_OSL").Offset(i) = hinit(i) + z0(i) ws_o.Range("_OL").Offset(i) = U(i).x / b0(i) + z0(i) ws_o.Range("_suishin").Offset(i) = U(i).x / b0(i) Next Close Application.StatusBar = False Set ws_o = Nothing Set ws_jk = Nothing End Sub Private Sub set_C() Dim i As Long Dim h As Double Dim uu As Double Dim ie As Double '摩擦勾配 Dim wk As Double Dim qq As Double For i = ist To ied - 1 C(i).x = 0 h = U(i).x / b0(i) qq = U(i).y uu = qq / (b0(i) * h) If h > 0 Then ie = manning(i) ^ 2 * uu * Abs(uu) / h ^ (4# / 3#) Else ie = 0 End If 'If h > 0 Then ' ie = manning(i) ^ 2 * qq ^ 2 / h ^ (10# / 3#) 'Else ' ie = 0 'End If wk = eps * (U(i - 1).y - 2 * U(i).y + U(i + 1).y) / dx(i) ^ 2 C(i).y = g * b0(i) * h * (s0x(i) - ie) + wk Next i C(ist - 1) = C(ist) C(ied) = C(ied - 1) End Sub '************************************************ ' 予測子段階で使う人工粘性係数の計算 ' ' '************************************************ Private Sub set_V() Dim i As Long Dim kx As Double Dim h As Double Dim uu As Double Dim ustar As Double Dim ief As Double Dim hdx As Double Dim hux As Double For i = ist To ied - 1 h = U(i).x / b0(i) uu = U(i).y / (h * b0(i)) '摩擦速度の計算 'If (h > 0) Then ' ief = ((h * manning(i)) ^ 2#) / (h ^ (4# / 3#)) 'エネルギー勾配 ' ustar = Sqr(g * h * ief) 'Else ' ustar = 0# 'End If If (h > 0) Then ustar = Sqr(g) * manning(i) * uu / (h ^ (1# / 6#)) Else ustar = 0# End If hdx = U(i - 1).x / b0(i - 1) hux = U(i + 1).x / b0(i + 1) kx = kv * ustar * h / dx(i) V(i).x = kx * (hdx - 2 * h + hux) V(i).y = kx * (U(i - 1).y - 2 * U(i).y + U(i + 1).y) Next i V(ist - 1) = V(ist) V(ied) = V(ied - 1) End Sub Private Sub set_E() Dim i As Long Dim h As Double Dim uu As Double For i = ist To ied - 1 h = U(i).x / b0(i) uu = U(i).y / (h * b0(i)) E(i).x = U(i).y E(i).y = 0.5 * g * b0(i) * h ^ 2 + uu ^ 2 * (b0(i) * h) Next i E(ist - 1) = E(ist) E(ied) = E(ied - 1) End Sub Private Sub set_preC() Dim i As Long Dim h As Double Dim uu As Double Dim qq As Double Dim ie As Double 'エネルギー勾配 Dim wk As Double For i = ist To ied - 1 preC(i).x = 0 h = preU(i).x / b0(i) qq = preU(i).y uu = qq / (h * b0(i)) If h > 0 Then ie = manning(i) ^ 2 * uu * Abs(uu) / h ^ (4# / 3#) Else ie = 0 End If 'If h > 0 Then ' ie = manning(i) ^ 2 * qq ^ 2 / h ^ (10# / 3#) 'Else ' ie = 0 'End If wk = eps * (preU(i - 1).y - 2 * preU(i).y + preU(i + 1).y) / dx(i) ^ 2 preC(i).y = g * b0(i) * h * (s0x(i) - ie) + wk Next i preC(ist - 1) = preC(ist) preC(ied) = preC(ied - 1) End Sub '************************************************ ' 修正子段階で使う人工粘性係数の計算 ' ' '************************************************ Private Sub set_preV() Dim i As Long Dim kx As Double Dim h As Double Dim uu As Double Dim ustar As Double Dim ief As Double Dim hdx As Double Dim hux As Double For i = ist To ied - 1 h = preU(i).x / b0(i) uu = preU(i).y / (h * b0(i)) '摩擦速度の計算 'If (h > 0) Then ' ief = ((h * manning(i)) ^ 2#) / (h ^ (4# / 3#)) 'エネルギー勾配 ' ustar = Sqr(g * h * ief) 'Else ' ustar = 0# 'End If If (h > 0) Then ustar = Sqr(g) * manning(i) * uu / (h ^ (1# / 6#)) Else ustar = 0# End If hdx = preU(i - 1).x / b0(i - 1) hux = preU(i + 1).x / b0(i + 1) kx = kv * ustar * h / dx(i) preV(i).x = kx * (hdx - 2 * h + hux) preV(i).y = kx * (preU(i - 1).y - 2 * preU(i).y + preU(i + 1).y) Next i preV(ist - 1) = preV(ist) preV(ied) = preV(ied - 1) End Sub Private Sub set_preE() Dim i As Long Dim h As Double, uu As Double For i = ist To ied - 1 h = preU(i).x / b0(i) uu = preU(i).y / (h * b0(i)) preE(i).x = preU(i).y preE(i).y = 0.5 * g * b0(i) * h ^ 2 + uu ^ 2 * (b0(i) * h) Next i preE(ist - 1) = preE(ist) preE(ied) = preE(ied - 1) End Sub '************************************************ ' 修正子段階の計算 ' ' '************************************************ Private Sub correct() Dim i As Long Call set_preE Call set_preV Call set_preC For i = ist To ied - 1 dtdx = dt / dx(i) U(i).x = (U(i).x + preU(i).x) _ - dtdx * (preE(i + 1).x - preE(i).x + preV(i + 1).x - preV(i).x) _ + dt * preC(i).x U(i).y = (U(i).y + preU(i).y) _ - dtdx * (preE(i + 1).y - preE(i).y + preV(i + 1).y - preV(i).y) _ + dt * preC(i).y U(i).x = U(i).x / 2# U(i).y = U(i).y / 2# Next i U(ist - 1) = U(ist) U(ied) = U(ied - 1) End Sub '************************************************ ' 予測子段階の計算 ' ' '************************************************ Private Sub predict() Dim i As Long Call set_E Call set_V Call set_C For i = ist To ied - 1 dtdx = dt / dx(i) preU(i).x = U(i).x _ - dtdx * (E(i).x - E(i - 1).x - V(i).x + V(i - 1).x) _ + dt * C(i).x preU(i).y = U(i).y _ - dtdx * (E(i).y - E(i - 1).y - V(i).y + V(i - 1).y) _ + dt * C(i).y Next i preU(ist - 1) = preU(ist) preU(ied) = preU(ied - 1) End Sub '************************************************ ' CFL条件による計算刻み時間の設定 ' ' '************************************************ Private Sub setDT() Dim i As Long Dim uu As Double Dim h As Double Dim da As Double Dim ddx As Double For i = ist To ied - 1 h = U(i).x / b0(i) uu = U(i).y / (h * b0(i)) If (h > 0#) Then da = dx(i) / (uu + Sqr(g * h) + 2 * eps / dx(i)) If dt > da Then dt = da End If End If Next i End Sub Private Sub setCInit() Dim i As Long Dim h As Double Dim uu As Double Dim qq As Double Dim ie As Double 'エネルギー勾配 For i = 1 To ied C(i).x = 0 h = hinit(i) qq = qhyd(1) uu = qhyd(1) / (h * b0(i)) If h > 0 Then ie = manning(i) ^ 2 * uu * Abs(uu) / h ^ (4# / 3#) Else ie = 0 End If 'If h > 0 Then ' ie = manning(i) ^ 2 * qq ^ 2 / h ^ (10# / 3#) 'Else ' ie = 0 'End If C(i).y = g * b0(i) * h * (s0x(i) - ie) preC(i) = C(i) Next i End Sub Private Sub setEInit() Dim i As Long Dim h As Double Dim uu As Double For i = 1 To ied h = hinit(i) uu = qhyd(1) / (h * b0(i)) E(i).x = qhyd(1) E(i).y = (g * b0(i) * h ^ 2) / 2# + uu ^ 2 * (b0(i) * h) preE(i) = E(i) Next i End Sub Private Sub setUInit() Dim i As Long For i = 1 To ied U(i).x = b0(i) * hinit(i) U(i).y = qhyd(1) preU(i) = U(i) Next i End Sub Private Sub setS0x() Dim i As Long For i = ist To ied - 1 s0x(i) = (z0(i - 1) - z0(i + 1)) / (dx(i - 1) + dx(i + 1)) Next i s0x(ist - 1) = s0x(ist) s0x(ied) = s0x(ied - 1) End Sub Private Sub readData() Dim i As Long Dim tl As Double Dim ws_data As Worksheet Set ws_data = Sheets("河道データ") For i = 1 To ied totalx(i) = ws_data.Cells(i + 2, "B") '累積距離 dx(i) = ws_data.Cells(i + 2, "C") '断面区間距離 z0(i) = ws_data.Cells(i + 2, "D") '河床高 manning(i) = ws_data.Cells(i + 2, "E") 'マニングの粗度係数 b0(i) = ws_data.Cells(i + 2, "F") '川幅 level(i) = ws_data.Cells(i + 2, "G") '水位 hinit(i) = level(i) - z0(i) '水深 Next i End Sub '************************************************ ' 等流計算 ' 初期水位として使用する ' '************************************************ Private Sub Uniformflow() Dim i As Long Dim qq As Double Dim zs0x As Double qq = qhyd(1) zs0x = (z0(1) - z0(ied)) / totalx(ied) '等流水深 For i = 1 To ied If s0x(i) > 0 Then hinit(i) = (manning(i) * qq / b0(i) / (Sqr(s0x(i)))) ^ (3# / 5#) '河床勾配が正の場合 Else hinit(i) = (manning(i) * qq / b0(i) / (Sqr(zs0x))) ^ (3# / 5#) '河床勾配が負の場合 End If level(i) = z0(i) + hinit(i) Next i End Sub '************************************************ ' 不等流計算(ルンゲ・クッタ法) ' 初期水位として使用する ' '************************************************ Private Sub non_Uniformflow() Dim i As Long Dim qq As Double Dim aa As Double Dim bb As Double Dim cc As Double Dim fh As Double Dim fdh As Double Dim dh As Double Dim h00 As Double Dim zang As Double Dim hs(1000) As Double qq = q '不等流水深 zang = Abs(z0(2) - z0(1)) / dx(1) hinit(1) = (manning(1) * qq / b0(1) / (Sqr(zang))) ^ (3# / 5#) 'h00 hs(1) = hinit(1) For i = 2 To ied cc = -z0(i) + z0(i - 1) - hs(i - 1) - qq ^ 2 / (2# * g * b0(i) ^ 2 * hs(i - 1) ^ 2) _ - dx(i) * manning(i) ^ 2 * qq ^ 2 / (2# * b0(i) ^ 2 * hs(i - 1) ^ (10# / 3#)) hs(i) = hs(i - 1) g120: aa = qq ^ 2 / (2# * g * b0(i) ^ 2) bb = -dx(i) * manning(i) ^ 2 * qq ^ 2 / (2# * b0(i) ^ 2) fh = hs(i) + aa / hs(i) ^ 2 + bb / hs(i) ^ (10# / 3#) + cc fdh = 1# - 2# * aa / hs(i) ^ 3 - 10# / 3# * bb / hs(i) ^ (13# / 3#) dh = -fh / fdh If Abs(dh) < 0.00001 Then GoTo g135: hs(i) = hs(i) + dh If hs(i) <= 0 Then hs(i) = hs(i) - dh / 2# End If GoTo g120: g135: hinit(i) = hs(i) 'Debug.Print i, hinit(i) level(i) = z0(i) + hinit(i) Next i End Sub '-------------------------------------------- ' 計算結果の出力その1 ' '-------------------------------------------- Private Sub output(ncount As Long) Dim i As Long Dim ws_out As Worksheet Set ws_out = Sheets("結果") ncount = ncount + 1 ws_out.Cells(ncount, 1) = "time:" ws_out.Cells(ncount, 2) = time ncount = ncount + 1 ws_out.Cells(ncount, 1) = "i" ws_out.Cells(ncount, 2) = "累積距離" ws_out.Cells(ncount, 3) = "水深" ws_out.Cells(ncount, 4) = "流速" ws_out.Cells(ncount, 5) = "流量" ws_out.Cells(ncount, 6) = "川幅" ws_out.Cells(ncount, 7) = "河床高" ws_out.Cells(ncount, 8) = "水位" For i = 1 To ied ncount = ncount + 1 ws_out.Cells(ncount, 1) = i ws_out.Cells(ncount, 2) = totalx(i) ws_out.Cells(ncount, 3) = U(i).x / b0(i) ws_out.Cells(ncount, 4) = U(i).y / U(i).x ws_out.Cells(ncount, 5) = U(i).y ws_out.Cells(ncount, 6) = b0(i) ws_out.Cells(ncount, 7) = z0(i) ws_out.Cells(ncount, 8) = z0(i) + U(i).x / b0(i) Next i End Sub '-------------------------------------------- ' 計算結果の出力その2 ' '-------------------------------------------- Public Sub outputm(mcount As Long) Dim i As Long Dim n As Long Dim ws_h As Worksheet Set ws_h = Sheets("水深結果") Dim ws_i As Worksheet Set ws_i = Sheets("水位結果") Dim ws_u As Worksheet Set ws_u = Sheets("流速結果") Dim ws_q As Worksheet Set ws_q = Sheets("流量結果") 'mcount = mcount + 1 ws_h.Cells(1, mcount) = Int(time + dt) & "step" ws_i.Cells(1, mcount) = Int(time + dt) & "step" ws_u.Cells(1, mcount) = Int(time + dt) & "step" ws_q.Cells(1, mcount) = Int(time + dt) & "step" 'time & "step" n = 0 For i = 1 To ied n = n + 1 ws_h.Cells(i + 1, 1) = Int(i) & "断面" ws_h.Cells(i + 1, 2) = totalx(i) ws_h.Cells(i + 1, mcount) = U(i).x / b0(i) ws_i.Cells(i + 1, 1) = Int(i) & "断面" ws_i.Cells(i + 1, 2) = totalx(i) ws_i.Cells(i + 1, mcount) = U(i).x / b0(i) + z0(i) ws_u.Cells(i + 1, 1) = Int(i) & "断面" ws_u.Cells(i + 1, 2) = totalx(i) ws_u.Cells(i + 1, mcount) = U(i).y / U(i).x ws_q.Cells(i + 1, 1) = Int(i) & "断面" 'i & "断面" ws_q.Cells(i + 1, 2) = totalx(i) ws_q.Cells(i + 1, mcount) = U(i).y Next i mcount = mcount + 1 End Sub