Goda_Loading / app.py
edwinrajeev's picture
Update app.py
e1e061c
#!/usr/bin/env python
# coding: utf-8
# In[5]:
from scipy.optimize import fsolve
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.lines import Line2D
import matplotlib.image as mpimg
from matplotlib.offsetbox import AnchoredText
import plotly.figure_factory as ff
import pandas as pd
from io import BytesIO
import base64
# In[17]:
def dispersion(T, h):
""" Dispersion relationship
uses fsolve to find the wave length
Parameters
----------
T : float
wave period [s]
h : float
water depth [m]
Returns
L : float
the wave length [m]
"""
g=32
# deep water wave length
L0 = g*T**2/(2*np.pi)
# define dispersion relation with a lambda function to solve L
dispersion = lambda L : L0 * np.tanh(2*np.pi*h/L) - L
# solve for L
L = fsolve(dispersion, L0)[0]
print(L)
return L
# In[24]:
def goda(Case, Hs, Hmax, h, d, h_acc, hc, T, beta, rho, slope_foreshore, B, lambda_, Still_Water_Level, Top_of_Wall_Height, Bottom_of_Wall, Pmin, s, p2_bottom):
'''Parameters
----------
Hs : float
mean of the highest 1/3 of the wave heights [m].
Hmax : float
design wave height, equal to the mean of the highest 1/250 of
the wave heights [m].
h : float
water depth [m]
d : float
water depth in front of the caisson, on top of the foundation [m]
h_acc : float
submerged depth of the caisson [m]
hc : float
height of the caisson above the water line [m]
Bm : float
width of the berm [m]
T : float
wave period, Goda (2000) advises to use :math:`T_{1/3}` [s]
beta : float
angle between direction of wave approach and a line normal to
the breakwater [rad]
rho : float
density of water [kg/m³]
slope_foreshore : float
slope of the foreshore [rad]
lambda_ : list, optional, default: [1, 1, 1]
modification factors of Takahasi (2002) for alternative
monolithic breakwater. Input must be
\\lambda_= [:math:`\\lambda_1, \\lambda_2, \\lambda_3`].'''
# set dimensions as private variables
h = h
d = d
h_acc = h_acc
hc = hc
rho = rho
g=32
# water depth at a location of 5x H1/3
hb = Hs #h + 5 * np.tan(slope_foreshore) * Hs
L = dispersion(T=T, h=h)
# compute wave pressure coefficients (Goda, 2000)
alpha_1 = (0.6 + 0.5*((4*np.pi*h/L)/ np.sinh(4*np.pi*h/L))**2)
alpha_2_1 = ((hb-d)/(3*hb)*(Hmax/d)**2)
alpha_2_2 = (2*d/Hmax)
alpha_2 = min((alpha_2_1), (alpha_2_2))
alpha_3 = 1 - (h_acc/h) * (1-1/np.cosh(2*np.pi*h/L))
alpha_star = alpha_2
# Compute the elevation to which the wave pressure is exerted
eta_star = 0.75*(1 + np.cos(beta))*lambda_[0]*Hmax
# Compute the wave pressures
p1 = (0.5*(1 + np.cos(beta))* (lambda_[0]*alpha_1 + lambda_[1]*alpha_star*np.cos(beta)**2)*rho*g*Hmax)
p3 = alpha_3*p1
if eta_star > hc:
p4 = p1*(1-hc/eta_star)
else:
p4 = 0
#Computes the Uplift wave forces
pu = (0.5*(1 + np.cos(beta))* lambda_[2]*alpha_1*alpha_3*rho*g*Hmax)
# Determine h_c_star
h_c_star = min([eta_star, hc])
#Computes the Horizontal force due to the pressure
P = (0.5*(p1+p3)*h_acc + 0.5*(p1+p4)*h_c_star)/1000
goda.p1 = p1
goda.p3 = p3
goda.hc = hc
goda.eta_star = eta_star
goda.h_acc = h_acc
goda.pu = pu
def distributed_load(loads, positions):
# loads is a list of load values at different positions
# positions is a list of positions corresponding to the load values
x_centroid = 0
y_centroid = 0
total_load = 0
for i in range(len(loads)):
x_centroid += loads[i] * positions[i]
y_centroid += loads[i]
total_load += loads[i]
x_centroid /= y_centroid
return (total_load, x_centroid)
# Example usage
loads = [goda.p1, p4, goda.p3]
positions = [Still_Water_Level, Top_of_Wall_Height, Bottom_of_Wall]
resultant, centroid = distributed_load(loads, positions)
#Suction Loads (wave load under a wave trough)
Steepness = Hs/L
depth_to_wavelength = h/L
print('Steepness(H/L) = ' + str(Steepness))
print('h/L = ' + str(depth_to_wavelength))
img = mpimg.imread('Goda_Suction.png')
imgplot = plt.imshow(img)
plt.axis('off')
plt.show()
Pmin = Pmin
s = s
p2_bottom = p2_bottom
Suction_Load = Pmin*rho*g*h*Hs/1000
Load_Distance_from_Bottom = s*h
Bottom_Pressure = p2_bottom*rho*g*Hs/1000
#Horizontal Loading Table Data
data_matrix = [['Parameters', 'Units', 'Value'],
[ 'Acceleration due to gravity', 'g[ft/s2]', g],
[ 'Water Density', '[slug/ft3]', rho],
['Wave Period', 'T[s]', T],
['Significant Wave Height', 'Hs[ft]', Hs],
['Max. Wave Height', 'Hmax[ft]', round(Hmax,2)],
['Depth in front of scour protection', 'h[ft]', h],
['Water Depth 5Hs away', 'hb[ft]', h],
['Height of Seawall from bottom to SWL', 'h\'[ft]', h_acc],
['Height of Seawall above SWL', 'hc[ft]', hc],
['Depth in front of Seawall', 'd[ft]', d],
['Wavelength', 'L[ft]', round(L,2)],
['Angle of Incoming Waves', 'deg', beta],
[ ],
['a1', '', round(alpha_1,2)],
['a2', '', round(alpha_star, 2)],
['a3', '', round(alpha_3,2)],
['Eta*', '[ft]', round(eta_star,2)],
['hc*', '[ft]', h_c_star],
[ ],
['p1', '[ksf]', round(p1/1000,2)],
['p2', '[ksf]', round(p4/1000,2)],
['p3', '[ksf]', round(p3/1000,2)],
[ ],
['Force on Breakwater', '[kip/ft]', round(P,2)]]
#fig = ff.create_table(data_matrix)
#fig.update_layout(width=1000)
df = pd.DataFrame(data_matrix)
# Generate a unique filename for each CSV file
filename = f'goda_horizontal_load_{Case}.csv'
# Create a buffer to hold the CSV data
csv_buffer = BytesIO()
df.to_csv(csv_buffer, header=None, index=None)
# Reset the buffer position to the start
csv_buffer.seek(0)
# Create a download link for the generated CSV file
b64 = base64.b64encode(csv_buffer.read()).decode()
href = f'<a href="data:file/csv;base64,{b64}" download="{filename}">Download Horizontal Loading CSV</a>'
st.markdown(href, unsafe_allow_html=True)
#fig.write_image()
# Suction Loads Data Table
data_matrix = [['Parameters', 'Units', 'Value'],
[ 'Acceleration due to gravity', 'g[ft/s2]', g],
[ 'Water Density', '[slug/ft3]', rho],
['Wave Period', 'T[s]', T],
['Significant Wave Height', 'Hs[ft]', Hs],
['Max. Wave Height', 'Hmax[ft]', round(Hmax,2)],
['Depth in front of Seawall', 'd[ft]', d],
['Wavelength', 'L[ft]', round(L,2)],
['Seabed Bottom Elevation', '[ft]', Bottom_of_Wall],
[ ],
['Wave Steepness', 'H/L', round(Steepness,2)],
['Depth to Wavelength Ratio', 'h/L', round(depth_to_wavelength, 2)],
['Nondimensional Value of Wave Thrust Load', 'Pmin/pgHh', round(Pmin,2)],
['Nondimensional Value of Wave Thrust Arm', 's/d', round(s,2)],
['Suction Load', '[kip/ft]', round(Suction_Load,2)],
['Load Distance from Seabed Bottom', 's[ft]', round(Load_Distance_from_Bottom,2)],
['Load Elevation', '[ft] MSL', round(Bottom_of_Wall + Load_Distance_from_Bottom,2)]]
df = pd.DataFrame(data_matrix)
# Generate a unique filename for each CSV file
filename = f'goda_suction_load_{Case}.csv'
# Create a buffer to hold the CSV data
csv_buffer = BytesIO()
df.to_csv(csv_buffer, header=None, index=None)
# Reset the buffer position to the start
csv_buffer.seek(0)
# Create a download link for the generated CSV file
b64 = base64.b64encode(csv_buffer.read()).decode()
href = f'<a href="data:file/csv;base64,{b64}" download="{filename}">Download Suction Loading CSV</a>'
st.markdown(href, unsafe_allow_html=True)
# get the width
B = B
p = np.array([goda.p3,
goda.p1,
goda.p1-goda.p1*goda.hc/goda.eta_star])/1000
y = np.array([Bottom_of_Wall, Still_Water_Level, Top_of_Wall_Height])
x = np.array([0, B])
pu = np.array([goda.pu, 0])/1000
# scale the size of the caisson with the pressure
scale = np.max(p)/np.max(y)
scale_1 = np.max(y)/np.max(p)
y = y
x = x
pu_1 = pu*scale_1*0.25
B = B*scale
p_s = np.array([Bottom_Pressure, 1.5*Bottom_Pressure, 0])
y_s = np.array([Bottom_of_Wall, Bottom_of_Wall+Load_Distance_from_Bottom, Still_Water_Level])
x_s = np.array([0, B])
# scale the size of the caisson with the pressure
scale_s = np.max(y_s)/np.max(p)
x_s = x
#y_s = y_s[0:2]
custom_lines = [Line2D([0], [0], color='k', lw=4), Line2D([0], [0], color='b', lw=4), Line2D([0], [0], color='g', lw=4),
Line2D([0], [0], color='r', lw=4)
]
fig, ax = plt.subplots()
# plot the caisson and wlev
plt.vlines(x=0, ymin=((Bottom_of_Wall)), ymax=Top_of_Wall_Height, linewidth=2, color='k')
plt.vlines(x=-B, ymin=((Bottom_of_Wall)), ymax=Top_of_Wall_Height, linewidth=2, color = 'k')
plt.hlines(y=-(abs(Bottom_of_Wall)), xmin=0, xmax=-B, linewidth=2, color = 'k')
plt.hlines(y=Top_of_Wall_Height, xmin=0, xmax=-B, linewidth=2, color='k')
plt.hlines(y=(Still_Water_Level), xmin=0, xmax=np.max(p)*1.3, color='b')
# plot pressure distributions
plt.hlines(y=Bottom_of_Wall, xmin=0, xmax=p[0], color='g')
plt.hlines(y=Top_of_Wall_Height, xmin=0, xmax=p[2], color='g')
plt.plot(p, y, color='g')
#plt.vlines(x=0, ymin=Bottom_of_Wall, ymax=Bottom_of_Wall - pu_1[0], color='purple')
#plt.plot([0,-B], Bottom_of_Wall-pu_1, color='purple')
# plot suction load distributions
plt.hlines(y=Bottom_of_Wall, xmin=-p_s[0], xmax=0, color='r')
#plt.hlines(y=-y_s[1], xmin=-p_s[1], xmax=0, color='r')
plt.plot(-p_s, y_s, color='r')
# red arrow
plt.arrow(-p_s[1], Bottom_of_Wall+Load_Distance_from_Bottom , p_s[1], 0, head_width=0.15*Load_Distance_from_Bottom, head_length=0.03, linewidth=4, color='r', length_includes_head=True)
# green arrow
plt.arrow(resultant, centroid , -resultant, 0, head_width=0.15*Load_Distance_from_Bottom, head_length=0.03, linewidth=4, color='g', length_includes_head=True)
# Dimensions Annotation Suction
plt.arrow(-0.025, Bottom_of_Wall, 0, (Load_Distance_from_Bottom), color='k', head_length = 0.15*Load_Distance_from_Bottom, head_width = 0.01, length_includes_head = True)
plt.arrow(-0.025, Bottom_of_Wall+Load_Distance_from_Bottom, 0, -Load_Distance_from_Bottom, color='k', head_length = 0.15*Load_Distance_from_Bottom, head_width = 0.01, length_includes_head = True)
plt.annotate(str(round(Load_Distance_from_Bottom, 2)) + ' ft', xy=(0, 0),
xytext=(-0.03, (Bottom_of_Wall+Load_Distance_from_Bottom)/.45), rotation=90 )
# Dimensions Annotation Horizontal
plt.arrow(0.025, Bottom_of_Wall, 0, -(Bottom_of_Wall-centroid), color='k', head_length = 0.15*Load_Distance_from_Bottom, head_width = 0.01, length_includes_head = True)
plt.arrow(0.025, Bottom_of_Wall+Load_Distance_from_Bottom, 0, -Load_Distance_from_Bottom, color='k', head_length = 0.15*Load_Distance_from_Bottom, head_width = 0.01, length_includes_head = True)
plt.annotate(str(round(-Bottom_of_Wall+centroid, 1)) + ' ft', xy=(0, 0),
xytext=(0.05, -(-Bottom_of_Wall+centroid)/1.5), rotation=90 )
#invert axes
plt.xlim(np.max(p)*1.3, -np.max(p_s))
#plt.ylim(Bottom_of_Wall*1.6, np.max(y)*2)
#plt.ylim(np.max(pu_1)+10, (-np.max(y)-5))
HL = 'Horizontal Load (kip/ft) = ' + str(round(P,2))
#UL = 'Uplift Load (ksf/ft) = ' + str(round(pu[0],2))
SL = 'Suction Load (kip/ft) = ' + str(round(Suction_Load, 2))
VW = 'Seawall'
SW = 'Still Water Level'
# add title and label
plt.title('Pressure distributions computed with Goda (2000)')
plt.xlabel('Pressure [ksf/ft]')
plt.ylabel('Surface Elevation [ft], NGVD 29')
plt.legend(custom_lines, [VW, SW, HL, SL], loc ='lower left')
# add grid and show plot
plt.grid()
plt.savefig('Case_Number_' + str(Case) + '.png', dpi = 300)
st.pyplot(fig)
return goda.p1, p4, goda.p3, P, pu[0], Suction_Load, Bottom_Pressure, Load_Distance_from_Bottom
# In[29]:
import streamlit as st
#def main():
# st.title("Goda Horizontal Loading Calculator")
# # Display the image
# img = mpimg.imread('Goda_Suction.png')
# st.image(img, use_column_width=True)
# User Inputs
# Case_number = st.number_input("Case Number", value=3, min_value=1, step=1)
# B = st.number_input("Width of Wall", value=2.0, min_value=0.0)
# Bottom_of_Wall = st.number_input("Bottom of Wall", value=-11.92)
# Still_Water_Level = st.number_input("Stillwater Level", value=0.0)
# Top_of_Wall_Height = st.number_input("Top of Wall Height", value=7.27)
# Hs = st.number_input("Hs", value=4.5)
# T = st.number_input("T", value=7.0)
# beta = st.number_input("Beta", value=0.0)
# rho = st.number_input("Rho", value=2.0)
# Pmin = st.number_input("Non-Dimensional Pmin (For Suction Loads - from Graphs Above)", value=0.4)
# s = st.number_input("Non-Dimensional s (For Suction Loads - from Graphs Above)", value=0.5)
# p2_bottom = st.number_input("Non-Dimensional p2 (For Suction Loads - from Graphs Above)", value=0.55)
# Hmax = Hs*1.8 #design wave height, equal to the mean of the highest 1/250 of the wave heights [m].
# h = Still_Water_Level - Bottom_of_Wall #water depth [m]
# d = h #water depth in front of the caisson, on top of the foundation [m]
# h_acc = h #submerged depth of the caisson [m]
# hc = Top_of_Wall_Height - Still_Water_Level #height of the caisson above the water line [m]
# slope_foreshore = [1,100] #slope of the foreshore [rad]
# lambda_=[1,1,1]
# if st.button("Calculate"):
# result = goda(Case = Case_number, Hs=Hs, Hmax=Hmax, h=h, d=d, h_acc=h_acc, hc=hc, T=T,
# beta=beta, rho=rho, slope_foreshore=slope_foreshore, B = B, lambda_=lambda_,
# Still_Water_Level = Still_Water_Level, Top_of_Wall_Height= Top_of_Wall_Height,
# Bottom_of_Wall=Bottom_of_Wall, Pmin=Pmin, s=s, p2_bottom=p2_bottom )
def main():
st.title("Goda Horizontal Loading Calculator")
# Display the image
img = mpimg.imread('Goda_Suction.png')
st.image(img, use_column_width=True)
# User Inputs
Case_number = st.number_input("Case Number", value=3, min_value=1, step=1)
Hs = st.number_input("Wave Height, Hs [ft]", value=4.5)
T = st.number_input("Period, T [s]", value=7.0)
h = st.number_input("Depth, h [ft]", value=11.0)
if st.button("Run Dispersion"):
dispersion_result = dispersion(T=T, h=h)
st.write("Suction Load Parameters:")
st.write("Wavelength:", dispersion_result)
st.write("Wave Steepness:", Hs/dispersion_result)
st.write("h/L:", h/dispersion_result)
B = 2.0 #st.number_input("Width of Wall [ft]", value=2.0, min_value=0.0)
Bottom_of_Wall = st.number_input("Bottom of Wall [ft]", value=-11.92)
Still_Water_Level = st.number_input("Stillwater Level [ft]", value=0.0)
Top_of_Wall_Height = st.number_input("Top of Wall Height [ft]", value=7.27)
beta = st.number_input("Beta [deg]", value=0.0)
rho = 2 #st.number_input("Rho", value=2.0)
Pmin = st.number_input("Non-Dimensional Pmin (For Suction Loads - from Graphs Above)", value=0.4)
s = st.number_input("Non-Dimensional s (For Suction Loads - from Graphs Above)", value=0.5)
p2_bottom = st.number_input("Non-Dimensional p2 (For Suction Loads - from Graphs Above)", value=0.55)
Hmax = Hs*1.8 #design wave height, equal to the mean of the highest 1/250 of the wave heights [m].
h = Still_Water_Level - Bottom_of_Wall #water depth [m]
d = h #water depth in front of the caisson, on top of the foundation [m]
h_acc = h #submerged depth of the caisson [m]
hc = Top_of_Wall_Height - Still_Water_Level #height of the caisson above the water line [m]
slope_foreshore = [1,100] #slope of the foreshore [rad]
lambda_=[1,1,1]
if st.button("Run Goda"):
goda_result = goda(Case=Case_number, Hs=Hs, Hmax=Hmax, h=h, d=d, h_acc=h_acc, hc=hc, T=T,
beta=beta, rho=rho, slope_foreshore=slope_foreshore, B=B, lambda_=lambda_,
Still_Water_Level=Still_Water_Level, Top_of_Wall_Height=Top_of_Wall_Height,
Bottom_of_Wall=Bottom_of_Wall, Pmin=Pmin, s=s, p2_bottom=p2_bottom)
#st.write("Goda Result:")
#st.write("Output:", goda_result)
if __name__ == "__main__":
main()