damyarou

python, GMT などのプログラム

設計 仮排水路設計における Flood Routine の活用(3)

記事の最後に行く

ここでは、「設計 仮排水路設計における Flood Routine の活用(2)」で述べた事項に関連する計算・作図プログラムのうち、以下の4つを掲載する。

  • トンネル標準断面作図プログラム
  • トンネル通水量計算・作図プログラム
  • 貯水池水位容量曲線作図プログラム
  • 洪水波形作図プログラム

トンネル標準断面作図プログラム

このような説明図を描くプログラムが意外に難しいというか面倒くさい。

断面形は、幅と高さが等しい複合円である。 この断面の場合、トンネル内幅を  D とすれば、上半円の半径は  D/2、下半円の半径は  D となり、インバート幅は  (\sqrt{3}-1) D=0.732 D となる。 道路トンネルの場合、インバート幅をきっちりした数字とする場合が多く、下半円の半径が中途半端な数字となることが多いが、水路トンネルの場合のインバートの制約は、施工用重機が往来できればいい。このため、水路トンネルとしてのこの断面形状は、幾何学的にきれいで結構気に入っている。

トンネル形状は、中心を原点として、水平右の点から角度を指定して (x, y) 座標を求めて置き、一気にプロットしている。

寸法線と寸法は、両矢印に記載するものと、片矢印に記載するものがあるため、以下のように3つの関数を作成して描画している。

両矢印を描く関数

def barrow(x1,y1,x2,y2):
    # (x1,y1),(x2,y2):両矢印始点と終点
    col='#333333'
    arst='<->,head_width=3,head_length=10'
    aprop=dict(arrowstyle=arst,connectionstyle='arc3',facecolor=col,edgecolor=col,shrinkA=0,shrinkB=0,lw=1)
    plt.annotate('',
        xy=(x1,y1), xycoords='data',
        xytext=(x2,y2), textcoords='data', fontsize=0, arrowprops=aprop)

片矢印を描く関数

def sarrow(x1,y1,x2,y2):
    # (x1,y1):矢印先端座標
    # (x2,y2):矢印始点座標
    col='#333333'
    arst='->,head_width=3,head_length=10'
    aprop=dict(arrowstyle=arst,connectionstyle='arc3',facecolor=col,edgecolor=col,shrinkA=0,shrinkB=0,lw=1)
    plt.annotate('',
        xy=(x1,y1), xycoords='data',
        xytext=(x2,y2), textcoords='data', fontsize=0, arrowprops=aprop)

指定した直線に対し文字列を描画する関数

def atext(x1,y1,x2,y2,ss,dd,ii):
    # (x1,y1),(x2,y2):矢印始点と終点
    # 矢印始点と終点座標は文字列の傾きを考慮して決定する
    # ss:描画文字列
    # dd:文字列中央の寸法線からの距離
    # ii:1なら寸法線の上側,2なら寸法線の下側にテキストを描画
    al=np.sqrt((x2-x1)**2+(y2-y1)**2)
    cs=(x2-x1)/al
    sn=(y2-y1)/al
    rt=np.degrees(np.arccos(cs))
    if y2-y1<0: rt=-rt
    if ii==1:
        xs=0.5*(x1+x2)-dd*sn
        ys=0.5*(y1+y2)+dd*cs
        plt.text(xs,ys,ss,ha='center',va='center',rotation=rt)
    else:
        xs=0.5*(x1+x2)+dd*sn
        ys=0.5*(y1+y2)-dd*cs
        plt.text(xs,ys,ss,ha='center',va='center',rotation=rt)

プログラム全文

import numpy as np
import matplotlib.pyplot as plt


def barrow(x1,y1,x2,y2):
    # (x1,y1),(x2,y2):両矢印始点と終点
    col='#333333'
    arst='<->,head_width=3,head_length=10'
    aprop=dict(arrowstyle=arst,connectionstyle='arc3',facecolor=col,edgecolor=col,shrinkA=0,shrinkB=0,lw=1)
    plt.annotate('',
        xy=(x1,y1), xycoords='data',
        xytext=(x2,y2), textcoords='data', fontsize=0, arrowprops=aprop)

    
def sarrow(x1,y1,x2,y2):
    # (x1,y1):矢印先端座標
    # (x2,y2):矢印始点座標
    col='#333333'
    arst='->,head_width=3,head_length=10'
    aprop=dict(arrowstyle=arst,connectionstyle='arc3',facecolor=col,edgecolor=col,shrinkA=0,shrinkB=0,lw=1)
    plt.annotate('',
        xy=(x1,y1), xycoords='data',
        xytext=(x2,y2), textcoords='data', fontsize=0, arrowprops=aprop)

    
def atext(x1,y1,x2,y2,ss,dd,ii):
    # (x1,y1),(x2,y2):矢印始点と終点
    # 矢印始点と終点座標は文字列の傾きを考慮して決定する
    # ss:描画文字列
    # dd:文字列中央の寸法線からの距離
    # ii:1なら寸法線の上側,2なら寸法線の下側にテキストを描画
    al=np.sqrt((x2-x1)**2+(y2-y1)**2)
    cs=(x2-x1)/al
    sn=(y2-y1)/al
    rt=np.degrees(np.arccos(cs))
    if y2-y1<0: rt=-rt
    if ii==1:
        xs=0.5*(x1+x2)-dd*sn
        ys=0.5*(y1+y2)+dd*cs
        plt.text(xs,ys,ss,ha='center',va='center',rotation=rt)
    else:
        xs=0.5*(x1+x2)+dd*sn
        ys=0.5*(y1+y2)-dd*cs
        plt.text(xs,ys,ss,ha='center',va='center',rotation=rt)

        
def tunnel(d0):
    rr=d0/2
    ang=np.linspace(0,np.pi,180,endpoint=False)
    xx1=rr*np.cos(ang)
    yy1=rr*np.sin(ang)
    rr=d0
    ang=np.linspace(np.pi,np.pi+np.radians(30),30,endpoint=True)
    xx2=d0/2+rr*np.cos(ang)
    yy2=rr*np.sin(ang)
    ang=np.linspace(np.radians(-30),0,30,endpoint=True)
    xx3=-d0/2+rr*np.cos(ang)
    yy3=rr*np.sin(ang)
    xx=np.hstack([xx1,xx2,xx3])
    yy=np.hstack([yy1,yy2,yy3])
    return xx,yy
    

def main():
    d0=8.0
    fsz=16
    xmin=-6; xmax=6
    ymin=-6; ymax=6
    plt.figure(figsize=(6,6),facecolor='w')
    plt.rcParams['font.size']=fsz
    plt.rcParams['font.family']='sans-serif'
    plt.xlim([xmin,xmax])
    plt.ylim([ymin,ymax])
    plt.axis('off')
    plt.gca().set_aspect('equal',adjustable='box')
#    plt.title(tstr,loc='center',fontsize=fsz)
    xx,yy=tunnel(d0)
    plt.plot(xx,yy,'-',color='#000000',lw=3)

    xtc=0; ytc= d0/2
    xbc=0; ybc=-d0/2
    xcl=-d0/2; ycl=0
    xcr= d0/2; ycr=0
    xbl=d0/2-d0*np.cos(np.radians(30)); ybl=-d0/2
    xbr=d0*np.cos(np.radians(30))-d0/2; ybr=-d0/2
    ds=1.0
    plt.plot([0,0],[ybc-0.5*ds,ytc+0.5*ds],'-.',color='#000000',lw=1)
    plt.plot([xcl-0.5*ds,xcr+0.5*ds],[0,0],'-.',color='#000000',lw=1)

    ss='$(\sqrt{3}-1) D$'; dd=0.5*ds; ii=-1
    plt.plot([xbl,xbl],[ybl,ybl-1.5*ds],'-',color='#000000',lw=1)
    plt.plot([xbr,xbr],[ybr,ybr-1.5*ds],'-',color='#000000',lw=1)
    x1=xbl; y1=ybl-1.0*ds; x2=xbr; y2=y1
    barrow(x1,y1,x2,y2)
    atext(x1,y1,x2,y2,ss,dd,ii)

    ss='$D$'; dd=0.3*ds; ii=1
    plt.plot([xcl,xcl],[ycl,ytc+1.5*ds],'-',color='#000000',lw=1)
    plt.plot([xcr,xcr],[ycr,ytc+1.5*ds],'-',color='#000000',lw=1)
    x1=xcl; y1=ytc+1.0*ds; x2=xcr; y2=y1
    barrow(x1,y1,x2,y2)
    atext(x1,y1,x2,y2,ss,dd,ii)

    ss='$D$'; dd=0.3*ds; ii=1
    plt.plot([xtc,xcl-1.5*ds],[ytc,ytc],'-',color='#000000',lw=1)
    plt.plot([xbl,xcl-1.5*ds],[ybl,ybl],'-',color='#000000',lw=1)
    x1=xcl-1.0*ds; y1=ybl; x2=x1; y2=ytc
    barrow(x1,y1,x2,y2)
    atext(x1,y1,x2,y2,ss,dd,ii)
 
    ss='$D \; / \; 2$'; dd=0.3*ds; ii=1
    x1=d0/2*np.cos(np.radians(30)); y1=x2=d0/2*np.sin(np.radians(30)); x2=0; y2=0
    sarrow(x1,y1,x2,y2)
    atext(x2,y2,x1,y1,ss,dd,ii)
    
    ss='$D$'; dd=0.3*ds; ii=1
    x1=xbr; y1=ybr; x2=xcl; y2=ycl;
    sarrow(x1,y1,x2,y2)
    atext(0.5*(x1+x2),0.5*(y1+y2),x1,y1,ss,dd,ii)
    x1=xbl; y1=ybl; x2=xcr; y2=ycr;
    sarrow(x1,y1,x2,y2)
    atext(x1,y1,0.5*(x1+x2),0.5*(y1+y2),ss,dd,ii)
    
    plt.tight_layout()
    fnameF='fig_model.jpg'
    plt.savefig(fnameF, dpi=100, bbox_inches="tight", pad_inches=0.1)
    plt.show()


#---------------
# Execute
#---------------
if __name__ == '__main__': main()

トンネル通水量計算・作図プログラム

等流水深部(自由水面)での計算は、通水断面積・潤辺は厳密な計算をせず、通水部を小さな台形に近似して計算している。

import numpy as np
import matplotlib.pyplot as plt


# global variables
dh=0.1 # increment of reservoir water level
g=9.8       # gravity acceleration
n=0.015     # Manning's roughness coefficient
elvs=64.0   # invert elevation of entrance     
elve=62.5   # invert elevation of exit


def drawfig():
    fsz=16
    xmin=0 ; xmax=5000; dx=500
    ymin=60; ymax=110; dy=10
    tstr='Discharge Capacity of Diversion Tunnel'
    plt.figure(figsize=(10,6),facecolor='w')
    plt.rcParams['font.size']=fsz
    plt.rcParams['font.family']='sans-serif'
    plt.xlim([xmin,xmax])
    plt.ylim([ymin,ymax])
    plt.xlabel('Discharge Capacity (m$^3$/s)')
    plt.ylabel('Reservoir water Level (EL.m)')
    plt.xticks(np.arange(xmin,xmax+dx,dx))
    plt.yticks(np.arange(ymin,ymax+dy,dy))
    plt.grid(color='#999999',linestyle='solid')
    plt.title(tstr,loc='left',fontsize=fsz)
    a_d0=np.array([5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0])
    l_col=[
        '#dddddd',
        '#cccccc',
        '#bbbbbb',
        '#aaaaaa',
        '#999999',
        '#666666',
        '#333333',
        '#000000',
    ]
    for d0,col in zip(a_d0,l_col):
        fnameR='inp_sec_{0:0>2d}.txt'.format(int(d0))
        data = np.loadtxt(fnameR, usecols=(0,1) , skiprows=0)
        el=data[:,0]
        qq=data[:,1]
        ss='D={0:.0f}m'.format(d0)
        plt.plot(qq,el,'-',color=col,lw=2,label=ss)
    plt.plot([xmin,xmax],[elvs,elvs],'-',color='#0000ff',lw=1)
    xs=10; ys=elvs; ss='Tunnel Entrance Invert EL.{0:.1f}m'.format(elvs)
    plt.text(xs,ys,ss,color='#0000ff',ha='left',va='top',fontsize=fsz)
    plt.legend(fontsize=fsz-2)
    fnameF='fig_sec.jpg'
    plt.savefig(fnameF, dpi=100, bbox_inches="tight", pad_inches=0.2)
    plt.show()

    
def loss_calc(ell,rho1,theta1,rho2,theta2,d0):
    a0=-0.5*d0
    r1=0.5*d0
    hd=r1
    nn=int((hd+r1)/dh)+1

    sel=[]
    sqq=[]
    saa=[]
    w1=d0*(np.sqrt(3)-1)
    i=(elvs-elve)/ell
    el=elvs
    qq=0.0
    aa=0.0
    ss=w1
    rr=aa/ss
    sel=sel+[el]
    sqq=sqq+[qq]
    saa=saa+[aa]
    # free flow
    for j in range(1,nn):
        h=dh*float(j)
        y=h-hd
        if y<0.0:
            r=d0; a=a0
        if 0.0<=y and y<=r1:
            r=r1; a=0.0
        x=a+np.sqrt(r**2-y**2)
        w2=2*x
        da=0.5*(w1+w2)*dh
        ds=2*np.sqrt(dh**2+np.abs(0.5*(w1-w2))**2)
        aa=aa+da
        ss=ss+ds
        rr=aa/ss
        vv=1/n*rr**(2/3)*np.sqrt(i)
        qq=aa*vv
        el=elvs+h
        w1=w2
        sel=sel+[el]
        sqq=sqq+[qq]
        saa=saa+[aa]
    # pressure flow
    fe=0.25
    fo=1.0
    fb1=(0.131+0.1632*(d0/rho1))*np.sqrt(theta1/90.0)
    fb2=(0.131+0.1632*(d0/rho2))*np.sqrt(theta2/90.0)
    ff=2*g*n*n/rr**(1/3)
    while 1:
        if 110.0<el: break
        h=h+dh
        el=elvs+h
        head=el-elve-hd
        vv=np.sqrt(2*g*head/(fe+fo+ff*ell/rr+fb1+fb2))
        qq=aa*vv
        sel=sel+[el]
        sqq=sqq+[qq]
        saa=saa+[aa]
        a_el=np.array(sel)
        a_qq=np.array(sqq)
        a_aa=np.array(saa)
    return a_el,a_qq,a_aa


def main():
    for d0 in [5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0]:
        fnameW='inp_sec_{0:0>2d}.txt'.format(int(d0))
        # inside tunnel
        ell=400.0
        rho1=230; theta1=39.5
        rho2=200; theta2=48.2
        sel1,sqq1,saa1=loss_calc(ell,rho1,theta1,rho2,theta2,d0)
        # outside tunnel
        ell=450.0
        rho1=260; theta1=39.5
        rho2=230; theta2=48.2
        sel2,sqq2,saa2=loss_calc(ell,rho1,theta1,rho2,theta2,d0)
        # total flow capacity
        sel=0.5*(sel1+sel2)
        sqq=sqq1+sqq2
        saa=saa1+saa2
        fout=open(fnameW,'w')
        for j in range(0,len(sel)):
            print('{0:10.3f}{1:10.3f}{2:10.3f}'.format(sel[j],sqq[j],saa[j]),file=fout)
        fout.close()
    drawfig()

    
#==============
# Execution
#==============
if __name__ == '__main__': main()

貯水池水位容量曲線作図プログラム

水位と容量の関係は、オリジナルデータでは標高10mピッチで与えられているため、3次スプラインで内挿し、標高1mピッチのデータとして出力・作図している。

import numpy as np
from scipy.interpolate import interp1d
import matplotlib.pyplot as plt


def drawfig(el1,vv1,el2,vv2):
    fsz=16
    xmin=0 ; xmax=500; dx=50
    ymin=60; ymax=110; dy=5
    tstr='Storage Capacity Curve'
    plt.figure(figsize=(10,6),facecolor='w')
    plt.rcParams['font.size']=fsz
    plt.rcParams['font.family']='sans-serif'
    plt.xlim([xmin,xmax])
    plt.ylim([ymin,ymax])
    plt.xlabel('Storage ($\\times 10^6 \; m^3$)')
    plt.ylabel('Reservoir water Level (EL.m)')
    plt.xticks(np.arange(xmin,xmax+dx,dx))
    plt.yticks(np.arange(ymin,ymax+dy,dy))
    plt.grid(color='#999999',linestyle='solid')
    plt.title(tstr,loc='left',fontsize=fsz)
    plt.plot(vv1,el1,'-',color='#0000ff',lw=2,clip_on=False)
    plt.plot(vv2,el2,'o',color='#0000ff',clip_on=False)
    fnameF='fig_hv.jpg'
    plt.savefig(fnameF, dpi=100, bbox_inches="tight", pad_inches=0.2)
    plt.show()


def main():
    # vv x 1e6 (m3)
    data=np.array([[60, 0],
               [70, 2.485],
               [80, 21.670],
               [90, 88.555],
               [100, 223.959],
               [110, 446.817],
               [120, 778.284],
               [130, 1238.519],
               [140, 1865.721],
               [150, 2375.546],
               [160, 3416.319],
               [170, 4773.768]])
    _el=data[:,0]
    _vv=data[:,1]
    f = interp1d(_el, _vv, kind='cubic')
    xmin=60
    xmax=170
    dx  =1
    ndx=int((xmax-xmin)/dx)+1
    el = np.linspace(xmin,xmax,ndx)
    vv =f(el)
    fnameW='inp_hv.txt'
    fout=open(fnameW,'w')
    for i in range(0,ndx):
        print('{0:5.1f}  {1:12.3f}'.format(el[i],vv[i]),file=fout)
    fout.close()

    ii1=np.where(el<=110)
    ii2=np.where(_el<=110)
    el1=el[ii1]; vv1=vv[ii1]
    el2=_el[ii2]; vv2=_vv[ii2]
    drawfig(el1,vv1,el2,vv2)

    
#==============
# Execution
#==============
if __name__ == '__main__': main()

洪水波形作図プログラム

1時間ピッチで与えられた流量をそのままプロットしている。 Flood Routine における水位追跡の時間ピッチは、ここで指定されている洪水波形の時間ピッチとしている。

import numpy as np
import matplotlib.pyplot as plt


def drawfig(tt,qq):
    fsz=16
    xmin=0 ; xmax=132; dx=12
    ymin=0; ymax=3500; dy=500
    tstr='Hydrograph (20 years return period flood)'
    plt.figure(figsize=(10,6),facecolor='w')
    plt.rcParams['font.size']=fsz
    plt.rcParams['font.family']='sans-serif'
    plt.xlim([xmin,xmax])
    plt.ylim([ymin,ymax])
    plt.xlabel('Time (hours)')
    plt.ylabel('Discharge (m$^3$/s)')
    plt.xticks(np.arange(xmin,xmax+dx,dx))
    plt.yticks(np.arange(ymin,ymax+dy,dy))
    plt.grid(color='#999999',linestyle='solid')
    plt.title(tstr,loc='left',fontsize=fsz)
    plt.plot(tt,qq,'-',color='#0000ff',lw=2)
    i=np.argmax(qq)
    plt.text(tt[i],qq[i],'Qmax={0:.0f}'.format(qq[i]),va='bottom',ha='center',color='#000000',fontsize=fsz)
    fnameF='fig_hydro.jpg'
    plt.savefig(fnameF, dpi=100, bbox_inches="tight", pad_inches=0.2)
    plt.show()


def main():
    fnameR='inp_hydro.txt'
    data = np.loadtxt(fnameR, usecols=(0,1) , skiprows=0)
    tt=data[:,0]
    qq=data[:,1]
    drawfig(tt,qq)

    
#==============
# Execution
#==============
if __name__ == '__main__': main()

Thank you.

記事の先頭に行く