# Entropyk Moteur de simulation thermodynamique pour cycles frigorifiques, pompes à chaleur et systèmes CVC (HVAC/R). Entropyk assemble une **machine** (compresseur, échangeurs, détendeur, boucles secondaires…) sous forme de graphe de composants, résout le système d’équations non linéaires, et expose le même modèle via **Rust**, **CLI JSON**, **Python**, **C** et **WebAssembly**. > Documentation approfondie : [`DOCUMENTATION.md`](./DOCUMENTATION.md) · Exemples avancés : [`EXAMPLES_FULL.md`](./EXAMPLES_FULL.md) · Frontières Modelica : [`docs/modelica-boundary-proof.md`](./docs/modelica-boundary-proof.md) --- ## Table des matières 1. [Ce que fait Entropyk](#1-ce-que-fait-entropyk) 2. [Architecture du dépôt](#2-architecture-du-dépôt) 3. [Principes physiques et DoF](#3-principes-physiques-et-dof) 4. [Le solveur](#4-le-solveur) 5. [Catalogue des composants](#5-catalogue-des-composants) 6. [Mode CLI](#6-mode-cli) 7. [API Rust (SystemBuilder)](#7-api-rust-systembuilder) 8. [Frontières Fixed / Free (style Modelica)](#8-frontières-fixed--free-style-modelica) 9. [EXV, orifice et débit](#9-exv-orifice-et-débit) 10. [Fluides et backends](#10-fluides-et-backends) 11. [Interface web](#11-interface-web) 12. [Bindings Python / C / WASM](#12-bindings-python--c--wasm) 13. [Installation et commandes](#13-installation-et-commandes) 14. [Exemples fournis](#14-exemples-fournis) 15. [Conventions de développement](#15-conventions-de-développement) --- ## 1. Ce que fait Entropyk Entropyk simule un **cycle frigorifique / PAC / chiller** en régime permanent : 1. Vous déclarez des **composants** (compresseur, condenseur, EXV, évaporateur, sources d’air/eau…). 2. Vous les **câblez** par des arêtes (`comp:outlet → cond:inlet`). 3. Le moteur construit un vecteur d’état, assemble résidus + Jacobien, et **Newton** (ou Picard / fallback) converge. 4. Vous obtenez pressions, enthalpies, débits, puissances, COP, et diagnostics DoF. Cas d’usage typiques : | Cas | Comment | |-----|---------| | Point de design d’un chiller | Config JSON + `entropyk-cli run` | | Pressions émergentes (SST/SDT libres) | `emergent_pressure: true` sur HX + EXV | | Calibration inverse (cible SH / capacité) | Contrôles `SaturatedController` / facteurs `z_ua` | | Rating IPLV / SCOP / SEER | Sous-commandes `rate`, `scop`, `seer` | | Qualif. échangeur isolé | `qualify` | | Schéma interactif | UI `apps/web` → API `ui-server` | --- ## 2. Architecture du dépôt ``` Entropyk/ ├── crates/ │ ├── core/ # Newtypes physiques : Pressure, Temperature, Enthalpy, MassFlow… │ ├── fluids/ # FluidBackend + CoolProp / Tabular / Incompressible │ ├── components/ # Tous les composants (trait Component) │ ├── solver/ # Graphe, DoF, Newton / Picard / Fallback / Homotopy │ ├── entropyk/ # Façade : SystemBuilder, SimulationResult, rating │ ├── cli/ # Binaire entropyk-cli + exemples JSON │ └── vendors/ # Parsers données constructeurs (Copeland, Danfoss, SWEP, Bitzer) ├── bindings/ │ ├── python/ # PyO3 (chemin réel — pas crates/bindings/) │ ├── c/ # FFI C + cbindgen │ └── wasm/ # WebAssembly ├── apps/web/ # Workbench diagramme (Next.js) ├── demo/ # ui-server Axum (:3030) ├── docs/ # Manuels, Modelica, tutoriels └── plans/ # Plans d’audit / remediation ``` Flux de données : ```text JSON config / SystemBuilder / UI │ ▼ create_component → System (graphe) │ ▼ finalize() + DoF gate → vecteur d’état [ṁ, P, h]… │ ▼ Newton / Picard / Fallback │ ▼ SimulationResult (états, énergies, COP, diagnostics) ``` --- ## 3. Principes physiques et DoF ### Vecteur d’état Chaque **arête** du graphe porte trois inconnues : | Slot | Symbole | Unité SI | |------|---------|----------| | 0 | ṁ | kg/s | | 1 | P | Pa | | 2 | h | J/kg | Sur une branche série (1 entrée / 1 sortie), les arêtes partagent souvent le **même ṁ** (topologie CM1.4) : le solveur réduit alors le nombre d’inconnues de débit. ### Degrés de liberté (DoF) Un système est **carré** si : ```text n_équations = n_inconnues ``` - Trop d’équations → **sur-contraint** → `finalize()` refuse (DoF gate). - Pas assez → **sous-contraint** → refuse aussi en production (CLI). Chaque composant déclare un nombre d’équations et des **rôles** (`EquationRole`) : bilan d’énergie, chute de pression, Dirichlet de frontière, fermeture de sortie (SH/SC/qualité), actionneur… Règle d’or (alignée Modelica) : **aucun composant ne doit fixer à la fois ṁ et P** sur le même flux. --- ## 4. Le solveur Implémentation : `crates/solver`. ### Stratégies disponibles | Stratégie JSON | Comportement | |----------------|--------------| | `"newton"` (**défaut**) | Newton–Raphson : `x ← x − α J⁻¹ r`. Jacobien analytique des composants. Recherche linéaire Armijo optionnelle (activée si contrôles / orifice / Free-P eau). | | `"picard"` | Substitution successive amortie : `x ← (1−ω)x + ω G(x)`, ω ≈ 0,5. Plus robuste, plus lente. | | `"fallback"` | Newton d’abord ; en cas de divergence → Picard ; retour à Newton si le résidu redescend sous un seuil. | Tolérance typique : `1e-6`. Nombre d’itérations CLI : souvent `300` (augmenter pour des Jacobiens partiellement numériques, ex. certains HX). ### Boucle Newton (schéma) ```text 1. Seed initial (frontières + staging HP/BP si emergent_pressure) 2. Calculer r(x) = résidus de tous les composants 3. Assembler J(x) = ∂r/∂x 4. Résoudre J·Δx = −r 5. Appliquer x ← clamp(x + α·Δx) (bornes P ≥ 10 kPa, actionneurs…) 6. Répéter jusqu’à ‖r‖ < tolérance ``` ### Ce qui n’est **pas** le solveur - Pas de dynamique temporelle (régime permanent). - Pas de CFD : les HX sont des modèles 0D/1D (LMTD, ε-NTU, corrélations). - Les propriétés fluides viennent du **backend** (CoolProp…), pas d’hypothèses hardcodées (politique « zero fallback » côté composants sérieux). --- ## 5. Catalogue des composants Tous implémentent le trait `Component` (`n_equations`, `compute_residuals`, `jacobian_entries`, ports…). Types CLI = chaînes `"type"` dans le JSON (voir `crates/cli/src/run.rs`). ### 5.1 Compresseurs | Type CLI | Rôle | Paramètres clés | |----------|------|-----------------| | `IsentropicCompressor` | Compresseur η_is + déplacement volumétrique ; mode **emergent** courant | `displacement_m3`, `speed_hz`, `volumetric_efficiency`, `isentropic_efficiency`, `emergent_pressure` | | `Compressor` | Cartographie AHRI 540 / SST–SDT (ṁ, puissance) | coeffs `m1`…`m10` ou carte polynomiale | | `ScrewEconomizerCompressor` / `ScrewCompressor` | Vis + port écono, VFD, slide valve optionnel | courbes SST/SDT, `speed_hz` | | `CentrifugalCompressor` | Carte polytropique (facteur de débit, Mach) | `diameter_m`, `speed_rpm`, γ, R | En mode **emergent**, le compresseur impose typiquement la **loi de ṁ** (déplacement × ρ × η_vol) et l’énergie de refoulement ; les pressions HP/BP émergent des HX. Si un EXV à **orifice Fixed** métre le débit, le CLI bascule le compresseur en **ṁ externe** (énergie seule) pour rester carré. ### 5.2 Détente / vannes | Type CLI | Rôle | Notes critiques | |----------|------|-----------------| | `IsenthalpicExpansionValve` / `EXV` | Laminants isenthalpiques (`h_out = h_in`) | **Sans `orifice_kv`**, `opening` n’a **aucun effet** — voir [§9](#9-exv-orifice-et-débit) | | `ExpansionValve` | Modèles débit orifice / Cd·A / TXV Eames | `flow_model`, `opening`, `beta_m2`… | | `CapillaryTube` | Capillaire adiabatique segmenté | `diameter_m`, `length_m`, `n_segments` | | `ReversingValve` / `FourWayValve` | 4 voies PAC (froid/chaud) | `mode`, `pressure_drop_pa` | | `BypassValve` | Bypass hydronique proportionnel | `opening`, `cv` | ### 5.3 Échangeurs frigorifiques | Type CLI | Rôle | Notes | |----------|------|-------| | `Condenser` | Condensation + côté secondaire (eau/air) | `ua`, `emergent_pressure`, `subcooling_k`, `secondary_fluid`, ΔP secondaire optionnelle | | `Evaporator` | Évaporation DX + secondaire | `ua`, `superheat_k` / emergent, `secondary_fluid` | | `FloodedEvaporator` | Flooded / recirculation | fermeture vapeur saturée ou `quality_control` | | `FloodedCondenser` | Condenseur flooded | sortie sous-refroidie | | `HeatExchanger` | HX générique 4 ports (LMTD / ε-NTU) | `hot_fluid_id`, `cold_fluid_id`, `ua` | | `BphxEvaporator` / `BphxCondenser` | Plaques brasées + corrélations HTC | géométrie plaques, corrélations Longo/Shah… | | `AirCooledCondenser` | T_cond ≈ OAT + approach | `oat_k`, `approach_k` | | `FinCoilCondenser` | Bobine ailettée air | géométrie tubes/ailettes | | `MchxCondenserCoil` | Microcanaux | géométrie MCHX | | `CondenserCoil` / `EvaporatorCoil` | Bobines dédiées | variantes rating | | `Economizer` | IHX ON/OFF/BYPASS | machine à états | | `GasCooler` | Refroidisseur de gaz CO₂ | HTC Pettersen | | `ShellAndTubeHx` | Rating Bell-Delaware | | | `FanCoilUnit` | FCU eau–air | ε-NTU + BPF | | `FreeCoolingExchanger` | Free-cooling côté eau | | **Pressions émergentes** (`emergent_pressure: true`) : le HX ne pince plus P_sat sur une T de design ; la pression flotte et est fermée par SC/SH/qualité + bilans d’énergie. **Secondaire 4 ports** : brancher `BrineSource`/`AirSource` → `secondary_inlet` → `secondary_outlet` → `BrineSink`/`AirSink`. Le HX propage la pression (fermeture isobare ou ΔP quadratique de rating). ### 5.4 Tuyauterie, pompes, air | Type CLI | Rôle | Notes | |----------|------|-------| | `Pipe` / `RefrigerantPipe` / `WaterPipe` / `AirDuct` | Conduits Darcy–Weisbach | `length_m`, `diameter_m` ; `pressure_drop_pa = 0` → **ΔP Darcy** depuis L/D + ṁ ; `> 0` → ΔP imposé | | `Pump` | Courbes H/η + affinity laws | | | `Fan` | Courbes pression/η + affinity | souvent sur boucle air | | `FlowSplitter` / `FlowMerger` | Jonctions | | | `Drum` | Séparateur L/V (flooded) | | ### 5.5 Frontières (sources / sinks) | Type CLI | Fluide | Impose typiquement | |----------|--------|--------------------| | `RefrigerantSource` / `RefrigerantSink` | Frigorigène | P (+ qualité ou h), ṁ optionnel | | `BrineSource` / `BrineSink` | Eau / glycol | T, ṁ, P (Fixed/Free) | | `AirSource` / `AirSink` | Air humide | T_dry, RH, ṁ, P | Voir [§8](#8-frontières-fixed--free-style-modelica). ### 5.6 Divers | Type CLI | Rôle | |----------|------| | `ThermalLoad` | Charge thermique Q (couplage) | | `HeatSource` | Injection Q inline | | `Anchor` / `RefrigerantNode` | Nœud / ancre SH optionnelle | | `Placeholder` | Composant stub (tests / topology) | ### 5.7 Intégration obligatoire d’un nouveau composant Lorsqu’on ajoute un composant, il doit être câblé **partout** : 1. Trait `Component` + Jacobien exact dans `crates/components` 2. Export façade `crates/entropyk` 3. Bras `create_component` dans `crates/cli/src/run.rs` 4. Wrapper Python (PyO3) et WASM si exposé 5. Meta UI (`apps/web/src/lib/componentMeta.ts`) si visible dans le workbench --- ## 6. Mode CLI Binaire : `entropyk-cli` (`crates/cli`). ### Sous-commandes | Commande | Rôle | |----------|------| | `run` | Une simulation depuis un JSON | | `batch` | Dossier de configs, parallèle | | `validate` | Vérifie le JSON / topologie sans résoudre (ou validation légère) | | `qualify` | Qualification HX (régime frigorigène fixe, balayage secondaire) | | `rate` | IPLV (AHRI 550/590) / ESEER | | `scop` | SCOP EN 14825 (bins chauffage) | | `seer` | SEER EN 14825 (bins froid) | | `schema` | Émet le JSON Schema du Model IR | Flags globaux : `-v` / `--verbose`, `-q` / `--quiet`. ### Exemples d’invocation ```bash # Build cargo build --release -p entropyk-cli # Chiller air R134a cargo run -p entropyk-cli -- run \ --config crates/cli/examples/chiller_aircooled_r134a.json \ --output result.json # Validation cargo run -p entropyk-cli -- validate --config mon_cycle.json # Batch cargo run -p entropyk-cli -- batch -d ./scenarios/ -p 4 -O results.json # Rating IPLV cargo run -p entropyk-cli -- rate -c crates/cli/examples/rate_chiller_iplv_ahri.json # Schema cargo run -p entropyk-cli -- schema -o model-ir.schema.json ``` ### Schéma JSON minimal ```json { "name": "Mon chiller", "fluid": "R134a", "fluid_backend": "CoolProp", "circuits": [ { "id": 0, "name": "Circuit principal", "components": [ { "type": "IsentropicCompressor", "name": "comp", "...": "..." }, { "type": "Condenser", "name": "cond", "...": "..." }, { "type": "IsenthalpicExpansionValve", "name": "exv", "...": "..." }, { "type": "Evaporator", "name": "evap", "...": "..." } ], "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" } ] } ], "controls": [], "solver": { "strategy": "newton", "max_iterations": 300, "tolerance": 1e-6 } } ``` ### Pipeline interne de `run` 1. Parse `ScenarioConfig` 2. Pour chaque composant : `create_component(...)` (CoolProp, params, modes orifice / emergent…) 3. Ajout des arêtes nommées `nom:port` 4. `finalize()` + contrôle DoF 5. Seed (frontières + staging HP/BP) 6. Solve selon `solver.strategy` 7. Sérialisation JSON : états d’arêtes, performances, `dof`, `failure_diagnostics` si échec ### Contrôles (régulation / calibration) Bloc optionnel `controls` : boucles type `SaturatedController` qui lient une **mesure** (capacité, SH…) à un **actionneur** (`opening`, `z_ua`, `f_m`…). Le solveur augmente alors le vecteur d’état d’inconnues d’actionneurs + résidus de tracking. --- ## 7. API Rust (SystemBuilder) Façade : crate `entropyk`. ```rust use entropyk::SystemBuilder; // + types composants depuis entropyk / entropyk_components fn main() -> Result<(), Box> { let system = SystemBuilder::new() .with_fluid("R134a")? // .component("comp", Box::new(...))? // .edge_with_ports("comp", "outlet", "cond", "inlet")? .build()?; // Ou bas niveau : // let mut newton = entropyk_solver::NewtonConfig::default(); // let result = newton.solve(&mut system)?; Ok(()) } ``` Points d’entrée utiles : - `SystemBuilder` — construction ergonomique + JSON round-trip (`to_config_json` / `from_config_json`) - `System` — graphe, `finalize`, `dof_report`, `validate_system_dof` - `NewtonConfig` / `PicardConfig` / `FallbackConfig` — stratégies - `SimulationResult` — sortie structurée --- ## 8. Frontières Fixed / Free (style Modelica) Alignement documenté dans [`docs/modelica-boundary-proof.md`](./docs/modelica-boundary-proof.md). | Pattern Modelica | Source | Sink | Conséquence | |------------------|--------|------|-------------| | **MassFlowSource_T** (défaut Entropyk si ṁ imposé) | Fixed T, Fixed ṁ, **Free P** | Fixed P, Free T_out | Le HX/propager ΔP ferme le DoF pression | | **Boundary_pT** | Fixed P, Fixed T, Free ṁ | Fixed P | Il faut une résistance hydraulique (pipe / ΔP HX) entre les deux P | | Rating T_out | Free ṁ | Fixed P + Fixed T_out | ṁ devient inconnu (calibration) | Flags JSON : `fix_pressure`, `fix_temperature`, `fix_mass_flow` (booléens). **Interdit** : Fixed ṁ **et** Fixed P sur la même source sans degré de liberté ailleurs. ΔP secondaire de rating (eau/air) : ```json "secondary_rated_pressure_drop_pa": 40000, "secondary_rated_m_flow_kg_s": 0.5 ``` --- ## 9. EXV, orifice et débit Trois modes pour `IsenthalpicExpansionValve` : ### Mode A — Isenthalpique seul (exemples chillers classiques) ```json { "type": "IsenthalpicExpansionValve", "name": "exv", "emergent_pressure": true } ``` - Équation : `h_out − h_in = 0` - **ṁ imposé par le compresseur** (déplacement) - `opening` **ignoré** (même s’il apparaît dans l’UI avec une valeur par défaut) ### Mode B — Orifice Fixed (opening = paramètre) ```json { "type": "IsenthalpicExpansionValve", "name": "exv", "emergent_pressure": true, "orifice_kv": 2.0e-6, "opening": 0.6, "fix_opening": true } ``` Loi : ```text ṁ = Kv · opening · √(2 · ρ_in · max(ΔP, 0)) ``` Le CLI met le compresseur en **ṁ métré** (lâche la loi de déplacement) pour rester carré. ### Mode C — Orifice Free (opening = inconnue) ```json "orifice_kv": 2.0e-6, "fix_opening": false ``` `opening` est une inconnue ; il faut une boucle de régulation (ex. SH → SaturatedController). > **Piège UI** : le catalogue montre « Opening » même sans Kv. Sans `orifice_kv` explicite, changer l’ouverture ne change **rien**. Exemple dédié : `crates/cli/examples/chiller_r134a_exv_orifice.json`. --- ## 10. Fluides et backends | Backend | Usage | |---------|--------| | **CoolProp** (`fluid_backend: "CoolProp"`) | Frigorigènes (R134a, R410A…), eau — défaut sérieux | | **Tabular** | Tables interpolées (WASM / hors CoolProp) | | **Incompressible** | Glycols / liquides (ρ, μ de design) | | **Cached / Damped** | Wrappers perf / stabilité | Types physiques dans `entropyk-core` : toujours SI (Pa, K, J/kg, kg/s). Les JSON d’entrée acceptent souvent °C / bar pour l’ergonomie ; la conversion est faite à la construction. --- ## 11. Interface web | Élément | Chemin | |---------|--------| | Front Next.js | `apps/web` | | API Axum | `cargo run -p entropyk-demo --bin ui-server` → `http://localhost:3030` | Fonctionnalités : - Palette de composants + glyph ISO - Câblage React Flow - Ledger DoF temps réel (`dofLedger.ts`) - Coach Fixed/Free Modelica (`boundaryFix.ts`, `dofCoach.ts`) - Solve via `POST /api/simulate` ```bash # Terminal 1 cargo run -q -p entropyk-demo --bin ui-server # Terminal 2 cd apps/web && npm run dev ``` --- ## 12. Bindings Python / C / WASM Chemins réels : `bindings/python`, `bindings/c`, `bindings/wasm` (pas sous `crates/`). ### Python (`uv` obligatoire) ```bash uv pip install -e ./bindings/python uv pip install maturin cd bindings/python && uv run maturin develop --release uv run pytest tests/ ``` ### C ```bash cargo build --release -p entropyk-c # header généré sous target/ (voir bindings/c/README.md) ``` ### WASM Voir `bindings/wasm/README.md` — adapté aux backends tabulaires côté client. > Certaines classes Python historiques sont encore des **stubs / mocks** (audit 2026-07) : vérifier les warnings à la construction et préférer le chemin CLI / Rust pour la physique complète. --- ## 13. Installation et commandes ### Prérequis - Rust (édition workspace 2021+) - CoolProp précompilé sous `vendor/coolprop` (lien via `coolprop-sys`) - Pour l’UI : Node.js + npm - Pour Python : [`uv`](https://github.com/astral-sh/uv) ### Commandes courantes ```bash # Build / tests cargo build cargo test cargo test -p entropyk-components cargo test -p entropyk-cli --test hx_standalone # CLI cargo run -p entropyk-cli -- run -c crates/cli/examples/chiller_aircooled_r134a.json # Clippy / format cargo fmt cargo clippy # UI API (port 3030) cargo run -q -p entropyk-demo --bin ui-server ``` Sous Windows, si `ui-server.exe` est verrouillé pendant `cargo test --workspace`, exclure le package démo : ```bash cargo test --workspace --exclude entropyk-demo --no-fail-fast ``` --- ## 14. Exemples fournis Répertoire : `crates/cli/examples/`. | Fichier | Intérêt | |---------|---------| | `chiller_aircooled_r134a.json` | Chiller air 4 ports, emergent, air + eau glacée | | `chiller_watercooled_r410a.json` | Chiller eau R410A | | `chiller_flooded_4port_watercooled.json` | FloodedEvaporator + DoF carré | | `chiller_r134a_emergent_pressure.json` | Pressions émergentes | | `chiller_r134a_exv_orifice.json` | EXV avec orifice (opening physique) | | `chiller_r134a_superheat_control.json` | Boucle SH | | `chiller_r134a_slide_valve.json` | Slide valve vis | | `chiller_r134a_dual_circuit_staging.json` | Dual circuit | | `heatpump_airsource_r410a.json` | PAC air | | `heatpump_r410a_reversing_valve.json` | Vanne 4 voies | | `hx_air_water_4port.json` | HX isolé air–eau | | `bphx_evaporator_condenser.json` | Plaques brasées | | `capillary_tube_r134a.json` | Capillaire | | `rate_chiller_iplv_ahri.json` | Rating IPLV | | `scop_heatpump_r134a.json` | SCOP | --- ## 15. Conventions de développement - **Langage code** : Rust, `Result` partout (politique zero-panic en production). - **Jacobiens** : analytiques exacts ; pas de différences finies sauf chemin explicitement documenté / temporaire. - **Types** : newtypes SI (`Pressure`, `Enthalpy`…) — pas de `f64` nus aux frontières publiques. - **Docs techniques / commits** : anglais ; communication projet possible en français. - **Git** : branche `main`, messages impératifs anglais. - **BMAD** : workflows sous `_bmad/` — suivre les fichiers YAML/XML à la lettre si activés. ### Ajouter un composant (checklist) 1. Struct + `Component` dans `crates/components` 2. Tests unitaires (résidus, Jacobien FD-check) 3. Export `lib.rs` + façade `entropyk` 4. Bras CLI `create_component` 5. Exemple JSON sous `crates/cli/examples/` 6. Meta UI + bindings si besoin --- ## Liens utiles | Document | Contenu | |----------|---------| | [`DOCUMENTATION.md`](./DOCUMENTATION.md) | Modèles physiques, solveur, API | | [`EXAMPLES_FULL.md`](./EXAMPLES_FULL.md) | Scénarios avancés | | [`docs/CLI_TUTORIAL.md`](./docs/CLI_TUTORIAL.md) | Tutoriel CLI | | [`docs/modelica-boundary-proof.md`](./docs/modelica-boundary-proof.md) | Preuve Fixed/Free | | [`docs/components/`](./docs/components/) | Fiches composants | | [`AGENTS.md`](./AGENTS.md) | Instructions agents / structure | | [`crates/cli/README.md`](./crates/cli/README.md) | Détails CLI | | [`apps/web/README.md`](./apps/web/README.md) | UI | --- **Projet** : Entropyk · **Langage** : Rust · **Licence / version** : voir `Cargo.toml` (v0.1.x)