diagram_ph/app/services/thermodynamics.py

251 lines
8.4 KiB
Python

"""
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