File size: 4,798 Bytes
78ff8fc | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | import streamlit as st
import math
st.set_page_config(page_title="Geotech Engineering Solver", layout="wide")
st.title("🧱 Geotechnical Engineering Solver")
st.markdown("Built using **American Standards** (ASTM, NAVFAC, Terzaghi, Meyerhof, Coduto).")
# Tabs for modules
tabs = st.tabs([
"Phase Relationships",
"Soil Classification (USCS)",
"Bearing Capacity (Terzaghi & Meyerhof)",
])
# Constants
WATER_DENSITY = 1.0 # g/cm³
# PHASE RELATIONSHIPS TAB
with tabs[0]:
st.header("Phase Relationships")
st.markdown("Enter known values. Leave unknowns blank.")
col1, col2 = st.columns(2)
with col1:
rho_wet = st.number_input("Wet Density (g/cm³)", step=0.01, format="%.3f")
w = st.number_input("Moisture Content (as decimal, e.g. 0.12)", step=0.01, format="%.3f")
Gs = st.number_input("Specific Gravity Gs", step=0.01, format="%.3f")
with col2:
rho_dry = st.number_input("Dry Density (g/cm³)", step=0.01, format="%.3f")
e = st.number_input("Void Ratio", step=0.01, format="%.3f")
S = st.number_input("Degree of Saturation (decimal)", step=0.01, format="%.3f")
if st.button("Calculate Phase Relationships"):
results = {}
if rho_dry == 0 and rho_wet and w:
rho_dry = rho_wet / (1 + w)
results["Dry Density"] = f"{rho_dry:.3f} g/cm³"
if e == 0 and Gs and rho_dry:
e = (Gs * WATER_DENSITY / rho_dry) - 1
results["Void Ratio"] = f"{e:.3f}"
if e and not S and Gs and w:
S = (w * Gs) / e
results["Degree of Saturation"] = f"{S*100:.2f} %"
if e:
n = e / (1 + e)
results["Porosity"] = f"{n*100:.2f} %"
if e and S:
Av = (e / (1 + e)) * (1 - S)
results["Air Voids"] = f"{Av*100:.2f} %"
st.subheader("Results:")
if results:
for k, v in results.items():
st.success(f"{k}: {v}")
else:
st.warning("Not enough data to compute results.")
# SOIL CLASSIFICATION TAB
with tabs[1]:
st.header("Soil Classification (USCS)")
st.markdown("Based on **ASTM D2487 - Unified Soil Classification System**.")
gravel = st.number_input("Gravel (%)", 0.0, 100.0, step=0.1)
sand = st.number_input("Sand (%)", 0.0, 100.0, step=0.1)
fines = st.number_input("Fines (Silt + Clay) (%)", 0.0, 100.0, step=0.1)
LL = st.number_input("Liquid Limit (LL)", 0.0, 100.0)
PL = st.number_input("Plastic Limit (PL)", 0.0, 100.0)
if st.button("Classify Soil"):
if fines > 50:
PI = LL - PL
if PI > 7 and LL > 50:
soil_type = "CH (Fat Clay)"
elif PI > 7 and LL <= 50:
soil_type = "CL (Lean Clay)"
elif PI <= 7 and LL <= 50:
soil_type = "ML (Silt)"
else:
soil_type = "MH (Elastic Silt)"
elif fines <= 50:
if fines > 12:
soil_type = "SM or SC (Silty/Clayey Sand)"
elif sand > gravel:
soil_type = "SP or SW (Poorly or Well Graded Sand)"
else:
soil_type = "GP or GW (Poorly or Well Graded Gravel)"
else:
soil_type = "Unclassified"
st.success(f"USCS Soil Classification: **{soil_type}**")
# BEARING CAPACITY TAB
with tabs[2]:
st.header("Bearing Capacity (Terzaghi & Meyerhof)")
st.markdown("Formulas from **Terzaghi (1943)** and **Meyerhof (1951)** for shallow foundations.")
φ = st.number_input("φ (Friction Angle, degrees)", 0.0, 45.0, step=0.1)
c = st.number_input("Cohesion (kPa)", step=1.0)
gamma = st.number_input("Soil Unit Weight (kN/m³)", 10.0, 30.0, step=0.1)
B = st.number_input("Footing Width B (m)", step=0.1)
D = st.number_input("Depth of Foundation D (m)", step=0.1)
shape = st.selectbox("Footing Shape", ["Strip", "Square", "Circular"])
if st.button("Compute Bearing Capacity"):
φ_rad = math.radians(φ)
Nq = math.exp(math.pi * math.tan(φ_rad)) * (math.tan(math.radians(45) + φ_rad / 2) ** 2)
Nc = (Nq - 1) / math.tan(φ_rad) if φ > 0 else 5.14
Nγ = 2 * (Nq + 1) * math.tan(φ_rad)
if shape == "Strip":
sc = sq = sγ = 1
elif shape == "Square":
sc = 1.3
sq = 1.2
sγ = 0.8
elif shape == "Circular":
sc = 1.3
sq = 1.2
sγ = 0.6
q_ult = c * Nc * sc + gamma * D * Nq * sq + 0.5 * gamma * B * Nγ * sγ
FS = 3
q_allow = q_ult / FS
st.subheader("Results")
st.success(f"Ultimate Bearing Capacity q_ult = {q_ult:.2f} kPa")
st.info(f"Allowable Bearing Capacity (FS={FS}) = {q_allow:.2f} kPa")
|