EricCRX commited on
Commit
451dbc3
·
verified ·
1 Parent(s): 4d4b548

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +235 -0
  2. requirements.txt +7 -0
app.py ADDED
@@ -0,0 +1,235 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ """Untitled3.ipynb
3
+
4
+ Automatically generated by Colab.
5
+
6
+ Original file is located at
7
+ https://colab.research.google.com/drive/11sS74P6WlrbXCzSh9_b8ELPTtcfdsz8s
8
+ """
9
+
10
+ # -*- coding: utf-8 -*-
11
+ # HW3: Deterministic calculator + LLM explanation (Gradio)
12
+ # Topic: Simply supported beam with center point load (max bending stress & midspan deflection)
13
+
14
+ import json
15
+ import math
16
+ from dataclasses import dataclass, asdict
17
+
18
+ import gradio as gr
19
+ import numpy as np
20
+ import pandas as pd
21
+
22
+
23
+ LLM_MODEL_ID = "google/flan-t5-small"
24
+
25
+ try:
26
+ from transformers import pipeline
27
+ _llm = pipeline("text2text-generation", model=LLM_MODEL_ID)
28
+ except Exception:
29
+ _llm = None # no transformers
30
+
31
+ # -----------------------------
32
+
33
+ # -----------------------------
34
+
35
+ @dataclass
36
+ class BeamInputs:
37
+ L_m: float # 跨度(m)
38
+ P_kN: float # 中点集中力(kN)
39
+ E_GPa: float # 弹性模量(GPa)
40
+ I_cm4: float # 截面惯性矩(cm^4)
41
+ c_cm: float # 中性轴到受拉/受压边缘距离(cm)- 极纤维距离
42
+ allowable_MPa: float | None = None # 允许应力(MPa,可选)
43
+ yield_MPa: float | None = None # 屈服强度(MPa,可选)
44
+ safety_factor: float | None = None # 安全系数 n(可选)
45
+
46
+ def _validate(x, lo, hi, name):
47
+ if not (lo <= x <= hi):
48
+ raise gr.Error(f"{name} 超出有效范围 [{lo}, {hi}]")
49
+
50
+ def validate_inputs(inp: BeamInputs):
51
+ _validate(inp.L_m, 0.5, 50.0, "跨度 L (m)")
52
+ _validate(inp.P_kN, 0.1, 2000.0, "荷载 P (kN)")
53
+ _validate(inp.E_GPa, 1.0, 300.0, "弹性模量 E (GPa)")
54
+ _validate(inp.I_cm4, 1.0, 1e9, "惯性矩 I (cm^4)")
55
+ _validate(inp.c_cm, 0.01, 200.0, "极纤维距离 c (cm)")
56
+ if inp.safety_factor is not None:
57
+ _validate(inp.safety_factor, 1.0, 5.0, "安全系数 n")
58
+ if inp.allowable_MPa is not None:
59
+ _validate(inp.allowable_MPa, 1.0, 5000.0, "允许应力 (MPa)")
60
+ if inp.yield_MPa is not None:
61
+ _validate(inp.yield_MPa, 10.0, 10000.0, "屈服强度 (MPa)")
62
+
63
+ def beam_calc(inp: BeamInputs):
64
+ """
65
+ Simply supported beam with a centered point load P.
66
+ M_max = P*L/4
67
+ sigma_max = M_max * c / I
68
+ delta_mid = P * L^3 / (48 * E * I)
69
+ 单位处理见下。
70
+ """
71
+ validate_inputs(inp)
72
+
73
+
74
+ P_N = inp.P_kN * 1_000 # kN -> N
75
+ L = inp.L_m # m
76
+ E_Pa = inp.E_GPa * 1e9 # GPa -> Pa
77
+ I_m4 = inp.I_cm4 * 1e-8 # cm^4 -> m^4 (1 cm = 0.01 m → (0.01)^4 = 1e-8)
78
+ c_m = inp.c_cm * 0.01 # cm -> m
79
+
80
+
81
+ M_max_Nm = P_N * L / 4.0
82
+ sigma_Pa = M_max_Nm * c_m / I_m4
83
+ sigma_MPa = sigma_Pa / 1e6
84
+ delta_m = P_N * (L**3) / (48 * E_Pa * I_m4)
85
+ delta_mm = delta_m * 1e3
86
+
87
+
88
+ allow = None
89
+ if inp.allowable_MPa is not None:
90
+ allow = float(inp.allowable_MPa)
91
+ elif inp.yield_MPa is not None and inp.safety_factor is not None:
92
+ allow = float(inp.yield_MPa) / float(inp.safety_factor)
93
+
94
+ utilization = (sigma_MPa / allow) if (allow and allow > 0) else None
95
+ pass_check = (utilization <= 1.0) if utilization is not None else None
96
+
97
+ record = {
98
+ "scope": "Simply supported beam, centered point load; small deflection; linear elastic; prismatic section.",
99
+ "inputs": {
100
+ "L_m": inp.L_m,
101
+ "P_kN": inp.P_kN,
102
+ "E_GPa": inp.E_GPa,
103
+ "I_cm4": inp.I_cm4,
104
+ "c_cm": inp.c_cm,
105
+ "allowable_MPa": inp.allowable_MPa,
106
+ "yield_MPa": inp.yield_MPa,
107
+ "safety_factor": inp.safety_factor,
108
+ },
109
+ "units": {
110
+ "L_m": "m", "P_kN": "kN", "E_GPa": "GPa",
111
+ "I_cm4": "cm^4", "c_cm": "cm",
112
+ "sigma_MPa": "MPa", "M_max_kN_m": "kN·m", "delta_mm": "mm",
113
+ },
114
+ "formulas": {
115
+ "M_max": "P*L/4",
116
+ "sigma_max": "M_max * c / I",
117
+ "delta_mid": "P * L^3 / (48 * E * I)"
118
+ },
119
+ "results": {
120
+ "M_max_kN_m": M_max_Nm / 1_000.0, # N·m -> kN·m
121
+ "sigma_MPa": sigma_MPa,
122
+ "delta_mm": delta_mm,
123
+ "allowable_MPa": allow,
124
+ "utilization": utilization,
125
+ "pass_check": pass_check
126
+ },
127
+ "notes": [
128
+ "If allowable stress is not provided, pass/fail is left as None.",
129
+ "For non-rectangular/I-beam sections, user provides I and c (or catalogs)."
130
+ ]
131
+ }
132
+
133
+ table = pd.DataFrame(
134
+ {
135
+ "Quantity": ["M_max", "sigma_max", "delta_mid", "allowable", "utilization", "pass"],
136
+ "Value": [
137
+ round(record["results"]["M_max_kN_m"], 4),
138
+ round(record["results"]["sigma_MPa"], 4),
139
+ round(record["results"]["delta_mm"], 4),
140
+ (None if allow is None else round(allow, 4)),
141
+ (None if utilization is None else round(utilization, 4)),
142
+ str(pass_check)
143
+ ],
144
+ "Unit": ["kN·m", "MPa", "mm", "MPa", "-", "-"]
145
+ }
146
+ )
147
+ return record, table
148
+
149
+ # -----------------------------
150
+ # 2) LLM
151
+ # -----------------------------
152
+
153
+ def explain_record(record: dict) -> str:
154
+ compact = json.dumps(record, ensure_ascii=False)
155
+ prompt = (
156
+ "You are an engineering assistant. Explain the beam calculation results clearly for a non-expert.\n"
157
+ "Use the JSON below. Restate the inputs (with units), show the formulas, plug in numbers, and summarize.\n"
158
+ "If allowable stress is present, state pass/fail and utilization. Avoid hallucinations; only use given data.\n"
159
+ f"JSON:\n{compact}\n"
160
+ "Write 120-200 words. Use bullet points for steps. Keep units."
161
+ )
162
+ if _llm is not None:
163
+ try:
164
+ out = _llm(prompt, max_new_tokens=220, do_sample=False)[0]["generated_text"]
165
+ return out
166
+ except Exception:
167
+ pass
168
+
169
+ r = record["results"]
170
+ i = record["inputs"]
171
+ lines = [
172
+ "### Explanation",
173
+ f"- Span L = {i['L_m']} m; Center load P = {i['P_kN']} kN.",
174
+ f"- E = {i['E_GPa']} GPa; I = {i['I_cm4']} cm^4; c = {i['c_cm']} cm.",
175
+ "- Formulas: M=P·L/4; σ=M·c/I; δ=P·L³/(48·E·I).",
176
+ f"- Computed: M_max = {r['M_max_kN_m']:.3f} kN·m; σ_max = {r['sigma_MPa']:.3f} MPa; δ_mid = {r['delta_mm']:.3f} mm.",
177
+ ]
178
+ if r["allowable_MPa"] is not None:
179
+ lines.append(f"- Allowable = {r['allowable_MPa']:.3f} MPa; utilization = {r['utilization']:.3f}.")
180
+ lines.append(f"- Pass/Fail: {r['pass_check']}.")
181
+ else:
182
+ lines.append("- No allowable stress provided → pass/fail not evaluated.")
183
+ return "\n".join(lines)
184
+
185
+ # -----------------------------
186
+ # 3) Gradio
187
+ # -----------------------------
188
+
189
+ def run_calc(L_m, P_kN, E_GPa, I_cm4, c_cm, allowable_MPa, yield_MPa, safety_factor):
190
+
191
+ allowable = None if (allowable_MPa is None or allowable_MPa == "") else float(allowable_MPa)
192
+ fy = None if (yield_MPa is None or yield_MPa == "") else float(yield_MPa)
193
+ n = None if (safety_factor is None or safety_factor == "") else float(safety_factor)
194
+
195
+ inp = BeamInputs(
196
+ L_m=float(L_m), P_kN=float(P_kN), E_GPa=float(E_GPa),
197
+ I_cm4=float(I_cm4), c_cm=float(c_cm),
198
+ allowable_MPa=allowable, yield_MPa=fy, safety_factor=n
199
+ )
200
+ rec, table = beam_calc(inp)
201
+ expl = explain_record(rec)
202
+ return table, expl, rec
203
+
204
+ with gr.Blocks() as demo:
205
+ gr.Markdown("# Simply Supported Beam — Center Load\nDeterministic calculator + LLM explanation (first principles).")
206
+
207
+ with gr.Row():
208
+ with gr.Column():
209
+ L_m = gr.Slider(0.5, 30.0, value=6.0, step=0.1, label="Span L (m)")
210
+ P_kN = gr.Slider(0.1, 500.0, value=20.0, step=0.1, label="Center load P (kN)")
211
+ E_GPa = gr.Slider(10.0, 300.0, value=200.0, step=1.0, label="Elastic modulus E (GPa)")
212
+ I_cm4 = gr.Number(value=8000.0, label="Second moment of area I (cm^4)") # 例如 IPE/I型钢量级
213
+ c_cm = gr.Number(value=15.0, label="Extreme fiber distance c (cm)")
214
+
215
+ with gr.Accordion("Optional: Allowables", open=False):
216
+ allowable_MPa = gr.Number(value=None, label="Allowable stress σ_allow (MPa)")
217
+ yield_MPa = gr.Number(value=None, label="Yield strength fy (MPa)")
218
+ safety_factor = gr.Number(value=1.5, label="Safety factor n")
219
+
220
+ run_btn = gr.Button("Compute")
221
+
222
+ with gr.Column():
223
+ results = gr.Dataframe(headers=["Quantity", "Value", "Unit"], label="Numerical results", wrap=True)
224
+ explanation = gr.Markdown(label="Explain the results")
225
+ record_json = gr.JSON(label="Structured record (for LLM)")
226
+
227
+ run_btn.click(
228
+ fn=run_calc,
229
+ inputs=[L_m, P_kN, E_GPa, I_cm4, c_cm, allowable_MPa, yield_MPa, safety_factor],
230
+ outputs=[results, explanation, record_json],
231
+ api_name="run_calc",
232
+ )
233
+
234
+ if __name__ == "__main__":
235
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ gradio>=4.24
2
+ pandas
3
+ numpy
4
+ transformers>=4.41
5
+ sentencepiece
6
+ accelerate
7
+ huggingface_hub>=0.23