chore: sync project state and current artifacts
This commit is contained in:
@@ -0,0 +1,195 @@
|
||||
# Story 10.2: RefrigerantSource et RefrigerantSink
|
||||
|
||||
**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 `RefrigerantSource` et `RefrigerantSink` implémentent le trait `Component`,
|
||||
> Afin de pouvoir définir des conditions aux limites pour les fluides frigorigènes avec titre.
|
||||
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
Les fluides frigorigènes (R410A, R134a, CO2, etc.) nécessitent des conditions aux limites spécifiques:
|
||||
|
||||
- Possibilité de spécifier le **titre** (vapor quality) au lieu de l'enthalpie
|
||||
- Validation que le fluide est bien un réfrigérant
|
||||
- Support des propriétés thermodynamiques via CoolProp
|
||||
|
||||
---
|
||||
|
||||
## Spécifications Techniques
|
||||
|
||||
### RefrigerantSource
|
||||
|
||||
```rust
|
||||
/// Source pour fluides frigorigènes compressibles.
|
||||
///
|
||||
/// Impose une pression et une enthalpie (ou titre) fixées sur le port de sortie.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RefrigerantSource {
|
||||
/// Identifiant du fluide frigorigène (ex: "R410A", "R134a", "CO2")
|
||||
fluid_id: String,
|
||||
/// Pression de set-point [Pa]
|
||||
p_set: Pressure,
|
||||
/// Enthalpie de set-point [J/kg]
|
||||
h_set: Enthalpy,
|
||||
/// Titre optionnel (vapor quality, 0-1)
|
||||
vapor_quality: Option<VaporQuality>,
|
||||
/// Débit massique optionnel [kg/s]
|
||||
mass_flow: Option<MassFlow>,
|
||||
/// Port de sortie connecté
|
||||
outlet: ConnectedPort,
|
||||
}
|
||||
|
||||
impl RefrigerantSource {
|
||||
/// Crée une source réfrigérant avec pression et enthalpie fixées.
|
||||
pub fn new(
|
||||
fluid_id: impl Into<String>,
|
||||
pressure: Pressure,
|
||||
enthalpy: Enthalpy,
|
||||
outlet: ConnectedPort,
|
||||
) -> Result<Self, ComponentError>;
|
||||
|
||||
/// Crée une source réfrigérant avec pression et titre fixés.
|
||||
/// L'enthalpie est calculée automatiquement via CoolProp.
|
||||
pub fn with_vapor_quality(
|
||||
fluid_id: impl Into<String>,
|
||||
pressure: Pressure,
|
||||
vapor_quality: VaporQuality,
|
||||
outlet: ConnectedPort,
|
||||
) -> Result<Self, ComponentError>;
|
||||
|
||||
/// Définit le débit massique imposé.
|
||||
pub fn set_mass_flow(&mut self, mass_flow: MassFlow);
|
||||
}
|
||||
```
|
||||
|
||||
### RefrigerantSink
|
||||
|
||||
```rust
|
||||
/// Puits pour fluides frigorigènes compressibles.
|
||||
///
|
||||
/// Impose une contre-pression fixe sur le port d'entrée.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RefrigerantSink {
|
||||
/// Identifiant du fluide frigorigène
|
||||
fluid_id: String,
|
||||
/// Contre-pression [Pa]
|
||||
p_back: Pressure,
|
||||
/// Enthalpie de retour optionnelle [J/kg]
|
||||
h_back: Option<Enthalpy>,
|
||||
/// Port d'entrée connecté
|
||||
inlet: ConnectedPort,
|
||||
}
|
||||
|
||||
impl RefrigerantSink {
|
||||
/// Crée un puits réfrigérant avec contre-pression fixe.
|
||||
pub fn new(
|
||||
fluid_id: impl Into<String>,
|
||||
pressure: Pressure,
|
||||
inlet: ConnectedPort,
|
||||
) -> Result<Self, ComponentError>;
|
||||
|
||||
/// Définit une enthalpie de retour fixe.
|
||||
pub fn set_return_enthalpy(&mut self, enthalpy: Enthalpy);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Implémentation du Trait Component
|
||||
|
||||
```rust
|
||||
impl Component for RefrigerantSource {
|
||||
fn n_equations(&self) -> usize { 2 }
|
||||
|
||||
fn compute_residuals(&self, _state: &SystemState, residuals: &mut ResidualVector)
|
||||
-> Result<(), ComponentError>
|
||||
{
|
||||
residuals[0] = self.outlet.pressure().to_pascals() - self.p_set.to_pascals();
|
||||
residuals[1] = self.outlet.enthalpy().to_joules_per_kg() - self.h_set.to_joules_per_kg();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn energy_transfers(&self, _state: &SystemState) -> Option<(Power, Power)> {
|
||||
Some((Power::from_watts(0.0), Power::from_watts(0.0)))
|
||||
}
|
||||
|
||||
fn port_enthalpies(&self, _state: &SystemState) -> Result<Vec<Enthalpy>, ComponentError> {
|
||||
Ok(vec![self.h_set])
|
||||
}
|
||||
|
||||
fn port_mass_flows(&self, _state: &SystemState) -> Result<Vec<MassFlow>, ComponentError> {
|
||||
match self.mass_flow {
|
||||
Some(mdot) => Ok(vec![MassFlow::from_kg_per_s(-mdot.to_kg_per_s())]),
|
||||
None => Ok(vec![]),
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Fichiers à Créer/Modifier
|
||||
|
||||
| Fichier | Action |
|
||||
|---------|--------|
|
||||
| `crates/components/src/flow_boundary/mod.rs` | Créer module avec ré-exports |
|
||||
| `crates/components/src/flow_boundary/refrigerant.rs` | Créer `RefrigerantSource`, `RefrigerantSink` |
|
||||
| `crates/components/src/lib.rs` | Exporter les nouveaux types |
|
||||
|
||||
---
|
||||
|
||||
## Critères d'Acceptation
|
||||
|
||||
- [ ] `RefrigerantSource::new()` crée une source avec P et h fixées
|
||||
- [ ] `RefrigerantSource::with_vapor_quality()` calcule l'enthalpie depuis le titre
|
||||
- [ ] `RefrigerantSink::new()` crée un puits avec contre-pression
|
||||
- [ ] `energy_transfers()` retourne `(Power(0), Power(0))`
|
||||
- [ ] `port_enthalpies()` retourne `[h_set]`
|
||||
- [ ] `port_mass_flows()` retourne le débit si spécifié
|
||||
- [ ] Validation que le fluide est un réfrigérant valide
|
||||
- [ ] Tests unitaires complets
|
||||
|
||||
---
|
||||
|
||||
## Tests Requis
|
||||
|
||||
```rust
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn test_refrigerant_source_new() { /* ... */ }
|
||||
|
||||
#[test]
|
||||
fn test_refrigerant_source_with_vapor_quality() { /* ... */ }
|
||||
|
||||
#[test]
|
||||
fn test_refrigerant_source_energy_transfers_zero() { /* ... */ }
|
||||
|
||||
#[test]
|
||||
fn test_refrigerant_source_port_enthalpies() { /* ... */ }
|
||||
|
||||
#[test]
|
||||
fn test_refrigerant_sink_new() { /* ... */ }
|
||||
|
||||
#[test]
|
||||
fn test_refrigerant_sink_with_return_enthalpy() { /* ... */ }
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Références
|
||||
|
||||
- [Architecture Document](../../plans/boundary-condition-refactoring-architecture.md)
|
||||
- [Story 10-1: Nouveaux types physiques](./10-1-new-physical-types.md)
|
||||
Reference in New Issue
Block a user