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")