# Story 10.3: BrineSource et BrineSink avec Support Glycol **Epic:** 10 - Enhanced Boundary Conditions **Priorité:** P0-CRITIQUE **Estimation:** 3h **Statut:** backlog **Dépendances:** Story 10-1 (Nouveaux types physiques) --- ## Story > En tant que moteur de simulation thermodynamique, > Je veux que `BrineSource` et `BrineSink` supportent les mélanges eau-glycol avec concentration, > Afin de pouvoir simuler des circuits de caloporteurs avec propriétés thermophysiques correctes. --- ## Contexte Les caloporteurs liquides (eau, PEG, MEG, saumures) sont utilisés dans: - Circuits primaire/secondaire de chillers - Systèmes de chauffage urbain - Applications basse température avec protection antigel La **concentration en glycol** affecte: - Viscosité (perte de charge) - Chaleur massique (capacité thermique) - Point de congélation (protection antigel) --- ## Spécifications Techniques ### BrineSource ```rust /// Source pour fluides caloporteurs liquides (eau, PEG, MEG, saumures). /// /// Impose une température et une pression fixées sur le port de sortie. /// La concentration en glycol est prise en compte pour les propriétés. #[derive(Debug, Clone)] pub struct BrineSource { /// Identifiant du fluide (ex: "Water", "MEG", "PEG") fluid_id: String, /// Concentration en glycol (% massique, 0 = eau pure) concentration: Concentration, /// Température de set-point [K] t_set: Temperature, /// Pression de set-point [Pa] p_set: Pressure, /// Enthalpie calculée depuis T et concentration [J/kg] h_set: Enthalpy, /// Débit massique optionnel [kg/s] mass_flow: Option, /// Débit volumique optionnel [m³/s] volume_flow: Option, /// Port de sortie connecté outlet: ConnectedPort, } impl BrineSource { /// Crée une source d'eau pure. pub fn water( temperature: Temperature, pressure: Pressure, outlet: ConnectedPort, ) -> Result; /// Crée une source de mélange eau-glycol. pub fn glycol_mixture( fluid_id: impl Into, concentration: Concentration, temperature: Temperature, pressure: Pressure, outlet: ConnectedPort, ) -> Result; /// Définit le débit massique imposé. pub fn set_mass_flow(&mut self, mass_flow: MassFlow); /// Définit le débit volumique imposé. /// Le débit massique est calculé avec la masse volumique du mélange. pub fn set_volume_flow(&mut self, volume_flow: VolumeFlow, density: f64); } ``` ### BrineSink ```rust /// Puits pour fluides caloporteurs liquides. #[derive(Debug, Clone)] pub struct BrineSink { /// Identifiant du fluide fluid_id: String, /// Concentration en glycol concentration: Concentration, /// Contre-pression [Pa] p_back: Pressure, /// Température de retour optionnelle [K] t_back: Option, /// Port d'entrée connecté inlet: ConnectedPort, } impl BrineSink { /// Crée un puits pour eau pure. pub fn water( pressure: Pressure, inlet: ConnectedPort, ) -> Result; /// Crée un puits pour mélange eau-glycol. pub fn glycol_mixture( fluid_id: impl Into, concentration: Concentration, pressure: Pressure, inlet: ConnectedPort, ) -> Result; } ``` --- ## Calcul des Propriétés ### Enthalpie depuis Température et Concentration ```rust /// Calcule l'enthalpie d'un mélange eau-glycol. /// /// Utilise CoolProp avec la syntaxe de mélange: /// - Eau pure: "Water" /// - Mélange MEG: "MEG-MASS%" ou "INCOMP::MEG-MASS%" fn calculate_enthalpy( fluid_id: &str, concentration: Concentration, temperature: Temperature, pressure: Pressure, ) -> Result { // Pour CoolProp, utiliser: // PropsSI("H", "T", T, "P", P, fluid_string) // où fluid_string = format!("INCOMP::{}-{}", fluid_id, concentration.to_percent()) } ``` --- ## Fichiers à Créer/Modifier | Fichier | Action | |---------|--------| | `crates/components/src/flow_boundary/brine.rs` | Créer `BrineSource`, `BrineSink` | | `crates/components/src/flow_boundary/mod.rs` | Ajouter ré-exports | --- ## Critères d'Acceptation - [ ] `BrineSource::water()` crée une source d'eau pure - [ ] `BrineSource::glycol_mixture()` crée une source avec concentration - [ ] L'enthalpie est calculée correctement depuis T et concentration - [ ] `BrineSink::water()` crée un puits pour eau - [ ] `BrineSink::glycol_mixture()` crée un puits avec concentration - [ ] `energy_transfers()` retourne `(Power(0), Power(0))` - [ ] `port_enthalpies()` retourne `[h_set]` - [ ] Validation de la concentration (0-100%) - [ ] Tests unitaires avec différents pourcentages de glycol --- ## Tests Requis ```rust #[cfg(test)] mod tests { #[test] fn test_brine_source_water() { /* ... */ } #[test] fn test_brine_source_meg_30_percent() { /* ... */ } #[test] fn test_brine_source_enthalpy_calculation() { /* ... */ } #[test] fn test_brine_source_volume_flow_conversion() { /* ... */ } #[test] fn test_brine_sink_water() { /* ... */ } #[test] fn test_brine_sink_meg_mixture() { /* ... */ } } ``` --- ## Notes d'Implémentation ### Support CoolProp pour Mélanges CoolProp supporte les mélanges incompressibles via la syntaxe: ``` INCOMP::MEG-30 // MEG à 30% massique INCOMP::PEG-40 // PEG à 40% massique ``` Vérifier que le backend CoolProp utilisé dans le projet supporte cette syntaxe. --- ## Références - [Architecture Document](../../plans/boundary-condition-refactoring-architecture.md) - [Story 10-1: Nouveaux types physiques](./10-1-new-physical-types.md) - [CoolProp Incompressible Fluids](http://www.coolprop.org/fluid_properties/Incompressibles.html)