Entropyk/bindings/python/refrigerant_comparison.ipynb
Sepehr fa480ed303 feat: implement mass balance validation for Story 7.1
- Added port_mass_flows to Component trait and implements for core components.
- Added System::check_mass_balance and integrated it into the solver.
- Restored connect methods for ExpansionValve, Compressor, and Pipe to fix integration tests.
- Updated Python and C bindings for validation errors.
- Updated sprint status and story documentation.
2026-02-21 23:21:34 +01:00

410 lines
17 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Comparaison des Réfrigérants pour Applications Courantes\n",
"\n",
"Ce notebook compare les propriétés thermodynamiques de différents réfrigérants pour des applications typiques:\n",
"\n",
"- **Climatisation** : Température d'évaporation ~7°C, Condensation ~45°C\n",
"- **Réfrigération commerciale** : Tévap ~-10°C, Tcond ~40°C\n",
"- **Froid négatif** : Tévap ~-35°C, Tcond ~35°C"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import entropyk\n",
"import pandas as pd\n",
"import numpy as np\n",
"\n",
"# Pour les graphiques (optionnel)\n",
"try:\n",
" import matplotlib.pyplot as plt\n",
" HAS_MATPLOTLIB = True\n",
"except ImportError:\n",
" HAS_MATPLOTLIB = False\n",
" print(\"matplotlib non disponible - graphiques désactivés\")\n",
"\n",
"print(\"Entropyk chargé avec succès!\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 1. Paramètres des Applications"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Définir les conditions opératoires pour chaque application\n",
"applications = {\n",
" \"Climatisation\": {\n",
" \"T_evap_C\": 7.0,\n",
" \"T_cond_C\": 45.0,\n",
" \"surchauffe_K\": 5.0,\n",
" \"sous-refroidissement_K\": 3.0,\n",
" },\n",
" \"Réfrigération commerciale\": {\n",
" \"T_evap_C\": -10.0,\n",
" \"T_cond_C\": 40.0,\n",
" \"surchauffe_K\": 5.0,\n",
" \"sous-refroidissement_K\": 3.0,\n",
" },\n",
" \"Froid négatif\": {\n",
" \"T_evap_C\": -35.0,\n",
" \"T_cond_C\": 35.0,\n",
" \"surchauffe_K\": 5.0,\n",
" \"sous-refroidissement_K\": 3.0,\n",
" },\n",
" \"Pompe à chaleur\": {\n",
" \"T_evap_C\": -5.0,\n",
" \"T_cond_C\": 55.0,\n",
" \"surchauffe_K\": 5.0,\n",
" \"sous-refroidissement_K\": 5.0,\n",
" },\n",
"}\n",
"\n",
"for app_name, params in applications.items():\n",
" print(f\"{app_name}:\")\n",
" print(f\" Évaporation: {params['T_evap_C']}°C\")\n",
" print(f\" Condensation: {params['T_cond_C']}°C\")\n",
" print(f\" Delta T: {params['T_cond_C'] - params['T_evap_C']}K\")\n",
" print()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 2. Fluides à Comparer"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Liste des fluides avec leurs propriétés GWP et sécurité\n",
"fluides = {\n",
" \"R134a\": {\"GWP\": 1430, \"Classe\": \"A1\", \"Type\": \"HFC\"},\n",
" \"R410A\": {\"GWP\": 2088, \"Classe\": \"A1\", \"Type\": \"HFC\"},\n",
" \"R32\": {\"GWP\": 675, \"Classe\": \"A2L\", \"Type\": \"HFC\"},\n",
" \"R290\": {\"GWP\": 3, \"Classe\": \"A3\", \"Type\": \"Naturel\"},\n",
" \"R600a\": {\"GWP\": 3, \"Classe\": \"A3\", \"Type\": \"Naturel\"},\n",
" \"R744\": {\"GWP\": 1, \"Classe\": \"A1\", \"Type\": \"Naturel\"},\n",
" \"R1234yf\": {\"GWP\": 4, \"Classe\": \"A2L\", \"Type\": \"HFO\"},\n",
" \"R1234ze(E)\": {\"GWP\": 7, \"Classe\": \"A2L\", \"Type\": \"HFO\"},\n",
" \"R454B\": {\"GWP\": 146, \"Classe\": \"A2L\", \"Type\": \"Mélange\"},\n",
" \"R513A\": {\"GWP\": 631, \"Classe\": \"A1\", \"Type\": \"Mélange\"},\n",
"}\n",
"\n",
"df_fluides = pd.DataFrame.from_dict(fluides, orient='index')\n",
"df_fluides.index.name = \"Fluide\"\n",
"df_fluides"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 3. Comparaison des Pressions de Travail"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Afficher les pressions de saturation pour chaque application\n",
"print(\"=== Pressions de Saturation (bar) ===\\n\")\n",
"\n",
"for app_name, params in applications.items():\n",
" print(f\"--- {app_name} ---\")\n",
" print(f\"{'Fluide':12s} {'P_evap':>10s} {'P_cond':>10s} {'Ratio':>8s}\")\n",
" print(\"-\" * 45)\n",
" \n",
" for fluide in fluides:\n",
" # Note: Les valeurs réelles nécessitent CoolProp\n",
" # Ici on utilise des valeurs approximatives pour démonstration\n",
" if fluide == \"R744\":\n",
" # CO2 a des pressions très élevées\n",
" p_evap_approx = {\"Climatisation\": 45, \"Réfrigération commerciale\": 26, \"Froid négatif\": 12, \"Pompe à chaleur\": 30}\n",
" p_cond_approx = {\"Climatisation\": 90, \"Réfrigération commerciale\": 75, \"Froid négatif\": 65, \"Pompe à chaleur\": 120}\n",
" elif fluide == \"R410A\":\n",
" p_evap_approx = {\"Climatisation\": 6.2, \"Réfrigération commerciale\": 3.5, \"Froid négatif\": 1.5, \"Pompe à chaleur\": 4.8}\n",
" p_cond_approx = {\"Climatisation\": 26.5, \"Réfrigération commerciale\": 24, \"Froid négatif\": 21, \"Pompe à chaleur\": 34}\n",
" elif fluide == \"R134a\":\n",
" p_evap_approx = {\"Climatisation\": 3.8, \"Réfrigération commerciale\": 2.0, \"Froid négatif\": 0.8, \"Pompe à chaleur\": 2.8}\n",
" p_cond_approx = {\"Climatisation\": 11.6, \"Réfrigération commerciale\": 10.2, \"Froid négatif\": 8.9, \"Pompe à chaleur\": 15}\n",
" elif fluide == \"R32\":\n",
" p_evap_approx = {\"Climatisation\": 5.8, \"Réfrigération commerciale\": 3.2, \"Froid négatif\": 1.3, \"Pompe à chaleur\": 4.4}\n",
" p_cond_approx = {\"Climatisation\": 24, \"Réfrigération commerciale\": 21.5, \"Froid négatif\": 19, \"Pompe à chaleur\": 30}\n",
" elif fluide == \"R290\":\n",
" p_evap_approx = {\"Climatisation\": 5.5, \"Réfrigération commerciale\": 2.8, \"Froid négatif\": 1.0, \"Pompe à chaleur\": 4.0}\n",
" p_cond_approx = {\"Climatisation\": 15.5, \"Réfrigération commerciale\": 13.5, \"Froid négatif\": 11.5, \"Pompe à chaleur\": 20}\n",
" else:\n",
" # Valeurs génériques\n",
" p_evap_approx = {k: 3.0 for k in applications}\n",
" p_cond_approx = {k: 10.0 for k in applications}\n",
" \n",
" p_evap = p_evap_approx[app_name]\n",
" p_cond = p_cond_approx[app_name]\n",
" ratio = p_cond / p_evap\n",
" \n",
" print(f\"{fluide:12s} {p_evap:10.1f} {p_cond:10.1f} {ratio:8.2f}\")\n",
" print()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 4. Performance Théorique (COP) par Application"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# COP théorique de Carnot et valeurs typiques\n",
"print(\"=== COP par Application ===\\n\")\n",
"\n",
"cop_data = []\n",
"for app_name, params in applications.items():\n",
" T_evap_K = params['T_evap_C'] + 273.15\n",
" T_cond_K = params['T_cond_C'] + 273.15\n",
" \n",
" # COP de Carnot\n",
" cop_carnot = T_evap_K / (T_cond_K - T_evap_K)\n",
" \n",
" # COP réels typiques (60-70% de Carnot)\n",
" cop_real = cop_carnot * 0.65\n",
" \n",
" cop_data.append({\n",
" \"Application\": app_name,\n",
" \"T_evap (°C)\": params['T_evap_C'],\n",
" \"T_cond (°C)\": params['T_cond_C'],\n",
" \"COP Carnot\": round(cop_carnot, 2),\n",
" \"COP Réel (~)\": round(cop_real, 2),\n",
" })\n",
"\n",
"df_cop = pd.DataFrame(cop_data)\n",
"df_cop"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 5. Recommandations par Application"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"recommandations = {\n",
" \"Climatisation\": {\n",
" \"Principal\": \"R32\",\n",
" \"Alternatives\": [\"R290\", \"R454B\"],\n",
" \"Raisons\": \"R32: bon COP, GWP modéré, compatible R410A. R290: meilleur COP, faible charge.\",\n",
" },\n",
" \"Réfrigération commerciale\": {\n",
" \"Principal\": \"R744 (CO2)\",\n",
" \"Alternatives\": [\"R290\", \"R404A (existant)\"],\n",
" \"Raisons\": \"CO2: GWP=1, toutes températures. R290: haute efficacité, charge limitée.\",\n",
" },\n",
" \"Froid négatif\": {\n",
" \"Principal\": \"R744 (CO2) cascade\",\n",
" \"Alternatives\": [\"R290/R600a cascade\"],\n",
" \"Raisons\": \"CO2 cascade ou R290/R600a pour GWP minimal.\",\n",
" },\n",
" \"Pompe à chaleur\": {\n",
" \"Principal\": \"R290\",\n",
" \"Alternatives\": [\"R32\", \"R744\"],\n",
" \"Raisons\": \"R290: excellent COP haute température. R744: transcritique pour eau chaude.\",\n",
" },\n",
"}\n",
"\n",
"for app, rec in recommandations.items():\n",
" print(f\"\\n{'='*60}\")\n",
" print(f\"{app}\")\n",
" print(f\"{'='*60}\")\n",
" print(f\" Principal: {rec['Principal']}\")\n",
" print(f\" Alternatives: {', '.join(rec['Alternatives'])}\")\n",
" print(f\" Raisons: {rec['Raisons']}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 6. Matrice de Sélection Rapide"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Matrice de compatibilité\n",
"compatibilite = {\n",
" \"R134a\": {\"Climatisation\": \"★★★\", \"Réfrigération\": \"★★★\", \"Froid négatif\": \"★★\", \"Pompe chaleur\": \"★★\", \"GWP\": 1430},\n",
" \"R410A\": {\"Climatisation\": \"★★★★\", \"Réfrigération\": \"★★\", \"Froid négatif\": \"★\", \"Pompe chaleur\": \"★★★\", \"GWP\": 2088},\n",
" \"R32\": {\"Climatisation\": \"★★★★★\", \"Réfrigération\": \"★★★\", \"Froid négatif\": \"★\", \"Pompe chaleur\": \"★★★★\", \"GWP\": 675},\n",
" \"R290\": {\"Climatisation\": \"★★★★★\", \"Réfrigération\": \"★★★★\", \"Froid négatif\": \"★★★\", \"Pompe chaleur\": \"★★★★★\", \"GWP\": 3},\n",
" \"R600a\": {\"Climatisation\": \"★★\", \"Réfrigération\": \"★★★\", \"Froid négatif\": \"★★★★\", \"Pompe chaleur\": \"★★\", \"GWP\": 3},\n",
" \"R744\": {\"Climatisation\": \"★★★\", \"Réfrigération\": \"★★★★★\", \"Froid négatif\": \"★★★★★\", \"Pompe chaleur\": \"★★★★\", \"GWP\": 1},\n",
" \"R1234yf\": {\"Climatisation\": \"★★★★\", \"Réfrigération\": \"★★★\", \"Froid négatif\": \"★\", \"Pompe chaleur\": \"★★\", \"GWP\": 4},\n",
" \"R454B\": {\"Climatisation\": \"★★★★\", \"Réfrigération\": \"★★★\", \"Froid négatif\": \"★\", \"Pompe chaleur\": \"★★★\", \"GWP\": 146},\n",
" \"R513A\": {\"Climatisation\": \"★★★\", \"Réfrigération\": \"★★★\", \"Froid négatif\": \"★★\", \"Pompe chaleur\": \"★★\", \"GWP\": 631},\n",
"}\n",
"\n",
"print(\"\\n=== Matrice de Sélection ===\")\n",
"print(\"★★★★★ = Excellent, ★★★★ = Très bon, ★★★ = Bon, ★★ = Acceptable, ★ = Déconseillé\\n\")\n",
"\n",
"for fluide, scores in compatibilite.items():\n",
" print(f\"{fluide:12s} | GWP:{scores['GWP']:5d} | Clim:{scores['Climatisation']} | Réfrig:{scores['Réfrigération']} | Nég:{scores['Froid négatif']} | PAC:{scores['Pompe chaleur']}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 7. Exemple de Code: Cycle Multi-Fluides"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def create_cycle_for_fluid(fluid: str, app_name: str = \"Climatisation\"):\n",
" \"\"\"\n",
" Crée un cycle optimisé pour un fluide et une application donnée.\n",
" \"\"\"\n",
" params = applications[app_name]\n",
" \n",
" # Ajuster les composants selon le fluide\n",
" if fluid == \"R744\":\n",
" # CO2: haute pression, échangeur gaz cooler\n",
" ua_cond = 8000.0 # Plus élevé pour CO2\n",
" ua_evap = 5000.0\n",
" elif fluid == \"R290\" or fluid == \"R600a\":\n",
" # Hydrocarbures: excellents transferts thermiques\n",
" ua_cond = 4000.0\n",
" ua_evap = 3500.0\n",
" else:\n",
" # HFC/HFO standards\n",
" ua_cond = 5000.0\n",
" ua_evap = 3000.0\n",
" \n",
" system = entropyk.System()\n",
" \n",
" comp = entropyk.Compressor(\n",
" speed_rpm=2900.0,\n",
" displacement=0.0001,\n",
" efficiency=0.85,\n",
" fluid=fluid\n",
" )\n",
" cond = entropyk.Condenser(ua=ua_cond)\n",
" exv = entropyk.ExpansionValve(fluid=fluid, opening=0.8)\n",
" evap = entropyk.Evaporator(ua=ua_evap)\n",
" \n",
" comp_idx = system.add_component(comp)\n",
" cond_idx = system.add_component(cond)\n",
" exv_idx = system.add_component(exv)\n",
" evap_idx = system.add_component(evap)\n",
" \n",
" system.add_edge(comp_idx, cond_idx)\n",
" system.add_edge(cond_idx, exv_idx)\n",
" system.add_edge(exv_idx, evap_idx)\n",
" system.add_edge(evap_idx, comp_idx)\n",
" \n",
" system.finalize()\n",
" return system\n",
"\n",
"# Test\n",
"for fluid in [\"R134a\", \"R32\", \"R290\", \"R744\"]:\n",
" system = create_cycle_for_fluid(fluid, \"Climatisation\")\n",
" print(f\"{fluid:8s}: {system.state_vector_len} variables d'état\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 8. Résumé Exécutif"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print(\"\"\"\n",
"╔══════════════════════════════════════════════════════════════════════════╗\n",
"║ RÉSUMÉ - SÉLECTION DES RÉFRIGÉRANTS ║\n",
"╠══════════════════════════════════════════════════════════════════════════╣\n",
"║ CLIMATISATION ║\n",
"║ → R32 (standard), R290 (performant, charge limitée), R454B (retrofit) ║\n",
"║ ║\n",
"║ RÉFRIGÉRATION COMMERCIALE ║\n",
"║ → R744/CO2 (futur), R290 (nouveau), R404A (existant) ║\n",
"║ ║\n",
"║ FROID NÉGATIF ║\n",
"║ → R744 cascade, R290/R600a cascade ║\n",
"║ ║\n",
"║ POMPE À CHALEUR ║\n",
"║ → R290 (haute température), R32 (standard), R744 (transcritique) ║\n",
"╠══════════════════════════════════════════════════════════════════════════╣\n",
"║ TENDANCE RÉGLEMENTAIRE: GWP < 750 d'ici 2025-2030 ║\n",
"║ → Privilégier: R290, R600a, R744, R1234yf, R32 ║\n",
"╚══════════════════════════════════════════════════════════════════════════╝\n",
"\"\"\")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.0"
}
},
"nbformat": 4,
"nbformat_minor": 4
}