Entropyk/_bmad-output/implementation-artifacts/11-2-drum-recirculation-drum.md

4.3 KiB

Story 11.2: Drum - Ballon de Recirculation

Epic: 11 - Advanced HVAC Components
Priorité: P0-CRITIQUE
Estimation: 6h
Statut: backlog
Dépendances: Story 11.1 (Node)


Story

En tant qu'ingénieur chiller,
Je veux un composant Drum pour la recirculation d'évaporateur,
Afin de simuler des cycles à évaporateur flooded.


Contexte

Le ballon de recirculation (Drum) est un composant essentiel des évaporateurs flooded. Il reçoit:

  1. Le flux d'alimentation (feed) depuis l'économiseur
  2. Le retour de l'évaporateur (mélange enrichi en vapeur)

Et sépare en:

  1. Liquide saturé (x=0) vers la pompe de recirculation
  2. Vapeur saturée (x=1) vers le compresseur

Équations Mathématiques

Ports:
  in1:  Feed (depuis économiseur)
  in2:  Retour évaporateur (diphasique)
  out1: Liquide saturé (x=0)
  out2: Vapeur saturée (x=1)

Équations (8):

1. Mélange entrées:
   ṁ_total = ṁ_in1 + ṁ_in2
   h_mixed = (ṁ_in1·h_in1 + ṁ_in2·h_in2) / ṁ_total

2. Bilan masse:
   ṁ_out1 + ṁ_out2 = ṁ_total

3. Bilan énergie:
   ṁ_out1·h_out1 + ṁ_out2·h_out2 = ṁ_total·h_mixed

4. Pression out1:
   P_out1 - P_in1 = 0

5. Pression out2:
   P_out2 - P_in1 = 0

6. Liquide saturé:
   h_out1 - h_sat(P, x=0) = 0

7. Vapeur saturée:
   h_out2 - h_sat(P, x=1) = 0

8. Continuité fluide (implicite via FluidId)

Fichiers à Créer/Modifier

Fichier Action
crates/components/src/drum.rs Créer
crates/components/src/lib.rs Ajouter mod drum; pub use drum::*

Implémentation

// crates/components/src/drum.rs

use entropyk_core::{Power, Calib};
use entropyk_fluids::{FluidBackend, FluidId};
use crate::{Component, ComponentError, ConnectedPort, JacobianBuilder, ResidualVector, SystemState};
use std::sync::Arc;

/// Drum - Ballon de recirculation pour évaporateurs
#[derive(Debug)]
pub struct Drum {
    fluid_id: String,
    feed_inlet: ConnectedPort,
    evaporator_return: ConnectedPort,
    liquid_outlet: ConnectedPort,
    vapor_outlet: ConnectedPort,
    fluid_backend: Arc<dyn FluidBackend>,
    calib: Calib,
}

impl Drum {
    pub fn new(
        fluid: impl Into<String>,
        feed_inlet: ConnectedPort,
        evaporator_return: ConnectedPort,
        liquid_outlet: ConnectedPort,
        vapor_outlet: ConnectedPort,
        backend: Arc<dyn FluidBackend>,
    ) -> Result<Self, ComponentError> {
        Ok(Self {
            fluid_id: fluid.into(),
            feed_inlet,
            evaporator_return,
            liquid_outlet,
            vapor_outlet,
            fluid_backend: backend,
            calib: Calib::default(),
        })
    }
    
    /// Ratio de recirculation (m_liquid / m_feed)
    pub fn recirculation_ratio(&self, state: &SystemState) -> f64 {
        let m_liquid = self.liquid_outlet.mass_flow().to_kg_per_s();
        let m_feed = self.feed_inlet.mass_flow().to_kg_per_s();
        if m_feed > 0.0 { m_liquid / m_feed } else { 0.0 }
    }
}

impl Component for Drum {
    fn n_equations(&self) -> usize { 8 }
    
    fn compute_residuals(
        &self,
        state: &SystemState,
        residuals: &mut ResidualVector,
    ) -> Result<(), ComponentError> {
        // ... implémentation complète
        Ok(())
    }
    
    fn energy_transfers(&self, _state: &SystemState) -> Option<(Power, Power)> {
        Some((Power::from_watts(0.0), Power::from_watts(0.0)))
    }
}

Critères d'Acceptation

  • Drum::n_equations() retourne 8
  • Liquide outlet est saturé (x=0)
  • Vapeur outlet est saturée (x=1)
  • Bilan masse satisfait
  • Bilan énergie satisfait
  • Pressions égales sur tous les ports
  • recirculation_ratio() retourne m_liq/m_feed
  • Validation: fluide pur requis

Tests Requis

#[test]
fn test_drum_equations_count() {
    assert_eq!(drum.n_equations(), 8);
}

#[test]
fn test_drum_saturated_outlets() {
    // Vérifier h_liq = h_sat(x=0), h_vap = h_sat(x=1)
}

#[test]
fn test_drum_mass_balance() {
    // m_liq + m_vap = m_feed + m_return
}

#[test]
fn test_drum_recirculation_ratio() {
    // ratio = m_liq / m_feed
}

Références