File size: 8,121 Bytes
6ed39bb dbb9ee4 6ed39bb a28aa68 6ed39bb dbb9ee4 0ad8067 dbb9ee4 6ed39bb 304cac9 6ed39bb a28aa68 a698771 |
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 |
import math as m
import gradio as gr
import pandas as pd
import numpy as np
from math import log10, pi
from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
# Assuming darcy_weisbach_calculation and explain_results functions are defined elsewhere or in this string
# For this example, I'll include them for completeness. In a real scenario,
# you might have these in separate files or ensure they are defined before this string.
def darcy_weisbach_calculation(
rho, # kg/m^3
mu, # Pa路s
D, # m
L, # m
Q, # m^3/s
eps=1.5e-6 # m, absolute roughness (default ~ smooth steel)
):
"""
Assumptions:
- Steady, incompressible, Newtonian fluid
- Fully developed internal flow in a straight, horizontal, circular pipe
- Single-phase, isothermal
- Darcy friction factor: laminar f=64/Re; turbulent via Swamee鈥揓ain explicit fit
Valid ranges (typical sanity):
- 500 <= rho <= 2000 kg/m^3
- 0.2e-3 <= mu <= 5e-3 Pa路s
- 0.005 <= D <= 1.0 m
- 0.5 <= L <= 1000 m
- 1e-5 <= Q <= 2.0 m^3/s
- 0 <= eps <= 5e-3 m
"""
# Derived quantities
A = pi*(D**2)/4.0
v = Q / A
Re = rho * v * D / mu
# Friction factor
if Re < 2300:
f = 64.0 / max(Re, 1e-9) # protect division
regime = "laminar"
else:
# Swamee鈥揓ain explicit approximation for turbulent flow
# f = 0.25 / [log10( (eps/(3.7D)) + (5.74/Re^0.9) )]^2
term = (eps/(3.7*D)) + (5.74/(Re**0.9))
f = 0.25 / (log10(term)**2)
regime = "turbulent"
# Darcy鈥揥eisbach head loss: h_f = f*(L/D)*(v^2/(2g))
g = 9.80665 # m/s^2
hf = f * (L/D) * (v**2/(2*g))
# Pressure drop: 螖P = rho*g*h_f
dP = rho * g * hf
# Structured, human-readable message
message = {
"title": "Darcy鈥揥eisbach Head Loss Calculator",
"scope": [
"Steady, incompressible, fully developed flow in a straight circular pipe",
"Single-phase, isothermal, horizontal run"
],
"assumptions": [
"Newtonian fluid",
"Darcy friction factor: laminar f=64/Re; turbulent via Swamee鈥揓ain explicit formula",
"No fittings/minor losses included"
],
"inputs": {
"density_rho_kg_per_m3": rho,
"viscosity_mu_Pa_s": mu,
"diameter_D_m": D,
"length_L_m": L,
"flow_rate_Q_m3_per_s": Q,
"roughness_eps_m": eps
},
"derived": {
"area_A_m2": A,
"avg_velocity_v_m_per_s": v,
"Reynolds_Re": Re,
"friction_factor_f": f,
"flow_regime": regime
},
"outputs": {
"head_loss_hf_m": hf,
"pressure_drop_dP_Pa": dP
},
"formulas": [
"A = 蟺 D^2 / 4",
"v = Q / A",
"Re = 蟻 v D / 渭",
"Laminar: f = 64 / Re",
"Turbulent: f = 0.25 / [log10(蔚/(3.7D) + 5.74/Re^0.9)]^2",
"h_f = f (L/D) (v^2 / (2g))",
"螖P = 蟻 g h_f"
],
"constants": {
"g_m_per_s2": g
},
"notes": [
"For turbulent flow with significant fittings, include minor losses separately.",
"Check cavitation or NPSH if near pumps; this tool reports line loss only."
],
"valid_ranges": {
"rho_kg_per_m3": [500, 2000],
"mu_Pa_s": [0.0002, 0.005],
"D_m": [0.005, 1.0],
"L_m": [0.5, 1000],
"Q_m3_per_s": [1e-5, 2.0],
"eps_m": [0.0, 0.005]
}
}
return message
# Small instruction-tuned model for concise, low-latency explanations.
# Change model if desired; keep it tiny for Spaces CPU.
model_id = "hf-internal-testing/tiny-random-LlamaForCausalLM" # placeholder tiny model
# For practical explanations, replace with a small instruct model like:
# model_id = "HuggingFaceH4/zephyr-7b-alpha" # requires more resources
# or a tiny flan-t5: "google/flan-t5-small"
def load_llm_pipeline(model_name=model_id, task="text2text-generation"): # Changed task to text2text-generation
try:
pipe = pipeline(task, model=model_name, device_map="auto")
except Exception:
# Fallback small model available in most environments
pipe = pipeline(task, model="google/flan-t5-small")
return pipe
llm = load_llm_pipeline()
def explain_results(structured_message):
# Convert the structured dict into a readable block and prompt the LLM
import json
context = json.dumps(structured_message, indent=2)
prompt = (
"You are an engineering tutor. Read the structured calculation JSON and produce a clear, concise explanation for a non-expert.\n"
"Goals:\n"
"- This tool calculates pressure loss in a straight pipe using the Darcy-Weisbach equation. It assumes steady, incompressible, Newtonian fluid flow in a horizontal pipe and calculates friction based on flow regime (laminar or turbulent).\n\n" # Fixed escaping
"- Highlight the formulas and what they mean physically.\n"
"- Interpret the Reynolds number and friction factor.\n"
"- Explain head loss and pressure drop magnitudes and practical implications.\n"
"- If inputs look out of typical ranges, gently flag them.\n"
"Stay under 180 words. Avoid equations in LaTeX; use plain words.\n\n"
f"JSON:\n{{context}}\n\n"
"Explanation:"
)
out = llm(prompt, max_new_tokens=220)
text = out[0]["generated_text"] if isinstance(out, list) else str(out)
# In case the model echoes the prompt, try to extract the tail
if "Explanation:" in text:
text = text.split("Explanation:", 1)[-1].strip()
return text
def run_calc(rho, mu, D, L, Q, eps):
msg = darcy_weisbach_calculation(rho, mu, D, L, Q, eps)
# Numeric panel summary
out_lines = []
out = msg["outputs"]
der = msg["derived"]
out_lines.append(f"Reynolds number: {der['Reynolds_Re']:.0f}")
out_lines.append(f"Friction factor: {der['friction_factor_f']:.5f} ({der['flow_regime']})")
out_lines.append(f"Head loss h_f: {out['head_loss_hf_m']:.4f} m")
out_lines.append(f"Pressure drop 螖P: {out['pressure_drop_dP_Pa']:.1f} Pa")
numeric_panel = "\n".join(out_lines)
# Explanation via LLM
explanation = explain_results(msg)
return numeric_panel, explanation
with gr.Blocks() as demo:
gr.Markdown("# Darcy鈥揥eisbach Pipe Loss (Deterministic)")
with gr.Row():
with gr.Column():
rho = gr.Slider(500, 2000, value=998.0, step=1.0, label="Density 蟻 (kg/m鲁)")
mu = gr.Slider(0.0002, 0.005, value=0.0010, step=0.0001, label="Viscosity 渭 (Pa路s)")
D = gr.Slider(0.005, 1.0, value=0.05, step=0.001, label="Diameter D (m)")
L = gr.Slider(0.5, 1000.0, value=50.0, step=0.5, label="Length L (m)")
Q = gr.Slider(1e-5, 2.0, value=0.005, step=1e-4, label="Flow rate Q (m鲁/s)")
eps= gr.Slider(0.0, 0.005, value=1.5e-6, step=1e-6, label="Roughness 蔚 (m)")
run_btn = gr.Button("Compute")
with gr.Column():
numeric = gr.Textbox(label="Numerical results", lines=6)
# Assuming 'explain' is defined elsewhere, e.g., as a gr.Textbox
# If not, you might need to define it here:
explain = gr.Textbox(label="Explanation", lines=10)
examples = gr.Examples(
examples=[
[998.0, 0.0010, 0.05, 50.0, 0.005, 1.5e-6], # Water, smooth steel
[870.0, 0.0015, 0.10, 200.0, 0.03, 4.5e-5], # Light oil, commercial steel
[1000.0, 0.0008, 0.02, 10.0, 0.0002, 1.0e-6] # Small tube, low flow
],
inputs=[rho, mu, D, L, Q, eps]
)
run_btn.click(run_calc, inputs=[rho, mu, D, L, Q, eps], outputs=[numeric, explain])
# Comment out the demo.launch() call as it will be handled by the Hugio Face Space
demo.launch(share=False, server_name="0.0.0.0") # Uncomment and add arguments for Space
|