| | 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 = st.tabs([ |
| | "Phase Relationships", |
| | "Soil Classification (USCS)", |
| | "Bearing Capacity (Terzaghi & Meyerhof)", |
| | ]) |
| |
|
| | |
| | WATER_DENSITY = 1.0 |
| |
|
| |
|
| | |
| | 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.") |
| |
|
| | |
| | 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}**") |
| |
|
| | |
| | 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") |
| |
|