ecopus commited on
Commit
0647a5e
·
verified ·
1 Parent(s): e287665

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -343
app.py DELETED
@@ -1,343 +0,0 @@
1
- # app.py
2
- import math
3
- from typing import Dict, Any
4
-
5
- def darcy_weisbach_head_loss(f: float, L: float, D: float, V: float) -> float:
6
- '''Compute head loss h_f using DarcyWeisbach: h_f = f * (L/D) * V^2/(2*g)'''
7
- g = 9.80665
8
- return f * (L / D) * V**2 / (2 * g)
9
-
10
- def reynolds_number(V: float, D: float, nu: float) -> float:
11
- return V * D / nu
12
-
13
- def default_friction_factor(Re: float, roughness: float, D: float) -> float:
14
- '''Estimate friction factor. roughness in m'''
15
- if Re == 0:
16
- return float('nan')
17
- if Re < 2300:
18
- return 64.0 / Re
19
- # Haaland approximation for turbulent flow
20
- e = roughness
21
- return ( -1.8 * math.log10( (e/(3.7*D))**1.11 + 6.9/Re ) )**-2
22
-
23
- def bernoulli_pipe_flow(
24
- P1: float, P2: float,
25
- V1: float, V2: float,
26
- z1: float = 0.0, z2: float = 0.0,
27
- rho: float = 1000.0,
28
- mu: float = 0.001, # Pa.s dynamic viscosity
29
- roughness: float = 1.5e-6, # m
30
- D: float = 0.1, # m
31
- L: float = 1.0, # m
32
- friction_factor: float = None,
33
- use_darcy: bool = True,
34
- g: float = 9.80665
35
- ) -> Dict[str, Any]:
36
- '''
37
- Deterministic backend.
38
-
39
- Inputs (SI units):
40
- P1, P2 : Pa
41
- V1, V2 : m/s
42
- z1, z2 : m
43
- rho : kg/m^3
44
- mu : Pa.s
45
- roughness : m
46
- D : m
47
- L : m
48
-
49
- Returns: structured dict containing:
50
- - inputs, intermediate values (Re, f, h_f),
51
- - head terms, computed left/right/pump_head,
52
- - explanations (text steps), summary.
53
- '''
54
- errors = []
55
- if rho <= 0: errors.append('rho must be > 0')
56
- if D <= 0: errors.append('D must be > 0')
57
- if L < 0: errors.append('L must be >= 0')
58
- for val in [P1,P2,V1,V2,z1,z2,rho,mu,D,L]:
59
- if not (isinstance(val,(int,float)) and math.isfinite(val)):
60
- errors.append('Inputs must be finite numbers')
61
- break
62
- if errors:
63
- return {'ok': False, 'errors': errors}
64
-
65
- nu = mu / rho
66
- Re1 = reynolds_number(V1, D, nu)
67
- Re2 = reynolds_number(V2, D, nu)
68
-
69
- f = friction_factor if friction_factor is not None else default_friction_factor(max(Re1,Re2), roughness, D)
70
- h_f = darcy_weisbach_head_loss(f, L, D, (V1+V2)/2.0) if use_darcy else 0.0
71
-
72
- # Bernoulli (in head units, m): Left = Right + h_f + h_pump - h_turbine
73
- left = P1/(rho*g) + V1**2/(2*g) + z1
74
- right = P2/(rho*g) + V2**2/(2*g) + z2
75
- # pump head required (positive => add head from 1->2)
76
- h_pump = left - right + h_f
77
-
78
- results = {
79
- 'ok': True,
80
- 'inputs': {
81
- 'P1_Pa': P1, 'P2_Pa': P2,
82
- 'V1_m_s': V1, 'V2_m_s': V2,
83
- 'z1_m': z1, 'z2_m': z2,
84
- 'rho_kg_m3': rho, 'mu_Pa_s': mu,
85
- 'D_m': D, 'L_m': L, 'roughness_m': roughness
86
- },
87
- 'intermediate': {
88
- 'g_m_s2': g,
89
- 'nu_m2_s': nu,
90
- 'Re1': Re1, 'Re2': Re2,
91
- 'friction_factor_f': f,
92
- 'head_loss_hf_m': h_f
93
- },
94
- 'head_terms': {
95
- 'P1_over_rho_g_m': P1/(rho*g),
96
- 'V1_sq_over_2g_m': V1**2/(2*g),
97
- 'z1_m': z1,
98
- 'P2_over_rho_g_m': P2/(rho*g),
99
- 'V2_sq_over_2g_m': V2**2/(2*g),
100
- 'z2_m': z2
101
- },
102
- 'computed': {
103
- 'left_hand_side_m': left,
104
- 'right_hand_side_m': right,
105
- 'pump_head_required_m': h_pump
106
- },
107
- 'explanations': []
108
- }
109
-
110
- # Steps (human-readable)
111
- steps = []
112
- steps.append(f"Compute kinematic viscosity ν = μ / ρ = {mu} / {rho} = {nu:.6g} m^2/s")
113
- steps.append(f"Reynolds numbers: Re1 = V1·D/ν = {V1}·{D}/{nu:.6g} = {Re1:.3g}; Re2 = {Re2:.3g}")
114
- steps.append(f"Friction factor f (estimated) = {f:.6g}")
115
- steps.append(f"Head loss h_f = f·(L/D)·V_avg^2/(2g) = {h_f:.6g} m (V_avg={(V1+V2)/2.0:.6g} m/s)")
116
- steps.append("Apply extended Bernoulli in head units (m):")
117
- steps.append(f"Left = P1/(ρg) + V1^2/(2g) + z1 = {results['head_terms']['P1_over_rho_g_m']:.6g} + {results['head_terms']['V1_sq_over_2g_m']:.6g} + {z1} = {left:.6g} m")
118
- steps.append(f"Right = P2/(ρg) + V2^2/(2g) + z2 = {results['head_terms']['P2_over_rho_g_m']:.6g} + {results['head_terms']['V2_sq_over_2g_m']:.6g} + {z2} = {right:.6g} m")
119
- steps.append(f"Pump head required h_pump = Left - Right + h_f = {h_pump:.6g} m")
120
-
121
- results['explanations'] = steps
122
- results['summary'] = (f"To move fluid from point 1 -> 2 requires pump head {h_pump:.6g} m. "
123
- f"Estimated friction factor f={f:.6g} (Re ~ {max(Re1,Re2):.3g}). Head loss h_f={h_f:.6g} m.")
124
- return results
125
-
126
- # Deterministic explainer (consumes the structured record and returns text)
127
- import json, requests, os
128
- from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
129
-
130
-
131
- def deterministic_explainer(record: dict) -> str:
132
- if not record.get('ok', False):
133
- return 'Errors: ' + '; '.join(record.get('errors', ['Unknown error']))
134
- lines = []
135
- lines.append("--- EXPLANATION (deterministic)---")
136
- # Summary (always string)
137
- summary = record.get('summary', '')
138
- lines.append(str(summary))
139
- lines.append("Inputs (SI):")
140
- for k,v in record['inputs'].items():
141
- lines.append(f" - {k}: {v}")
142
- lines.append('Intermediate values:')
143
- for k,v in record['intermediate'].items():
144
- lines.append(f" - {k}: {v}")
145
- lines.append('Calculation steps:')
146
- for s in record.get('explanations',[]):
147
- lines.append(' * '+s)
148
- lines.append('Notes: Assumptions: incompressible, single-phase, steady flow. Use within validated ranges only.')
149
- return '\n'.join(lines)
150
- # Local LLM setup
151
- MODEL_ID = "TinyLlama/TinyLlama-1.1B-Chat-v1.0"
152
- tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
153
- pipe = pipeline(
154
- task="text-generation",
155
- #model=AutoModelForCausalLM.from_pretrained(MODEL_ID),
156
- model=MODEL_ID,
157
- tokenizer=tokenizer
158
- )
159
-
160
- def _fmt_num(x, sig=4):
161
- '''Safe, short formatting for numbers (returns string).'''
162
- try:
163
- if x is None:
164
- return "N/A"
165
- if isinstance(x, (int,)):
166
- return str(x)
167
- if isinstance(x, float):
168
- # use general format with sig significant digits
169
- return f"{x:.{sig}g}"
170
- return str(x)
171
- except Exception:
172
- return str(x)
173
-
174
- def _llm_generate(prompt: str, max_tokens: int = 300) -> str:
175
- '''
176
- Run the local pipeline, then strip any echoed prompt and common instruction text.
177
- If the model echoes instructions, do one gentle retry with a simplified prompt.
178
- '''
179
- # Primary generation: deterministic (no sampling) is usually safer for engineering text.
180
- try:
181
- out = pipe(
182
- prompt,
183
- max_new_tokens=max_tokens,
184
- do_sample=False,
185
- temperature=0.0,
186
- return_full_text=True,
187
- )
188
- except Exception:
189
- # fallback: try return_full_text=False if first attempt fails for this model
190
- out = pipe(
191
- prompt,
192
- max_new_tokens=max_tokens,
193
- do_sample=False,
194
- temperature=0.0,
195
- return_full_text=False,
196
- )
197
-
198
- # get text (handle both pipeline variants)
199
- text = ""
200
- if isinstance(out, list) and len(out) > 0:
201
- text = out[0].get("generated_text", "") or out[0].get("text", "") or ""
202
- text = text or ""
203
- # If the model returned the prompt + output, strip the prompt if present
204
- if text.startswith(prompt):
205
- text = text[len(prompt):]
206
- text = text.strip()
207
-
208
- # If output looks like it merely repeated instructions, try a simpler short-prompt retry
209
- low_quality_indicators = [
210
- "Use bullet points", "Be sure to include", "Do not", "Do NOT",
211
- "Now produce", "System:", "User:", "Instruction:"
212
- ]
213
- if (not text) or any(ind in text for ind in low_quality_indicators) or len(text) < 10:
214
- # simple short retry prompt asking for only the final answer
215
- simple_prompt = prompt + "
216
-
217
- Now produce ONLY the requested explanation below (no re-statement of the prompt or instructions):
218
- "
219
- try:
220
- out2 = pipe(
221
- simple_prompt,
222
- max_new_tokens=max_tokens,
223
- do_sample=False,
224
- temperature=0.0,
225
- return_full_text=True,
226
- )
227
- except Exception:
228
- out2 = pipe(
229
- simple_prompt,
230
- max_new_tokens=max_tokens,
231
- do_sample=False,
232
- temperature=0.0,
233
- return_full_text=False,
234
- )
235
- text2 = out2[0].get("generated_text", "") or out2[0].get("text", "") or ""
236
- if text2.startswith(simple_prompt):
237
- text2 = text2[len(simple_prompt):]
238
- text2 = text2.strip()
239
- if text2 and len(text2) > 10 and not any(ind in text2 for ind in low_quality_indicators):
240
- return text2
241
- # final fallback:
242
- return "[LLM failed to generate a usable explanation — try a different model or reduce the prompt size]"
243
-
244
- return text
245
-
246
-
247
- def llm_explain(record: dict) -> str:
248
- '''Deterministic explanation using numeric values, LLM optional for style.'''
249
- if not record.get("ok", False):
250
- return "Errors: " + "; ".join(record.get("errors", []))
251
-
252
- computed = record.get("computed", {})
253
- intermediate = record.get("intermediate", {})
254
-
255
- # Extract values
256
- pump_head = computed.get("pump_head_required_m", None)
257
- f = intermediate.get("friction_factor_f", None)
258
- hf = intermediate.get("head_loss_hf_m", None)
259
- Re1 = intermediate.get("Re1", None)
260
- Re2 = intermediate.get("Re2", None)
261
-
262
- # Flow regime classification
263
- Re_avg = (Re1 + Re2) / 2 if (Re1 is not None and Re2 is not None) else None
264
- if Re_avg is None or Re_avg != Re_avg:
265
- regime = "unknown"
266
- elif Re_avg < 2300:
267
- regime = "laminar"
268
- else:
269
- regime = "turbulent"
270
-
271
- # Format numbers
272
- ph_str = _fmt_num(pump_head)
273
- f_str = _fmt_num(f)
274
- hf_str = _fmt_num(hf)
275
-
276
- # Deterministic summary
277
- summary = f"Pump head is {ph_str} m, friction factor is {f_str}, and head loss is {hf_str} m. Flow is {regime}."
278
-
279
- explanation = (
280
- f"Summary paragraph: {summary}
281
- "
282
- f"Flow regime: {regime}
283
- "
284
- f"Warning: none
285
- "
286
- f"Key result: {ph_str} m"
287
- )
288
-
289
- return explanation
290
- import gradio as gr
291
- import json, requests
292
-
293
- # Paste the bernoulli_pipe_flow, deterministic_explainer, hf_llm_explainer functions here
294
- # (copy from the Colab cells above). For brevity, this file assumes they are present.
295
-
296
- # For example, import them from a module if you split code. Here we assume they are defined above.
297
-
298
- def compute_and_explain(P1,P2,V1,V2,z1,z2,rho,mu,D,L,roughness,use_darcy,hf_token,explain_mode):
299
- record = bernoulli_pipe_flow(P1,P2,V1,V2,z1,z2,rho,mu,roughness,D,L, None, use_darcy)
300
- if not record.get('ok'):
301
- return record, 'Errors: ' + '; '.join(record.get('errors',[]))
302
- if explain_mode == 'deterministic':
303
- explanation = deterministic_explainer(record)
304
- elif explain_mode == 'local_llm':
305
- explanation = llm_explain(record)
306
- else:
307
- explanation = "Unknown explanation mode selected."
308
- return record, explanation
309
-
310
- with gr.Blocks() as demo:
311
- gr.Markdown("# Bernoulli Pipe Flow Calculator")
312
- gr.Markdown("This Space hosts a Bernoulli pipe flow calculator for calculating the pump head loss for an internal flow system through a pipe. An example of one such pipe system is shown below. To utilize this calculator, simply fill in the required system metrics and hit 'compute'.")
313
- gr.Image('/file=bernoulli.png')
314
- with gr.Row():
315
- with gr.Column(scale=2):
316
- P1 = gr.Number(value=101325, label='P1 [Pa]')
317
- P2 = gr.Number(value=101325, label='P2 [Pa]')
318
- V1 = gr.Number(value=1.0, label='V1 [m/s]')
319
- V2 = gr.Number(value=1.0, label='V2 [m/s]')
320
- z1 = gr.Number(value=0.0, label='z1 [m]')
321
- z2 = gr.Number(value=0.0, label='z2 [m]')
322
- rho = gr.Number(value=1000.0, label='rho [kg/m^3]')
323
- mu = gr.Number(value=0.001, label='mu [Pa.s]')
324
- D = gr.Number(value=0.1, label='D [m]')
325
- L = gr.Number(value=10.0, label='L [m]')
326
- roughness = gr.Number(value=1.5e-6, label='roughness [m]')
327
- use_darcy = gr.Checkbox(value=True, label='Use Darcy–Weisbach')
328
- hf_token = gr.Textbox(value='', label='HF API token (optional)')
329
- run_btn = gr.Button('Compute')
330
- with gr.Column(scale=3):
331
- numeric_out = gr.JSON(label='Structured numeric result (JSON)')
332
- gr.Markdown('---')
333
- explain_mode = gr.Radio(['deterministic','local_llm'], value='deterministic', label='Explanation mode')
334
- explanation_out = gr.Textbox(lines=15, label='Explanation')
335
-
336
- run_btn.click(
337
- compute_and_explain,
338
- inputs=[P1,P2,V1,V2,z1,z2,rho,mu,D,L,roughness,use_darcy,hf_token,explain_mode],
339
- outputs=[numeric_out, explanation_out]
340
- )
341
-
342
- demo.queue().launch()
343
-