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>
This commit is contained in:
2026-07-17 22:46:46 +02:00
parent 62efea0646
commit 3358b74342
275 changed files with 70187 additions and 5230 deletions

View File

@@ -0,0 +1,137 @@
# Entropyk Component Documentation / Documentation des composants Entropyk
> Bilingual reference (EN + FR) for every component usable from the CLI JSON config and the web UI.
> Référence bilingue (EN + FR) pour chaque composant CLI / UI.
>
> Each page documents: physical model, correlations (if any), residual equations, `n_equations()`,
> ports, system vs rating secondary, calibration Z-factors, and JSON parameters with defaults.
>
> Chaque fiche documente : modèle, corrélations, résidus, ports, modes système/rating, facteurs Z, paramètres JSON.
**Last major doc refresh:** 2026-07-17 — dual-mode HX Newton, compressor maps (AHRI / SSTSDT), correlation inventory, UI Fixed/Free, fallback solver.
### Full correlation & map inventory
**[correlations-and-maps.md](./correlations-and-maps.md)** — AHRI 540, screw bilinear presets, Longo/Shah/…, ε-NTU, pumps/fans, ΔP.
---
## Conventions
### State / État
- **State per edge:** `(ṁ, P, h)`. Series branches share one ṁ unknown (`same_branch_m`, CM1.4).
- **État par arête :** `(ṁ, P, h)`. Branches en série → un seul ṁ.
### DoF (degrees of freedom)
A real-machine solve requires **`n_equations = n_unknowns`**.
- **FIX** = impose a quantity (boundary T/P/ṁ, outlet SH/SC, quality residual, measured calib target…) → +equation or pin.
- **FREE** = solver unknown (emergent pressure, free opening, free `z_ua`, …).
CLI hard-fails on imbalance (`validate_system_dof`). Web UI: Fixed checkboxes + balance bar.
### System vs rating secondary (HX)
| Mode | Secondary definition | Secondary unknowns | Newton duty |
|------|----------------------|--------------------|-------------|
| **System** | Live ports `secondary_inlet` / `secondary_outlet` + Source/Sink | yes | ε-NTU Q from edge state |
| **Rating** | Scalars `secondary_inlet_temp_*` + ṁ·cp or `C_sec` | no | ε-NTU Q from scalars **in residuals** |
Both modes are first-class for Condenser / Evaporator / FloodedEvaporator.
Scalars are **not** limited to offline `rate()` only.
### Zero flow
Valid state. HX use `flow_regularization` (smooth `|ṁ|`, activity, Δh hold). See [flow-regularization.md](./flow-regularization.md).
### Emergent pressure
`emergent_pressure: true` lets condensing/evaporating pressure float from HX ↔ secondary energy balance instead of a fixed design pin.
### Calibration Z-factors (BOLT)
Default **1.0** = no correction. Typical range ~0.23 for inverse calib; production often ~0.81.2.
| Entropyk | BOLT | Effect |
|----------|------|--------|
| `z_flow` | `Z_flow_suc`, … | ṁ_eff = z_flow × ṁ_nom |
| `z_dp` | `Z_dpc`, … | ΔP_eff = z_dp × ΔP_nom |
| `z_ua` | `Z_UA`, `Z_Uev`, `Z_Ucd` | UA_eff = z_ua × UA_nom |
| `z_power` | `Z_power` | Ẇ_eff = z_power × Ẇ_nom |
| `z_etav` | — | η_v scale |
Legacy `f_*` and BOLT `Z_*` spellings accepted in JSON.
Recommended order: `z_flow → z_dp → z_ua → z_power → z_etav`.
**UI calibration pattern:** Fixed on measure (SST/SDT) + Free on `z_ua` (do **not** require the Advanced “Regulation loop” node for simple Z_UA calib).
### Solver strategies (CLI)
| `solver.strategy` | Behaviour |
|-------------------|-----------|
| `newton` | NewtonRaphson |
| `picard` | Sequential substitution |
| `fallback` | Intelligent Newton → Picard (`FallbackSolver`) |
---
## Compressors / Compresseurs
- [IsentropicCompressor](./isentropic-compressor.md)
- [ScrewEconomizerCompressor / ScrewCompressor](./screw-economizer-compressor.md)
- [Compressor (AHRI 540)](./compressor-ahri540.md)
## Heat exchangers / Échangeurs
| Component | Model / correlations | Notes |
|-----------|----------------------|--------|
| [Condenser](./condenser.md) | ε-NTU phase-change | dual secondary modes |
| [Evaporator](./evaporator.md) | ε-NTU DX + SH | dual secondary modes |
| [FloodedEvaporator](./flooded-evaporator.md) | ε-NTU + sat-vapor / quality | dual secondary modes |
| [FloodedCondenser](./flooded-condenser.md) | inner ε-NTU + SC control | prefer Condenser in production |
| [BphxEvaporator / BphxCondenser](./bphx.md) | **Longo / Shah** → UA + ε-NTU | geometry + correlation |
| [AirCooledCondenser](./air-cooled-condenser.md) | air-side coil | |
| [FinCoilCondenser](./fin-coil-condenser.md) | finned coil | |
| [MchxCondenserCoil](./mchx-condenser-coil.md) | microchannel | |
| [HeatExchanger (generic)](./heat-exchanger-generic.md) | generic ε-NTU / LMTD | |
| [FreeCoolingExchanger](./free-cooling-exchanger.md) | free cooling | |
| [Economizer](./economizer.md) | internal LMTD HX | not always a CLI leaf |
| [MovingBoundaryHX](./moving-boundary-hx.md) | multi-zone UA ID | research path |
| [Flow regularization](./flow-regularization.md) | zero-flow helpers | shared |
## Valves & expansion
- [IsenthalpicExpansionValve / EXV](./isenthalpic-expansion-valve.md)
- [ExpansionValve](./expansion-valve.md)
- [ReversingValve](./reversing-valve.md)
- [BypassValve](./bypass-valve.md)
## Flow network
- [FlowSplitter](./flow-splitter.md)
- [FlowMerger](./flow-merger.md)
- [Pipe](./pipe.md)
- [Drum](./drum.md)
## Rotating machines
- [Fan](./fan.md)
- [Pump](./pump.md)
## Boundaries
- [Refrigerant / Brine / Air Sources & Sinks](./boundaries.md)
## Inline nodes
- [Anchor & HeatSource](./anchor-heat-source.md)
## Inter-circuit coupling
- [ThermalLoad](./thermal-load.md)
---
See also: system capability notes under `docs/` and example machines in `crates/cli/examples/`.

View File

@@ -0,0 +1,50 @@
# AirCooledCondenser
Config type: `"AirCooledCondenser"`
Source: air-cooled condenser / coil stack in components
---
## EN
### Purpose & model
Air-cooled condenser: refrigerant condensation against outdoor air stream. Combines refrigerant-side phase-change energy balance with air-side capacity (fan flow × cp_air × effectiveness or coil model).
```
Q = ε · C_air · (T_cond T_air,in) # schematic ε-NTU air-side form
```
May wrap or specialize `Condenser` with air secondary defaults.
### Residuals
Similar to Condenser coupled path: refrigerant energy/momentum + air secondary when live ports or rating air stream set.
### Ports
Refrigerant inlet/outlet + air secondary_in/out when 4-port.
### Calibration
`z_ua` default **1.0**; fan speed may be free under head-pressure control.
### JSON
UA / coil geometry / OAT / face velocity / design capacity depending on arm — see CLI `create_component` and example air-cooled chillers.
---
## FR
### But
**Condenseur à air** : rejet de chaleur vers lair extérieur.
### Calibration
Z_UA = 1 par défaut ; vitesse ventilateur possible en régulation.
### JSON
Voir exemples CLI air-cooled.

View File

@@ -0,0 +1,60 @@
# Anchor & HeatSource (inline BOLT-style nodes)
Config types: `"Anchor"` / `"RefrigerantNode"`, `"HeatSource"`
Source: anchor / heat source modules in components
---
## EN
### Anchor (Refrigerant.Node)
Inline **probe or spec** on a refrigerant edge:
| Mode | Behaviour | DoF |
|------|-----------|-----|
| Probe (no key) | measures P/T/SH/SC — **DoF-neutral** | 0 equations |
| Spec | imposes **one** of `superheat_k`, `quality`, `t_c`/`t_k`, `p_bar` | **+1 equation** |
When imposing, free something elsewhere (emergent pressure, free actuator, free boundary).
### HeatSource (Heat.Source)
Injects `q_w` (or `q_kw`) into the stream energy balance:
```
ṁ · (h_out h_in) = Q_heat
```
Negative Q extracts heat. Can be linked as `cold_component` of a thermal coupling (motor cooling pattern).
### Ports
Inline on a single branch (inlet/outlet pass-through).
### Calibration
None required for probe mode.
### JSON (main)
| Key | Component | Meaning |
|-----|-----------|---------|
| `superheat_k` / `quality` / `t_c` / `p_bar` | Anchor | one optional FIX |
| `q_w` / `q_kw` | HeatSource | heat injection |
---
## FR
### Anchor
Sonde (0 DoF) ou **une** spécification (+1 équation) : SH, x, T ou P.
### HeatSource
Injection de chaleur `Q` dans le bilan dénergie du fluide.
### DoF
Imposer une spec Anchor ⇒ libérer ailleurs.

View File

@@ -0,0 +1,94 @@
# Boundaries — Sources & Sinks / Frontières
Config types: `RefrigerantSource`, `RefrigerantSink`, `BrineSource`, `BrineSink`, `AirSource`, `AirSink`
Sources: `refrigerant_boundary.rs`, `brine_boundary.rs`, `air_boundary.rs`
---
## EN
Boundary components fix **Dirichlet** conditions on one edge.
**Source** = one outlet; **Sink** = one inlet. These are the natural place to **FIX** machine inputs (T, P, ṁ).
### RefrigerantSource / RefrigerantSink
```
Source: P = P_set ; h = h(P, x) n ≈ 2
Sink: P = P_back ; optional h if x set n ≈ 12
```
| Key | Meaning | Default |
|-----|---------|---------|
| `fluid` | refrigerant | primary |
| `p_set_bar` / `p_back_bar` | pressure | ~10 bar typical |
| `quality` | vapor quality | 1.0 source |
### BrineSource / BrineSink (water / glycol)
```
Source: P, h(T), optional ṁ_set n = 2 or 3
Sink: P_back, optional T/h, ṁ n = 13
```
| Key | Meaning | Default |
|-----|---------|---------|
| `fluid` | Water / MEG / … | Water |
| `p_set_bar` / `p_back_bar` | pressure | 2 bar |
| `t_set_c` | temperature | 12 °C (source) |
| `concentration` | glycol mass % | 0 |
| `m_flow_kg_s` | imposed loop flow (BOLT `Vd_fixed`) | optional |
**Do not** combine `m_flow_kg_s` with another flow imposition on the same branch (pump curve + fixed ṁ → over-constrained).
### AirSource / AirSink
Psychrometric state (MagnusTetens style humidity + moist air enthalpy):
```
h ≈ 1006·T_c + W·(2.501e6 + 1860·T_c)
Source: fix P, h(T, RH) n = 2
```
| Key | Meaning | Default |
|-----|---------|---------|
| `t_dry_c` / `t_set_c` | dry-bulb | |
| `rh` | relative humidity | |
| `p_set_bar` | pressure | ~1 bar |
| `m_flow_kg_s` | optional mass flow | |
### System wiring for HX secondary
```
BrineSource.outlet → HX.secondary_inlet
HX.secondary_outlet → BrineSink.inlet
```
Without live wiring, HX may still run in **rating** mode with scalar secondary_* on the HX itself.
### Calibration
Boundaries generally have **no Z-factors**. They are pure Fixed inputs / back-pressure.
---
## FR
### Rôle
Imposent les **conditions aux limites** (P, T, ṁ). Cest là quon **fixe** les entrées machine.
### Eau (Brine)
Source : P, T, ṁ optionnel. Sink : contre-pression (T sortie souvent **libre** = émergente).
### Air
État psychrométrique (T sèche, HR → h).
### Câblage HX
Source → secondary_in → secondary_out → Sink pour le mode système.
### JSON
Voir tableaux EN.

View File

@@ -0,0 +1,119 @@
# BphxEvaporator / BphxCondenser (Brazed Plate HX)
Config types: `"BphxEvaporator"`, `"BphxCondenser"`
Source: `crates/components/src/heat_exchanger/bphx_evaporator.rs`, `bphx_condenser.rs`, shared geometry/correlation helpers
---
## EN
### Purpose & model
Brazed-plate HX with **geometry + two-phase correlation → h → UA estimate**, then runtime solve on an **inner ε-NTU** residual model.
#### Correlations (selectable)
Default **Longo 2004**. Also **Shah 1979**, **Shah 2021**.
Full registry (also Kandlikar, GungorWinterton, Gnielinski, DittusBoelter, Ko 2021, Friedel ΔP): see [correlations-and-maps.md](./correlations-and-maps.md).
Equivalent Reynolds construction (schematic):
```
Re_l = G · d_h / μ_l
Re_eq = Re_l · (1 x + x · √(ρ_l / ρ_v))
```
Longo-style Nu (illustrative forms used in the implementation path):
```
Evaporation: Nu ~ f(Re_eq, Pr_l) (e.g. 0.05 · Re_eq^0.8 · Pr_l^0.33)
Condensation: Nu ~ f(Re_eq, Pr_l, ρ*) (e.g. 1.875 · Re_eq^0.35 · Pr_l^0.33 · …)
h = Nu · k_l / d_h
UA_est = h · A · z_ua
```
Pressure drop (schematic):
```
ΔP = z_dp · 2 · f · L · G² / (ρ · d_h)
```
**Important:** the **Newton system residuals** for the component are the **inner ε-NTU** residual set (`n_equations` of the inner model, typically 2 for the base HX path). The correlation updates **UA** (when `update_ua_from_htc` / geometry path is engaged); it is **not** a full multi-zone moving-boundary residual stack.
### Modes / targets
| Type | Mode | Notes |
|------|------|--------|
| `BphxEvaporator` | **DX only** | Outlet is superheated vapor. `target_superheat_k` (default 5 K) is diagnostic/target storage — not a flooded shell model. For flooded shell-and-tube use `FloodedEvaporator`. |
| `BphxCondenser` | Subcooling target | `target_subcooling_k` (default 3 K) |
### Ports
4-port Modelica-style naming in the system graph when wired:
| Port | Role |
|------|------|
| `inlet` / `outlet` | Refrigerant |
| `secondary_inlet` / `secondary_outlet` | Secondary fluid |
Geometry fields: plate length/width, thickness, chevron, channel spacing, optional `dh_m` / `area_m2` overrides.
### Calibration
| Key | Meaning | Default |
|-----|---------|---------|
| `z_ua` / `Z_UA` | UA scale | **1.0** |
| `z_dp` / `Z_dpc` | ΔP scale | **1.0** |
| `ua` explicit | sets `z_ua = ua / UA_nom` | |
Legacy `f_ua` / `f_dp` accepted in JSON.
### JSON parameters (main)
| Key | Meaning | Default |
|-----|---------|---------|
| `n_plates` | plate count | 20 |
| `plate_length_m` / `plate_width_m` | geometry | |
| `chevron_angle_deg` | chevron | 60 |
| `correlation` | Longo2004 / Shah1979 / Shah2021 | Longo2004 |
| `target_superheat_k` | DX target (evap) | 5 K |
| `target_subcooling_k` | SC target (cond) | 3 K |
| `refrigerant` / `secondary_fluid` | fluids | |
| `z_ua`, `z_dp` | calib | 1.0 |
### DoF / system usage
Prefer live secondary wiring for closed loops. Pair `z_ua` free + measured SST/SDT for inverse calibration (same Fixed/Free discipline as other HX).
---
## FR
### But & modèle
Échangeurs **à plaques brasées** : géométrie + **corrélation biphasique** (Longo 2004 / Shah) → coefficient h → UA, puis solveur sur modèle **ε-NTU interne**.
Formes types :
```
Re_eq = Re_l · (1 x + x · √(ρ_l/ρ_v))
Nu = f(Re_eq, Pr, …) # Longo / Shah selon `correlation`
h = Nu · k / d_h
UA = h · A · z_ua
```
Le **Newton** ne résout pas la corrélation plaque par plaque : il résout le **HX ε-NTU** ; la corrélation **calibre/estime UA**.
### Modes
- **BphxEvaporator** : DX uniquement (pas un flooded shell).
- **BphxCondenser** : cible de sous-refroidissement.
### Calibration
`z_ua = 1`, `z_dp = 1` par défaut. Alias BOLT `Z_UA`, `Z_dpc`.
### Ports / JSON
Voir tableaux EN.

View File

@@ -0,0 +1,53 @@
# BypassValve
Config type: `"BypassValve"`
Source: `crates/components/src/bypass_valve.rs` (or valve module)
---
## EN
### Purpose & model
Bypass leg valve with opening characteristic (linear / equal-percentage / custom). Parallel path around a component (compressor, HX, etc.).
```
ṁ = f(opening, ΔP, kv, characteristic)
h_out ≈ h_in
```
### Residuals
Flow residual + energy (isenthalpic or low Δh).
### Ports
`inlet` / `outlet`.
### Actuator
`opening` ∈ [0, 1] — free when under control.
### JSON (main)
| Key | Meaning | Default |
|-----|---------|---------|
| `opening` | 01 | 01 |
| `kv` | capacity | |
| characteristic | linear / … | linear |
---
## FR
### But
**Vanne de by-pass** sur une branche parallèle.
### Actionneur
Ouverture 01.
### JSON
Voir EN.

View File

@@ -0,0 +1,131 @@
# Compressor (AHRI 540 + maps)
Config type: `"Compressor"`
Source: `crates/components/src/compressor.rs`
Related: `polynomials.rs` (Polynomial2D), registry `SstSdt` model variant
---
## EN
### Purpose
Positive-displacement compressor performance from **published coefficient maps**:
1. **AHRI 540** (CLI default for `"Compressor"`) — 10 coefficients M1M10
2. **SST/SDT polynomial** (API / registry) — 2D polynomials ṁ(SST,SDT), Ẇ(SST,SDT)
### Model A — AHRI 540
**Mass flow [kg/s]:**
```
ṁ = M1 · (1 (P_suc / P_dis)^(1/M2)) · ρ_suc · V_disp · N/60
```
**Power cooling [W]:**
```
Ẇ = M3 + M4 · (P_dis/P_suc) + M5 · T_suc + M6 · T_dis
```
**Power heating [W]:**
```
Ẇ = M7 + M8 · (P_dis/P_suc) + M9 · T_suc + M10 · T_dis
```
| Coeff | Role | Typical CLI default |
|-------|------|---------------------|
| M1 | flow scale | 0.85 |
| M2 | PR exponent (>0) | 2.5 |
| M3M6 | cooling power poly | 500, 1500, 2.5, 1.8 |
| M7M10 | heating power poly | 600, 1600, 3.0, 2.0 |
Also required: `speed_rpm`, `displacement_m3`, `efficiency` (isentropic / overall as used by the arm).
### Model B — SST/SDT polynomial (same `Compressor` type)
Select with JSON / UI: `"model_type": "SstSdt"` (aliases: `SstSdtPolynomial`, `sst_sdt`).
```
ṁ = Σ a_ij · SST^i · SDT^j [kg/s] (SST, SDT in Kelvin)
Ẇ = Σ b_ij · SST^i · SDT^j [W]
```
Bilinear form (CLI / UI coefficients):
```
ṁ = a00 + a10·SST + a01·SDT + a11·SST·SDT
Ẇ = b00 + b10·SST + b01·SDT + b11·SST·SDT
```
| JSON key | Role | Default (example) |
|----------|------|-------------------|
| `mf_a00``mf_a11` | mass-flow bilinear | 0.05, 0.001, 0.0005, 1e5 |
| `pw_b00``pw_b11` | power bilinear | 1000, 50, 30, 0.5 |
Also used by **ScrewEconomizerCompressor** (same bilinear form + eco fraction + presets Bitzer/Grasso).
### Residuals / ports
Two-port suction/discharge. Residual count depends on same-branch mass and model wiring (typically flow + energy).
### Calibration
| Factor | Default | Effect |
|--------|---------|--------|
| `z_flow` | **1.0** | scales ṁ |
| `z_power` | **1.0** | scales Ẇ |
### JSON (CLI `"Compressor"`)
| Key | Meaning | Default |
|-----|---------|---------|
| `model_type` | `Ahri540` \| `SstSdt` | `Ahri540` |
| `speed_rpm` | speed | **required** |
| `displacement_m3` | displacement | **required** |
| `efficiency` | efficiency | 0.85 |
| `fluid` | refrigerant | required |
| `m1``m10` | AHRI coeffs (if Ahri540) | see table |
| `mf_a00``mf_a11`, `pw_b00``pw_b11` | SST/SDT bilinear (if SstSdt) | see table |
| `p_suction_bar` / `h_suction_kj_kg` | init ports | 3.5 / 400 |
| `p_discharge_bar` / `h_discharge_kj_kg` | init ports | 12 / 440 |
### UI guidance
- **Modèle de carte** : bascule Ahri540 ↔ SstSdt
- Sections **AHRI 540** ou **Map SST/SDT** selon le choix
- Section **Machine** : speed, displacement, efficiency
- L**IsentropicCompressor** est un modèle physique différent (η_is + cylindrée)
---
## FR
### But
Compresseur à **cartes de performance** constructeur.
### AHRI 540
```
ṁ = M1 · (1 (P_s/P_d)^{1/M2}) · ρ · V · N/60
Ẇ = M3 + M4·PR + M5·T_s + M6·T_d (froid)
```
### Polynôme SST/SDT
```
ṁ, Ẇ = polynôme 2D en SST et SDT
```
(Utilisé surtout sur le **vis** ; presets Bitzer/Grasso.)
### Calibration
`z_flow`, `z_power` = **1.0** par défaut.
### JSON
Voir tableau EN (`m1``m10`, `speed_rpm`, `displacement_m3`).

View File

@@ -0,0 +1,124 @@
# Condenser / CondenserCoil
Config types: `"Condenser"`, `"CondenserCoil"`
Source: `crates/components/src/heat_exchanger/condenser.rs`
---
## EN
### Purpose & physical model
Refrigerant **condenser** rejecting heat to a secondary stream (water/glycol or air). Coupled duty is **phase-change ε-NTU** (isothermal refrigerant side at `T_cond(P)`):
```
ε = 1 exp(UA_eff / C_sec)
Q = ε · C_sec · (T_cond(P_in) T_sec,in) # heat rejected by refrigerant
```
- Optional lumped refrigerant ΔP: `ΔP = k · ṁ · |ṁ|`
- `CondenserCoil` locks secondary side to **Air** conventions
- **No plate correlation** here (see BPHX for Longo/Shah geometry UA)
`UA_eff` can be reduced by flooded-level actuator; `C_sec` can be scaled by fan speed φ when fan head-pressure is active.
### Dual secondary modes (Newton)
| Mode | Secondary source | `n_secondary` |
|------|------------------|---------------|
| **System** | Live edges ports 2/3 (`secondary_inlet` / `secondary_outlet`) | 1 or 2 |
| **Rating** | Scalars `secondary_inlet_temp_*` + capacity rate / ṁ·cp | 0 |
`coupled_ready` requires refrigerant indices **and** (live edges **or** rating scalars).
`live_secondary_stream` prefers edges; falls back to rating scalars (with fan φ scaling of `C_sec` when applicable).
### Residuals & `n_equations()` (coupled)
| Row | Equation |
|-----|----------|
| r0 | `P_out (P_in ΔP)` (skippable) |
| r1 | `ṁ · (h_in h_out) Q` |
| r2 (emergent) | `h_out h(P, T_cond SC)` subcooling closure |
| r_mass | `ṁ_out ṁ_in` if not same-branch |
| r_head (optional) | `T_cond T_target` (fan **or** flooded head-pressure) |
| r_sec | live secondary mass/energy only if edges present |
```
n_equations = n_thermo + (mass?) + (head?) + n_secondary
n_thermo = 2 normally, 3 with emergent_pressure (+ subcooling residual)
```
### Emergent pressure & actuators
- `emergent_pressure: true` + `subcooling_k` → condensing pressure is **solved**, not fixed by design T
- **Fan head-pressure:** free φ scales `C_sec = φ · C_nominal`; residual pins `T_cond`
- **Flooded head-pressure:** free level λ scales `UA_eff`; mutually exclusive with fan
### Ports
| Port | Index |
|------|-------|
| `inlet` / `outlet` | 0 / 1 refrigerant |
| `secondary_inlet` / `secondary_outlet` | 2 / 3 secondary |
System wiring: Source → secondary_in → secondary_out → Sink.
### Calibration
| Factor | Meaning | Default |
|--------|---------|---------|
| `z_ua` | UA scale | **1.0** |
| `z_dp` | ΔP scale | 1.0 |
| `z_flow` / `z_power` / `z_etav` | via shared Calib API | 1.0 |
UI: Fixed on SDT target + free `z_ua` for inverse calibration.
### JSON parameters (main)
| Key | Meaning | Default |
|-----|---------|---------|
| `ua` | UA [W/K] | required |
| `emergent_pressure` | free P_cond | false |
| `subcooling_k` | outlet SC [K] | 5 |
| `secondary_fluid` | Water / Air / … | |
| `secondary_inlet_temp_c` / mass_flow / cp | rating stream | |
| `pressure_drop_coeff` | k for ΔP | |
| `fan_head_pressure_target_c` | fan control | |
| `flooded_head_pressure_target_c` | level control | |
| `skip_pressure_eq` | drop r0 | false |
### Zero flow
Live `C_sec` uses `smooth_mass_magnitude(|ṁ|)`. Mass-flow index never remapped to a pressure column.
---
## FR
### But & modèle
Condenseur frigo → secondaire (eau/air). Duty **ε-NTU** :
```
Q = ε · C_sec · (T_cond(P) T_sec,in)
```
Pas de corrélation plaques (voir BPHX). UA global ± actionneurs fan/niveau.
### Modes secondaire
- **Système :** ports live Source/Sink
- **Rating :** scalaires T + ṁ·cp **dans le Newton** (pas seulement `rate()`)
### Pression émergente
`emergent_pressure` + sous-refroidissement : `P_cond` est **calculée**.
Fan ou flooded head-pressure = +1 actionneur libre.
### Calibration
`z_ua = 1` par défaut. Imposer SDT + libérer Z_UA pour caler le condenseur.
### Ports / JSON
Voir tableaux EN.

View File

@@ -0,0 +1,143 @@
# Correlations & performance maps / Corrélations & cartes
Master inventory of **every performance map and heat-transfer / pressure-drop correlation** wired in Entropyk (as of 2026-07-17).
Inventaire de **toutes** les cartes et corrélations du code.
Sources principales :
- `crates/components/src/compressor.rs` — AHRI 540 + SST/SDT
- `crates/components/src/screw_economizer_compressor.rs` — polynômes 2D + presets
- `crates/components/src/isentropic_compressor.rs` — η_is + volumétrique
- `crates/components/src/polynomials.rs` — Polynomial1D / Polynomial2D
- `crates/components/src/heat_exchanger/bphx_correlation.rs` — formules h
- `crates/components/src/heat_exchanger/correlation_registry.rs` — catalogue + domaines
- `crates/components/src/heat_exchanger/eps_ntu.rs` / `lmtd.rs` — HX génériques
- `crates/components/src/heat_exchanger/two_phase_dp.rs` — ΔP biphasique
- `crates/components/src/fan.rs` / `pump.rs` — courbes 1D
---
## EN
### 1. Compressors — performance maps
| Component | Model ID | Formula (summary) | Inputs | Outputs | UI / JSON |
|-----------|----------|-------------------|--------|---------|-----------|
| **IsentropicCompressor** | Physics + η_is | `h_dis = h_suc + (h_ish_suc)/η_is` ; emergent: `ṁ = ρ·V_d·N·η_vol·z_flow` | η_is, T guesses, V_d, N | ṁ, h_dis, W | η, emergent, displacement, speed |
| **Compressor** | **AHRI 540** (`model_type=Ahri540`) | `ṁ = M1·(1(P_s/P_d)^{1/M2})·ρ·V·N/60` ; `Ẇ_cool = M3+M4·PR+M5·T_s+M6·T_d` (heating M7M10) | M1…M10, V, N | ṁ, Ẇ | `m1``m10`, `speed_rpm`, `displacement_m3` |
| **Compressor** | **SST/SDT poly** (`model_type=SstSdt`) | `ṁ = a00+a10·SST+a01·SDT+a11·SST·SDT` ; same for Ẇ with `pw_b**` | bilinear coeffs | ṁ, Ẇ | `mf_a**`, `pw_b**` (CLI + UI) |
| **ScrewEconomizerCompressor** | **Bilinear SST/SDT** | `ṁ_suc = z_flow·(a00+a10·SST+a01·SDT+a11·SST·SDT)` ; same for Ẇ with b_ij ; eco fraction poly | presets + overrides | ṁ_suc, ṁ_eco, Ẇ | `preset`, `mf_a**`, `pw_b**` |
#### Screw presets (CLI)
| Preset | ṁ (a00,a10,a01,a11) | Power (b00,b10,b01,b11) | eco frac |
|--------|---------------------|-------------------------|----------|
| `bitzer_generic_200kw` | 1.35, 0.004, 0.0025, 1.2e5 | 58000, 180, 280, 0.4 | 0.13 |
| `grasso_generic_200kw` | 1.30, 0.0035, 0.0022, 1e5 | 60000, 190, 310, 0.45 | 0.11 |
| (none) | 1.2, 0.003, 0.002, 1e5 | 55000, 200, 300, 0.5 | 0.12 |
Temps in polynomials: **SST / SDT** as used by the curve implementation (see source; typically °C in manufacturer fits — verify against `Polynomial2D` evaluation units in code).
#### Calibration Z on compressors
| Factor | Effect |
|--------|--------|
| `z_flow` | scales ṁ |
| `z_flow_eco` | scales economizer ṁ (screw) |
| `z_power` | scales shaft power |
| `z_etav` | volumetric efficiency correction |
Default all **1.0**.
---
### 2. Heat exchangers — heat transfer correlations
| Correlation ID | Year | Purpose | Geometry | Wired in BPHX UI? |
|----------------|------|---------|----------|-------------------|
| **Longo2004** | 2004 | Evap / cond HTC (plates) | Brazed plate | **Yes** (default) |
| **Shah1979** | 1979 | Condensation HTC | Tubes (also selectable) | **Yes** |
| **Shah2021** | 2021 | Plate condensation | Plates | **Yes** |
| Kandlikar1990 | 1990 | Evaporation HTC | Tubes | Registry / BPHX enum |
| GungorWinterton1986 | 1986 | Evaporation HTC | Tubes | Registry |
| Gnielinski1976 | 1976 | Single-phase turbulent Nu | Tubes | Registry |
| DittusBoelter1930 | 1930 | Single-phase Nu (simple) | Tubes | Registry |
| Ko2021 | 2021 | Low-GWP plates | Plates | Registry |
| Friedel1979 | 1979 | Two-phase ΔP | Tubes/plates | Registry (ΔP) |
**BPHX runtime path:** correlation → h → `UA ≈ h·A·z_ua`**ε-NTU residuals** (not a full multi-zone MB model).
**Condenser / Evaporator / FloodedEvaporator:** **no** plate correlation — **lumped UA** + phase-change ε-NTU:
```
ε = 1 exp(UA/C_sec)
Q = ε · C_sec · ΔT_driving
```
**Generic HeatExchanger:** ε-NTU or LMTD (arrangement-dependent).
**Economizer (internal):** LMTD-style two-stream.
**MovingBoundaryHX:** multi-zone research path (not default production).
---
### 3. Pressure drop
| Model | Formula / role | Components |
|-------|----------------|------------|
| Quadratic refrigerant | `ΔP = k · ṁ · \|ṁ\|` | Condenser, Evaporator (optional) |
| BPHX friction | `ΔP = z_dp · 2·f·L·G²/(ρ·d_h)` (implementation path) | BPHX |
| Friedel 1979 | two-phase ΔP (registry) | selection stack |
| Pipe Darcy-style | f(L,D,ε,Re,ṁ) | Pipe |
| Valve orifice | `ṁ = Kv·opening·√(2·ρ·ΔP)` | EXV orifice, BypassValve |
---
### 4. Pumps & fans — 1D polynomials
```
y = c0 + c1·x + c2·x² + … (Polynomial1D)
```
- **Pump:** head H(Q), efficiency η(Q); affinity laws for speed.
- **Fan:** static pressure / power vs flow and speed.
---
### 5. Flow regularization (not a HTC correlation)
Smooth `|ṁ|`, activity α, duty blend — keeps Newton finite at zero flow. See [flow-regularization.md](./flow-regularization.md).
---
## FR
### Compresseurs
| Composant | Modèle | Formule clé |
|-----------|--------|-------------|
| Isentropic | Physique + η_is | h_dis isentropique corrigé ; ṁ = ρ V N η_vol |
| Compressor | **AHRI 540** M1M10 | ṁ(P,ρ,V,N) ; Ẇ(PR, T) |
| Screw | **Polynôme bilinéaire SST/SDT** | ṁ, W = a00+a10·SST+a01·SDT+a11·SST·SDT |
Presets vis : Bitzer / Grasso génériques 200 kW (coeffs dans CLI).
### Échangeurs — corrélations h
| Corrélation | Usage |
|-------------|--------|
| Longo 2004 | BPHX défaut évap/cond plaques |
| Shah 1979 / 2021 | condensation (tubes / plaques) |
| Kandlikar, GungorWinterton | évaporation tubes (registre) |
| Gnielinski, DittusBoelter | monophasique |
| Ko 2021 | plaques low-GWP |
| Friedel 1979 | ΔP biphasique |
**Condenser / Evaporator / Flooded :** **UA global + ε-NTU** (pas Longo).
### Pompes / ventilateurs
Polynômes 1D QH / Qη + lois daffinité.
### Calibration
Tous les Z par défaut **1.0** (pas de correction).

View File

@@ -0,0 +1,62 @@
# Drum (separator / recirculation drum)
Config type: `"Drum"`
Source: `crates/components/src/drum.rs`
---
## EN
### Purpose & model
Liquid/vapor **separator** used in flooded recirculation architectures. Splits a two-phase feed into liquid and vapor outlets; may accept an evaporator return.
Thermodynamics: equilibrium separation at drum pressure (quality split toward x≈0 liquid / x≈1 vapor legs), mass and energy balances across ports.
### Residuals & `n_equations()`
Multi-port balance residuals (mass + energy + pressure consistency). Exact count depends on active ports and edge wiring; treat as a multi-equation node — see unit tests and `n_equations()` in source.
### Ports (4-port naming)
| Port | Role |
|------|------|
| `feed_inlet` | two-phase feed |
| `evaporator_return` | return from flooded evaporator |
| `liquid_outlet` | liquid to pump / recirculation |
| `vapor_outlet` | vapor to compressor suction |
### Calibration
No primary Z-factor set; geometry/level control may be added in specialized builds.
### JSON (main)
| Key | Meaning | Default |
|-----|---------|---------|
| `fluid` / refrigerant | working fluid | primary |
| level / volume options | if exposed | |
### System note
A **flooded plate** topology is often Drum + recirculation + DX exchanger — not a mode of BPHX alone. Shell-and-tube flooded use `FloodedEvaporator`.
---
## FR
### But & modèle
**Ballon séparateur** liquide/vapeur pour architectures noyées / recirculation.
### Ports
Alimentation, retour évap, sortie liquide, sortie vapeur.
### DoF
Nœud multi-équations ; équilibrer avec le reste du circuit.
### JSON
Voir EN.

View File

@@ -0,0 +1,37 @@
# Economizer (internal)
Source: economizer HX used inside screw-economizer circuits (`HeatExchanger<LmtdModel>` patterns)
---
## EN
### Purpose & model
Internal heat exchanger that subcools liquid / evaporates injection gas for economized screw cycles. Often **not** a standalone CLI leaf — instantiated inside compressor economizer plumbing or macro components.
Model: LMTD or ε-NTU between liquid line and eco vapor.
### Residuals
Standard two-stream HX residuals of the inner model.
### Ports
Hot/cold legs as wired by the parent circuit.
### Note
For user-facing machines, configure economizer via **ScrewEconomizerCompressor** + circuit topology rather than a free-floating Economizer node unless the CLI arm exposes it.
---
## FR
### But
Échangeur **économiseur** interne (sous-refroidissement / injection).
### Note
Souvent intégré au circuit vis, pas un composant CLI autonome.

View File

@@ -0,0 +1,123 @@
# Evaporator / EvaporatorCoil
Config types: `"Evaporator"`, `"EvaporatorCoil"`
Source: `crates/components/src/heat_exchanger/evaporator.rs`
---
## EN
### Purpose & physical model
**DX (direct-expansion)** evaporator: refrigerant outlet is **superheated vapor** (not flooded two-phase). Phase-change ε-NTU against a hot secondary stream:
```
ε = 1 exp(UA / C_sec)
Q = ε · C_sec · (T_sec,in T_evap(P)) # heat absorbed by refrigerant
```
- Optional refrigerant ΔP = k·ṁ·|ṁ|
- `EvaporatorCoil` locks secondary side to **Air**
- **No plate correlation** (see BPHX / LongoShah for geometry-based UA)
Difference vs `FloodedEvaporator`: DX uses **superheat closure** (or regulated SH); flooded uses **saturated vapor** (or quality) by default.
### Dual secondary modes (Newton)
| Mode | Secondary | `n_secondary` |
|------|-----------|---------------|
| **System** | Live `secondary_inlet` / `secondary_outlet` | 1 or 2 |
| **Rating** | Scalars T_sec + C_sec (ṁ·cp) | 0 |
`coupled_ready` = refrigerant ready **and** (live edges **or** rating scalars).
`live_secondary_stream` = edges first, else rating scalars.
### Residuals & `n_equations()` (coupled emergent)
| Row | Equation |
|-----|----------|
| r0 | `P_out (P_in ΔP)` (optional skip) |
| r1 | `ṁ · (h_out h_in) Q` |
| r2 | `h_out h(P, T_evap+SH)` if superheat is imposed |
| r_mass | dropped if same-branch |
| r_sec | live secondary mass/energy if edges |
```
n_thermo = base (1 or 2) + 1 if imposes_superheat()
n_equations = n_thermo + mass? + n_secondary
```
### Superheat regulation (DoF)
| Setting | Effect |
|---------|--------|
| Default | SH residual active (`superheat_k` target) when emergent |
| `superheat_regulated: true` | **Drops** SH residual (1 eq) |
If SH residual is dropped, pair with a **free** EXV opening (and usually a control loop) so the system stays square. CLI DoF gate enforces balance.
### Ports
| Port | Index |
|------|-------|
| `inlet` / `outlet` | 0 / 1 refrigerant |
| `secondary_inlet` / `secondary_outlet` | 2 / 3 secondary |
### Calibration
| Factor | Default | Notes |
|--------|---------|-------|
| `z_ua` | **1.0** | UA scale |
| `z_dp` | 1.0 | ΔP scale |
UI Fixed: SST (`saturationTemperature`) + free `z_ua` for inverse calib.
### JSON parameters (main)
| Key | Meaning | Default |
|-----|---------|---------|
| `ua` | UA [W/K] | required |
| `emergent_pressure` | free P_evap | false |
| `superheat_k` | SH target [K] | 5 |
| `superheat_regulated` | drop SH residual | false |
| `secondary_fluid` / `secondary_*` | system edges or rating | |
| `skip_pressure_eq` | drop ΔP residual | false |
### energy_transfers
Coupled: `Q = ṁ·(h_out h_in)` as positive heat (cooling capacity).
### Zero flow
Smooth `|ṁ|` for live `C_sec`; no silent mass-index→pressure fallback.
---
## FR
### But & modèle
Évaporateur **DX** (sortie **surchauffée**). Duty ε-NTU :
```
Q = ε · C_sec · (T_sec,in T_evap(P))
```
Différence avec **FloodedEvaporator** : clôture **superheat**, pas vapeur saturée noyée.
### Modes secondaire
- **Système :** ports live
- **Rating :** scalaires T + ṁ·cp **dans le Newton**
### Régulation de surchauffe
`superheat_regulated: true` enlève le résidu SH → **libérer** louverture EXV (contrôle).
### Calibration
`z_ua = 1` par défaut. Fixed SST + Z_UA libre pour calage.
### Ports / JSON
Voir EN.

View File

@@ -0,0 +1,158 @@
# ExpansionValve (legacy, port-based)
Config type: `"ExpansionValve"`
Source: `crates/components/src/expansion_valve.rs`
> Distinct from `IsenthalpicExpansionValve` / `EXV`. Port-object based, with On/Off/Bypass operational states.
> Distinct de `IsenthalpicExpansionValve` / `EXV`. Basé sur objets Port, avec états On/Off/Bypass.
---
## EN
### Purpose & physical model
2-port isenthalpic throttling valve for refrigeration systems:
```
h_out = h_in (isenthalpic)
ṁ_out = ṁ_in (mass continuity, with z_flow scale)
P_out < P_in (throttling — pressure not closed by a flow law here)
Q = 0, W = 0 (adiabatic, no work)
```
Operational states:
| State | Behaviour |
|-------|-----------|
| **On** | isenthalpy + mass continuity |
| **Off** | zero mass flow (`opening` < 0.01 also forces off) |
| **Bypass** | adiabatic pipe: `P_out = P_in`, `h_out = h_in` |
`opening` does **not** enter the On residual set as a continuous flow coefficient; it only gates `is_effectively_off` below a 1 % threshold. For a free continuous opening + orifice law, use `IsenthalpicExpansionValve` with `orifice_kv`.
### Residuals & `n_equations()`
```
n_equations = 2 (always)
local state: state[0]=ṁ_in, state[1]=ṁ_out
```
| Row | On | Off | Bypass |
|-----|----|-----|--------|
| r0 | `h_out h_in` | `ṁ_in = 0` | `P_out P_in` (with isenthalpy pairing) |
| r1 | `ṁ_out z_flow·ṁ_in` | 0 | `h_out h_in` |
### Ports
| Role | Description |
|------|-------------|
| inlet | high pressure, typically subcooled liquid |
| outlet | low pressure, typically two-phase |
Type-state: `ExpansionValve<Disconnected>``.connect()``ExpansionValve<Connected>`.
### Calibration
| Factor | Effect | Default |
|--------|--------|---------|
| `z_flow` | `ṁ_eff = z_flow · ṁ_in` | **1.0** |
`set_calib_indices` supports a dynamic `z_flow` state index.
### Emergent pressure / orifice
**Not available** on this component. Prefer `"IsenthalpicExpansionValve"` / `"EXV"`.
### energy_transfers
`(Q, W) = (0, 0)` always.
### JSON parameters
| Key | Meaning | Unit | Default |
|-----|---------|------|---------|
| `fluid` | refrigerant | | **required** |
| `opening` | valve position (off if < 0.01) | | 1.0 |
| `p_inlet_bar` / `h_inlet_kj_kg` | inlet IC | bar / kJ/kg | 12.0 / 260.0 |
| `p_outlet_bar` / `h_outlet_kj_kg` | outlet IC | bar / kJ/kg | 3.5 / 260.0 |
### Known limitations
- Legacy port-based residual path; less integrated with CM1.4 edge ṁ sharing than EXV.
- No emergent-pressure or orifice actuator.
- Production cycles should use `IsenthalpicExpansionValve`.
---
## FR
### But & modèle physique
Vanne de laminage isenthalpique 2-port :
```
h_out = h_in
ṁ_out = ṁ_in (avec échelle z_flow)
Q = 0, W = 0
```
États opérationnels :
| État | Comportement |
|------|--------------|
| **On** | isenthalpie + continuité de masse |
| **Off** | débit nul (`opening` < 0.01 force aussi l'arrêt) |
| **Bypass** | tube adiabatique : `P_out = P_in`, `h_out = h_in` |
`opening` ne rentre **pas** dans les résidus On comme coefficient de débit continu ; il ne sert qu'au seuil d'arrêt. Pour une ouverture libre + orifice, utiliser `IsenthalpicExpansionValve` avec `orifice_kv`.
### Résiduels & `n_equations()`
```
n_equations = 2 (toujours)
état local : state[0]=ṁ_in, state[1]=ṁ_out
```
| Ligne | On | Off | Bypass |
|-------|----|-----|--------|
| r0 | `h_out h_in` | `ṁ_in = 0` | `P_out P_in` |
| r1 | `ṁ_out z_flow·ṁ_in` | 0 | `h_out h_in` |
### Ports
| Rôle | Description |
|------|-------------|
| entrée | haute pression, liquide sous-refroidi typique |
| sortie | basse pression, biphasique typique |
Typestate : `Disconnected``.connect()``Connected`.
### Calibration
| Facteur | Effet | Défaut |
|---------|-------|--------|
| `z_flow` | `ṁ_eff = z_flow · ṁ_in` | **1.0** |
### Pression émergente / orifice
**Non disponibles.** Préférer `"IsenthalpicExpansionValve"` / `"EXV"`.
### energy_transfers
`(Q, W) = (0, 0)` toujours.
### Paramètres JSON
| Clé | Signification | Unité | Défaut |
|-----|---------------|-------|--------|
| `fluid` | frigorigène | | **requis** |
| `opening` | position (off si < 0.01) | | 1.0 |
| `p_inlet_bar` / `h_inlet_kj_kg` | CI entrée | bar / kJ/kg | 12.0 / 260.0 |
| `p_outlet_bar` / `h_outlet_kj_kg` | CI sortie | bar / kJ/kg | 3.5 / 260.0 |
### Limites connues
- Chemin legacy port-object, moins intégré au partage ṁ CM1.4 que l'EXV.
- Pas de pression émergente ni d'actionneur orifice.
- Les cycles de production doivent utiliser `IsenthalpicExpansionValve`.

View File

@@ -0,0 +1,49 @@
# Fan
Config type: `"Fan"`
Source: `crates/components/src/fan.rs`
---
## EN
### Purpose & model
Air-moving machine with **performance curves** (pressure rise / power vs flow and speed). Typestate ports: disconnected → connected.
Affinity laws may scale curves with rotational speed.
### Residuals & `n_equations()`
Curve residuals linking ΔP, ṁ (or volume flow), and speed; energy/power residual when power is modeled. See `n_equations()` in source (typically small fixed count for the fan node).
### Ports
`inlet` / `outlet` on the air branch.
### Calibration
Curve multipliers / Z-style factors when exposed via calib API (default unity).
### JSON (main)
| Key | Meaning | Default |
|-----|---------|---------|
| curve data / preset | performance map | required |
| `speed` / ratio | operating speed | 1.0 full |
---
## FR
### But & modèle
**Ventilateur** sur courbes ΔP / débit / vitesse.
### Ports
Entrée / sortie air.
### JSON
Voir EN.

View File

@@ -0,0 +1,46 @@
# FinCoilCondenser
Config type: `"FinCoilCondenser"`
Source: finned-coil condenser geometry module
---
## EN
### Purpose & model
Finned-tube outdoor coil. Geometry (tubes, rows, fin pitch, face velocity) feeds air-side heat transfer estimates; refrigerant side condenses with subcooling target options.
Correlations: coil/fin air-side NuRe style relations as implemented in the geometry stack (see source for exact correlation names).
### Residuals
HX residual set analogous to Condenser + coil geometry parameters for UA construction.
### Ports
Refrigerant + air secondary ports.
### Calibration
`z_ua` / geometry scales — default unity.
### JSON (main)
Tube OD, rows, fin density, face velocity, OAT, design capacity — see componentMeta FinCoilCondenser params.
---
## FR
### But
**Batterie ailetée** de condensation air.
### Corrélations
Côté air basées géométrie (détail dans le code).
### JSON
Voir meta UI / CLI.

View File

@@ -0,0 +1,47 @@
# FloodedCondenser
Rust / SystemBuilder type: `FloodedCondenser`
Source: `crates/components/src/heat_exchanger/flooded_condenser.rs`
---
## EN
### Purpose & model
Flooded condenser on an inner `HeatExchanger<EpsNtuModel>` with optional **subcooling control** residual:
```
SC = (h_f(P) h_out) / cp_l # when subcooled
r_SC = SC SC_target
```
### Residuals & `n_equations()`
Base ≈ 3 (inner HX path); **+1** with subcooling control (default target ~5 K).
> **Status:** Prefer production **`Condenser` + `emergent_pressure`** for water-cooled machines. FloodedCondenser may lag the dual-mode / DoF discipline of FloodedEvaporator — treat as partial until fully aligned.
### Ports
Refrigerant + secondary via inner exchanger / 4-port names when wired.
### Calibration
Inner calib `z_ua` (default 1.0) when exposed.
---
## FR
### But
Condenseur **noyé** avec option de contrôle de sous-refroidissement.
### Statut
Préférer **`Condenser` + pression émergente** en production. Fiche partielle tant que le DoF nest pas aligné sur FloodedEvaporator.
### Calibration
Z_UA = 1 si exposé.

View File

@@ -0,0 +1,149 @@
# FloodedEvaporator
Config type: `"FloodedEvaporator"`
Source: `crates/components/src/heat_exchanger/flooded_evaporator.rs`
Example: `crates/cli/examples/chiller_flooded_4port_watercooled.json` (DoF 19=19, COP ≈ 6.45)
---
## EN
### Purpose & physical model
Shell-and-tube **flooded** evaporator. Refrigerant boils on the shell side; secondary (water/brine) flows in the tubes. Heat duty uses **phase-change ε-NTU** (`C_min = C_sec`, `C_r → 0`):
```
ε = 1 exp(UA / C_sec)
Q = ε · C_sec · (T_sec,in T_evap(P))
```
- `T_evap(P)` = saturation temperature of the refrigerant at edge pressure
- `C_sec` = secondary heat-capacity rate [W/K]
There is **no plate-geometry correlation** inside this component (unlike BPHX). UA is a **lumped parameter** (possibly scaled by calibration `z_ua` via the inner `HeatExchanger` calib API).
### Dual operating modes (both enter Newton residuals)
| Mode | How secondary is defined | Secondary Newton unknowns | When to use |
|------|--------------------------|---------------------------|-------------|
| **System (4-port)** | Live edges `secondary_inlet` / `secondary_outlet` (e.g. BrineSource → HX → BrineSink) | Yes (`n_secondary` = 1 or 2) | Closed water loop, real machine |
| **Rating** | Scalars `secondary_inlet_temp_*` + `C_sec` (`secondary_mass_flow_kg_s` × `cp` or `secondary_capacity_rate_w_per_k`) | No (`n_secondary` = 0) | Qualification / open-loop duty; still **coupled ε-NTU in residuals** |
`coupled_ready` = refrigerant indices ready **and** (live secondary edges **or** rating scalars).
Never falls through to generic four-port `HeatExchanger::inner` residuals for normal operation (seed path is local and finite).
**Rating residual energy:** uses full `Q` (not `α(ṁ)·Q`) so `ṁ = 0` is not a trivial root when `C_sec > 0`.
**System residual energy:** uses `effective_duty(Q, α_ref, α_sec)` from `flow_regularization` for zero-flow safety.
Also exposed: `rate(p_in)` open-loop rating API for sweeps (same ε-NTU formulas).
### Outlet closure (DoF-critical)
| Setting | Residual r2 | Typical use |
|---------|-------------|-------------|
| Default (`quality_control: false`) | `h_out h_g(P)` saturated vapor | Compressor suction after disengagement |
| `quality_control: true` | `x_out target_quality` | Legacy recirculation / two-phase outlet |
Both keep **the same** `n_equations` (quality replaces sat-vapor; it does not add an extra free residual by itself).
`quality_control: true` on a closed cycle often needs a **free actuator** elsewhere or the DoF gate rejects the graph.
### Residuals & `n_equations()`
| Row | Equation |
|-----|----------|
| r0 | `P_out P_in` (no refrigerant ΔP by default) |
| r1 | `ṁ_ref · (h_out h_in) Q_eff` |
| r2 | sat-vapor **or** quality target (see above) |
| r_sec mass | `ṁ_sec,out ṁ_sec,in` only if live edges and **not** same-branch |
| r_sec energy | live secondary energy + duty (blended at low ṁ) |
```
n_equations = 3 + n_secondary
n_secondary = 0 # rating (no live edges)
| 1 # live edges, same-branch ṁ
| 2 # live edges, independent ṁ in/out
```
### Ports
| Port | Index | Role |
|------|-------|------|
| `inlet` | 0 | Refrigerant from EXV |
| `outlet` | 1 | Refrigerant to compressor suction |
| `secondary_inlet` | 2 | Water/brine in |
| `secondary_outlet` | 3 | Water/brine out |
CLI aliases: `water_in` / `brine_in` → secondary_inlet, etc. (`resolve_port_index`).
### Calibration
| Factor | Effect | Default |
|--------|--------|---------|
| `z_ua` (BOLT `Z_UA`) | `UA_eff = z_ua · UA` via inner calib | **1.0** |
| `z_dp` | pressure-drop scale if ΔP model used | 1.0 |
Inverse calibration (CLI `controls[]` / UI Fixed checkboxes): impose a measure (e.g. SST = `saturationTemperature`) and free `z_ua`.
### JSON parameters
| Key | Meaning | Unit | Default |
|-----|---------|------|---------|
| `ua` | UA | W/K | **required** |
| `refrigerant` | refrigerant id | | primary fluid |
| `secondary_fluid` | secondary fluid | | Water / MEG |
| `quality_control` | quality residual instead of sat-vapor | bool | `false` |
| `target_quality` | x target if quality_control | | 0.7 |
| `secondary_inlet_temp_c` / `_k` | rating T_sec,in | °C / K | |
| `secondary_mass_flow_kg_s` | rating ṁ_sec | kg/s | |
| `secondary_cp_j_per_kgk` | rating cp | J/(kg·K) | 4186 |
| `secondary_capacity_rate_w_per_k` | rating C_sec direct | W/K | |
| calib `z_ua` / `z_dp` | Z-factors | | 1.0 |
### energy_transfers / mass
When coupled: cooling `Q ≈ ṁ·(h_out h_in)` (positive heat absorbed by refrigerant).
`port_mass_flows` reports 4-port signs without calling generic inner four-port.
### Zero flow
`flow_regularization` on system path: smooth `|ṁ|` for live `C_sec`, activity factors, secondary Δh hold. Seed residuals stay finite if P is non-physical.
---
## FR
### But & modèle
Évaporateur **noyé** tubes-calandre. Duty **ε-NTU** à changement de phase :
```
ε = 1 exp(UA / C_sec)
Q = ε · C_sec · (T_sec,in T_evap(P))
```
Pas de corrélation géométrique type Longo/Shah (voir BPHX pour ça). UA est un **paramètre global**, modulable par `z_ua` (défaut **1**).
### Deux modes (tous deux dans le Newton)
| Mode | Secondaire | Inconnues eau | Usage |
|------|------------|---------------|--------|
| **Système** | Ports live Source → HX → Sink | oui | Machine fermée |
| **Rating** | Scalaires T + ṁ·cp (ou C_sec) | non | Qualification ; Q ε-NTU **dans** les résidus |
### Clôture de sortie
- Défaut : **vapeur saturée** `h_out = h_g(P)` (aspiration compresseur).
- `quality_control: true` : `x_out x_cible` (même nombre déquations).
### Résiduels
`n_equations = 3 + n_secondary` (0 / 1 / 2). Voir tableau EN.
### Calibration
Imposer une mesure (SST) et libérer `z_ua` (UI case Fixed, ou `controls[]`).
`z_ua = 1` = pas de correction.
### Ports / JSON
Identiques aux tableaux EN.

View File

@@ -0,0 +1,48 @@
# FlowMerger
Config type: `"FlowMerger"`
Source: `crates/components/src/flow_merger.rs`
---
## EN
### Purpose & model
**N inlets → one outlet**. Mass and energy mix at common pressure:
```
ṁ_out = Σ ṁ_in,i
ṁ_out · h_out = Σ ṁ_in,i · h_in,i
P_out = P_in,i (ideal junction)
```
### Residuals & `n_equations()`
Mixing mass + energy + pressure equality constraints as implemented.
### Ports
`inlet_0``inlet_{n-1}`, `outlet`.
### Calibration
None by default.
### JSON
| Key | Meaning | Default |
|-----|---------|---------|
| `n_inlets` | number of inlets | ≥ 2 |
---
## FR
### But
**Mélangeur** N → 1. Conservation ṁ et H ; pression commune idéale.
### JSON
Voir EN.

View File

@@ -0,0 +1,56 @@
# Flow regularization (zero-flow helpers)
Source: `crates/components/src/heat_exchanger/flow_regularization.rs`
Used by: **FloodedEvaporator** (full residual path); **Condenser** / **Evaporator** (smooth `|ṁ|` for live `C_sec`).
---
## EN
### Why
Zero mass flow is a **valid** state (staging, circuit off, Newton trial steps). Hard branches like `if |m| < ε { Q = 0 }` create **Jacobian discontinuities**.
### API
| Function | Meaning |
|----------|---------|
| `flow_activity(m, ε)` | α = m²/(m²+ε²) ∈ [0,1), α(0)=0 |
| `flow_activity_derivative` | dα/dm |
| `effective_duty(Q, α_a, α_b)` | Q_eff = α_a · α_b · Q |
| `blend_transport_residual` | blend active transport residual with Δh hold |
| `blend_transport_partials` | analytic partials of the blend |
| `smooth_mass_magnitude` | C¹-ish smooth \|m\| for `C = \|ṁ\| · cp` |
| `smooth_mass_magnitude_derivative` | d\|m\|_smooth / dm |
Defaults: `DEFAULT_M_EPS_KG_S = 1e-4`, `DEFAULT_M_SCALE_KG_S = 0.05`.
### Interaction with rating mode (Flooded)
On **FloodedEvaporator system path** (live secondary): duty uses `effective_duty` with α_ref and α_sec.
On **Flooded rating path** (scalar C_sec only): residual energy uses **full Q** (no α_ref gate) so `ṁ_ref = 0` is not a trivial root when `C_sec > 0`.
### DoF rule
Regularization **must not** change `n_equations()`. It only reshapes residual values and derivatives.
---
## FR
### Pourquoi
Le débit nul est un état **valide**. Les `if |m| < ε` durs cassent le Newton.
### API
Voir le tableau EN.
### Rating vs système (Flooded)
- **Système (ports live)** : duty régularisée α_ref · α_sec · Q.
- **Rating (scalaires)** : Q **plein** dans le résidu énergie (pas de racine triviale ṁ=0).
### Règle DoF
La régularisation **ne change pas** `n_equations()`.

View File

@@ -0,0 +1,51 @@
# FlowSplitter
Config type: `"FlowSplitter"`
Source: `crates/components/src/flow_splitter.rs` (or equivalent)
---
## EN
### Purpose & model
One inlet → **N outlets**. Mass splits across outlet legs; pressure continuous at the node (common header assumption unless specialized ΔP models exist).
```
ṁ_in = Σ ṁ_out,i
P_out,i = P_in (ideal splitter)
h_out,i = h_in (same enthalpy)
```
### Residuals & `n_equations()`
Mass split + equal-P / equal-h constraints per topology. Port count depends on `n_outlets` configuration.
### Ports
| Port | Role |
|------|------|
| `inlet` | single inlet |
| `outlet_0``outlet_{n-1}` | outlets |
### Calibration
None by default.
### JSON
| Key | Meaning | Default |
|-----|---------|---------|
| `n_outlets` | number of legs | ≥ 2 |
---
## FR
### But
**Séparateur de débit** 1 → N. Conservation de ṁ ; même P/h idéalement.
### Ports / JSON
Voir EN.

View File

@@ -0,0 +1,44 @@
# FreeCoolingExchanger
Config types: `"FreeCoolingExchanger"`, `"FreeCooling"`
Source: free-cooling HX module
---
## EN
### Purpose & model
Free-cooling heat exchanger between two liquid loops (e.g. tower water ↔ chilled water) without vapor-compression. EffectivenessNTU or UA·LMTD between two single-phase streams.
```
Q = ε · C_min · (T_hot,in T_cold,in)
```
### Residuals
Two-stream energy balances + optional ΔP per leg.
### Ports
Hot and cold in/out (4-port).
### Calibration
`z_ua` default **1.0**.
### JSON
UA, fluids, optional secondary stream params — see CLI arm.
---
## FR
### But
Échangeur de **free-cooling** (liquideliquide), sans cycle frigo.
### Calibration
Z_UA = 1 par défaut.

View File

@@ -0,0 +1,60 @@
# HeatExchanger (generic)
Config type: `"HeatExchanger"`
Source: `crates/components/src/heat_exchanger/exchanger.rs` + ε-NTU / LMTD models
---
## EN
### Purpose & model
Generic two-stream HX with selectable model:
- **ε-NTU** effectiveness
- **LMTD** / counterflow forms
Ports: hot_in/out, cold_in/out (Modelica-style 4-port).
```
NTU = UA / C_min
ε = f(NTU, C_r, flow arrangement)
Q = ε · C_min · (T_hot,in T_cold,in)
```
**Requires live four-port edge state** for residual evaluation on the generic path — inlet-only scalar BCs do not invent outlet states.
### Residuals & `n_equations()`
Inner model residual count (often 23 per side balance depending on configuration).
### Ports
| Port | Role |
|------|------|
| `hot_inlet` / `hot_outlet` | hot stream |
| `cold_inlet` / `cold_outlet` | cold stream |
### Calibration
`z_ua` on UA (default 1.0).
### When not to use
For refrigeration condensers/evaporators prefer specialized `Condenser` / `Evaporator` / `FloodedEvaporator` / BPHX which know phase-change ε-NTU and secondary dual modes.
---
## FR
### But
Échangeur **générique** 4 ports (ε-NTU / LMTD).
### Attention
Exige un état **4 ports live**. Pour frigo, préférer Condenser / Evaporator / Flooded / BPHX.
### Calibration
Z_UA = 1 par défaut.

View File

@@ -0,0 +1,150 @@
# IsenthalpicExpansionValve (EXV)
Config types: `"IsenthalpicExpansionValve"`, `"EXV"`
Source: `crates/components/src/isenthalpic_expansion_valve.rs`
---
## EN
### Purpose & physical model
Isenthalpic expansion (throttling) valve for vapor-compression cycles. Three model families:
| Family | Trigger | Physics |
|--------|---------|---------|
| **A — Fixed pressure** | default | Pins `P_out = P_sat(T_evap)` + isenthalpy |
| **B — Emergent pressure** | `emergent_pressure: true` | Isenthalpy only; low-side P from evaporator |
| **C — Orifice** | `orifice_kv` set | Emergent + physical flow law; **opening is a free DoF** |
Orifice law (arch-6 physical actuator):
```
ṁ = Kv · opening · √(2 · ρ_in · max(P_in P_out, 0)) , opening ∈ [0, 1]
```
`with_orifice(kv)` / JSON `orifice_kv` forces `emergent_pressure = true`.
### Residuals & `n_equations()`
| Mode | same-branch | orifice | n_equations | Residuals |
|------|-------------|---------|-------------|-----------|
| Fixed P | no | no | 3 | r0 `P_out P_sat(T_evap)`; r1 `h_out h_in`; r2 `ṁ_out ṁ_in` |
| Fixed P | yes | no | 2 | r0, r1 |
| Emergent | no | no | 2 | r0 `h_out h_in`; r1 `ṁ_out ṁ_in` |
| Emergent | yes | no | 1 | r0 `h_out h_in` |
| Emergent + orifice | either | yes | +1 | + `ṁ Kv·opening·√(2·ρ_in·ΔP)` |
Orifice adds **1 equation** and the opening adds **1 unknown** → DoF stays balanced. Pair with a `superheat_regulated` evaporator (drops its SH residual) and a controller on `opening` for regulated superheat.
### Ports
| Edge | Role |
|------|------|
| 0 | inlet (cond → EXV) |
| 1 | outlet (EXV → evap) |
### Emergent pressure
Enabled by `emergent_pressure: true` or automatically by orifice mode. Removes the `P_out = P_sat(T_evap)` pin.
### Calibration / actuators
| Item | Notes |
|------|-------|
| Control factor `"opening"` | maps to `actuator` slot; requires `orifice_kv` |
| Free actuator `{name}__opening` | registered when orifice configured without a loop |
| `z_flow` / `z_dp` | **not** used on this component |
### measure_output / energy_transfers
Not specialized (`energy_transfers` none / adiabatic throttling: Q = W = 0).
### JSON parameters
| Key | Meaning | Unit | Default |
|-----|---------|------|---------|
| `t_evap_k` | target evaporating T for P_sat | K | 275.15 |
| `fluid` | refrigerant | | primary |
| `emergent_pressure` | drop P_evap pin | bool | false |
| `orifice_kv` | orifice coefficient Kv | m² | (none ⇒ no orifice) |
| `orifice_opening_init` | initial opening | | 0.5 |
| `orifice_opening_min` | min bound | | 0.02 |
| `orifice_opening_max` | max bound | | 1.0 |
### Notes
Preferred EXV for modern cycle configs. For the older port-object valve with On/Off/Bypass see [expansion-valve.md](./expansion-valve.md).
---
## FR
### But & modèle physique
Détendeur isenthalpique (laminage) pour cycles à compression de vapeur. Trois familles :
| Famille | Déclencheur | Physique |
|---------|-------------|----------|
| **A — Pression fixée** | défaut | Impose `P_out = P_sat(T_evap)` + isenthalpie |
| **B — Pression émergente** | `emergent_pressure: true` | Isenthalpie seule ; P BP par l'évaporateur |
| **C — Orifice** | `orifice_kv` | Émergent + loi de débit ; **ouverture = DoF libre** |
Loi d'orifice :
```
ṁ = Kv · opening · √(2 · ρ_in · max(P_in P_out, 0)) , opening ∈ [0, 1]
```
`orifice_kv` force `emergent_pressure = true`.
### Résiduels & `n_equations()`
| Mode | même branche | orifice | n_equations | Résidus |
|------|--------------|---------|-------------|---------|
| P fixe | non | non | 3 | r0 `P_out P_sat(T_evap)` ; r1 `h_out h_in` ; r2 `ṁ_out ṁ_in` |
| P fixe | oui | non | 2 | r0, r1 |
| Émergent | non | non | 2 | r0 `h_out h_in` ; r1 `ṁ_out ṁ_in` |
| Émergent | oui | non | 1 | r0 `h_out h_in` |
| Émergent + orifice | | oui | +1 | + `ṁ Kv·opening·√(2·ρ_in·ΔP)` |
L'orifice ajoute **1 équation** et l'ouverture **1 inconnu** → DoF équilibré. Couplé à un évaporateur `superheat_regulated` et un contrôleur sur `opening`, la surchauffe devient régulée.
### Ports
| Arête | Rôle |
|-------|------|
| 0 | entrée (cond → EXV) |
| 1 | sortie (EXV → évap) |
### Pression émergente
Via `emergent_pressure: true` ou automatiquement en mode orifice. Supprime le pin `P_out = P_sat(T_evap)`.
### Calibration / actionneurs
| Élément | Notes |
|---------|-------|
| Facteur `"opening"` | mappe le slot `actuator` ; nécessite `orifice_kv` |
| Actionneur libre `{name}__opening` | si orifice sans boucle |
| `z_flow` / `z_dp` | **non** utilisés |
### measure_output / energy_transfers
Non spécialisés ; laminage adiabatique (Q = W = 0).
### Paramètres JSON
| Clé | Signification | Unité | Défaut |
|-----|---------------|-------|--------|
| `t_evap_k` | T évaporation cible pour P_sat | K | 275.15 |
| `fluid` | frigorigène | | primaire |
| `emergent_pressure` | supprime le pin P_evap | bool | false |
| `orifice_kv` | coefficient d'orifice Kv | m² | (aucun ⇒ pas d'orifice) |
| `orifice_opening_init` | ouverture initiale | | 0.5 |
| `orifice_opening_min` | borne min | | 0.02 |
| `orifice_opening_max` | borne max | | 1.0 |
### Notes
EXV préféré pour les configs de cycle modernes. Ancienne vanne port-object → [expansion-valve.md](./expansion-valve.md).

View File

@@ -0,0 +1,214 @@
# IsentropicCompressor
Config type: `"IsentropicCompressor"`
Source: `crates/components/src/isentropic_compressor.rs`
---
## EN
### Purpose & physical model
Vapor-compression compressor for cycle simulation. Two operating families:
| Mode | When | Mass / pressure behaviour |
|------|------|---------------------------|
| **Fixed-pressure** (default) | `emergent_pressure: false` | Pins `P_dis = P_sat(T_cond)`; mass continuity across suction/discharge |
| **Emergent-pressure** | `emergent_pressure: true` | Closes ṁ with a **volumetric displacement law**; `P_dis` floats from the condenser ↔ secondary balance |
True isentropic path via CoolProp: `(P,h)→s` then `(P,s)→h_is`, corrected by isentropic efficiency:
```
h_dis = h_suc + (h_is h_suc) / η_is,eff
```
Swept mass flow (emergent only):
```
ṁ_calc = ρ_suc · V_s · N · η_vol(P_dis/P_suc) · f_VSD,vol
ṁ = σ · z_flow · ṁ_calc
```
Volumetric efficiency models:
| Model | Formula |
|-------|---------|
| Constant | `η_vol = const` (default 1.0) |
| Clearance | `η_vol = 1 + C C · (P_dis/P_suc)^(1/n)` |
Optional **VSD speed map** (quadratic, identity default `[1,0,0]`):
```
f(r) = c0 + c1·r + c2·r² , r = N / N_ref , clamped ∈ [0.1, 1.2]
η_vol,eff = η_vol · f_vol(r) ; η_is,eff = η_is · f_is(r)
```
Optional **liquid injection** desuperheat (no extra equation; φ from controls):
```
h_dis,eff = h_dis φ_inj · (h_dis h_f(P_dis)) , φ_inj ∈ [0, φ_max]
```
Design anchors `t_cond_k`, `t_evap_k`, `superheat_k` are used for fixed-pressure pins and as initial-condition helpers; in emergent mode the live suction `(P,h)` drives the isentropic path.
### Residuals & `n_equations()`
```
n_equations = (2 if same_branch else 3) + (1 if slide_valve active else 0)
```
| Row | Fixed-pressure | Emergent-pressure |
|-----|----------------|-------------------|
| r0 | `P_dis P_sat(T_cond)` | `ṁ σ·z_flow·ṁ_calc` |
| r1 | `H_dis h_dis` | `H_dis h_dis,eff` |
| r2 | `ṁ_dis ṁ_suc` (dropped if same-branch) | same |
| r3 | — | (slide) `T_sat(P_suc) SST_target` |
### Ports
| Index | Role |
|-------|------|
| 0 | suction (inlet) |
| 1 | discharge (outlet) |
Edge-wired via `set_system_context` (CM1.3 ṁ/P/h triples). `get_ports()` may be empty.
### Emergent pressure & actuators
- Requires `displacement_m3` and `speed_hz` when `emergent_pressure: true`.
- **Slide valve** (`slide_valve_sst_target_k` / `_c`): free actuator σ ∈ [σ_min, 1] scales swept volume and holds SST.
- **Liquid injection** (`liquid_injection: true`): φ_inj on the `actuator` / control factor `"injection"`; closing equation from a user `controls[]` loop (e.g. max DGT), not hard-coded.
### Calibration
| Factor | Effect | Default |
|--------|--------|---------|
| `z_flow` | scales swept ṁ (emergent r0) | **1.0** |
| `actuator` | slide σ **or** injection φ | |
### measure_output / energy_transfers
- `measure_output(Temperature)` → discharge gas temperature (DGT) for injection control.
- `energy_transfers`: `(Q, W) = (0, −ṁ·(h_dis,work h_suc))` — adiabatic; shaft work negative. With liquid injection, work uses un-desuperheated compression enthalpy.
### JSON parameters
| Key | Meaning | Unit | Default |
|-----|---------|------|---------|
| `isentropic_efficiency` | η_is | | 0.75 |
| `t_cond_k` | condensing sat. T (fixed pin / design) | K | 323.15 |
| `t_evap_k` | evaporating sat. T (design) | K | 275.15 |
| `superheat_k` | suction superheat design | K | 5.0 |
| `fluid` | refrigerant | | primary |
| `emergent_pressure` | enable displacement closure | bool | false |
| `displacement_m3` | swept volume V_s | m³/rev | 0.0 |
| `speed_hz` | rotational speed N | rev/s | 0.0 |
| `volumetric_efficiency` | constant η_vol | | 1.0 |
| `clearance` | clearance ratio C (enables clearance model) | | |
| `polytropic_n` | re-expansion exponent | | 1.1 |
| `vsd_reference_speed_hz` | VSD N_ref (enables map) | rev/s | |
| `vsd_volumetric_coeffs` | `[c0,c1,c2]` η_vol map | | [1,0,0] |
| `vsd_isentropic_coeffs` | `[c0,c1,c2]` η_is map | | [1,0,0] |
| `slide_valve_sst_target_k` / `_c` | slide SST setpoint | K / °C | |
| `liquid_injection` | enable injection desuperheat | bool | false |
| `slide_position_init` / `min` / `max` | free-actuator bounds | | 1.0 / 0.1 / 1.0 |
### Notes
Preferred cycle compressor for physics-based machines. For manufacturer AHRI maps use `"Compressor"`; for economized screws use `"ScrewEconomizerCompressor"`.
---
## FR
### But & modèle physique
Compresseur à compression de vapeur. Deux familles de fonctionnement :
| Mode | Quand | Comportement |
|------|-------|--------------|
| **Pression fixée** (défaut) | `emergent_pressure: false` | Impose `P_dis = P_sat(T_cond)` ; continuité de masse |
| **Pression émergente** | `emergent_pressure: true` | Ferme ṁ par une **loi volumétrique** ; `P_dis` flotte via le condenseur |
Chemin isentropique CoolProp + rendement :
```
h_dis = h_suc + (h_is h_suc) / η_is,eff
```
Débit balayé (émergent) :
```
ṁ_calc = ρ_suc · V_s · N · η_vol(P_dis/P_suc) · f_VSD,vol
ṁ = σ · z_flow · ṁ_calc
```
Modèles de rendement volumétrique : constant, ou volume mort `η_vol = 1 + C C·Pr^(1/n)`.
Carte VSD optionnelle (quadratique, identité `[1,0,0]`).
Injection liquide optionnelle : `h_dis,eff = h_dis φ_inj·(h_dis h_f(P_dis))` (pas d'équation interne).
### Résiduels & `n_equations()`
```
n_equations = (2 si même branche sinon 3) + (1 si tiroir actif)
```
| Ligne | Pression fixée | Pression émergente |
|-------|----------------|--------------------|
| r0 | `P_dis P_sat(T_cond)` | `ṁ σ·z_flow·ṁ_calc` |
| r1 | `H_dis h_dis` | `H_dis h_dis,eff` |
| r2 | `ṁ_dis ṁ_suc` (supprimée si même branche) | idem |
| r3 | — | (tiroir) `T_sat(P_suc) SST_cible` |
### Ports
| Index | Rôle |
|-------|------|
| 0 | aspiration (entrée) |
| 1 | refoulement (sortie) |
Câblage par arêtes (`set_system_context`, triples ṁ/P/h CM1.3).
### Pression émergente & actionneurs
- `displacement_m3` et `speed_hz` obligatoires en mode émergent.
- **Tiroir** (`slide_valve_sst_target_k` / `_c`) : actionneur libre σ pour tenir la SST.
- **Injection liquide** : φ_inj via boucle `controls[]` (ex. DGT max), facteur `"injection"`.
### Calibration
| Facteur | Effet | Défaut |
|---------|-------|--------|
| `z_flow` | échelle le débit balayé | **1.0** |
| `actuator` | position tiroir σ **ou** ratio d'injection φ | |
### measure_output / energy_transfers
- `Temperature` → température des gaz de refoulement (DGT).
- `(Q, W) = (0, −ṁ·(h_dis,work h_suc))` — adiabatique ; travail sur le compresseur négatif.
### Paramètres JSON
| Clé | Signification | Unité | Défaut |
|-----|---------------|-------|--------|
| `isentropic_efficiency` | η_is | | 0.75 |
| `t_cond_k` | T sat. condensation (pin / design) | K | 323.15 |
| `t_evap_k` | T sat. évaporation (design) | K | 275.15 |
| `superheat_k` | surchauffe aspiration design | K | 5.0 |
| `fluid` | fluide frigorigène | | primaire |
| `emergent_pressure` | active la fermeture volumétrique | bool | false |
| `displacement_m3` | cylindrée V_s | m³/tr | 0.0 |
| `speed_hz` | vitesse N | tr/s | 0.0 |
| `volumetric_efficiency` | η_vol constant | | 1.0 |
| `clearance` | rapport volume mort C | | |
| `polytropic_n` | exposant de détente | | 1.1 |
| `vsd_reference_speed_hz` | N_ref carte VSD | tr/s | |
| `vsd_volumetric_coeffs` | `[c0,c1,c2]` carte η_vol | | [1,0,0] |
| `vsd_isentropic_coeffs` | `[c0,c1,c2]` carte η_is | | [1,0,0] |
| `slide_valve_sst_target_k` / `_c` | consigne SST tiroir | K / °C | |
| `liquid_injection` | active la désurchauffe par injection | bool | false |
| `slide_position_init` / `min` / `max` | bornes actionneur libre | | 1.0 / 0.1 / 1.0 |
### Notes
Compresseur de cycle préféré pour les machines physiques. Cartes fabricant AHRI → `"Compressor"` ; vis économisée → `"ScrewEconomizerCompressor"`.

View File

@@ -0,0 +1,40 @@
# MchxCondenserCoil / MchxCoil
Config types: `"MchxCondenserCoil"`, `"MchxCoil"`
Source: microchannel condenser coil module
---
## EN
### Purpose & model
**Microchannel** air-cooled condenser coil. Compact multi-port tubes + air fins. UA from geometry and air/refrigerant side coefficients as coded; runtime residual path follows condenser-style energy balances.
### Residuals
Condenser-like refrigerant + air coupling residuals.
### Ports
Refrigerant + air.
### Calibration
Z-factors on UA/ΔP when exposed (default 1.0).
### JSON
Geometry and air-side setpoints per CLI arm / UI meta (`design_capacity_kw`, face velocity, OAT, …).
---
## FR
### But
Batterie **micro-canaux** de condensation.
### JSON
Voir meta UI / exemples.

View File

@@ -0,0 +1,35 @@
# MovingBoundaryHX
Source: moving-boundary / multi-zone HX identification helpers
---
## EN
### Purpose & model
Research / identification path: multi-zone (SH / TP / SC) UA allocation feeding an ε-NTU or zone energy balance. **Not** the default production Condenser/Evaporator path.
### Residuals
Zone energy balances + interface quality/enthalpy consistency when fully enabled. Coverage may be partial — check source and tests before relying in production machines.
### Correlations
Zone UA may come from geometry or identified parameters rather than a single Longo map.
### Recommendation
Production chillers: use **Condenser**, **Evaporator**, **FloodedEvaporator**, or **BPHX** with documented dual-mode secondary and DoF discipline.
---
## FR
### But
HX **moving-boundary** multi-zones (recherche / identification).
### Recommandation
En production : Condenser / Evaporator / Flooded / BPHX.

View File

@@ -0,0 +1,54 @@
# Pipe
Config type: `"Pipe"`
Source: `crates/components/src/pipe.rs`
---
## EN
### Purpose & model
Fluid duct with **friction pressure drop** (Darcy/Colebrook-style or equivalent implementation) and near-isenthalpic or adiabatic energy transport:
```
ΔP = f(L, D, ε, Re, ṁ, ρ)
h_out ≈ h_in (or with small heat loss if modeled)
```
### Residuals & `n_equations()`
Pressure-drop residual + energy residual (typically **2** on a series branch).
### Ports
`inlet` / `outlet`.
### Calibration
`z_dp` (or equivalent) scales ΔP when exposed via calib — default **1.0**.
### JSON (main)
| Key | Meaning | Default |
|-----|---------|---------|
| `length_m` | length | required |
| `diameter_m` | inner diameter | required |
| `roughness_m` | roughness | small metal default |
| fluid | water / refrigerant path | from circuit |
---
## FR
### But & modèle
**Conduite** avec pertes de charge et transport denthalpie.
### Calibration
Facteur de perte de charge (défaut 1).
### JSON
Voir EN.

View File

@@ -0,0 +1,56 @@
# Pump
Config type: `"Pump"`
Source: `crates/components/src/pump.rs`
---
## EN
### Purpose & model
Liquid pump with **head/power curves** vs volume flow and speed. Typestate connect pattern like Fan.
```
ΔP = ρ · g · H(Q, N)
Ẇ = f_power(Q, N)
```
### Residuals & `n_equations()`
Head residual + energy/power residual as implemented; see source `n_equations()`.
### Ports
`inlet` / `outlet` on liquid (brine/water) branch.
### DoF warning
Do **not** impose `m_flow_kg_s` on a BrineSource **and** a pump curve on the same branch without freeing one — over-constrained loop.
### Calibration
Curve scale factors when exposed (default 1.0).
### JSON (main)
| Key | Meaning | Default |
|-----|---------|---------|
| curves / preset | HQ map | required |
| speed | operating speed | |
---
## FR
### But & modèle
**Pompe** liquide sur courbes HQ.
### Attention DoF
Ne pas imposer ṁ Source **et** courbe pompe sur la même branche.
### Ports / JSON
Voir EN.

View File

@@ -0,0 +1,44 @@
# ReversingValve / FourWayValve
Config types: `"ReversingValve"`, `"FourWayValve"`
Source: reversing valve module
---
## EN
### Purpose & model
4-way reversing valve for heat-pump mode swap (heating ↔ cooling). Routes compressor discharge/suction between indoor and outdoor exchangers according to `mode` (or boolean heat/cool).
Ideal model: port permutation with negligible ΔP/Δh; real models may add leakage or pressure drop.
### Residuals
Port coupling residuals matching the selected flow graph for the active mode.
### Ports
Four refrigerant ports (naming depends on implementation: e.g. compressor discharge/suction, indoor, outdoor).
### JSON (main)
| Key | Meaning | Default |
|-----|---------|---------|
| `mode` / `reversing_mode` | heat / cool | |
### Calibration
Usually none; treat as topology switch.
---
## FR
### But
**Vanne 4 voies** pour inverser le cycle PAC.
### JSON
Mode chaud / froid. Voir EN.

View File

@@ -0,0 +1,93 @@
# ScrewEconomizerCompressor / ScrewCompressor
Config types: `"ScrewEconomizerCompressor"`, `"ScrewCompressor"`
Source: `crates/components/src/screw_economizer_compressor.rs`
Polynomials: `Polynomial2D` bilinear SST/SDT
---
## EN
### Purpose
Twin-screw compressor with **economizer injection** port. Manufacturer performance as **bi-quadratic (bilinear) maps** of SST and SDT.
### Performance maps
```
ṁ_suction = z_flow · (a00 + a10·SST + a01·SDT + a11·SST·SDT)
Ẇ_shaft = z_power · (b00 + b10·SST + b01·SDT + b11·SST·SDT)
ṁ_eco ≈ eco_fraction · ṁ_suction (or eco poly)
```
JSON coefficient names (CLI):
| Mass flow | Power |
|-----------|-------|
| `mf_a00`, `mf_a10`, `mf_a01`, `mf_a11` | `pw_b00`, `pw_b10`, `pw_b01`, `pw_b11` |
### Built-in presets
| `preset` | Meaning |
|----------|---------|
| `bitzer_generic_200kw` | Bitzer-like ~200 kW R134a map |
| `grasso_generic_200kw` | Grasso-like ~200 kW map |
| (empty) | generic defaults |
Explicit `mf_*` / `pw_*` **override** preset values.
### Ports
| Port | Role |
|------|------|
| `suction` / `inlet` | main suction |
| `discharge` / `outlet` | discharge |
| `economizer` / `eco` | intermediate injection |
### Other parameters
| Key | Meaning | Default |
|-----|---------|---------|
| `frequency_hz` | drive frequency | 50 |
| `nominal_frequency_hz` | rated f | 50 |
| `mechanical_efficiency` | η_mech | 0.92 |
| `economizer_fraction` | eco flow share | from preset |
### Calibration Z
| Factor | Default |
|--------|---------|
| `z_flow` | **1.0** |
| `z_flow_eco` | **1.0** |
| `z_power` | **1.0** |
| `z_etav` | 1.0 |
### UI
- Tab **General**: frequency, efficiency, preset
- Tab **Map (polynomials)**: mf_a** / pw_b** with defaults filled from preset
- Help documents the bilinear formula
---
## FR
### But
Compresseur **à vis** 3 ports + injection économiseur.
### Carte
Polynôme **bilinéaire** SST/SDT pour ṁ et puissance. Presets Bitzer / Grasso.
### Coeffs JSON
`mf_a00…a11` (débit), `pw_b00…b11` (puissance).
### Calibration
Z = **1** par défaut.
### Ports
Aspiration, refoulement, économiseur.

View File

@@ -0,0 +1,157 @@
# 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:
```text
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`
```text
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`
```json
"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 :
```text
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`.

View File

@@ -0,0 +1,32 @@
{
"name": "BPHX Evaporator and Condenser Bounded Test",
"fluid": "R134a",
"fluid_backend": "CoolProp",
"circuits": [
{
"id": 0,
"components": [
{ "type": "RefrigerantSource", "name": "src", "fluid": "R134a", "p_set_bar": 5.0, "quality": 0.3 },
{ "type": "BphxEvaporator", "name": "evap", "ua": 2000.0, "refrigerant": "R134a", "secondary_fluid": "Water", "secondary_inlet_temp_c": 12.0, "secondary_mass_flow_kg_s": 0.5, "secondary_cp_j_per_kgk": 4186.0 },
{ "type": "RefrigerantSink", "name": "sink", "fluid": "R134a", "p_back_bar": 5.0 }
],
"edges": [
{ "from": "src:outlet", "to": "evap:inlet" },
{ "from": "evap:outlet", "to": "sink:inlet" }
]
},
{
"id": 1,
"components": [
{ "type": "RefrigerantSource", "name": "src2", "fluid": "R134a", "p_set_bar": 15.0, "quality": 1.0 },
{ "type": "BphxCondenser", "name": "cond", "ua": 2000.0, "refrigerant": "R134a", "secondary_fluid": "Water", "secondary_inlet_temp_c": 30.0, "secondary_mass_flow_kg_s": 0.4, "secondary_cp_j_per_kgk": 4186.0 },
{ "type": "RefrigerantSink", "name": "sink2", "fluid": "R134a", "p_back_bar": 15.0 }
],
"edges": [
{ "from": "src2:outlet", "to": "cond:inlet" },
{ "from": "cond:outlet", "to": "sink2:inlet" }
]
}
],
"solver": { "strategy": "fallback", "max_iterations": 100, "tolerance": 1e-6 }
}

View File

@@ -0,0 +1,30 @@
{
"schema_version": "1.0",
"fluid": "R134a",
"fluid_backend": "CoolProp",
"circuits": [
{
"id": 0,
"name": "Capillary smoke",
"components": [
{
"type": "CapillaryTube",
"name": "cap",
"diameter_m": 0.0012,
"length_m": 1.8,
"n_segments": 24,
"p_inlet_bar": 12.0,
"h_inlet_kj_kg": 250.0,
"p_outlet_bar": 3.5,
"h_outlet_kj_kg": 250.0
}
],
"edges": []
}
],
"solver": {
"strategy": "newton",
"max_iterations": 50,
"tolerance": 1e-6
}
}

View File

@@ -0,0 +1,107 @@
{
"name": "Air-Cooled Chiller R134a (4-Port Modelica Style)",
"description": "Full emergent-pressure chiller. Condenser on air (AirSource→cond→AirSink), evaporator on chilled water (BrineSource→evap→BrineSink). MassFlowSource_T: Free P + Fixed ṁ/T; sinks Fixed P. secondary_humidity_ratio MUST match AirSource psychrometrics (W at T_dry, RH, P).",
"fluid": "R134a",
"fluid_backend": "CoolProp",
"circuits": [
{
"id": 0,
"name": "Refrigerant + secondary loops",
"components": [
{
"type": "IsentropicCompressor",
"name": "comp",
"isentropic_efficiency": 0.70,
"t_cond_k": 318.15,
"t_evap_k": 278.15,
"superheat_k": 5.0,
"emergent_pressure": true,
"displacement_m3": 6.5e-5,
"speed_hz": 50.0,
"volumetric_efficiency": 0.92
},
{
"type": "Condenser",
"name": "cond",
"ua": 2500.0,
"emergent_pressure": true,
"subcooling_k": 5.0,
"secondary_fluid": "Air",
"secondary_humidity_ratio": 0.01412,
"dp_model": "isobaric",
"secondary_rated_pressure_drop_pa": 150,
"secondary_rated_m_flow_kg_s": 1.2
},
{
"type": "IsenthalpicExpansionValve",
"name": "exv",
"t_evap_k": 278.15,
"emergent_pressure": true
},
{
"type": "Evaporator",
"name": "evap",
"ua": 1468.0,
"emergent_pressure": true,
"secondary_fluid": "Water",
"dp_model": "isobaric",
"secondary_rated_pressure_drop_pa": 40000,
"secondary_rated_m_flow_kg_s": 0.4778
},
{
"type": "AirSource",
"name": "cond_air_in",
"p_set_bar": 1.01325,
"t_dry_c": 35.0,
"rh": 40.0,
"m_flow_kg_s": 1.2,
"fix_pressure": false,
"fix_temperature": true,
"fix_mass_flow": true
},
{
"type": "AirSink",
"name": "cond_air_out",
"p_back_bar": 1.01325,
"fix_pressure": true
},
{
"type": "BrineSource",
"name": "evap_water_in",
"fluid": "Water",
"p_set_bar": 3.0,
"t_set_c": 12.0,
"m_flow_kg_s": 0.4778,
"fix_pressure": false,
"fix_temperature": true,
"fix_mass_flow": true
},
{
"type": "BrineSink",
"name": "evap_water_out",
"fluid": "Water",
"p_back_bar": 3.0,
"fix_pressure": true
}
],
"edges": [
{ "from": "comp:outlet", "to": "cond:inlet" },
{ "from": "cond:outlet", "to": "exv:inlet" },
{ "from": "exv:outlet", "to": "evap:inlet" },
{ "from": "evap:outlet", "to": "comp:inlet" },
{ "from": "cond_air_in:outlet", "to": "cond:secondary_inlet" },
{ "from": "cond:secondary_outlet", "to": "cond_air_out:inlet" },
{ "from": "evap_water_in:outlet", "to": "evap:secondary_inlet" },
{ "from": "evap:secondary_outlet", "to": "evap_water_out:inlet" }
]
}
],
"solver": {
"strategy": "newton",
"max_iterations": 300,
"tolerance": 1e-6
}
}

View File

@@ -0,0 +1,107 @@
{
"name": "Water-cooled chiller with FloodedEvaporator (4-port, square DoF)",
"description": "Honest machine topology: emergent refrigerant pressures + live secondary water loops. Flooded evaporator has NO quality_control residual (compressor suction). Budget target: n_eq = n_unk (19).",
"fluid": "R134a",
"fluid_backend": "CoolProp",
"circuits": [
{
"id": 0,
"name": "Refrigerant + secondary loops",
"components": [
{
"type": "IsentropicCompressor",
"name": "comp",
"isentropic_efficiency": 0.70,
"t_cond_k": 313.15,
"t_evap_k": 278.15,
"superheat_k": 5.0,
"emergent_pressure": true,
"displacement_m3": 5.0e-5,
"speed_hz": 50.0,
"volumetric_efficiency": 0.92
},
{
"type": "Condenser",
"name": "cond",
"ua": 2200.0,
"emergent_pressure": true,
"subcooling_k": 5.0,
"secondary_fluid": "Water",
"dp_model": "msh",
"tube_length_m": 6.0,
"tube_diameter_m": 0.0095,
"n_parallel_tubes": 2,
"secondary_rated_pressure_drop_pa": 30000,
"secondary_rated_m_flow_kg_s": 0.45
},
{
"type": "IsenthalpicExpansionValve",
"name": "exv",
"t_evap_k": 278.15,
"emergent_pressure": true
},
{
"type": "FloodedEvaporator",
"name": "evap",
"ua": 9000.0,
"refrigerant": "R134a",
"secondary_fluid": "Water",
"quality_control": false,
"secondary_rated_pressure_drop_pa": 40000,
"secondary_rated_m_flow_kg_s": 0.55
},
{
"type": "BrineSource",
"name": "cond_water_in",
"fluid": "Water",
"p_set_bar": 2.0,
"t_set_c": 30.0,
"m_flow_kg_s": 0.45,
"fix_pressure": false,
"fix_temperature": true,
"fix_mass_flow": true
},
{
"type": "BrineSink",
"name": "cond_water_out",
"fluid": "Water",
"p_back_bar": 2.0,
"fix_pressure": true
},
{
"type": "BrineSource",
"name": "evap_water_in",
"fluid": "Water",
"p_set_bar": 3.0,
"t_set_c": 12.0,
"m_flow_kg_s": 0.55,
"fix_pressure": false,
"fix_temperature": true,
"fix_mass_flow": true
},
{
"type": "BrineSink",
"name": "evap_water_out",
"fluid": "Water",
"p_back_bar": 3.0,
"fix_pressure": true
}
],
"edges": [
{ "from": "comp:outlet", "to": "cond:inlet" },
{ "from": "cond:outlet", "to": "exv:inlet" },
{ "from": "exv:outlet", "to": "evap:inlet" },
{ "from": "evap:outlet", "to": "comp:inlet" },
{ "from": "cond_water_in:outlet", "to": "cond:secondary_inlet" },
{ "from": "cond:secondary_outlet", "to": "cond_water_out:inlet" },
{ "from": "evap_water_in:outlet", "to": "evap:secondary_inlet" },
{ "from": "evap:secondary_outlet", "to": "evap_water_out:inlet" }
]
}
],
"solver": {
"strategy": "newton",
"max_iterations": 300,
"tolerance": 1e-6
}
}

View File

@@ -0,0 +1,105 @@
{
"name": "Water-cooled chiller — ΔT rating on evaporator loop",
"description": "Evap loop: Free ṁ + Fixed T_out=7 °C (ΔT=5 K from 12 °C). Cond loop keeps Fixed ṁ (stable anchor).",
"fluid": "R134a",
"fluid_backend": "CoolProp",
"circuits": [
{
"id": 0,
"name": "Refrigerant + secondary loops",
"components": [
{
"type": "IsentropicCompressor",
"name": "comp",
"isentropic_efficiency": 0.70,
"t_cond_k": 313.15,
"t_evap_k": 278.15,
"superheat_k": 5.0,
"emergent_pressure": true,
"displacement_m3": 5.0e-5,
"speed_hz": 50.0,
"volumetric_efficiency": 0.92
},
{
"type": "Condenser",
"name": "cond",
"ua": 2200.0,
"emergent_pressure": true,
"subcooling_k": 5.0,
"secondary_fluid": "Water",
"dp_model": "msh",
"tube_length_m": 6.0,
"tube_diameter_m": 0.0095,
"n_parallel_tubes": 2
},
{
"type": "IsenthalpicExpansionValve",
"name": "exv",
"t_evap_k": 278.15,
"emergent_pressure": true
},
{
"type": "FloodedEvaporator",
"name": "evap",
"ua": 9000.0,
"refrigerant": "R134a",
"secondary_fluid": "Water",
"quality_control": false
},
{
"type": "BrineSource",
"name": "cond_water_in",
"fluid": "Water",
"p_set_bar": 2.0,
"t_set_c": 30.0,
"m_flow_kg_s": 0.45,
"fix_pressure": false,
"fix_temperature": true,
"fix_mass_flow": true
},
{
"type": "BrineSink",
"name": "cond_water_out",
"fluid": "Water",
"p_back_bar": 2.0,
"fix_pressure": true
},
{
"type": "BrineSource",
"name": "evap_water_in",
"fluid": "Water",
"p_set_bar": 3.0,
"t_set_c": 12.0,
"m_flow_kg_s": 0.55,
"fix_pressure": false,
"fix_temperature": true,
"fix_mass_flow": false
},
{
"type": "BrineSink",
"name": "evap_water_out",
"fluid": "Water",
"p_back_bar": 3.0,
"t_set_c": 7.0,
"fix_pressure": true,
"fix_temperature": true
}
],
"edges": [
{ "from": "comp:outlet", "to": "cond:inlet" },
{ "from": "cond:outlet", "to": "exv:inlet" },
{ "from": "exv:outlet", "to": "evap:inlet" },
{ "from": "evap:outlet", "to": "comp:inlet" },
{ "from": "cond_water_in:outlet", "to": "cond:secondary_inlet" },
{ "from": "cond:secondary_outlet", "to": "cond_water_out:inlet" },
{ "from": "evap_water_in:outlet", "to": "evap:secondary_inlet" },
{ "from": "evap:secondary_outlet", "to": "evap_water_out:inlet" }
]
}
],
"solver": {
"strategy": "newton",
"max_iterations": 300,
"tolerance": 1e-6
}
}

View File

@@ -0,0 +1,28 @@
{
"fluid": "R134a",
"fluid_backend": "CoolProp",
"circuits": [{
"id": 0,
"components": [
{ "type": "IsentropicCompressor", "name": "comp", "isentropic_efficiency": 0.70, "t_cond_k": 318.15, "t_evap_k": 278.15, "superheat_k": 5.0, "emergent_pressure": true, "displacement_m3": 6.5e-5, "speed_hz": 50.0, "volumetric_efficiency": 0.92 },
{ "type": "Condenser", "name": "cond", "ua": 766.0, "emergent_pressure": true, "subcooling_k": 5.0, "secondary_fluid": "Water" },
{ "type": "IsenthalpicExpansionValve", "name": "exv", "t_evap_k": 278.15, "emergent_pressure": true, "orifice_kv": 2.0e-6, "orifice_opening_init": 0.5, "orifice_opening_min": 0.02, "orifice_opening_max": 1.0 },
{ "type": "Evaporator", "name": "evap", "ua": 1468.0, "emergent_pressure": true, "secondary_fluid": "Water" },
{ "type": "BrineSource", "name": "cond_water_in", "fluid": "Water", "p_set_bar": 2.0, "t_set_c": 30.0, "m_flow_kg_s": 0.3583 },
{ "type": "BrineSink", "name": "cond_water_out", "fluid": "Water", "p_back_bar": 2.0 },
{ "type": "BrineSource", "name": "evap_water_in", "fluid": "Water", "p_set_bar": 2.0, "t_set_c": 12.0, "m_flow_kg_s": 0.4778 },
{ "type": "BrineSink", "name": "evap_water_out", "fluid": "Water", "p_back_bar": 2.0 }
],
"edges": [
{ "from": "comp:outlet", "to": "cond:inlet" },
{ "from": "cond:outlet", "to": "exv:inlet" },
{ "from": "exv:outlet", "to": "evap:inlet" },
{ "from": "evap:outlet", "to": "comp:inlet" },
{ "from": "cond_water_in:outlet", "to": "cond:secondary_inlet" },
{ "from": "cond:secondary_outlet", "to": "cond_water_out:inlet" },
{ "from": "evap_water_in:outlet", "to": "evap:secondary_inlet" },
{ "from": "evap:secondary_outlet", "to": "evap_water_out:inlet" }
]
}],
"solver": { "strategy": "fallback", "max_iterations": 300, "tolerance": 1e-6 }
}

View File

@@ -0,0 +1,93 @@
{
"name": "Chiller R410A - Full Physics 4-Port (Newton convergence test)",
"description": "Cycle frigorifique complet avec IsentropicCompressor, Condenser, IsenthalpicExpansionValve et Evaporator en mode Modelica 4-port. Les cotes secondaires (eau condenseur + eau glacee) sont de vraies aretes du graphe (BrineSource → HX:secondary_inlet → HX:secondary_outlet → BrineSink), pas des parametres fixes. Le duty Q emerge du bilan ε-NTU couple a l'etat live des aretes secondaires.",
"fluid": "R410A",
"fluid_backend": "CoolProp",
"circuits": [
{
"id": 0,
"name": "Refrigerant + secondary loops",
"components": [
{
"type": "IsentropicCompressor",
"name": "comp",
"isentropic_efficiency": 0.75,
"t_cond_k": 323.15,
"t_evap_k": 275.15,
"superheat_k": 5.0,
"emergent_pressure": true,
"displacement_m3": 5.0e-5,
"speed_hz": 50.0,
"volumetric_efficiency": 0.92
},
{
"type": "Condenser",
"name": "cond",
"ua": 2000,
"emergent_pressure": true,
"subcooling_k": 5.0,
"secondary_fluid": "Water"
},
{
"type": "IsenthalpicExpansionValve",
"name": "exv",
"t_evap_k": 275.15,
"emergent_pressure": true
},
{
"type": "Evaporator",
"name": "evap",
"ua": 1800,
"emergent_pressure": true,
"secondary_fluid": "Water"
},
{
"type": "BrineSource",
"name": "cond_water_in",
"fluid": "Water",
"p_set_bar": 2.0,
"t_set_c": 30.0,
"m_flow_kg_s": 0.40
},
{
"type": "BrineSink",
"name": "cond_water_out",
"fluid": "Water",
"p_back_bar": 2.0
},
{
"type": "BrineSource",
"name": "evap_water_in",
"fluid": "Water",
"p_set_bar": 3.0,
"t_set_c": 12.0,
"m_flow_kg_s": 0.50
},
{
"type": "BrineSink",
"name": "evap_water_out",
"fluid": "Water",
"p_back_bar": 3.0
}
],
"edges": [
{ "from": "comp:outlet", "to": "cond:inlet" },
{ "from": "cond:outlet", "to": "exv:inlet" },
{ "from": "exv:outlet", "to": "evap:inlet" },
{ "from": "evap:outlet", "to": "comp:inlet" },
{ "from": "cond_water_in:outlet", "to": "cond:secondary_inlet" },
{ "from": "cond:secondary_outlet", "to": "cond_water_out:inlet" },
{ "from": "evap_water_in:outlet", "to": "evap:secondary_inlet" },
{ "from": "evap:secondary_outlet", "to": "evap_water_out:inlet" }
]
}
],
"solver": {
"strategy": "fallback",
"max_iterations": 300,
"tolerance": 1e-6
}
}

View File

@@ -0,0 +1,93 @@
{
"name": "Water-Cooled Chiller R410A (4-Port Modelica Style)",
"description": "Full emergent-pressure chiller cycle with both heat exchangers on water loops. Condenser water: BrineSource(30C) → cond:secondary_inlet → cond:secondary_outlet → BrineSink. Chilled water: BrineSource(12C) → evap:secondary_inlet → evap:secondary_outlet → BrineSink. Secondary sides are real graph edges — the duty Q is solved from the live edge state.",
"fluid": "R410A",
"fluid_backend": "CoolProp",
"circuits": [
{
"id": 0,
"name": "Refrigerant + secondary loops",
"components": [
{
"type": "IsentropicCompressor",
"name": "comp",
"isentropic_efficiency": 0.70,
"t_cond_k": 313.15,
"t_evap_k": 276.15,
"superheat_k": 5.0,
"emergent_pressure": true,
"displacement_m3": 5.0e-5,
"speed_hz": 50.0,
"volumetric_efficiency": 0.92
},
{
"type": "Condenser",
"name": "cond",
"ua": 2000.0,
"emergent_pressure": true,
"subcooling_k": 5.0,
"secondary_fluid": "Water"
},
{
"type": "IsenthalpicExpansionValve",
"name": "exv",
"t_evap_k": 276.15,
"emergent_pressure": true
},
{
"type": "Evaporator",
"name": "evap",
"ua": 1800.0,
"emergent_pressure": true,
"secondary_fluid": "Water"
},
{
"type": "BrineSource",
"name": "cond_water_in",
"fluid": "Water",
"p_set_bar": 2.0,
"t_set_c": 30.0,
"m_flow_kg_s": 0.40
},
{
"type": "BrineSink",
"name": "cond_water_out",
"fluid": "Water",
"p_back_bar": 2.0
},
{
"type": "BrineSource",
"name": "evap_water_in",
"fluid": "Water",
"p_set_bar": 3.0,
"t_set_c": 12.0,
"m_flow_kg_s": 0.50
},
{
"type": "BrineSink",
"name": "evap_water_out",
"fluid": "Water",
"p_back_bar": 3.0
}
],
"edges": [
{ "from": "comp:outlet", "to": "cond:inlet" },
{ "from": "cond:outlet", "to": "exv:inlet" },
{ "from": "exv:outlet", "to": "evap:inlet" },
{ "from": "evap:outlet", "to": "comp:inlet" },
{ "from": "cond_water_in:outlet", "to": "cond:secondary_inlet" },
{ "from": "cond:secondary_outlet", "to": "cond_water_out:inlet" },
{ "from": "evap_water_in:outlet", "to": "evap:secondary_inlet" },
{ "from": "evap:secondary_outlet", "to": "evap_water_out:inlet" }
]
}
],
"solver": {
"strategy": "fallback",
"max_iterations": 300,
"tolerance": 1e-6
}
}

View File

@@ -0,0 +1,30 @@
{
"fluid": "R410A",
"fluid_backend": "CoolProp",
"circuits": [{
"id": 0,
"components": [
{ "type": "IsentropicCompressor", "name": "comp", "isentropic_efficiency": 0.70, "t_cond_k": 313.15, "t_evap_k": 276.15, "superheat_k": 5.0, "emergent_pressure": true, "displacement_m3": 5.0e-5, "speed_hz": 50.0, "volumetric_efficiency": 0.92 },
{ "type": "ReversingValve", "name": "rv", "pressure_drop_kpa": 25.0, "pressure_drop_coeff": 5.0e5 },
{ "type": "Condenser", "name": "cond", "ua": 2000.0, "emergent_pressure": true, "subcooling_k": 5.0, "secondary_fluid": "Water" },
{ "type": "IsenthalpicExpansionValve", "name": "exv", "t_evap_k": 276.15, "emergent_pressure": true },
{ "type": "Evaporator", "name": "evap", "ua": 1800.0, "emergent_pressure": true, "secondary_fluid": "Air", "secondary_humidity_ratio": 0.010 },
{ "type": "BrineSource", "name": "cond_water_in", "fluid": "Water", "p_set_bar": 2.0, "t_set_c": 40.0, "m_flow_kg_s": 0.4 },
{ "type": "BrineSink", "name": "cond_water_out", "fluid": "Water", "p_back_bar": 2.0 },
{ "type": "AirSource", "name": "evap_air_in", "p_set_bar": 1.01325, "t_dry_c": 7.0, "rh": 50.0, "m_flow_kg_s": 0.5 },
{ "type": "AirSink", "name": "evap_air_out", "p_back_bar": 1.01325 }
],
"edges": [
{ "from": "comp:outlet", "to": "rv:inlet" },
{ "from": "rv:outlet", "to": "cond:inlet" },
{ "from": "cond:outlet", "to": "exv:inlet" },
{ "from": "exv:outlet", "to": "evap:inlet" },
{ "from": "evap:outlet", "to": "comp:inlet" },
{ "from": "cond_water_in:outlet", "to": "cond:secondary_inlet" },
{ "from": "cond:secondary_outlet", "to": "cond_water_out:inlet" },
{ "from": "evap_air_in:outlet", "to": "evap:secondary_inlet" },
{ "from": "evap:secondary_outlet", "to": "evap_air_out:inlet" }
]
}],
"solver": { "strategy": "fallback", "max_iterations": 300, "tolerance": 1e-6 }
}

View File

@@ -0,0 +1,88 @@
{
"name": "Four-Port Air-Water Heat Exchanger",
"fluid": "Water",
"fluid_backend": "CoolProp",
"circuits": [
{
"id": 0,
"components": [
{
"type": "BrineSource",
"name": "hot_water_in",
"fluid": "Water",
"p_set_bar": 2.0,
"t_set_c": 60.0,
"m_flow_kg_s": 0.5
},
{
"type": "HeatExchanger",
"name": "hx",
"ua": 3000.0,
"hot_fluid_id": "Water",
"cold_fluid_id": "Air",
"cold_humidity_ratio": 0.010
},
{
"type": "BrineSink",
"name": "hot_water_out",
"fluid": "Water",
"p_back_bar": 2.0
},
{
"type": "AirSource",
"name": "cold_air_in",
"p_set_bar": 1.01325,
"t_dry_c": 20.0,
"rh": 50.0,
"m_flow_kg_s": 1.0
},
{
"type": "Fan",
"name": "supply_fan",
"fluid": "Air",
"speed_ratio": 1.0,
"air_density_kg_per_m3": 1.204,
"design_flow_m3_s": 0.83,
"curve_p0": 250.0,
"curve_p1": 0.0,
"curve_p2": -20.0,
"eff_e0": 0.65,
"eff_e1": 0.0,
"eff_e2": 0.0
},
{
"type": "AirSink",
"name": "cold_air_out",
"p_back_bar": 1.01325
}
],
"edges": [
{
"from": "hot_water_in:outlet",
"to": "hx:hot_inlet"
},
{
"from": "hx:hot_outlet",
"to": "hot_water_out:inlet"
},
{
"from": "cold_air_in:outlet",
"to": "supply_fan:inlet"
},
{
"from": "supply_fan:outlet",
"to": "hx:cold_inlet"
},
{
"from": "hx:cold_outlet",
"to": "cold_air_out:inlet"
}
]
}
],
"solver": {
"strategy": "newton",
"max_iterations": 300,
"tolerance": 1e-6
}
}

View File

@@ -0,0 +1,47 @@
{
"name": "Chiller R410A - Single Circuit (Working)",
"description": "Circuit réfrigérant simple sans couplage thermique (fonctionne)",
"fluid": "R410A",
"circuits": [
{
"id": 0,
"name": "Circuit réfrigérant R410A",
"components": [
{
"type": "Placeholder",
"name": "comp",
"n_equations": 2
},
{
"type": "Placeholder",
"name": "cond",
"n_equations": 2
},
{
"type": "Placeholder",
"name": "exv",
"n_equations": 2
},
{
"type": "Placeholder",
"name": "evap",
"n_equations": 2
}
],
"edges": [
{ "from": "comp:outlet", "to": "cond:inlet" },
{ "from": "cond:outlet", "to": "exv:inlet" },
{ "from": "exv:outlet", "to": "evap:inlet" },
{ "from": "evap:outlet", "to": "comp:inlet" }
]
}
],
"solver": {
"strategy": "newton",
"max_iterations": 100,
"tolerance": 1e-6
}
}