Geo_Solve / app.py
Qasim-03's picture
Create app.py
78ff8fc verified
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")