""" Service pour les calculs thermodynamiques """ from typing import Dict, Optional, Any from app.core.refrigerant_loader import get_refrigerant class ThermodynamicsService: """Service pour effectuer les calculs thermodynamiques""" def calculate_from_px( self, refrigerant: str, pressure: float, quality: float ) -> Dict[str, Any]: """ Calcule les proprietes thermodynamiques a partir de P et x Args: refrigerant: Nom du refrigerant (ex: "R134a") pressure: Pression en Pa quality: Qualite (0-1) Returns: Dictionnaire avec toutes les proprietes """ lib = get_refrigerant(refrigerant) # Calculs des proprietes principales temperature = lib.T_px(pressure, quality) enthalpy = lib.h_px(pressure, quality) entropy = lib.s_px(pressure, quality) density = lib.rho_px(pressure, quality) temp_sat = lib.Ts_px(pressure, quality) # Proprietes de saturation enthalpy_liquid = lib.hsl_px(pressure, 0) enthalpy_vapor = lib.hsv_px(pressure, 1) density_liquid = lib.rhosl_px(pressure, 0) density_vapor = lib.rhosv_px(pressure, 1) return { "refrigerant": refrigerant, "inputs": { "pressure": pressure, "pressure_bar": pressure / 1e5, "quality": quality }, "properties": { "temperature": temperature, "temperature_celsius": temperature - 273.15, "enthalpy": enthalpy, "enthalpy_kj_kg": enthalpy / 1000, "entropy": entropy, "entropy_kj_kgK": entropy / 1000, "density": density, "specific_volume": 1 / density if density > 0 else None, "quality": quality }, "saturation": { "temperature": temp_sat, "temperature_celsius": temp_sat - 273.15, "enthalpy_liquid": enthalpy_liquid, "enthalpy_liquid_kj_kg": enthalpy_liquid / 1000, "enthalpy_vapor": enthalpy_vapor, "enthalpy_vapor_kj_kg": enthalpy_vapor / 1000, "density_liquid": density_liquid, "density_vapor": density_vapor, "latent_heat": enthalpy_vapor - enthalpy_liquid, "latent_heat_kj_kg": (enthalpy_vapor - enthalpy_liquid) / 1000 } } def calculate_from_pT( self, refrigerant: str, pressure: float, temperature: float ) -> Dict[str, Any]: """ Calcule les proprietes a partir de P et T Args: refrigerant: Nom du refrigerant pressure: Pression en Pa temperature: Temperature en K Returns: Dictionnaire avec les proprietes """ lib = get_refrigerant(refrigerant) enthalpy = lib.h_pT(pressure, temperature) # Determiner la qualite approximativement temp_sat = lib.Ts_px(pressure, 0.5) # Si proche de la saturation, calculer la qualite quality = None if abs(temperature - temp_sat) < 0.1: # En zone diphasique h_liquid = lib.hsl_px(pressure, 0) h_vapor = lib.hsv_px(pressure, 1) if h_vapor > h_liquid: quality = (enthalpy - h_liquid) / (h_vapor - h_liquid) quality = max(0, min(1, quality)) # Si qualite determinee, utiliser px pour avoir toutes les proprietes if quality is not None: return self.calculate_from_px(refrigerant, pressure, quality) # Sinon, calculer les proprietes de base (vapeur surchauffee ou liquide sous-refroidi) # Approximation: utiliser x=1 pour vapeur ou x=0 pour liquide if temperature > temp_sat: # Vapeur surchauffee, utiliser x=1 comme approximation quality_approx = 1.0 else: # Liquide sous-refroidi, utiliser x=0 comme approximation quality_approx = 0.0 result = self.calculate_from_px(refrigerant, pressure, quality_approx) result["properties"]["temperature"] = temperature result["properties"]["temperature_celsius"] = temperature - 273.15 result["properties"]["enthalpy"] = enthalpy result["properties"]["enthalpy_kj_kg"] = enthalpy / 1000 result["properties"]["quality"] = quality result["inputs"]["temperature"] = temperature result["inputs"]["temperature_celsius"] = temperature - 273.15 result["note"] = "Calcul a partir de P et T - proprietes approximatives hors saturation" return result def calculate_from_ph( self, refrigerant: str, pressure: float, enthalpy: float ) -> Dict[str, Any]: """ Calcule les proprietes a partir de P et h Args: refrigerant: Nom du refrigerant pressure: Pression en Pa enthalpy: Enthalpie en J/kg Returns: Dictionnaire avec les proprietes """ lib = get_refrigerant(refrigerant) # Calculer la qualite quality = lib.x_ph(pressure, enthalpy) # Utiliser la qualite pour calculer le reste return self.calculate_from_px(refrigerant, pressure, quality) def calculate_from_Tx( self, refrigerant: str, temperature: float, quality: float ) -> Dict[str, Any]: """ Calcule les proprietes a partir de T et x Args: refrigerant: Nom du refrigerant temperature: Temperature en K quality: Qualite (0-1) Returns: Dictionnaire avec les proprietes """ lib = get_refrigerant(refrigerant) # Calculer la pression pressure = lib.p_Tx(temperature, quality) # Utiliser la pression pour calculer le reste return self.calculate_from_px(refrigerant, pressure, quality) def get_saturation_properties( self, refrigerant: str, pressure: float ) -> Dict[str, Any]: """ Obtient les proprietes de saturation a une pression donnee Args: refrigerant: Nom du refrigerant pressure: Pression en Pa Returns: Proprietes de saturation (liquide et vapeur) """ lib = get_refrigerant(refrigerant) # Temperature de saturation temp_sat = lib.Ts_px(pressure, 0.5) # Proprietes liquide (x=0) h_liquid = lib.hsl_px(pressure, 0) rho_liquid = lib.rhosl_px(pressure, 0) s_liquid = lib.s_px(pressure, 0) # Proprietes vapeur (x=1) h_vapor = lib.hsv_px(pressure, 1) rho_vapor = lib.rhosv_px(pressure, 1) s_vapor = lib.s_px(pressure, 1) return { "refrigerant": refrigerant, "pressure": pressure, "pressure_bar": pressure / 1e5, "temperature_saturation": temp_sat, "temperature_saturation_celsius": temp_sat - 273.15, "liquid": { "enthalpy": h_liquid, "enthalpy_kj_kg": h_liquid / 1000, "density": rho_liquid, "specific_volume": 1 / rho_liquid if rho_liquid > 0 else None, "entropy": s_liquid, "entropy_kj_kgK": s_liquid / 1000 }, "vapor": { "enthalpy": h_vapor, "enthalpy_kj_kg": h_vapor / 1000, "density": rho_vapor, "specific_volume": 1 / rho_vapor if rho_vapor > 0 else None, "entropy": s_vapor, "entropy_kj_kgK": s_vapor / 1000 }, "latent_heat": h_vapor - h_liquid, "latent_heat_kj_kg": (h_vapor - h_liquid) / 1000 } # Instance globale du service _service: Optional[ThermodynamicsService] = None def get_thermodynamics_service() -> ThermodynamicsService: """Obtient l'instance du service thermodynamique""" global _service if _service is None: _service = ThermodynamicsService() return _service