Some checks failed
CI / check (push) Has been cancelled
Capture uncommitted solver robustness work (regularization, domain errors, linear solver lifecycle, tube DP/MSH), web workbench updates, and synced BMAD skills across IDE agent folders before starting BPHX pressure-drop. Co-authored-by: Cursor <cursoragent@cursor.com>
132 lines
14 KiB
Markdown
132 lines
14 KiB
Markdown
# Entropyk — Simulation Capabilities & Modelica Comparison / Capacités de simulation & comparaison Modelica
|
||
|
||
> Bilingual document (English first, French below) / Document bilingue (anglais d'abord, français ensuite).
|
||
>
|
||
> This analysis is **code-grounded**: every claim is traceable to the Rust sources in `crates/`.
|
||
> Cette analyse est **fondée sur le code** : chaque affirmation est traçable dans les sources Rust de `crates/`.
|
||
|
||
---
|
||
|
||
## EN — What Entropyk can simulate
|
||
|
||
### 1. Nature of the tool
|
||
|
||
Entropyk is a **steady-state, equation-based** thermodynamic-cycle simulator for refrigeration, heat-pump and HVAC systems. It is *not* a general-purpose DAE engine (like OpenModelica); it is a **domain-specific algebraic solver** built around a component graph.
|
||
|
||
- **Solving paradigm**: each component contributes residual equations `r(x) = 0` and an **analytic Jacobian**. The global system `F(x) = 0` is solved with Newton–Raphson, Picard (sequential substitution), a Newton-homotopy continuation, and a `FallbackSolver` that chains them. (`crates/solver/src/strategies/`)
|
||
- **State vector**: per flow edge `(ṁ, P, h)`; series branches share a single mass-flow unknown after a topology presolve (`|B| + 2·|E|` layout). (`crates/solver/src/system.rs`)
|
||
- **Fluid properties**: `CoolPropBackend` (production), `TestBackend` (mock/ideal), plus `TabularBackend` and `IncompressibleBackend` in the library. (`crates/fluids/`)
|
||
|
||
### 2. System-level capabilities
|
||
|
||
| Capability | Status | Evidence |
|
||
|---|---|---|
|
||
| Coupled algebraic solving with analytic Jacobian | ✅ | `Component::jacobian_entries`, `System::assemble_jacobian` |
|
||
| Explicit degrees-of-freedom balancing | ✅ | `System::validate_inverse_control_dof`, mass-flow presolve |
|
||
| Emergent pressures (SST/SDT float from HX↔secondary balance) | ✅ | `Condenser::with_emergent_pressure`, `Evaporator` `superheat_regulated` |
|
||
| Multi-circuit networks (up to 5) | ✅ | `CircuitId 0..4`, per-circuit flow edges |
|
||
| Inter-circuit thermal coupling (`thermal_couplings`) | ✅ physical mode | Set `hot_component` (duty provider, e.g. an ε-NTU `Condenser`) + `cold_component` (a `ThermalLoad` receiver): the coupling owns one unknown Q closed against the hot component's measured duty (`Q = η·duty_hot`) and injects Q into the cold loop's energy balance — First Law closes across circuits (`chiller_r410a_coupled_water_loop.json`). Entries without both fields are inert (Q pinned to 0, CLI warns). |
|
||
| Secondary-stream heat exchange (air/water, ε-NTU) | ✅ | `Condenser`/`Evaporator` `secondary_inlet_temp_c` + `secondary_mass_flow_kg_s` + `secondary_cp_j_per_kgk`; emergent capacity/COP (e.g. `chiller_r410a_full_physics.json` → COP≈4.98, First Law closes) |
|
||
| Steady-state supervisory control, co-solved | ✅ | `SaturatedController` (offset-free PI, anti-windup) |
|
||
| Override / selector priority (min/max) | ✅ | `override_network.rs`, smoothed `softMin/softMax`, activation continuation |
|
||
| Inverse / one-shot calibration | ✅ | `inverse/calibration.rs`, Z-factors `z_flow, z_dp, z_ua, z_power, z_etav` |
|
||
| Free actuators (e.g. EXV orifice opening) | ✅ | `System` free-actuator DoF (+1 unknown / +1 component eq) |
|
||
| Reusable parameterized subsystems (flattened) | ✅ | CLI `subsystems`/`instances`/`connections` → `flatten_instances()` |
|
||
| Hierarchical composition in Rust | ⚠️ partial | `MacroComponent` couples P/h at ports; ṁ continuity not yet coupled |
|
||
| Normative seasonal rating (IPLV/ESEER/SCOP/SEER) | ✅ | CLI `rate`, `scop`, `seer` (re-solves the cycle per load point/bin) |
|
||
| ON/OFF/BYPASS staging | ✅ (pre-solve) | `OperationalState`, `circuits[].enabled` |
|
||
| BOLT-style inline spec/probe nodes | ✅ | `Anchor` (= BOLT `BoundaryNode.Refrigerant.Node`): probe mode (DoF-neutral) or one imposed spec — signed `superheat_k` (dTsh, <0 = subcooling), `quality`, `t_c`/`t_k`, `p_bar` (`docs/components/anchor-heat-source.md`) |
|
||
| Inline heat injection (fixed or coupling-linked) | ✅ | `HeatSource` (= BOLT `BoundaryNode.Heat.Source`): `q_w` fixed duty + optional coupling-driven Q (motor-cooling pattern), exact Jacobian, excluded from COP aggregation (`chiller_r410a_bolt_nodes.json`) |
|
||
| Boundary-imposed loop flow | ✅ | `BrineSource`/`BrineSink` `m_flow_kg_s` (= BOLT `Vd_fixed=true`) |
|
||
|
||
### 3. Can we build models as complex as Modelica?
|
||
|
||
**Yes for the targeted domain, with caveats.** Entropyk reproduces the *ideas* that make Modelica HVAC libraries powerful:
|
||
|
||
- equation-based components with a coupled solve,
|
||
- reusable parameterized subsystems,
|
||
- co-solved supervisory control (setpoint tracking + min/max override priority, exactly the "BOLT"-style chiller control referenced in the code),
|
||
- inverse calibration and normative rating.
|
||
|
||
You can assemble multi-circuit chillers/heat-pumps with emergent pressures, secondary-fluid–coupled heat exchangers, economizer screw compressors, liquid injection, head-pressure control, free-cooling, and a supervisory control tree — comparable in *structural* complexity to a Modelica chiller model.
|
||
|
||
### 4. Gaps vs Modelica (be precise)
|
||
|
||
- **Steady-state only** — no time integration, no `der(x)`, no dynamic states (thermal masses, sensor lags). Everything targets `F(x)=0`.
|
||
- **No event handling** — no zero-crossing / reinit; `ModeSwitch` (hysteresis, min-runtime) lives *outside* the Newton solve and is time-based.
|
||
- **Causal edge connectors** — state is carried on edges/branches as `(ṁ,P,h)`; continuity is enforced by component residuals referencing state indices (a TESPy-like pattern), not Modelica acausal connectors with shared variables and language-level connection equations.
|
||
- **Hierarchy is mostly compile-time / flattened** — the CLI flattens subsystems before solving; nested subsystems inside the solver require Rust `MacroComponent`, whose port ṁ-continuity is still incomplete.
|
||
- **`thermal_couplings` transfers a measured duty, not a UA·ΔT law** — the physical mode closes `Q = η·duty_hot` (the hot component's ε-NTU duty) into a `ThermalLoad` receiver; the `ua` field is not used as a coupling conductance. For a genuinely two-sided UA·LMTD interface exchanger, use a two-sided `HeatExchanger`/BPHX or a secondary stream instead. Legacy entries without `hot_component`/`cold_component` are inert (Q pinned to 0, CLI warns).
|
||
- **CLI fluids limited** to CoolProp/Test (Tabular/Incompressible exist in the lib but are not wired to the CLI).
|
||
- **No user-authored arbitrary equations** — new behaviour requires implementing the `Component` trait in Rust.
|
||
|
||
### 5. One-sentence verdict
|
||
|
||
Entropyk is closer to a **TESPy/BOLT-style steady-state cycle solver with co-solved algebraic supervisory control and inverse calibration** than to a general Modelica DAE engine: excellent structural parity for HVAC/refrigeration cycles, but without transients, events, or acausal language-level connectors.
|
||
|
||
---
|
||
|
||
## FR — Ce qu'Entropyk permet de simuler
|
||
|
||
### 1. Nature de l'outil
|
||
|
||
Entropyk est un simulateur de **cycles thermodynamiques en régime permanent (steady-state)**, basé sur les **équations**, pour la réfrigération, les pompes à chaleur et le CVC. Ce n'est *pas* un moteur DAE généraliste (comme OpenModelica) : c'est un **solveur algébrique dédié au domaine**, organisé autour d'un graphe de composants.
|
||
|
||
- **Paradigme de résolution** : chaque composant fournit des équations résiduelles `r(x) = 0` et un **Jacobien analytique**. Le système global `F(x) = 0` est résolu par Newton–Raphson, Picard (substitution séquentielle), une continuation par homotopie de Newton, et un `FallbackSolver` qui les enchaîne. (`crates/solver/src/strategies/`)
|
||
- **Vecteur d'état** : par arête de flux `(ṁ, P, h)` ; les branches en série partagent un seul inconnu de débit après un presolve topologique (layout `|B| + 2·|E|`). (`crates/solver/src/system.rs`)
|
||
- **Propriétés fluides** : `CoolPropBackend` (production), `TestBackend` (mock/gaz idéal), plus `TabularBackend` et `IncompressibleBackend` dans la bibliothèque. (`crates/fluids/`)
|
||
|
||
### 2. Capacités au niveau système
|
||
|
||
| Capacité | État | Preuve (code) |
|
||
|---|---|---|
|
||
| Résolution algébrique couplée + Jacobien analytique | ✅ | `Component::jacobian_entries`, `System::assemble_jacobian` |
|
||
| Équilibrage explicite des degrés de liberté (DoF) | ✅ | `System::validate_inverse_control_dof`, presolve débit |
|
||
| Pressions émergentes (SST/SDT flottent selon l'équilibre HX↔secondaire) | ✅ | `Condenser::with_emergent_pressure`, `Evaporator` `superheat_regulated` |
|
||
| Réseaux multi-circuits (jusqu'à 5) | ✅ | `CircuitId 0..4`, arêtes de flux par circuit |
|
||
| Couplage thermique inter-circuits (`thermal_couplings`) | ✅ mode physique | Renseigner `hot_component` (fournisseur de puissance, ex. `Condenser` ε-NTU) + `cold_component` (récepteur `ThermalLoad`) : le couplage porte un inconnu Q fermé sur la puissance mesurée du composant chaud (`Q = η·duty_hot`) et injecte Q dans le bilan d'énergie de la boucle froide — le 1er principe ferme entre circuits (`chiller_r410a_coupled_water_loop.json`). Les entrées sans ces deux champs sont inertes (Q épinglé à 0, la CLI avertit). |
|
||
| Échange par flux secondaire (air/eau, ε-NTU) | ✅ | `Condenser`/`Evaporator` `secondary_inlet_temp_c` + `secondary_mass_flow_kg_s` + `secondary_cp_j_per_kgk` ; capacité/COP émergents (ex. `chiller_r410a_full_physics.json` → COP≈4.98, 1er principe fermé) |
|
||
| Contrôle supervisoire steady-state, co-résolu | ✅ | `SaturatedController` (PI offset-free, anti-windup) |
|
||
| Priorité par override / sélecteur (min/max) | ✅ | `override_network.rs`, `softMin/softMax` lissés, continuation d'activation |
|
||
| Calibration inverse / one-shot | ✅ | `inverse/calibration.rs`, facteurs Z `z_flow, z_dp, z_ua, z_power, z_etav` |
|
||
| Actuateurs libres (ex. ouverture orifice EXV) | ✅ | DoF free-actuator (+1 inconnu / +1 éq. composant) |
|
||
| Sous-systèmes paramétrés réutilisables (aplatis) | ✅ | CLI `subsystems`/`instances`/`connections` → `flatten_instances()` |
|
||
| Composition hiérarchique en Rust | ⚠️ partiel | `MacroComponent` couple P/h aux ports ; continuité ṁ pas encore couplée |
|
||
| Rating saisonnier normatif (IPLV/ESEER/SCOP/SEER) | ✅ | CLI `rate`, `scop`, `seer` (re-résout le cycle par point/bin) |
|
||
| Staging ON/OFF/BYPASS | ✅ (pré-solve) | `OperationalState`, `circuits[].enabled` |
|
||
| Nœuds spec/sonde inline style BOLT | ✅ | `Anchor` (= `BoundaryNode.Refrigerant.Node` de BOLT) : mode sonde (neutre en DoF) ou une spec imposée — `superheat_k` signé (dTsh, <0 = sous-refroidissement), `quality`, `t_c`/`t_k`, `p_bar` (`docs/components/anchor-heat-source.md`) |
|
||
| Injection de chaleur inline (fixe ou liée à un couplage) | ✅ | `HeatSource` (= `BoundaryNode.Heat.Source` de BOLT) : puissance fixe `q_w` + Q optionnel piloté par couplage (pattern refroidissement moteur), Jacobien exact, exclu de l'agrégation COP (`chiller_r410a_bolt_nodes.json`) |
|
||
| Débit de boucle imposé à la frontière | ✅ | `BrineSource`/`BrineSink` `m_flow_kg_s` (= `Vd_fixed=true` de BOLT) |
|
||
|
||
### 3. Peut-on bâtir des modèles aussi complexes que Modelica ?
|
||
|
||
**Oui pour le domaine visé, avec des réserves.** Entropyk reproduit les *idées* qui font la puissance des bibliothèques HVAC Modelica :
|
||
|
||
- composants basés équations, résolus de façon couplée ;
|
||
- sous-systèmes paramétrés réutilisables ;
|
||
- contrôle supervisoire co-résolu (suivi de consigne + priorité min/max, exactement le style de contrôle chiller « BOLT » référencé dans le code) ;
|
||
- calibration inverse et rating normatif.
|
||
|
||
On peut assembler des groupes froids / PAC multi-circuits avec pressions émergentes, échangeurs couplés au fluide secondaire, compresseurs à vis avec économiseur, injection liquide, contrôle de pression de refoulement, free-cooling et un arbre de contrôle supervisoire — d'une complexité *structurelle* comparable à un modèle chiller Modelica.
|
||
|
||
### 4. Écarts vs Modelica (précis)
|
||
|
||
- **Régime permanent uniquement** — pas d'intégration temporelle, pas de `der(x)`, pas d'états dynamiques (masses thermiques, retards capteurs). Tout vise `F(x)=0`.
|
||
- **Pas de gestion d'événements** — pas de zero-crossing / reinit ; `ModeSwitch` (hystérésis, durée min) est *hors* du Newton et basé sur le temps.
|
||
- **Connecteurs causaux par arête** — l'état est porté par les arêtes/branches en `(ṁ,P,h)` ; la continuité est imposée par des résidus composants référençant des indices d'état (motif type TESPy), pas des connecteurs acausaux Modelica à variables partagées.
|
||
- **Hiérarchie surtout compile-time / aplatie** — la CLI aplatit les sous-systèmes avant résolution ; l'imbrication dans le solveur passe par `MacroComponent` (Rust), dont la continuité ṁ aux ports est incomplète.
|
||
- **`thermal_couplings` transfère une puissance mesurée, pas une loi UA·ΔT** — le mode physique ferme `Q = η·duty_hot` (la puissance ε-NTU du composant chaud) dans un récepteur `ThermalLoad` ; le champ `ua` ne sert pas de conductance de couplage. Pour un échangeur d'interface UA·LMTD réellement à deux flux, utiliser un `HeatExchanger`/BPHX à deux flux ou un flux secondaire. Les entrées legacy sans `hot_component`/`cold_component` sont inertes (Q épinglé à 0, la CLI avertit).
|
||
- **Fluides CLI limités** à CoolProp/Test (Tabular/Incompressible existent dans la lib mais ne sont pas branchés à la CLI).
|
||
- **Pas d'équations utilisateur arbitraires** — tout nouveau comportement nécessite d'implémenter le trait `Component` en Rust.
|
||
|
||
### 5. Verdict en une phrase
|
||
|
||
Entropyk se rapproche d'un **solveur de cycles steady-state type TESPy/BOLT avec contrôle supervisoire algébrique co-résolu et calibration inverse**, plutôt que d'un moteur DAE Modelica généraliste : excellente parité structurelle pour les cycles CVC/réfrigération, mais sans transitoire, sans événements, ni connecteurs acausaux au niveau langage.
|
||
|
||
---
|
||
|
||
## Component catalog / Catalogue des composants
|
||
|
||
See per-component bilingual documentation in [`docs/components/`](./components/README.md).
|
||
Voir la documentation bilingue par composant dans [`docs/components/`](./components/README.md).
|