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