# 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).
