UDF: wall heat transfer¶
Status: seam live, no user path yet. The solver consumes
pipe.py_heat on every driver, but the only things that write it are
built-in closures — there is no kind = "python" for [pipe.heat].
Read the chapter overview for the shared contract.
What exists today¶
_overlay_py_sources applies pipe.py_heat(rho, u, p) -> s_E alongside
friction and porous. Five built-in closures produce one:
| producer | selected by |
|---|---|
make_egr_cooler_py_heat |
[pipe.heat] kind = "egr_cooler" |
make_charge_air_cooler_py_heat |
kind = "charge_air_cooler" |
make_flow_nu_py_heat |
kind = "flow_nu" |
make_wall_coupled_py_heat |
a [[wall]] thermal coupling |
make_multilayer_wall_py_heat |
a multilayer wall |
So unlike friction, this seam is already carrying load. That is
exactly why it is not first: a kind = "python" arm here shares a seam
with five existing producers, and the interaction (what happens when a
wall coupling and a user closure both want to write py_heat) is a
design question, not a plumbing one.
What a user path would need to settle¶
- Conflict rule. A
[[wall]]coupling setspy_heaton the gas pipe during network assembly, after_attach_closures. Last writer wins today, silently. A user closure must either refuse to coexist, or the seam must become a list. - Energy accounting.
py_heatreturnss_Eonly, and the energy audit (analysis/energy_audit.py) enumerates heat closures to form its control volume. A user closure that the audit cannot enumerate would make CV-B unformable — the audit is written to refuse rather than silently mis-attribute, so this must be wired deliberately. - Sign convention.
s_E < 0removes energy from the gas. The built-ins are consistent; a user-facing contract should state it once, in the units the audit expects (W/m³).
Until those are answered, use kind = "flow_nu" (correlation-driven,
Re/Pr-dependent) which covers most of what a hand-written heat closure
would do.