File size: 7,985 Bytes
7324519
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# =========================
# Column Buckling Calculator — Euler Elastic (Rectangular Section)
# =========================

import math
import gradio as gr
import pandas as pd

SCOPE_MD = """
### Scope & Assumptions
- **Problem:** Axially compressed **prismatic column** (rectangular cross-section), **Euler elastic buckling**.
- **Outputs:** Governing critical load \(P_{cr}\), governing axis, slenderness \(λ\), factor of safety vs. applied load \(P\), verdict.
- **Method:** Euler buckling (linear-elastic, small deflection), **no inelastic (Johnson)**, **no eccentricity**, **no imperfections**.
- **Section:** Rectangle (width \(b\), height \(h\)); checks both axes and picks the **weaker axis** (smaller \(P_{cr}\)).
- **End conditions:** Choose \(K\): Fixed–Fixed (0.5), Fixed–Pinned (0.7), Pinned–Pinned (1.0), Fixed–Free (2.0).
- **Units:** SI (m, N, GPa, MPa). Input \(P\) in kN. Results show \(P_{cr}\) in **kN**.

### Valid Ranges (hard checks)
- 0.1 < L ≤ 20 m
- 0 < P ≤ 5*10^6 N
- 1 ≤ E ≤ 400 GPa
- 10 ≤ Sy ≤ 3000 MPa (for context only; not used in Euler (P_{cr}\)
- 0.005 < b ≤ 2 m
- 0.005 < h ≤ 2 m
"""

# ----- Validation -----
def _validate_inputs(L_m, P_kN, E_GPa, Sy_MPa, b_m, h_m):
    errs = []
    def in_range(name, val, lo, hi):
        if not (lo < val <= hi):
            errs.append(f"{name} must be in ({lo}, {hi}] (got {val}).")
    in_range("Length L [m]", L_m, 0.1, 20.0)
    in_range("Load P [kN]", P_kN, 0.0, 5000.0)  # 5e6 N
    in_range("Elastic modulus E [GPa]", E_GPa, 1.0, 400.0)
    in_range("Yield strength Sy [MPa]", Sy_MPa, 10.0, 3000.0)
    in_range("Width b [m]", b_m, 0.005, 2.0)
    in_range("Height h [m]", h_m, 0.005, 2.0)
    if errs:
        raise ValueError("\n".join(errs))

# ----- Core Math -----
def euler_buckling_rect(L_m, P_kN, E_GPa, Sy_MPa, b_m, h_m, K):
    """
    Euler elastic buckling for a rectangular column.
    Checks both principal axes and selects the governing (smaller Pcr).
    """
    _validate_inputs(L_m, P_kN, E_GPa, Sy_MPa, b_m, h_m)

    # SI conversions
    P_applied_N = float(P_kN) * 1e3
    E_Pa = float(E_GPa) * 1e9

    # Section properties
    A = b_m * h_m
    Ix = b_m * (h_m**3) / 12.0
    Iy = h_m * (b_m**3) / 12.0
    rx = (Ix / A) ** 0.5
    ry = (Iy / A) ** 0.5

    KL = K * L_m
    Pcr_x = (math.pi**2) * E_Pa * Ix / (KL**2)
    Pcr_y = (math.pi**2) * E_Pa * Iy / (KL**2)

    # Governing axis (smaller Pcr)
    if Pcr_x <= Pcr_y:
        axis = "x (buckles about the weak direction of Ix → bending about h)"
        Pcr = Pcr_x
        r_govern = rx
        I_govern = Ix
    else:
        axis = "y (buckles about the weak direction of Iy → bending about b)"
        Pcr = Pcr_y
        r_govern = ry
        I_govern = Iy

    slenderness = KL / r_govern if r_govern > 0 else math.inf
    fos = Pcr / P_applied_N if P_applied_N > 0 else math.inf
    ok = P_applied_N <= Pcr

    # Pretty print helpers
    def _fmt(x, d=6):
        try:
            return f"{x:.{d}g}"
        except Exception:
            return str(x)

    steps_md = "\n".join([
        "## Show the math (Euler elastic buckling)",
        f"L = {_fmt(L_m)} m,  K = {_fmt(K)},  KL = {K} * {L_m} = {KL:.6g} m",
        f"E = {_fmt(E_GPa)} GPa,  P = {_fmt(P_kN)} kN  (= {P_applied_N:.6g} N)",
        f"b = {_fmt(b_m)} m,  h = {_fmt(h_m)} m",
        "",
        "Area and moments of inertia:",
        f"A = b * h = {b_m} * {h_m} = {A:.6e} m^2",
        f"Ix = b * h^3 / 12 = {b_m} * {h_m}^3 / 12 = {Ix:.6e} m^4",
        f"Iy = h * b^3 / 12 = {h_m} * {b_m}^3 / 12 = {Iy:.6e} m^4",
        f"rx = sqrt(Ix / A) = sqrt({Ix:.6e} / {A:.6e}) = {rx:.6e} m",
        f"ry = sqrt(Iy / A) = sqrt({Iy:.6e} / {A:.6e}) = {ry:.6e} m",
        "",
        "Euler critical loads:",
        "Pcr = π^2 * E * I / (K*L)^2",
        f"Pcr_x = (π^2) * ({E_GPa} * 10^9) * ({Ix:.6e}) / ({K} * {L_m})^2 = {Pcr_x:.6e} N",
        f"Pcr_y = (π^2) * ({E_GPa} * 10^9) * ({Iy:.6e}) / ({K} * {L_m})^2 = {Pcr_y:.6e} N",
        f"Governing axis: {axis}",
        f"Pcr(governing) = {Pcr:.6e} N = {Pcr/1e3:.3f} kN",
        "",
        "Slenderness (governing axis):",
        f"λ = (K*L) / r_governing = {KL:.6g} / {r_govern:.6e} = {slenderness:.2f}",
        "",
        "Check vs applied load:",
        f"FoS_buckling = Pcr / P = {Pcr:.6e} / {P_applied_N:.6e} = {fos:.3f}",
        f"Verdict: {'OK (no buckling at P)' if ok else 'NOT OK (buckles at P)'}"
    ])

    results = {
        "A_m2": A,
        "Ix_m4": Ix,
        "Iy_m4": Iy,
        "rx_m": rx,
        "ry_m": ry,
        "Pcr_x_N": Pcr_x,
        "Pcr_y_N": Pcr_y,
        "Pcr_governing_N": Pcr,
        "P_applied_N": P_applied_N,
        "FoS_buckling": fos,
        "governing_axis": axis,
        "slenderness_governing": slenderness,
        "ok": bool(ok),
    }
    verdict = {
        "message": "OK: no Euler buckling at the applied load" if ok else "NOT OK: Euler buckling likely at the applied load",
        "governing_axis": axis
    }
    return results, verdict, steps_md

# ----- Gradio glue -----
END_CONDITIONS = {
    "Fixed–Fixed (K=0.5)": 0.5,
    "Fixed–Pinned (K=0.7)": 0.7,
    "Pinned–Pinned (K=1.0)": 1.0,
    "Fixed–Free / Cantilever (K=2.0)": 2.0,
}

def run_once(L_m, P_kN, E_GPa, Sy_MPa, b_m, h_m, end_condition):
    try:
        K = END_CONDITIONS[end_condition]
        res, ver, steps = euler_buckling_rect(
            float(L_m), float(P_kN), float(E_GPa), float(Sy_MPa),
            float(b_m), float(h_m), float(K)
        )
        df = pd.DataFrame([{
            "Pcr_x [kN]": round(res["Pcr_x_N"]/1e3, 3),
            "Pcr_y [kN]": round(res["Pcr_y_N"]/1e3, 3),
            "Pcr (governing) [kN]": round(res["Pcr_governing_N"]/1e3, 3),
            "Applied P [kN]": round(res["P_applied_N"]/1e3, 3),
            "FoS_buckling [-]": round(res["FoS_buckling"], 3),
            "Slenderness (λ)": round(res["slenderness_governing"], 2),
            "Governing axis": res["governing_axis"],
            "Verdict": ver["message"],
        }])
        explain = (
            f"Column buckles about {res['governing_axis']}: "
            f"Pcr={res['Pcr_governing_N']/1e3:.2f} kN vs P={res['P_applied_N']/1e3:.2f} kN "
            f"(FoS={res['FoS_buckling']:.2f}) → {ver['message']}."
        )
        return df, explain, steps, ""
    except Exception as e:
        return pd.DataFrame(), "", "", f"Input error:\n{e}"

with gr.Blocks(title="Column Buckling — Euler Elastic") as demo:
    gr.Markdown("# Column Buckling Calculator — Euler Elastic (Rectangular Section)")
    gr.Markdown(SCOPE_MD)

    with gr.Row():
        with gr.Column():
            gr.Markdown("### Geometry & Material")
            L_m   = gr.Number(value=3.0,  label="Length L [m]")
            b_m   = gr.Number(value=0.06, label="Width b [m]")
            h_m   = gr.Number(value=0.10, label="Height h [m]")
            E_GPa = gr.Number(value=200., label="Elastic modulus E [GPa]")
            Sy_MPa= gr.Number(value=250., label="Yield strength Sy [MPa] (context)")
        with gr.Column():
            gr.Markdown("### Load & End Condition")
            P_kN  = gr.Number(value=200.0, label="Applied load P [kN]")
            end_condition = gr.Radio(
                list(END_CONDITIONS.keys()),
                value="Pinned–Pinned (K=1.0)",
                label="End conditions (effective-length factor K)"
            )

    run_btn = gr.Button("Compute")

    gr.Markdown("### Results")
    results_df = gr.Dataframe(label="Numerical results", interactive=False)

    gr.Markdown("### Explain the result")
    explain_md = gr.Markdown()

    gr.Markdown("### Show the math")
    steps_md = gr.Markdown()

    err_box = gr.Textbox(label="Errors", interactive=False)

    run_btn.click(
        fn=run_once,
        inputs=[L_m, P_kN, E_GPa, Sy_MPa, b_m, h_m, end_condition],
        outputs=[results_df, explain_md, steps_md, err_box]
    )

if __name__ == "__main__":
    demo.launch(debug=False)