Files
Entropyk/apps/web/public/docs/components/thermal-load.md
sepehr 3358b74342 Add diagram workbench UI with Modelica DoF coaching and ISO glyphs.
Ship the Next.js cycle editor with CAD chrome, technical HX symbols, Fixed/Free boundary guidance, and secondary water/air pressure drop support in the solver stack.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-17 22:46:46 +02:00

5.6 KiB
Raw Blame History

ThermalLoad

Cold-side receiver of a physical inter-circuit thermal coupling. Récepteur côté froid d'un couplage thermique physique inter-circuits.


EN

Physical model

ThermalLoad models a hydronic load segment — e.g. the cooling-water side of a shared heat exchanger — that receives an externally-determined heat rate Q [W] from the solver's thermal-coupling layer.

It follows the BOLT/Modelica boundary pattern (BOLT.BoundaryNode.Coolant.Source → HX → Sink): the loop's pressure and inlet temperature are fixed by boundary components, not by the load:

BrineSource(P_set, T_in) ──edge──▶ ThermalLoad ──edge──▶ BrineSink(P_back, T free)

The outlet temperature is emergent: T_out = T_in + Q / (ṁ·cp) (the sink temperature must be left free — do not set t_set_c on the BrineSink, or the loop becomes over-determined).

Residual equations — n_equations() = 2

r0:  ṁ  ṁ_design                       (imposed design flow)
r1:  ṁ_design·(h_out  h_in)  Q_ext    (energy balance, Q_ext = state[q_idx])

The energy balance uses the design flow (a constant): r0 already pins ṁ = ṁ_design, and the constant form keeps the block linear and structurally nonsingular even when the initializer starts at ṁ = 0.

Q_ext is read from the per-coupling state unknown wired by System::finalize() via Component::set_external_heat_index. Unwired ⇒ Q_ext = 0 (adiabatic pass-through).

DoF balance (water loop)

Unknowns: 1 ṁ (shared branch) + 2×(P,h) + 1 Q = 6. Equations: BrineSource 2 + ThermalLoad 2 + BrineSink 1 (T free) + coupling 1 = 6. ✓

Jacobian

Exact and analytic (the whole block is linear): unit entry on the ṁ row, ±ṁ_design on r1's enthalpy columns, 1 on the coupling Q column.

Operational states

State r0 r1
On ṁ = ṁ_design ṁ_design·Δh = Q
Bypass ṁ = ṁ_design h_out = h_in (adiabatic)
Off ṁ = 0 h_out = h_in

measure_output

Kind Value
Capacity / HeatTransferRate abs(Q_ext) [W]
MassFlowRate inlet ṁ [kg/s]

energy_transfers

(Q_ext, 0) — heat added to the component is positive. The component is excluded from cycle-performance aggregation (counts_in_cycle_performance() = false): the absorbed Q is the primary cycle's rejected duty, not extra cooling capacity. It still participates in per-component First Law validation.

JSON parameters (CLI)

Parameter Unit Default Description
mass_flow_kg_s kg/s 0.5 Imposed design mass flow (must be > 0)

Usage with thermal_couplings

"components": [
  { "type": "BrineSource", "name": "cw_in", "fluid": "Water",
    "p_set_bar": 2.0, "t_set_c": 30.0 },
  { "type": "ThermalLoad", "name": "cw_load", "mass_flow_kg_s": 0.9 },
  { "type": "BrineSink", "name": "cw_out", "fluid": "Water", "p_back_bar": 2.0 }
],
...
"thermal_couplings": [
  { "hot_circuit": 0, "cold_circuit": 1, "ua": 5000.0, "efficiency": 1.0,
    "hot_component": "cond", "cold_component": "cw_load" }
]

The coupling owns one unknown Q closed against the hot component's measured duty (Q = η·duty_hot via measure_output(Capacity)); the ThermalLoad consumes Q in r1, so the heat genuinely crosses the circuit boundary and the First Law closes across circuits. Keep the water-loop conditions consistent with the hot component's secondary stream (same T_in, ṁ, cp).

Full example: crates/cli/examples/chiller_r410a_coupled_water_loop.json.


FR

Modèle physique

ThermalLoad modélise un segment de charge hydronique — par exemple le côté eau de refroidissement d'un échangeur partagé — qui reçoit une puissance thermique Q [W] déterminée extérieurement par la couche de couplage thermique du solveur.

Il suit le pattern de frontières BOLT/Modelica (BOLT.BoundaryNode.Coolant.Source → HX → Sink) : la pression et la température d'entrée de la boucle sont fixées par des composants frontières, pas par la charge :

BrineSource(P_set, T_in) ──arête──▶ ThermalLoad ──arête──▶ BrineSink(P_back, T libre)

La température de sortie est émergente : T_out = T_in + Q / (ṁ·cp) (laisser la température du sink libre — ne pas mettre t_set_c sur le BrineSink, sinon la boucle est surdéterminée).

Équations résiduelles — n_equations() = 2

Débit imposé (ṁ = ṁ_design) + bilan d'énergie (ṁ_design·(h_out h_in) = Q_ext). Le bilan utilise le débit de conception (constante) : r0 épingle déjà ṁ, et la forme constante garde le bloc linéaire et structurellement non singulier même si l'initialiseur part de ṁ = 0.

Q_ext est lu depuis l'inconnu d'état du couplage, câblé par System::finalize() via set_external_heat_index. Non câblé ⇒ Q_ext = 0 (passage adiabatique).

Bilan DoF (boucle d'eau)

Inconnues : 1 ṁ (branche partagée) + 2×(P,h) + 1 Q = 6. Équations : BrineSource 2 + ThermalLoad 2 + BrineSink 1 (T libre) + couplage 1 = 6. ✓

energy_transfers et performance

(Q_ext, 0) — chaleur reçue positive. Le composant est exclu de l'agrégation de performance du cycle (counts_in_cycle_performance() = false) : le Q absorbé est la puissance rejetée du cycle primaire. Il participe néanmoins à la validation du 1er principe par composant.

Paramètres JSON (CLI)

mass_flow_kg_s (kg/s, défaut 0.5) — débit de conception imposé. P et T_in se règlent sur le BrineSource ; P_back sur le BrineSink.

Exemple complet : crates/cli/examples/chiller_r410a_coupled_water_loop.json.