feat(components): add ThermoState generators and Eurovent backend demo
This commit is contained in:
553
EXAMPLES.md
Normal file
553
EXAMPLES.md
Normal file
@@ -0,0 +1,553 @@
|
||||
# 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<dyn std::error::Error>> {
|
||||
// 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<dyn std::error::Error>> {
|
||||
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<dyn std::error::Error>> {
|
||||
// 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<dyn std::error::Error>> {
|
||||
// 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<dyn std::error::Error>> {
|
||||
// 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*
|
||||
Reference in New Issue
Block a user