Spaces:
Sleeping
Sleeping
| import math | |
| import gradio | |
| import pandas as pd | |
| # ---------------- Settings ---------------- | |
| TITLE = "Simply-Supported I-Beam" | |
| DESC = "Point load @ midspan or uniform load (UDL). SI units. Euler–Bernoulli." | |
| # ---------------- Deterministic backend ---------------- | |
| def _compute(load_type, L_m, E_GPa, Ix_m4, mode, Sx_m3, depth_m, | |
| P_kN, w_kNpm, sigma_allow_MPa, defl_ratio): | |
| # --- Validation --- | |
| if L_m <= 0: raise ValueError("Span L must be > 0.") | |
| if E_GPa <= 0: raise ValueError("E must be > 0.") | |
| if Ix_m4 <= 0: raise ValueError("Ix must be > 0.") | |
| has_Sx = (mode == "I have Sx") | |
| if has_Sx and Sx_m3 <= 0: raise ValueError("Sx must be > 0.") | |
| if (not has_Sx) and depth_m <= 0: raise ValueError("Depth must be > 0 when Sx not provided.") | |
| if load_type == "Point @ midspan" and P_kN <= 0: raise ValueError("P must be > 0 for point load.") | |
| if load_type == "Uniform (UDL)" and w_kNpm <= 0: raise ValueError("w must be > 0 for UDL.") | |
| # --- Units --- | |
| E = E_GPa * 1e9 | |
| P = P_kN * 1e3 | |
| w = w_kNpm * 1e3 | |
| # --- Section properties --- | |
| if has_Sx: | |
| Sx = Sx_m3 | |
| c = Ix_m4 / Sx | |
| h = 2 * c | |
| else: | |
| h = depth_m | |
| c = h / 2 | |
| Sx = Ix_m4 / c | |
| # --- Beam formulas --- | |
| if load_type == "Point @ midspan": | |
| Mmax = P * L_m / 4.0 | |
| dmax = P * (L_m**3) / (48.0 * E * Ix_m4) | |
| else: | |
| Mmax = w * (L_m**2) / 8.0 | |
| dmax = 5.0 * w * (L_m**4) / (384.0 * E * Ix_m4) | |
| sigma = Mmax / Sx | |
| # --- Checks --- | |
| stress_ok, SF = None, None | |
| if sigma_allow_MPa and sigma_allow_MPa > 0: | |
| sigma_MPa = sigma / 1e6 | |
| SF = sigma_allow_MPa / max(sigma_MPa, 1e-12) | |
| stress_ok = sigma_MPa <= sigma_allow_MPa | |
| defl_ok, defl_lim = None, None | |
| if defl_ratio and defl_ratio > 0: | |
| defl_lim = (L_m * 1e3) / defl_ratio | |
| defl_ok = (dmax * 1e3) <= defl_lim | |
| # --- Context text --- | |
| text = [] | |
| text.append(f"### 🔍 Contextual Explanation") | |
| text.append(f"**Beam Type:** Simply supported ({load_type.lower()}) with span **L = {L_m:.2f} m**.") | |
| text.append(f"**Material:** E = {E_GPa:.1f} GPa, **Section:** Ix = {Ix_m4:.2e} m⁴, Sx = {Sx:.2e} m³, depth = {h:.3f} m.") | |
| text.append(f"\n#### Results Overview") | |
| text.append(f"- Maximum bending moment **Mmax = {Mmax/1e3:.2f} kN·m**.") | |
| text.append(f"- Maximum deflection **δmax = {dmax*1e3:.3f} mm**, ratio **δ/L = {dmax/L_m:.5f}**.") | |
| text.append(f"- Bending stress **σmax = {sigma/1e6:.2f} MPa**.") | |
| if sigma_allow_MPa > 0: | |
| if stress_ok: | |
| text.append(f"✅ Stress **({sigma/1e6:.2f} MPa)** ≤ allowable **({sigma_allow_MPa:.2f} MPa)**.") | |
| else: | |
| text.append(f"⚠️ Stress **({sigma/1e6:.2f} MPa)** exceeds allowable **({sigma_allow_MPa:.2f} MPa)**.") | |
| if defl_ratio > 0: | |
| if defl_ok: | |
| text.append(f"✅ Deflection **({dmax*1e3:.3f} mm)** ≤ limit (L/{defl_ratio:.0f} = {defl_lim:.2f} mm).") | |
| else: | |
| text.append(f"⚠️ Deflection **({dmax*1e3:.3f} mm)** exceeds limit (L/{defl_ratio:.0f} = {defl_lim:.2f} mm).") | |
| text.append("\n#### Engineering Meaning") | |
| text.append("The bending moment represents internal torque; deflection is beam sag. " | |
| "Safe design ensures both remain below limits to prevent failure or deformation.") | |
| context_text = "\n".join(text) | |
| # --- Return two outputs --- | |
| data = { | |
| "inputs": { | |
| "load_type": load_type, | |
| "L_m": L_m, "E_GPa": E_GPa, "Ix_m4": Ix_m4, | |
| "Sx_m3": Sx, "depth_m": h, | |
| "P_kN": P_kN if load_type.startswith("Point") else 0.0, | |
| "w_kN_per_m": w_kNpm if load_type.startswith("Uniform") else 0.0, | |
| "sigma_allow_MPa": sigma_allow_MPa or None, | |
| "deflection_ratio": defl_ratio or None, | |
| }, | |
| "solution": { | |
| "M_max_kN_m": Mmax / 1e3, | |
| "sigma_max_MPa": sigma / 1e6, | |
| "delta_max_mm": dmax * 1e3, | |
| "delta_over_L": dmax / L_m, | |
| }, | |
| "checks": { | |
| "stress_ok": stress_ok, "SF_stress": SF, | |
| "deflection_ok": defl_ok, | |
| "deflection_limit_mm": defl_lim, "deflection_ratio": defl_ratio or None, | |
| }, | |
| } | |
| return data, context_text | |
| # ---------------- Gradio UI ---------------- | |
| with gradio.Blocks() as demo: | |
| gradio.Markdown(f"# {TITLE}") | |
| gradio.Markdown(DESC) | |
| with gradio.Row(): | |
| load_type = gradio.Radio(choices=["Point @ midspan", "Uniform (UDL)"], value="Point @ midspan", label="Load case") | |
| L_m = gradio.Number(value=3.0, label="Span L [m]", precision=4) | |
| E_GPa = gradio.Number(value=200.0, label="Young's modulus E [GPa]", precision=3) | |
| Ix_m4 = gradio.Number(value=8.0e-6, label="Second moment Ix [m^4]", precision=10) | |
| with gradio.Row(): | |
| mode = gradio.Radio(choices=["I have Sx", "I have depth (h) only"], value="I have Sx", label="Section input") | |
| Sx_m3 = gradio.Number(value=4.0e-4, label="Section modulus Sx [m^3]", precision=8, visible=True) | |
| depth_m = gradio.Number(value=0.30, label="Depth h [m]", precision=4, visible=False) | |
| def _toggle(v): | |
| return gradio.update(visible=(v=="I have Sx")), gradio.update(visible=(v!="I have Sx")) | |
| mode.change(_toggle, inputs=mode, outputs=[Sx_m3, depth_m]) | |
| with gradio.Row(): | |
| P_kN = gradio.Number(value=20.0, label="Point load P [kN]", precision=3) | |
| w_kNpm = gradio.Number(value=5.0, label="UDL w [kN/m]", precision=4) | |
| with gradio.Row(): | |
| sigma_allow = gradio.Number(value=250.0, label="Allowable stress [MPa] (0=skip)", precision=3) | |
| defl_ratio = gradio.Number(value=360, label="Deflection limit L/ratio (0=skip)", precision=0) | |
| # --- Two output sections --- | |
| with gradio.Tab("Numerical Results"): | |
| out = gradio.JSON(label="Results") | |
| with gradio.Tab("Understanding the Results"): | |
| context_out = gradio.Markdown() | |
| inputs = [load_type, L_m, E_GPa, Ix_m4, mode, Sx_m3, depth_m, | |
| P_kN, w_kNpm, sigma_allow, defl_ratio] | |
| for comp in inputs: | |
| comp.change(fn=_compute, inputs=inputs, outputs=[out, context_out]) | |
| gradio.Examples( | |
| examples=[ | |
| ["Point @ midspan", 3.0, 200.0, 8.0e-6, "I have Sx", 4.0e-4, 0.30, 20.0, 0.0, 250.0, 360], | |
| ["Uniform (UDL)", 4.5, 200.0, 1.2e-5, "I have Sx", 6.0e-4, 0.35, 0.0, 8.0, 200.0, 360], | |
| ["Uniform (UDL)", 2.5, 70.0, 3.5e-6, "I have depth (h) only", 0.0, 0.22, 0.0, 6.0, 160.0, 240], | |
| ], | |
| inputs=inputs, | |
| label="Examples", | |
| cache_examples=False, | |
| ) | |
| demo.launch() | |