10 KiB
Story 10.4: AirSource et AirSink avec Propriétés Psychrométriques
Epic: 10 - Enhanced Boundary Conditions
Priorité: P1-HIGH
Estimation: 4h
Statut: done
Dépendances: Story 10-1 (Nouveaux types physiques)
Story
En tant que moteur de simulation thermodynamique,
Je veux queAirSourceetAirSinksupportent les propriétés psychrométriques,
Afin de pouvoir simuler les côtés air des échangeurs de chaleur (évaporateurs, condenseurs).
Acceptance Criteria
AirSource::from_dry_bulb_rh()crée une source avec T sèche et HRAirSource::from_dry_and_wet_bulb()calcule HR depuis T bulbe humidespecific_enthalpy()retourne l'enthalpie de l'air humidehumidity_ratio()retourne le rapport d'humiditéAirSink::new()crée un puits à pression atmosphériqueenergy_transfers()retourne(Power(0), Power(0))- Validation de l'humidité relative (0-100%)
- Tests unitaires avec valeurs de référence ASHRAE
Tasks / Subtasks
-
Task 1: Implémenter AirSource (AC: #1, #2, #3, #4, #7)
- 1.1 Créer struct avec champs :
t_dry_k,rh,p_set_pa,w(calculé),h_set_jkg(calculé),outlet - 1.2 Implémenter
from_dry_bulb_rh()avec calculs psychrométriques (W, h) - 1.3 Implémenter
from_dry_and_wet_bulb()via formule de Sprung - 1.4 Implémenter
Component::compute_residuals()(2 équations) - 1.5 Implémenter
Component::jacobian_entries()(diagonal 1.0) - 1.6 Implémenter
Component::get_ports(),port_mass_flows(),port_enthalpies(),energy_transfers() - 1.7 Ajouter accesseurs :
t_dry(),rh(),p_set(),humidity_ratio(),h_set() - 1.8 Ajouter setters :
set_temperature(),set_rh()(recalcul automatique)
- 1.1 Créer struct avec champs :
-
Task 2: Implémenter AirSink (AC: #5, #6)
- 2.1 Créer struct avec champs :
p_back_pa,t_back_k(optional),rh_back(optional),h_back_jkg(optional),inlet - 2.2 Implémenter
new()constructor (1-équation mode par défaut) - 2.3 Implémenter count dynamique d'équations (1 ou 2)
- 2.4 Implémenter méthodes
Componenttrait - 2.5 Ajouter
set_return_temperature(),clear_return_temperature()pour toggle dynamique
- 2.1 Créer struct avec champs :
-
Task 3: Fonctions psychrométriques (AC: #3, #4, #8)
- 3.1 Implémenter
saturation_vapor_pressure()(Magnus-Tetens) - 3.2 Implémenter
humidity_ratio_from_rh() - 3.3 Implémenter
specific_enthalpy_from_w() - 3.4 Implémenter
rh_from_wet_bulb()(formule de Sprung)
- 3.1 Implémenter
-
Task 4: Intégration du module (AC: #5, #6)
- 4.1 Ajouter
pub mod air_boundarydanscrates/components/src/lib.rs - 4.2 Ajouter
pub use air_boundary::{AirSink, AirSource}
- 4.1 Ajouter
-
Task 5: Tests (AC: #1-8)
- 5.1 Tests AirSource :
from_dry_bulb_rh,from_dry_and_wet_bulb, wet > dry retourne erreur - 5.2 Tests psychrométriques :
saturation_vapor_pressure(ASHRAE ref),humidity_ratio,specific_enthalpy - 5.3 Tests AirSink : création, pression invalide, toggle dynamique
- 5.4 Tests résiduels zéro au set-point (AirSource et AirSink 1-eq et 2-eq)
- 5.5 Tests trait object (
Box<dyn Component>) - 5.6 Tests
energy_transfers()= (0, 0) - 5.7 Tests signatures
- 5.1 Tests AirSource :
-
Task 6: Validation
- 6.1
cargo test --package entropyk-components --lib -- air_boundary→ 23 passed, 0 failed - 6.2
cargo test --package entropyk-components --lib→ 469 passed, 0 failed (aucune régression) - 6.3 Aucun avertissement clippy dans
air_boundary.rs
- 6.1
-
Task 7: Code Review Fixes (AI-Review)
- 7.1 Fixed
set_temperature()andset_rh()to returnResult<(), ComponentError> - 7.2 Fixed
humidity_ratio_from_rh()to returnResult<f64, ComponentError>instead of silent 0.0 - 7.3 Added validation for P_v >= P_atm error case
- 7.4 Updated Sprung formula documentation for unventilated psychrometers
- 7.5 Tightened ASHRAE test tolerances (0.5% for P_sat, 1% for h and W)
- 7.6 Tightened specific_enthalpy test range (45-56 kJ/kg for 25°C/50%RH)
- 7.7 Updated File List with missing files from Epic 10
- 7.1 Fixed
Dev Notes
Architecture Patterns (MUST follow)
- NewType Pattern: Utiliser
RelativeHumiditydeentropyk_core, jamaisf64nu pour l'humidité - Zero-Panic Policy: Toutes les méthodes retournent
Result<T, ComponentError> - Component Trait: Implémenter toutes les méthodes du trait de façon identique aux composants existants
- Pas de dépendance backend: Contrairement à BrineSource/RefrigerantSource, AirSource utilise des formules analytiques (Magnus-Tetens) — pas besoin de
FluidBackend
Pattern suivi
Ce composant suit le pattern exact de brine_boundary.rs et refrigerant_boundary.rs, avec les différences :
| Aspect | RefrigerantSource | BrineSource | AirSource |
|---|---|---|---|
| État spec | (P, VaporQuality) | (P, T, Concentration) | (T_dry, RH, P_atm) |
| Validation fluide | !is_incompressible() |
is_incompressible() |
aucune (air) |
| Backend requis | Oui | Oui | Non (analytique) |
| Calcul enthalpie | FluidBackend::PQ | FluidBackend::PT | Magnus-Tetens |
Formules Psychrométriques
// Pression de saturation (Magnus-Tetens)
P_sat = 610.78 * exp(17.27 * T_c / (T_c + 237.3)) [Pa]
// Rapport d'humidité
W = 0.622 * P_v / (P_atm - P_v) où P_v = RH * P_sat
// Enthalpie spécifique [J/kg_da]
h = 1006 * T_c + W * (2_501_000 + 1860 * T_c)
// Humidité relative depuis bulbe humide (Sprung)
e = e_sat(T_wet) - 6.6e-4 * (T_dry - T_wet) * P_atm
RH = e / e_sat(T_dry)
Fichier créé
crates/components/src/air_boundary.rs— AirSource, AirSink, helpers psychrométriques
Fix préexistant
Corrigé flooded_evaporator.rs:171-172 qui utilisait une méthode inexistante enthalpy_px(). Remplacé par l'appel correct via FluidBackend::property() avec FluidState::from_px().
Dev Agent Record
Agent Model Used
openrouter/anthropic/claude-sonnet-4.6
Debug Log References
Aucun blocage. Fix d'une erreur de compilation préexistante dans flooded_evaporator.rs (méthode enthalpy_px inexistante remplacée par backend.property(...) avec FluidState::from_px(...)).
Completion Notes List
- Créé
crates/components/src/air_boundary.rsavecAirSourceetAirSink - Implémenté 4 helpers psychrométriques :
saturation_vapor_pressure,humidity_ratio_from_rh,specific_enthalpy_from_w,rh_from_wet_bulb - Utilisé
RelativeHumiditydeentropyk_corepour la sécurité des types - Aucune dépendance au
FluidBackend— formules analytiques Magnus-Tetens AirSinkdynamique : toggle entre 1-équation (pression seule) et 2-équations (P + h)- 23 tests unitaires passent dont 3 validations ASHRAE de référence
- 469 tests au total dans le package, 0 régression
- Module exporté dans
lib.rsavecAirSourceetAirSink - Fix secondaire :
flooded_evaporator.rserreur de compilation préexistante corrigée
File List
crates/components/src/air_boundary.rs(créé)crates/components/src/lib.rs(modifié — ajout module + re-exports)crates/components/src/heat_exchanger/flooded_evaporator.rs(modifié — fix erreur de compilation préexistante)
Files Created in Epic 10 (Related Context)
crates/components/src/brine_boundary.rs(créé — Story 10-3)crates/components/src/refrigerant_boundary.rs(créé — Story 10-2)crates/components/src/drum.rs(créé — Story 11-2)
Change Log
- 2026-02-23: Implémentation AirSource et AirSink avec propriétés psychrométriques complètes (Story 10-4)
- 2026-02-23: Code Review (AI) — Fixed 8 issues:
- Fixed
set_temperature()andset_rh()to returnResultwith proper error handling - Fixed
humidity_ratio_from_rh()to returnResultinstead of silent 0.0 on invalid P_v - Added validation for P_v >= P_atm (now returns descriptive error)
- Updated Sprung formula documentation to clarify unventilated psychrometer assumption
- Tightened ASHRAE test tolerances: P_sat (0.5%), enthalpy (1%), humidity ratio (1%)
- Tightened specific_enthalpy test range from (40-80) to (45-56) kJ/kg
- Updated File List with related files from Epic 10
- 23 tests pass, 0 regressions, 0 air_boundary clippy warnings
- Fixed
Senior Developer Review (AI)
Reviewer: Claude-4 (Sonnet)
Date: 2026-02-23
Outcome: ✅ APPROVED with Fixes Applied
Issues Found and Fixed
🔴 Critical (1)
- Missing Result type on setters —
set_temperature()andset_rh()did not returnResultdespite potential failure modes. FIXED: Both now returnResult<(), ComponentError>with proper validation.
🟡 High (2)
-
Sprung formula assumptions undocumented — The psychrometric constant A_psy = 6.6e-4 is specific to unventilated psychrometers. FIXED: Added explicit documentation about this assumption.
-
ASHRAE test tolerances too loose — Original tolerances (1.6% for P_sat, 2.6% for h) were too permissive. FIXED: Tightened to 0.5% for P_sat and 1% for h and W.
🟡 Medium (2)
-
File List incomplete — Story documented only 3 files but Epic 10 created 6+ files. FIXED: Added "Files Created in Epic 10 (Related Context)" section.
-
Silent error handling —
humidity_ratio_from_rh()returned 0.0 when P_v >= P_atm instead of error. FIXED: Now returns descriptiveComponentError::InvalidState.
🟢 Low (3)
- RH clamping without warning — Documented behavior, acceptable for production use.
- Test enthalpy range too wide — Was 40-80 kJ/kg, now 45-56 kJ/kg (ASHRAE standard).
- Documentation mismatch — Setter docs claimed Result return type but didn't implement it. FIXED: Implementation now matches documentation.
Verification
- ✅ All 23 air_boundary tests pass
- ✅ All 469 component tests pass (0 regressions)
- ✅ 0 clippy warnings specific to air_boundary.rs
- ✅ All Acceptance Criteria validated
- ✅ All Tasks marked [x] verified complete
Recommendation
Story is READY FOR PRODUCTION. All critical and high issues resolved. Test coverage excellent (23 tests, including 3 ASHRAE reference validations).