Hydraulic design of restricted orifice surge tank
(25 March 2021)
This document describes design formulas and design example of restricted orifice surge tank.
Introduction
Function of surge tank
In general, a long pressure tunnel, the headrace / tailrace of pumped storage power plant needs a surge tank. The necessity of surge tank is judged whether length of pressure tunnel exceeds 500m or not. A surge tank has following functions.
- To absorb abnormal pressure increase in the tunnel by water hammering when load rejection or input power rejection.
- To absorb the abnormal pressure decrease in the tunnel by supplying water when rapid increase of discharge.
Surge tanks are categorized in following 4 types.
- Simple surge tank
- Differential surge tank
- Restricted orifice surge tank (An orifice of a surge tank is called a ”port”)
- Surge tank with chamber
These days Restricted Orifice Surge Tanks are usually adopted. This type can effectively attenuate amplitude of the water level in the tank and has comparatively simple design. In addition, in the case that a surge tank is constructed deep under the ground, such as a tailrace surge tank, the diameter of vertical shaft can be reduced by adding upper chamber.
Requirements for Hydraulic Design of Restricted Orifice Surge Tank
The following conditions are required for the design of Restricted Orifice Surge Tank.
- The maximum amplitude of water level by surging is between the elevation of top and bottom of the tank.
- To meet the required static and dynamic stability conditions of water level amplitude.
- Maximum discharge does not exceed the following critical discharge.
Fundamental differential equations
Equation of motion
Euler's equation of fluid motion in one-dimensional problem is as follows.
When the flow direction from reservoir to surge tank is positive, and the direction of water surface movement from up to dawn on the basis of reservoir water level in a surge tank is positive, positive gradient of water head is upward movement of water level in the surge tank.
If head loss exists, the acceleration of the water in the pressure tunnel is reduced by .
Because friction loss ([tex:h=cvv]) in the pressure tunnel and resistance loss of the port () are caused in the case of Restricted Orifice Surge Tank, the equation of motion is given as follows taking into consideration the flow direction.
Equation of continuity
When all flow direction of tunnel discharge, discharge in a surge tank and discharge of turbine is assumed positive, equation of continuity is given as follows.
Resistance of port
Because the port velocity () is what discharge in a surge tank is divided by the effective area of the port, the resistance of the port () can be given as follows, considering the flow direction.
Fundamental differential equations
In the surging analysis, above simultaneous differential equations are solved by Runge-Kutta method and the time series of the water surface profile in the surge tank can be obtained.
Equations for basic design of restricted orifice surge tank
Maximum water level rise in surge tank
For the estimation of the maximum water level rise from reservoir water level at the total load interception in the restricted orifice surge tank, Vogt-Forchheimer's equations shown below have been used.
These equations are one of the simple solution of the fundamental differential equation under the condition of instant interception of initial discharge.
To obtain the maximum water level rise of , Bisection method can be applied considering below equations.
In bove equations, the following conditions have to be satisfied everytime. These are for maintaining the positive values in the logarithm paragraph in the function of .
Considering above conditions, the minimum limit of in Bisection method can be set as followings.
And the maximum water level rise in the restricted orifice surge tank have to be smaller than the maximum water level rise of free surging. Therefore, the maximum water level rise of free surging shown below can be set as the maximum limit of in Bisection method.
Using and as limit values of Bisection method, Vogt-Forchheimer's equations can be solved.
For the calculation of the water level rise, following issues shall be considered.
- To adopt the most rigid condition of water level of the reservoir corresponding to the discharge conditions.
- To set the small roughness in the case of load imterception or input interception, and to set the large roughness in the case of load rapid increase.
The actual conditions based on METI standard considered are shown below.
Case | water level and roughness |
Headrace surge tank |
Tailrace surge tank |
---|---|---|---|
Load interception |
Reservoir water level Checked water level in shaft Variation of roughness |
HWL of upper reservoir Up surge WL |
LWL of lower reservoir Down surge WL |
Load rapidly increase |
Reservoir water level Checked water level in shaft Variation of roughness |
LWL of upper reservoir Down surge WL |
HWL of lower reservoir Up surge WL |
Input interception |
Reservoir water level Checked water level in shaft Variation of roughness |
LWL of upper reservoir Down surge WL |
HWL of lower reservoir Up surge WL |
note
- Above values of roughness variable are for concrete lining.
- In case of steel lining, roughness variable is instead of for concrete.
- In case of no lining, roughness variable is instead of for concrete.
Requirement for stability of water level vibration
For the stability against the water level vibration, Thoma-Schuller's stability conditions shown below shall be satisfied.
where, means the gross head and .
Critical discharge
The critical discharge by Calame-Garden is defined as follow.
If the critical discharge of is smaller than the maximum discharge of , the maximum water level rise for the critical discharge of shall be checked. However, the surge tank shaft diameter is usually defined to satisfy the condition of .
Required conditions for section area of surge tank shaft
Considering the conditions for the stability and the critical discharge, the section area of surge tank shaft of is defined to satisfy the following conditions.
Port diameter and shaft diameter
The resistance of the port can be calculated as follow.
The relationship between port resistance and the maximum water Level rise are shown below.
where, can be obtained from Vogt-Forchheimer's equations.
Usually, the port diameter is defined as a value which is little bit larger than the optimal point.
Design of chamber type surge tank
Since the Vogt-Forchheimer's equations give the maximum water level rise for a sinmle shaft type surge tank, ingenuity is needed to define the shape of chamber type surge tank. In case that a chamber type surge tank is required, the chamber size can be defined refering following figures. It shall be noted an air tunnel should be installed for a chamber type surge tank at the top of chamber.
Simple shaft type | Chamber type |
---|---|
Numerical solution of fundamental differential equations
Basic equations of Runge-Kutta method
Runge-Kutta method is a numerical integration method for the first order ordinary differential equation. The basic equatuins are shown below.
Solution by Runge-Kutta method
Subject
Using the known parameters of , and at time , to estimate the unknown parameters of and at time , where the value of at time is given (known) parameter.
Step of solving
Firstly, following functions are defined for the surging analysis.
Where,
The calculation steps by Runge-Kutta method are shown.
Step-1
Step-2
Step-3
Step-4
Step-5
Design example
Headrace surge tank of PSPP
Preparation work
Since the head loss is calculated for the maximum plant discharge in many cases, the head loss for design of surge tank will be modified as shown below considering changes of the discharge and Manning's roughness coefficient also.
Item | Symbol | Unit | Load interception |
Load increase |
Input interception |
---|---|---|---|---|---|
Discharge | Q_org | m3/s | 338 | 338 | 236.6 |
Reservoir water level | RWL | EL.m | 1340 (FSL) |
1315 (MOL) |
1315 (MOL) |
Roughness coefficient | n_org | 0.013 | 0.013 | 0.013 | |
Headloss of pressure tunnel | hl_org | m | 13.065 | 13.065 | 13.065 |
Modified roughnee coefficient |
n | 0.0115 (-0.0015) |
0.0145 (+0.0015) |
0.0115 (-0.0015) |
|
Modified head loss | hl | m | 10.224 | 16.254 | 5.010 |
note
A midified head loss is calculated using following equation.
Where,
- is headloss at discharge of and roughness coefficient of .
- is headloss at discharge of and roughness coefficient of .
Actual calculations of modified head losses of pressure tunnel are shown below.
For load interception
For load increase
For input interception
Input data arrangement for surging analysis
Item | Symbol | Unit | Load interception |
Load increase |
Input interception |
---|---|---|---|---|---|
Gross head | Hg | m | 677 | 677 | 677 |
Discharge | Q | m3/s | 338 => 0 |
169 => 338 |
236.6 => 0 |
Closing time | Tc | sec | 8 | 40 | 8 |
Reservoir water level | RWL | EL.m | 1340 (FSL) |
1315 (MOL) |
1315 (MOL) |
Diameter of pressure tunnel | d | m | 8.2 | 8.2 | 8.2 |
Length of pressure tunnel | L | m | 4800 | 4800 | 4800 |
Section area of pressure tunnel | f | m2 | 52.810 | 52.810 | 52.810 |
Average velocity of pressure tunnel |
v0 | m/s | 6.400 | 6.400 | 4.478 |
Headloss of pressure tunnel | hl | m | 10.224 | 16.254 | 5.010 |
Velocity head of pressure tunnel |
hb | m | 2.090 | 2.090 | 1.023 |
Total headloss | h0=hl+hb | m | 12.314 | 18.344 | 6.033 |
Loss coefficient of pressure tunnel |
c=h0/v02 | 0.301 | 0.448 | 0.310 | |
Diameter of shaft | DF | m | 21.000 | 21.000 | 21.000 |
Diameter of port | Dp | m | 4.500 | 4.500 | 4.500 |
Section area of shaft | F | m2 | 346.316 | 346.316 | 346.316 |
Section area of shaft | Fp | m2 | 15.904 | 15.904 | 15.904 |
Discharge coefficient of port | Cd | 0.9 | 0.9 | 0.9 |
note
- Items shown by bold font in above table are defined by the analysis using Vogt-Forchheimer's equations.
- The discharge coefficient of port for inflow () is not always the same as that for outflow (), and the values depend on the detailed shape of the port. However, the safety side results can be obtained, if the larger discharge coefficients are used. Therefore, has been used for some studies.
Selection of shaft diameter and port diameter
For the headrace surge tank, The shaft diameter of 21.0m and the port diameter of 4.5m are selected considering the target water level rise of 35m.
* Free surge water rise Ds=20 z*=58.075 Ds=21 z*=55.310 Ds=22 z*=52.796 Ds=23 z*=50.500 Ds=24 z*=48.396 * Requirements for stability Hg/6=112.833m # for static stabity Dsr1= 7.0m # for dynamic stability (1) Dsr2= 9.2m # for dynamic stability (2) Dsr3=43.9m # for critical discharge
Result of surging analysis of headrace surge tank
Tailrace surge tank of PSPP
Preparation work
Since the head loss is calculated for the maximum plant discharge in many case, the head loss for design of surge tank will be modified as shown below considering changes of the discharge and Manning's roughness coefficient also.
Item | Symbol | Unit | Load interception |
Load increase |
Input interception |
---|---|---|---|---|---|
Discharge | Q_org | m3/s | 338 | 338 | 236.6 |
Reservoir water level | RWL | EL.m | 630 (MOL) |
670 (FSL) |
670 (FSL) |
Roughness coefficient | n_org | 0.013 | 0.013 | 0.013 | |
Headloss of pressure tunnel | hl_org | m | 5.151 | 5.151 | 5.151 |
Modified roughnee coefficient |
n | 0.0115 (-0.0015) |
0.0145 (+0.0015) |
0.0115 (-0.0015) |
|
Modified head loss | hl | m | 4.031 | 6.408 | 1.975 |
note
A midified head loss is calculated using following equation.
Where, + [tex:h{l1}] is headloss at discharge of and roughness coefficient of . + [tex:h{l2}] is headloss at discharge of and roughness coefficient of .
Actual calculations of modified head losses of pressure tunnel are shown below.
For load interception
For load increase
For input interception
Input data arrangement for surging analysis
Item | Symbol | Unit | Load interception |
Load increase |
Input interception |
---|---|---|---|---|---|
Gross head | Hg | m | 677 | 677 | 677 |
Discharge | Q | m3/s | 338 => 0 |
169 => 338 |
236.6 => 0 |
Closing time | Tc | sec | 8 | 40 | 8 |
Reservoir water level | RWL | EL.m | 630 (MOL) |
670 (FSL) |
670 (FSL) |
Diameter of pressure tunnel | d | m | 8.2 | 8.2 | 8.2 |
Length of pressure tunnel | L | m | 1749 | 1749 | 1749 |
Section area of pressure tunnel | f | m2 | 52.810 | 52.810 | 52.810 |
Average velocity of pressure tunnel |
v0 | m/s | 6.400 | 6.400 | 4.480 |
Headloss of pressure tunnel | hl | m | 4.031 | 6.408 | 1.975 |
Velocity head of pressure tunnel |
hb | m | 2.090 | 2.090 | 1.024 |
Total headloss | h0=hl+hb | m | 6.121 | 8.498 | 2.999 |
Loss coefficient of pressure tunnel |
c=h0/v02 | 0.149 | 0.207 | 0.149 | |
Diameter of shaft | DF | m | 10.000 | 10.000 | 10.000 |
Diameter of port | Dp | m | 4.500 | 4.500 | 4.500 |
Section area of shaft | F | m2 | 78.540 | 78.540 | 78.540 |
Section area of shaft | Fp | m2 | 15.904 | 15.904 | 15.904 |
Discharge coefficient of port | Cd | 0.9 | 0.9 | 0.9 |
note
- Items shown by bold font in above table are defined by the analysis using Vogt-Forchheimer's equations.
- The discharge coefficient of port for inflow () is not always the same as that for outflow (), and the values depend on the detailed shape of the port. However, the safety side results can be obtained, if the larger discharge coefficients are used. Therefore, has been used for some studies.
Selection of shaft diameter and port diameter
For the tailrace surge tank, The shaft diameter of 10.0m and the port diameter of 4.5m are selected considering the required minimum shaft diameter of 8.0m which is defined to satisfy the dynamic stability condition. For the tailrace surge tank, the target water level rise is not considered, because it can have a upper chamber.
* Free surge water rise Ds= 8 z*=87.641 Ds= 9 z*=77.903 Ds=10 z*=70.113 Ds=11 z*=63.739 Ds=12 z*=58.427 * Requirements for stability Hg/6=112.833m # for static stabity Dsr1= 4.6m # for dynamic stability (1) Dsr2= 8.0m # for dynamic stability (2) Dsr3=37.6m # for critical discharge
Dimensions of upper chamber
Since the water level rise to the upsurge water level from FSL of the lower reservoir is 52.363m which is estimated by Vogt-Forchheimer's equations, the corresponding water volume can be calculated as follow.
In case that the invert level of upper chamber is set to 10m higher than the FSL of lower reservoir and the chamber dimensions are assumed as 15.0m wide x 7.0m high x 40.0m long, the water volume corresponding to these volumes can be calculated as follows.
From above,
Therefore, assumed chamber dimensions can be accepted. The wall height of upper chamber will be set as 8.0m with 1.0m margin to water surface.
Result of surging analysis of headrace surge tank
Programs
Maximum water level rize
#============================== # Vogt-Forchheimer's equation # Bisection Method #============================== import numpy as np import matplotlib.pyplot as plt # global variables g=9.8 # gravity acceleration def inp_JH(): q0=338 # discharge of pressure tunnel cd=0.9 # discharge coefficient of port h0=12.314 # head loss of pressure tunnel tl=4800 # length of pressure tunnel including untake tunnel ft=52.810 # section area of pressure tunnel hg=677 # gross head dds=21 # design shaft diameter ddp=4.5 # design port diameter shaft=np.arange(20,25,1).astype(np.float64) # shaft diameter: parameter port=np.arange(0.1,10.05,0.05).astype(np.float64) # port diameter: parameter tstr='PSPP-J Headrace Surge Tank (h0={0:.3f})'.format(h0) xmin=0; xmax=10; dx=1 ymin=0; ymax=50; dy=10 fnameF='fig_JH_zmax.png' return q0,cd,h0,tl,ft,hg,dds,ddp,shaft,port,tstr,xmin,xmax,dx,ymin,ymax,dy,fnameF def inp_JT(): q0=338 # discharge of pressure tunnel cd=0.9 # discharge coefficient of port h0=6.121 # head loss of pressure tunnel tl=1749 # length of pressure tunnel including untake tunnel ft=52.810 # section area of pressure tunnel hg=677 # gross head dds=10 # design shaft diameter ddp=4.5 # design port diameter shaft=np.arange(8,13,1).astype(np.float64) # shaft diameter: parameter port=np.arange(0.1,10.05,0.05).astype(np.float64) # port diameter: parameter tstr='PSPP-J Tailrace Surge Tank (h0={0:.3f})'.format(h0) xmin=0; xmax=10; dx=1 ymin=0; ymax=90; dy=10 fnameF='fig_JT_zmax.png' return q0,cd,h0,tl,ft,hg,dds,ddp,shaft,port,tstr,xmin,xmax,dx,ymin,ymax,dy,fnameF def drawfig(shaft,port,zz,zd,dzz,ddp,xmin,xmax,dx,ymin,ymax,dy,tstr,fnameF): fsz=16 xsize=8; ysize=6 # size of figure fig=plt.figure(figsize=(xsize,ysize),facecolor='w') plt.rcParams['font.size']=fsz plt.rcParams['font.family']='sans-serif' plt.xlim([xmin,xmax]) plt.ylim([ymin,ymax]) plt.xlabel('Port diameter (m)') plt.ylabel('Maximum water level rise (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) for i,sh in enumerate(shaft): # Since zm is monotone increasing function for port diameter, # non-converged values of zm are omitted from plot data n=np.argmin(zz[i,:]) plt.plot(port[n:],zz[i,n:],color='#000000',lw=1) xs=xmax ys=zz[i,-1] ss='Ds={0:.0f}m'.format(sh) plt.text(xs,ys,ss,color='#000000',ha='right',va='bottom',fontsize=fsz-2) plt.plot([xmin],[ymin],'-',color='#000000',lw=1,label="Water level rise") plt.plot(port,zd,'--',color='#000000',lw=1,label="$|z_m'|=k_0-h_0$") plt.plot([ddp],[dzz],'o',color='#000000',ms=8,label='Design point') plt.plot([xmin,ddp],[dzz,dzz],'-',color='#000000',lw=0.5) plt.plot([ddp,ddp],[ymin,dzz],'-',color='#000000',lw=0.5) ss1='Dp={0:.1f}m'.format(ddp) ss2='Zmax={0:.3f}m'.format(dzz) plt.text(ddp,ymin,ss1,color='#000000',ha='left',va='bottom',rotation=90,fontsize=fsz-2) plt.text(xmin,dzz,ss2,color='#000000',ha='left',va='bottom',rotation=0,fontsize=fsz-2) # plt.legend(loc='lower right',fontsize=fsz-2,shadow=True) plt.legend(loc='lower right',fontsize=fsz-2,shadow=True,numpoints=1,title='Ds: shaft diameter').get_title().set_fontsize(fsz-2) plt.tight_layout() plt.savefig(fnameF, dpi=200, bbox_inches="tight", pad_inches=0.1) plt.show() def func(z,param): # h0 is global variable h0=param[0] md=param[1] k0=param[2] if md*k0<1: f=((1+md*z)-np.log(1+md*z))-((1+md*h0)-np.log(1-md*k0)) if md*k0>1: f=((md*z-1)+np.log(md*z-1))-(np.log(md*k0-1)-(md*h0+1)) return f def bisection(x01,x02,param): imax=100 # maximum number of iterations err=1.0e-10 # allowable error of the zero value x1=x01 x2=x02 for i in range(0,imax): xi=0.5*(x1+x2) f1=func(x1,param) f2=func(x2,param) fi=func(xi,param) if abs(x2-x1) < err: break # converged if 0<f1*f2: break # no solution if f1*fi < 0.0: x2=xi if fi*f2 < 0.0: x1=xi return xi def cal_z(param,zs): h0=param[0] md=param[1] k0=param[2] eps1=1.0e-10 zmax=0 z2=zs # maximum limit of assumed solution if md*k0<1: z1=-1/md+eps1 # minimum limit of assumed solution if md*k0>1: z1= 1/md+eps1 # minimum limit of assumed solution zmax=bisection(z1,z2,param) return zmax def main(): for iii in [1,2]: if iii==1: q0,cd,h0,tl,ft,hg,dds,ddp,shaft,port,tstr,xmin,xmax,dx,ymin,ymax,dy,fnameF=inp_JH() if iii==2: q0,cd,h0,tl,ft,hg,dds,ddp,shaft,port,tstr,xmin,xmax,dx,ymin,ymax,dy,fnameF=inp_JT() v0=q0/ft # flow velocity of pressure tunnel fs=np.pi*shaft**2/4 # shaft diameter fp=np.pi*port**2/4 # port diameter zz=np.zeros((len(shaft),len(port)),dtype=np.float64) # array for |zm| zd=np.zeros(len(port),dtype=np.float64) # array for |zrm'| eps=0.0001 dzz=0 for i in range(len(fs)): for j in range(len(port)): k0=1/2/g*(q0/cd/fp[j])**2 # k0 md=2*g*fs[i]*(h0+k0)/tl/ft/v0**2 # m' zs=v0*np.sqrt(tl*ft/g/fs[i]) # free surge water rise param=np.array([h0,md,k0]) zz[i,j]=np.abs(cal_z(param,zs)) # calculation of |zm| # set design water level rize at design point # dzz : design water level rise # dds : design shaft diameter # ddp : design port diameter if dds-eps<shaft[i] and shaft[i]<dds+eps: if ddp-eps<port[j] and port[j]<ddp+eps: dzz=zz[i,j] zd=1/2/g*(q0/cd/fp)**2-h0 # |zrm'|=k0-h0 drawfig(shaft,port,zz,zd,dzz,ddp,xmin,xmax,dx,ymin,ymax,dy,tstr,fnameF) # Free surge water rise zs=v0*np.sqrt(tl*ft/g/fs) # free surge water rise print('* Free surge water rise') for i in range(len(fs)): print('Ds={0:2.0f} z*={1:6.3f}'.format(shaft[i],zs[i])) # required diameter fp=np.pi*ddp**2/4 cc=h0/v0**2 k0=1/2/g*(q0/cd/fp)**2 f1d=h0*tl*ft/cc/(h0+k0)/g/hg; dr1=np.sqrt(4*f1d/np.pi) # Thoma-Schuller's dynamic stability (1) f2d=tl*ft/2/cc/g/(hg-dzz); dr2=np.sqrt(4*f2d/np.pi) # Thoma-Schuller's dynamic stability (2) f3d=h0*tl*ft**3/2/g/cc**2/k0/q0**2; dr3=np.sqrt(4*f3d/np.pi) # Calame-Garden's critical discharge hh=hg/6 print('* Requirements for stability') print('Hg/6={0:6.3f}m # for static stabity'.format(hh)) print('Dsr1={0:4.1f}m # for dynamic stability (1)'.format(dr1)) print('Dsr2={0:4.1f}m # for dynamic stability (2)'.format(dr2)) print('Dsr3={0:4.1f}m # for critical discharge'.format(dr3)) #============== # Execution #============== if __name__ == '__main__': main()
Creation of Input data for surging analysis
The positive direction of discharge is defined to surgetank from reservoir. Therefore, followings shall be noted.
- The discharge in the case of input intersection for headrace surge tank has negative sign.
- The discharge in the case of load interception and load increase for tailrace surge tank have negative signs.
Input data format is shown below.
Variables | Description |
---|---|
strcom | comment (title of figure) |
ICT, AFCA, AFCT | ICT=1(normal), AFCA=0 (AFC discharge), AFCT=1 (period of AFC) |
TMAX, dt, DTWR | calculation time, time increment for calc, time increment for print |
PAA, PCI, PCO | section area of port, C for port inflow, C for port outflow |
RWL, TNL, TNA, TNC | Reservoir WL, tunnel length, tunnel section area, c of tunnel |
NST | number of section |
SAA[i], SEL[i], SLB[I] ...... |
section area, elevation, label |
NQT | number of discharge input points |
QTQ[i], QTI[I] ...... |
discharge at specified time, time |
ymin, ymax | range of y-axis of drawing |
The case of each created file is shown below.
Case | File name |
---|---|
Headrace surge tank: load interception | inp_surge_JH1.csv |
Headrace surge tank: load increase | inp_surge_JH2.csv |
Headrace surge tank: input interception | inp_surge_JH3.csv |
Tailrace surge tank: load interception | inp_surge_JT1.csv |
Tailrace surge tank: load increase | inp_surge_JT2.csv |
Tailrace surge tank: input interception | inp_surge_JT3.csv |
# strcom comment (title of figure) # ICT, AFCA, AFCT ICT=1(normal), AFCA=0 (AFC discharge), AFCT=1 (period of AFC) # TMAX,dt,DTWR calculation time, time increment for calc, time increment for print # PAA, PCI, PCO section area of port, C for port inflow, C for port outflow # RWL, TNL, TNA, TNC Reservoir WL, tunnel length, tunnel section area, c of tunnel # NST number of section # SAA[i], SEL[i], SLB[i] section area, elevation, label # ...... # NQT number of discharge input points # QTQ[i], QTI[i] discharge at specified time, time # ...... # ymin, ymax for drawing # PSPP-J headrace ST fnameW='inp_surge_JH1.csv' f=open(fnameW,'w') print('Load Interception (PSPP-J headrace ST)',file=f) print('1,0,1',file=f) print('600,0.01,0.1',file=f) print('15.904,0.9,0.9',file=f) print('1340,4800,52.810,0.301',file=f) print('2',file=f) print('346.313,1379.0,Top of Shaft (EL.1379.0)',file=f) print('346.313,1275.0,Bottom of Shaft (EL.1275.0)',file=f) print('3',file=f) print('338,0',file=f) print('0,8',file=f) print('0,9999',file=f) print('1270,1390',file=f) f.close() fnameW='inp_surge_JH2.csv' f=open(fnameW,'w') print('Load Increase (PSPP-J headrace ST)',file=f) print('1,0,1',file=f) print('600,0.01,0.1',file=f) print('15.904,0.9,0.9',file=f) print('1315,4800,52.810,0.448',file=f) print('2',file=f) print('346.313,1379.0,Top of Shaft (EL.1379.0)',file=f) print('346.313,1275.0,Bottom of Shaft (EL.1275.0)',file=f) print('3',file=f) print('169,0',file=f) print('338,40',file=f) print('338,9999',file=f) print('1270,1390',file=f) f.close() fnameW='inp_surge_JH3.csv' f=open(fnameW,'w') print('Input Interception (PSPP-J headrace ST)',file=f) print('1,0,1',file=f) print('600,0.01,0.1',file=f) print('15.904,0.9,0.9',file=f) print('1315,4800,52.810,0.301',file=f) print('2',file=f) print('346.313,1379.0,Top of Shaft (EL.1379.0)',file=f) print('346.313,1275.0,Bottom of Shaft (EL.1275.0)',file=f) print('3',file=f) print('-236.6,0',file=f) print('0,8',file=f) print('0,9999',file=f) print('1270,1390',file=f) f.close() # PSPP-J tailrace ST fnameW='inp_surge_JT1.csv' f=open(fnameW,'w') print('Load Interception (PSPP-J headrace ST)',file=f) print('1,0,1',file=f) print('600,0.01,0.1',file=f) print('15.904,0.9,0.9',file=f) print('630,1749,52.810,0.149',file=f) print('3',file=f) print('600.000,688.0,Top of chamber wall (EL.688.0)',file=f) print('600.000,680.0,Bottom of chamber (EL.680.0)',file=f) print('78.540,556.3,Bottom of shaft (EL.556.3)',file=f) print('3',file=f) print('-338,0',file=f) print('0,8',file=f) print('0,9999',file=f) print('550,700',file=f) f.close() fnameW='inp_surge_JT2.csv' f=open(fnameW,'w') print('Load Interception (PSPP-J headrace ST)',file=f) print('1,0,1',file=f) print('600,0.01,0.1',file=f) print('15.904,0.9,0.9',file=f) print('670,1749,52.810,0.207',file=f) print('3',file=f) print('600.000,688.0,Top of chamber wall (EL.688.0)',file=f) print('600.000,680.0,Bottom of chamber (EL.680.0)',file=f) print('78.540,556.3,Bottom of shaft (EL.556.3)',file=f) print('3',file=f) print('-169,0',file=f) print('-338,40',file=f) print('-338,9999',file=f) print('550,700',file=f) f.close() fnameW='inp_surge_JT3.csv' f=open(fnameW,'w') print('Load Interception (PSPP-J headrace ST)',file=f) print('1,0,1',file=f) print('600,0.01,0.1',file=f) print('15.904,0.9,0.9',file=f) print('670,1749,52.810,0.149',file=f) print('3',file=f) print('600.000,688.0,Top of chamber wall (EL.688.0)',file=f) print('600.000,680.0,Bottom of chamber (EL.680.0)',file=f) print('78.540,556.3,Bottom of shaft (EL.556.3)',file=f) print('3',file=f) print('236.6,0',file=f) print('0,8',file=f) print('0,9999',file=f) print('550,700',file=f) f.close()
Surging analysis
#========================== # Surging Analysis #========================== import numpy as np import sys import matplotlib.pyplot as plt import time def wout(dts,zw,vw,qn,fout): #print of Time, WL of Surge tank, Velocity of Tunnel, Discharge, k cf=0.5*(PCI+PCO)*PAA k=fk(vw,qn,cf) print('{0:15e},{1:15e},{2:15e},{3:15e},{4:15e}'.format(dts,zw,vw,qn,k),file=fout) def fz(v,q,fa): return (q-TNA*v)/fa def fk(v,q,cf): return np.abs((TNA*v-q)/cf)*(TNA*v-q)/cf/2.0/g def fv(z,v,wrk): return (z-TNC*np.abs(v)*v-wrk)/TNL*g def qncal(tt): qn=QI+AFCA*np.sin(2.0*np.pi/AFCT*tt) if tt>=AFCS: for i in range(1,NQT): if QTI[i-1]<tt and tt<=QTI[i]: qn=QTQ[i-1]+(QTQ[i]-QTQ[i-1])/(QTI[i]-QTI[i-1])*(tt-QTI[i-1]) break return qn def runge(qo,vo,zo,fa,dtt,dts): wrk=0.0 dz0=dtt*fz(vo,qo,fa) cf=PCI*PAA # Water level rising (in-flow from port) if dz0>0.0: cf=PCO*PAA # Water level drop (out-flow from port) wrk=fk(vo,qo,cf) dv0=dtt*fv(zo,vo,wrk) v1=vo+0.5*dv0 z1=zo+0.5*dz0 dtw=dts-dtt*0.5 q1=qncal(dtw) wrk=fk(v1,q1,cf) dv1=dtt*fv(z1,v1,wrk) dz1=dtt*fz(v1,q1,fa) v1=vo+0.5*dv1 z1=zo+0.5*dz1 wrk=fk(v1,q1,cf) dv2=dtt*fv(z1,v1,wrk) dz2=dtt*fz(v1,q1,fa) v1=vo+dv2 z1=zo+dz2 dtw=dts q2=qncal(dtw) wrk=fk(v1,q2,cf) dv3=dtt*fv(z1,v1,wrk) dz3=dtt*fz(v1,q2,fa) dv=(dv0+2.0*dv1+2.0*dv2+dv3)/6.0 dz=(dz0+2.0*dz1+2.0*dz2+dz3)/6.0 return dv,dz,q2 def datainp(fnameR): # data input global g global strcom global ICT,AFCA,AFCT global TMAX,DT,DTWR global PAA,PCI,PCO global RWL,TNL,TNA,TNC global NST,SEL,SAA,SLB global NQT,QTQ,QTI global AFCS, QI global ymin,ymax g=9.8 fin=open(fnameR,'r') text=fin.readline() text=text.strip() strcom=text # Comment text=fin.readline() text=text.strip() text=text.split(',') ICT =int(text[0]) # Calculation case (1: normal, 2: AFC) AFCA=float(text[1]) # Discharge of half amplitude of AFC(m3/s) AFCT=float(text[2]) # Period of AFC(s) text=fin.readline() text=text.strip() text=text.split(',') TMAX=float(text[0]) # End time of calculation DT =float(text[1]) # Time increment for calculation DTWR=float(text[2]) # Time increment for print out text=fin.readline() text=text.strip() text=text.split(',') PAA=float(text[0]) # Section area of Port PCI=float(text[1]) # Discharge coefficient of Port for inflow PCO=float(text[2]) # Discharge coefficient of Port for outflow text=fin.readline() text=text.strip() text=text.split(',') RWL=float(text[0]) # Reservoir Water Level TNL=float(text[1]) # Length of pressure tunnel TNA=float(text[2]) # Section area of pressure tunnel TNC=float(text[3]) # Head loss coefficient of pressure tunnel SAA=[] SEL=[] SLB=[] text=fin.readline() text=text.strip() text=text.split(',') NST=int(text[0]) # Number of sections for i in range(0,NST): text=fin.readline() text=text.strip() text=text.split(',') SAA=SAA+[float(text[0])] # Section area of specified level in the shaft SEL=SEL+[float(text[1])] # Level definition of sections of shaft (EL) SLB=SLB+[text[2]] # Label for section (text: for drawing) QTQ=[] QTI=[] text=fin.readline() text=text.strip() text=text.split(',') NQT=int(text[0]) # #Number of discharge input points for i in range(0,NQT): text=fin.readline() text=text.strip() text=text.split(',') QTQ=QTQ+[float(text[0])] # Discharge at specified time point QTI=QTI+[float(text[1])] # Time at specified time point text=fin.readline() text=text.strip() text=text.split(',') ymin=float(text[0]) ymax=float(text[1]) fin.close() # Preprocessing QI=QTQ[0] if ICT==1: AFCS=-1.0 if ICT==2: AFCS=QTI[1] _list = [[-1]*3 for i in range(0,NST)] for i in range(0,NST): _list[i][0]=SEL[i] _list[i][1]=SAA[i] _list[i][2]=SLB[i] _list.sort() # Sort section numbers in small order of elevation for i in range(0,NST): SEL[i]=_list[i][0] SAA[i]=_list[i][1] SLB[i]=_list[i][2] del _list SAA=SAA+[SAA[NST-1]] # Dummy for judgement of top level (section area) SEL=SEL+[SEL[NST-1]] # Dummy for judgement of top level (EL) def calc(fnameW): # Main calculation fout=open(fnameW,'w') print('Time,WL of Surge tank,Velocity of Tunnel,Discharge,k',file=fout) nnp=int(DTWR/DT+0.00001) # Step number of print out dto=DT # Time increment qn=QI # Initial discharge vi=qn/TNA # Initial velocity of tunnel discharge zi=TNC*vi*vi # Initial head loss due to initial velocity if vi<0.0: zi=-TNC*vi*vi # Definition of sign of initial head loss (direction of flow) zo=RWL-zi # Initial water level in Surge Tank # Print out initial values (time=0) dts=0.0 zw=zo vw=vi zi=zi qn=qn wout(dts,zw,vw,qn,fout) #To search the section number with initial water level for j in range(NST-1,-1,-1): if SEL[j]<zo: break npe=j #Number of section with initial water level npw=0 #Initialization of counter for print out dts=0.0 #Initialization of elapsed time iret=0 while dts<=TMAX: dts=dts+dto #The time found solution npw=npw+1 fa=SAA[npe] dv,dz,q1=runge(qn,vi,zi,fa,dto,dts) zw=RWL-zi-dz iw=npe+1 if iw>NST-1: iw=NST-1 if zw<SEL[npe] or SEL[iw]<zw: dti=0.1*dto for ic in range(1,11): dtw=dts-dto+dti*float(ic) zw=RWL-zi if SEL[npe+1]<zw: npe=npe+1 if zw<SEL[npe]: npe=npe-1 if NST-1<npe: iret=1 # water level greater than USWL if npe<0: iret=2 # water level less than DSWL fa=SAA[npe] dv,dz,q2=runge(q1,vi,zi,fa,dti,dtw) vi=vi+dv zi=zi+dz q1=q2 else: vi=vi+dv zi=zi+dz qn=q1 # Print out results if npw>=nnp: npw=0 zw=RWL-zi vw=vi qn=q1 wout(dts,zw,vw,qn,fout) fout.close() return iret def drawfig(fnameW,fnameF): data=np.loadtxt(fnameW,delimiter=',', skiprows=1, usecols=(0,1)) ti=data[:,0] wl=data[:,1] xmin=0.0 xmax=TMAX fsz=14 fig=plt.figure(figsize=(10, 5),facecolor='w') plt.rcParams['font.size']=fsz plt.rcParams['font.family']='sans-serif' plt.xlabel('Time (second)') plt.ylabel('Elevation (EL.m)') plt.xlim(xmin,xmax) plt.ylim(ymin,ymax) plt.grid(linestyle='--') plt.plot(ti,wl,color='black',lw=2.0,label='WL in the shaft') plt.hlines(RWL,xmin,xmax,alpha=0.3,color='black',lw=1.5,linestyles='-.') plt.text(xmax-10,RWL,'RWL (EL.{0:.1f})'.format(RWL),fontsize=fsz,color='black',ha='right',va='bottom') for i in range(0,NST): if SLB[i].find('xxx')<0: plt.hlines(SEL[i],xmin,xmax,alpha=0.3,color='black',lw=1.5,linestyles='-') plt.text(xmax-10,SEL[i],SLB[i],fontsize=fsz,color='black',ha='right',va='bottom') n1=np.argmax(wl) n2=np.argmin(wl) plt.text(ti[n1],wl[n1],'max:{0:.3f}({1:.1f}sec)'.format(wl[n1],ti[n1]),fontsize=fsz,color='black',ha='left',va='bottom') plt.text(ti[n2],wl[n2],'min:{0:.3f}({1:.1f}sec)'.format(wl[n2],ti[n2]),fontsize=fsz,color='black',ha='left',va='top') plt.title(strcom,loc='left',fontsize=fsz) plt.savefig(fnameF,dpi=200) plt.show() plt.close() def main(): lstr1=['JH1','JH2','JH3'] lstr2=['JT1','JT2','JT3'] lstr=lstr1+lstr2 for str in lstr: start=time.time() fnameR='inp_surge_'+str+'.csv' fnameW='out_surge_'+str+'.csv' fnameF='_fig_surge_'+str+'.png' #param=sys.argv param=['surge', fnameR,fnameW,fnameF] fnameR=param[1] # input data file fnameW=param[2] # output data file fnameF=param[3] # output image data file datainp(fnameR) iret=calc(fnameW) time1=time.time()-start drawfig(fnameW,fnameF) time2=time.time()-start-time1 print('iret={0:d}'.format(iret)) if iret==0: print('succsessful termination') if iret==1: print('water level is greater than Top of the shaft') if iret==2: print('water level is less than Bottom of the shaft') print(time1) print(time2) #============== # Execution #============== if __name__ == '__main__': main()
Marge images
# 画像結合 # https://note.nkmk.me/python-pillow-concat-images/ from PIL import Image import os import glob def comb_h(im1, im2): dst = Image.new('RGB', (im1.width + im2.width, im1.height)) dst.paste(im1, (0, 0)) dst.paste(im2, (im1.width, 0)) return dst def comb_v(im1, im2): dst = Image.new('RGB', (im1.width, im1.height + im2.height)) dst.paste(im1, (0, 0)) dst.paste(im2, (0, im1.height)) return dst def multi_comb_h(im_list): _im=im_list.pop(0) for im in im_list: _im=comb_h(_im, im) return _im def multi_comb_v(im_list): _im=im_list.pop(0) for im in im_list: _im=comb_v(_im, im) return _im fig_01='_fig_surge_JH1.png'; im_01 = Image.open(fig_01) fig_02='_fig_surge_JH2.png'; im_02 = Image.open(fig_02) fig_03='_fig_surge_JH3.png'; im_03 = Image.open(fig_03) fnameF='fig_surge_JH.png' im_list_1=[im_01, im_02, im_03] multi_comb_v(im_list_1).save(fnameF) fig_01='_fig_surge_JT1.png'; im_01 = Image.open(fig_01) fig_02='_fig_surge_JT2.png'; im_02 = Image.open(fig_02) fig_03='_fig_surge_JT3.png'; im_03 = Image.open(fig_03) fnameF='fig_surge_JT.png' im_list_1=[im_01, im_02, im_03] multi_comb_v(im_list_1).save(fnameF) file_list = glob.glob('_*.png') for file in file_list: print("remove:{0}".format(file)) os.remove(file)
That's all. Thank you.