# Exemples d'utilisation - Entropyk Ce document présente des exemples d'utilisation de la bibliothèque Entropyk, basés sur les composants actuellement développés (Epic 1 : Extensible Component Framework). ## Table des matières 1. [Types physiques (entropyk-core)](#1-types-physiques-entropyk-core) 2. [Ports et connexions](#2-ports-et-connexions) 3. [Compresseur (AHRI 540)](#3-compresseur-ahri-540) 4. [Détendeur (expansion valve)](#4-détendeur-expansion-valve) 5. [Conduite (pipe)](#5-conduite-pipe) 6. [Pompe](#6-pompe) 7. [Ventilateur](#7-ventilateur) 8. [Échangeurs de chaleur](#8-échangeurs-de-chaleur) 9. [Machine à états (ON/OFF/BYPASS)](#9-machine-à-états-onoffbypass) 10. [Polynômes et courbes de performance](#10-polynômes-et-courbes-de-performance) --- ## 1. Types physiques (entropyk-core) Les types physiques utilisent le pattern NewType pour la sécurité des unités à la compilation. ```rust use entropyk_core::{Pressure, Enthalpy, Temperature, MassFlow, Power}; fn main() { // Pression : Pascals, bar, PSI let p = Pressure::from_bar(3.5); println!("Pression: {} Pa = {:.2} bar", p.to_pascals(), p.to_bar()); // Enthalpie : J/kg let h = Enthalpy::from_joules_per_kg(400_000.0); println!("Enthalpie: {:.0} J/kg", h.to_joules_per_kg()); // Température : Kelvin, Celsius, Fahrenheit let t = Temperature::from_celsius(25.0); println!("Température: {:.2} K = {:.1} °C", t.to_kelvin(), t.to_celsius()); // Débit massique : kg/s let m = MassFlow::from_kg_per_s(0.05); println!("Débit: {:.4} kg/s", m.to_kg_per_s()); // Puissance : Watts let w = Power::from_watts(1500.0); println!("Puissance: {:.0} W", w.to_watts()); // Opérations arithmétiques let p2 = p + Pressure::from_bar(1.0); let p3 = p * 2.0; } ``` --- ## 2. Ports et connexions Le système de ports utilise le **Type-State pattern** : les ports doivent être connectés avant utilisation dans le solveur. ```rust use entropyk_components::port::{Port, FluidId, ConnectionError}; use entropyk_core::{Pressure, Enthalpy}; fn main() -> Result<(), ConnectionError> { // Créer deux ports déconnectés (même fluide, pression et enthalpie pour validation) let port1 = Port::new( FluidId::new("R134a"), Pressure::from_bar(1.0), Enthalpy::from_joules_per_kg(400_000.0), ); let port2 = Port::new( FluidId::new("R134a"), Pressure::from_bar(1.0), Enthalpy::from_joules_per_kg(400_000.0), ); // Connecter les ports let (mut connected1, mut connected2) = port1.connect(port2)?; // Une fois connectés, on peut lire et modifier les valeurs println!("Pression port 1: {:.2} bar", connected1.pressure().to_bar()); connected1.set_pressure(Pressure::from_bar(1.5)); connected1.set_enthalpy(Enthalpy::from_joules_per_kg(450_000.0)); Ok(()) } ``` ### Gestion des erreurs de connexion ```rust use entropyk_components::port::{Port, FluidId, ConnectionError}; use entropyk_core::{Pressure, Enthalpy}; fn main() { // Erreur : fluides incompatibles let r134a = Port::new( FluidId::new("R134a"), Pressure::from_bar(1.0), Enthalpy::from_joules_per_kg(400_000.0), ); let water = Port::new( FluidId::new("Water"), Pressure::from_bar(1.0), Enthalpy::from_joules_per_kg(400_000.0), ); match r134a.connect(water) { Err(ConnectionError::IncompatibleFluid { from, to }) => { println!("Erreur: {} et {} sont incompatibles", from, to); } _ => {} } // Erreur : pression différente let p1 = Port::new( FluidId::new("R134a"), Pressure::from_pascals(100_000.0), Enthalpy::from_joules_per_kg(400_000.0), ); let p2 = Port::new( FluidId::new("R134a"), Pressure::from_pascals(200_000.0), Enthalpy::from_joules_per_kg(400_000.0), ); match p1.connect(p2) { Err(ConnectionError::PressureMismatch { .. }) => { println!("Erreur: pression non compatible"); } _ => {} } } ``` --- ## 3. Compresseur (AHRI 540) Le compresseur utilise les coefficients AHRI 540 pour le débit massique et la puissance. ```rust use entropyk_components::compressor::{Compressor, Ahri540Coefficients}; use entropyk_components::port::{FluidId, Port}; use entropyk_core::{Pressure, Enthalpy}; fn main() -> Result<(), Box> { // Coefficients AHRI 540 (exemple typique) let coeffs = Ahri540Coefficients::new( 0.85, 2.5, // M1, M2 (débit) 500.0, 1500.0, -2.5, 1.8, // M3-M6 (puissance refroidissement) 600.0, 1600.0, -3.0, 2.0 // M7-M10 (puissance chauffage) ); // Créer les ports (même P et h pour validation) let suction = Port::new( FluidId::new("R134a"), Pressure::from_bar(3.5), Enthalpy::from_joules_per_kg(400_000.0), ); let discharge = Port::new( FluidId::new("R134a"), Pressure::from_bar(3.5), Enthalpy::from_joules_per_kg(400_000.0), ); // Créer le compresseur déconnecté let compressor = Compressor::new( coeffs, suction, discharge, 2900.0, // RPM 0.0001, // Volume balayé (m³/tour) 0.85 // Rendement mécanique )?; println!("Compresseur créé: fluide={}, vitesse={} RPM", compressor.fluid_id(), compressor.speed_rpm() ); Ok(()) } ``` ### Modèle SST/SDT (températures de saturation) ```rust use entropyk_components::compressor::{Compressor, SstSdtCoefficients}; use entropyk_components::polynomials::Polynomial2D; // Modèle bilinéaire: ṁ = a00 + a10*SST + a01*SDT + a11*SST*SDT let mass_coeffs = SstSdtCoefficients::bilinear( 0.05, 0.001, 0.0005, 0.00001, // coefficients débit 1000.0, 50.0, 30.0, 0.5 // coefficients puissance ); // Évaluer à SST=273K, SDT=313K let mass_flow = mass_coeffs.mass_flow_at(273.15, 313.15); let power = mass_coeffs.power_at(273.15, 313.15); ``` --- ## 4. Détendeur (expansion valve) Le détendeur modélise une détente isenthalpique (h_out = h_in). ```rust use entropyk_components::expansion_valve::ExpansionValve; use entropyk_components::port::{FluidId, Port}; use entropyk_core::{Pressure, Enthalpy}; fn main() -> Result<(), Box> { let inlet = Port::new( FluidId::new("R134a"), Pressure::from_bar(10.0), Enthalpy::from_joules_per_kg(250_000.0), ); let outlet = Port::new( FluidId::new("R134a"), Pressure::from_bar(10.0), Enthalpy::from_joules_per_kg(250_000.0), ); // Ouverture optionnelle: None = variable, Some(1.0) = pleinement ouvert let valve = ExpansionValve::new(inlet, outlet, Some(1.0))?; println!("Détendeur créé: fluide={}", valve.fluid_id()); // États opérationnels: On, Off, Bypass // valve.set_operational_state(OperationalState::Off); Ok(()) } ``` --- ## 5. Conduite (pipe) Modélisation de la perte de charge avec l'équation de Darcy-Weisbach. ```rust use entropyk_components::pipe::{Pipe, PipeGeometry, roughness}; use entropyk_components::port::{FluidId, Port}; use entropyk_core::{Pressure, Enthalpy}; fn main() -> Result<(), Box> { // Géométrie: 10m de tuyau cuivre 22mm, lisse let geometry = PipeGeometry::new( 10.0, // longueur (m) 0.022, // diamètre intérieur (m) roughness::SMOOTH, // rugosité (m) )?; let inlet = Port::new( FluidId::new("Water"), Pressure::from_bar(2.0), Enthalpy::from_joules_per_kg(84_000.0), ); let outlet = Port::new( FluidId::new("Water"), Pressure::from_bar(2.0), Enthalpy::from_joules_per_kg(84_000.0), ); // Eau à 20°C: ρ≈998 kg/m³, μ≈0.001 Pa·s let pipe = Pipe::new( geometry, inlet, outlet, 998.0, // densité 0.001, // viscosité )?; println!("Conduite créée: L={}m, D={}m", pipe.geometry().length_m, pipe.geometry().diameter_m ); Ok(()) } ``` ### Rugosités typiques ```rust use entropyk_components::pipe::roughness; // roughness::SMOOTH // Cuivre, plastique (0.0015 mm) // roughness::STEEL_COMMERCIAL // Acier commercial (0.045 mm) // roughness::GALVANIZED_IRON // Fer galvanisé (0.15 mm) // roughness::CAST_IRON // Fonte (0.26 mm) // roughness::PLASTIC // PVC/HDPE (0.0015 mm) ``` --- ## 6. Pompe Courbes de performance polynomiales + lois d'affinité pour la variation de vitesse. ```rust use entropyk_components::pump::{Pump, PumpCurves}; use entropyk_components::port::{FluidId, Port}; use entropyk_core::{Pressure, Enthalpy}; fn main() -> Result<(), Box> { // Courbe hauteur: H = 30 - 10*Q - 50*Q² (m) // Courbe rendement: η = 0.5 + 0.3*Q - 0.5*Q² let curves = PumpCurves::quadratic( 30.0, -10.0, -50.0, // H = h0 + h1*Q + h2*Q² 0.5, 0.3, -0.5, // η = e0 + e1*Q + e2*Q² )?; let inlet = Port::new( FluidId::new("Water"), Pressure::from_bar(1.0), Enthalpy::from_joules_per_kg(100_000.0), ); let outlet = Port::new( FluidId::new("Water"), Pressure::from_bar(1.0), Enthalpy::from_joules_per_kg(100_000.0), ); let pump = Pump::new(curves, inlet, outlet, 1000.0)?; // Évaluer la courbe à un débit donné (pompe connectée requise pour pressure_rise) let head = pump.curves().head_at_flow(0.05); let eff = pump.curves().efficiency_at_flow(0.05); println!("À Q=0.05 m³/s: H={:.2} m, η={:.2}%", head, eff * 100.0); Ok(()) } ``` --- ## 7. Ventilateur Similaire à la pompe, avec courbe de pression statique. ```rust use entropyk_components::fan::{Fan, FanCurves}; use entropyk_components::port::{FluidId, Port}; use entropyk_core::{Pressure, Enthalpy}; fn main() -> Result<(), Box> { // Courbe pression statique (Pa) et rendement let curves = FanCurves::quadratic( 500.0, -100.0, -50.0, // P_s = p0 + p1*Q + p2*Q² 0.4, 0.2, -0.3, // η )?; let inlet = Port::new( FluidId::new("Air"), Pressure::from_pascals(101_325.0), Enthalpy::from_joules_per_kg(300_000.0), ); let outlet = Port::new( FluidId::new("Air"), Pressure::from_pascals(101_325.0), Enthalpy::from_joules_per_kg(300_000.0), ); let fan = Fan::new(curves, inlet, outlet, 1.2)?; // ρ_air ≈ 1.2 kg/m³ let pressure = fan.curves().static_pressure_at_flow(1.0); println!("À Q=1 m³/s: ΔP={:.0} Pa", pressure); Ok(()) } ``` --- ## 8. Échangeurs de chaleur ### Condenseur (LMTD) ```rust use entropyk_components::heat_exchanger::Condenser; // UA = 10 kW/K let condenser = Condenser::new(10_000.0); // Avec température de saturation personnalisée let condenser = Condenser::with_saturation_temp(15_000.0, 323.15); println!("Condenseur: UA={} W/K, n_equations={}", condenser.ua(), condenser.n_equations()); ``` ### Évaporateur ```rust use entropyk_components::heat_exchanger::Evaporator; let evaporator = Evaporator::new(8_000.0); ``` ### Économiseur ```rust use entropyk_components::heat_exchanger::Economizer; let economizer = Economizer::new(5_000.0); ``` ### Modèles de transfert (LMTD vs ε-NTU) ```rust use entropyk_components::heat_exchanger::{LmtdModel, EpsNtuModel, FlowConfiguration, ExchangerType}; // LMTD - contre-courant let lmtd = LmtdModel::new(5000.0, FlowConfiguration::CounterFlow); // ε-NTU - échangeur à plaques let eps_ntu = EpsNtuModel::new(5000.0, ExchangerType::CounterFlow); ``` --- ## 9. Machine à états (ON/OFF/BYPASS) Les composants supportent trois états opérationnels (FR6-FR8). ```rust use entropyk_components::state_machine::{OperationalState, CircuitId, StateManageable}; fn main() { // États disponibles let on = OperationalState::On; // Opération normale let off = OperationalState::Off; // Débit nul let bypass = OperationalState::Bypass; // Conduite adiabatique (P_in=P_out, h_in=h_out) // Propriétés des états println!("On actif: {}", on.is_active()); println!("Multiplicateur débit Off: {}", off.mass_flow_multiplier()); // 0.0 println!("Multiplicateur débit Bypass: {}", bypass.mass_flow_multiplier()); // 1.0 // Transitions assert!(on.can_transition_to(OperationalState::Off)); // Identification des circuits (multi-circuit, ex: PAC double circuit) let circuit_primary = CircuitId::new("primary"); let circuit_secondary = CircuitId::new("secondary"); println!("Circuit: {}", circuit_primary); } ``` ### Utilisation avec un composant ```rust // Sur un compresseur, pompe, détendeur, etc. // compressor.set_operational_state(OperationalState::Off); // pump.set_speed_ratio(0.5); // 50% vitesse pour VFD ``` --- ## 10. Polynômes et courbes de performance ### Polynôme 1D ```rust use entropyk_components::polynomials::Polynomial1D; // P(x) = 1 + 2x + 3x² let poly = Polynomial1D::new(vec![1.0, 2.0, 3.0]); let y = poly.evaluate(2.0); // 1 + 4 + 12 = 17 ``` ### Polynôme 2D ```rust use entropyk_components::polynomials::Polynomial2D; // Modèle bilinéaire: f(x,y) = a00 + a10*x + a01*y + a11*x*y let poly = Polynomial2D::bilinear(1.0, 0.1, 0.2, 0.01); let z = poly.evaluate(10.0, 20.0); ``` ### Lois d'affinité (pompes/ventilateurs) ```rust use entropyk_components::polynomials::AffinityLaws; // À 50% de vitesse: Q₂/Q₁=0.5, H₂/H₁=0.25, P₂/P₁=0.125 let ratio = 0.5; let flow_ratio = AffinityLaws::flow_ratio(ratio); // 0.5 let head_ratio = AffinityLaws::head_ratio(ratio); // 0.25 let power_ratio = AffinityLaws::power_ratio(ratio); // 0.125 ``` --- ## Exécution des exemples ### Binaires de démonstration ```bash # State Machine (compresseur ON/OFF/BYPASS) cargo run -p entropyk-demo --bin compressor-test # Ports et connexions cargo run -p entropyk-demo --bin ports # Détendeur cargo run -p entropyk-demo --bin expansion_valve # Conduite cargo run -p entropyk-demo --bin pipe # Pompe cargo run -p entropyk-demo --bin pump ``` ### Tests ```bash cargo test --workspace cargo test -p entropyk-components cargo test -p entropyk-core ``` ### Documentation ```bash cargo doc --workspace --open ``` --- ## Composants développés (état actuel) | Composant | Statut | Trait Component | |-----------|--------|-----------------| | Port/Connexion | ✅ | - | | Compresseur (AHRI 540, SST/SDT) | ✅ | ✅ | | Détendeur | ✅ | ✅ | | Conduite | ✅ | ✅ | | Pompe | ✅ | ✅ | | Ventilateur | ✅ | ✅ | | Condenseur/Évaporateur/Économiseur | ✅ | ✅ | | Modèle externe | ✅ | ✅ | | State Machine | ✅ | - | --- *Document généré à partir du code et de README_STORY_1_3.md - Février 2026*