chore: sync project state and current artifacts
This commit is contained in:
221
bindings/python/examples/complete_thermodynamic_system.py
Normal file
221
bindings/python/examples/complete_thermodynamic_system.py
Normal file
@@ -0,0 +1,221 @@
|
||||
import entropyk
|
||||
import math
|
||||
|
||||
def build_complete_system():
|
||||
# ── 1. Initialisation du graphe du système ──
|
||||
system = entropyk.System()
|
||||
print("Construction du système Entropyk complet...")
|
||||
|
||||
# Paramètres fluides
|
||||
refrigerant = "R410A"
|
||||
water = "Water"
|
||||
|
||||
# =========================================================================
|
||||
# BOUCLE 1 : CIRCUIT FRIGORIFIQUE (REFRIGERANT R410A)
|
||||
# =========================================================================
|
||||
|
||||
# 1.1 Compresseur (Modèle Polynomial AHRI 540)
|
||||
compressor = system.add_component(entropyk.Compressor(
|
||||
m1=0.85, m2=2.5, m3=500.0, m4=1500.0, m5=-2.5, m6=1.8, m7=600.0, m8=1600.0, m9=-3.0, m10=2.0,
|
||||
speed_rpm=3600.0,
|
||||
displacement=0.00008,
|
||||
efficiency=0.88,
|
||||
fluid=refrigerant
|
||||
))
|
||||
|
||||
# 1.2 Tuyau de refoulement (vers condenseur)
|
||||
pipe_hot = system.add_component(entropyk.Pipe(
|
||||
length=5.0,
|
||||
diameter=0.02,
|
||||
fluid=refrigerant
|
||||
))
|
||||
|
||||
# 1.3 Condenseur (Rejet de chaleur)
|
||||
condenser = system.add_component(entropyk.Condenser(
|
||||
ua=4500.0,
|
||||
fluid=refrigerant,
|
||||
water_temp=30.0, # Température d'entrée côté eau/air
|
||||
water_flow=2.0
|
||||
))
|
||||
|
||||
# 1.4 Ligne liquide
|
||||
pipe_liquid = system.add_component(entropyk.Pipe(
|
||||
length=10.0,
|
||||
diameter=0.015,
|
||||
fluid=refrigerant
|
||||
))
|
||||
|
||||
# 1.5 Division du débit (FlowSplitter) vers 2 évaporateurs
|
||||
splitter = system.add_component(entropyk.FlowSplitter(n_outlets=2))
|
||||
|
||||
# 1.6 Branche A : Détendeur + Évaporateur 1
|
||||
exv_a = system.add_component(entropyk.ExpansionValve(fluid=refrigerant, opening=0.5))
|
||||
evap_a = system.add_component(entropyk.Evaporator(
|
||||
ua=2000.0,
|
||||
fluid=refrigerant,
|
||||
water_temp=12.0,
|
||||
water_flow=1.0
|
||||
))
|
||||
|
||||
# 1.7 Branche B : Détendeur + Évaporateur 2
|
||||
exv_b = system.add_component(entropyk.ExpansionValve(fluid=refrigerant, opening=0.5))
|
||||
evap_b = system.add_component(entropyk.Evaporator(
|
||||
ua=2000.0,
|
||||
fluid=refrigerant,
|
||||
water_temp=15.0, # Température d'eau légèrement différente
|
||||
water_flow=1.0
|
||||
))
|
||||
|
||||
# 1.8 Fusion du débit (FlowMerger)
|
||||
merger = system.add_component(entropyk.FlowMerger(n_inlets=2))
|
||||
|
||||
# 1.9 Tuyau d'aspiration (retour compresseur)
|
||||
pipe_suction = system.add_component(entropyk.Pipe(
|
||||
length=5.0,
|
||||
diameter=0.025,
|
||||
fluid=refrigerant
|
||||
))
|
||||
|
||||
# --- Connexions de la boucle frigo ---
|
||||
system.add_edge(compressor, pipe_hot)
|
||||
system.add_edge(pipe_hot, condenser)
|
||||
system.add_edge(condenser, pipe_liquid)
|
||||
|
||||
# Splitter
|
||||
system.add_edge(pipe_liquid, splitter)
|
||||
system.add_edge(splitter, exv_a)
|
||||
system.add_edge(splitter, exv_b)
|
||||
|
||||
# Branches parallèles
|
||||
system.add_edge(exv_a, evap_a)
|
||||
system.add_edge(exv_b, evap_b)
|
||||
|
||||
# Merger
|
||||
system.add_edge(evap_a, merger)
|
||||
system.add_edge(evap_b, merger)
|
||||
|
||||
system.add_edge(merger, pipe_suction)
|
||||
system.add_edge(pipe_suction, compressor)
|
||||
|
||||
# =========================================================================
|
||||
# BOUCLE 2 : CIRCUIT RÉSEAU HYDRAULIQUE (EAU - Côté Évaporateur Principal)
|
||||
# (Juste de la tuyauterie et une pompe pour montrer les FlowSource/FlowSink)
|
||||
# =========================================================================
|
||||
|
||||
water_source = system.add_component(entropyk.FlowSource(
|
||||
fluid=water,
|
||||
pressure_pa=101325.0, # 1 atm
|
||||
temperature_k=285.15 # 12 °C
|
||||
))
|
||||
|
||||
water_pump = system.add_component(entropyk.Pump(
|
||||
pressure_rise_pa=50000.0, # 0.5 bar
|
||||
efficiency=0.6
|
||||
))
|
||||
|
||||
water_pipe = system.add_component(entropyk.Pipe(
|
||||
length=20.0,
|
||||
diameter=0.05,
|
||||
fluid=water
|
||||
))
|
||||
|
||||
water_sink = system.add_component(entropyk.FlowSink())
|
||||
|
||||
# --- Connexions Hydrauliques Principales ---
|
||||
system.add_edge(water_source, water_pump)
|
||||
system.add_edge(water_pump, water_pipe)
|
||||
system.add_edge(water_pipe, water_sink)
|
||||
|
||||
|
||||
# =========================================================================
|
||||
# BOUCLE 3 : CIRCUIT VENTILATION (AIR - Côté Condenseur)
|
||||
# =========================================================================
|
||||
|
||||
air_source = system.add_component(entropyk.FlowSource(
|
||||
fluid="Air",
|
||||
pressure_pa=101325.0,
|
||||
temperature_k=308.15 # 35 °C d'air ambiant
|
||||
))
|
||||
|
||||
condenser_fan = system.add_component(entropyk.Fan(
|
||||
pressure_rise_pa=200.0, # 200 Pa de montée en pression par le ventilo
|
||||
efficiency=0.5
|
||||
))
|
||||
|
||||
air_sink = system.add_component(entropyk.FlowSink())
|
||||
|
||||
# --- Connexions Ventilation ---
|
||||
system.add_edge(air_source, condenser_fan)
|
||||
system.add_edge(condenser_fan, air_sink)
|
||||
|
||||
|
||||
# ── 4. Finalisation du système ──
|
||||
print("Finalisation du graphe (Construction de la topologie)...")
|
||||
system.finalize()
|
||||
print(f"Propriétés du système : {system.node_count} composants, {system.edge_count} connexions.")
|
||||
print(f"Taille du vecteur d'état mathématique : {system.state_vector_len} variables.")
|
||||
|
||||
return system
|
||||
|
||||
|
||||
def solve_system(system):
|
||||
# ── 5. Configuration Avancée du Solveur (Story 6-6) ──
|
||||
print("\nConfiguration de la stratégie de résolution...")
|
||||
|
||||
# (Optionnel) Critères de convergence fins
|
||||
convergence = entropyk.ConvergenceCriteria(
|
||||
pressure_tolerance_pa=5.0,
|
||||
mass_balance_tolerance_kgs=1e-6,
|
||||
energy_balance_tolerance_w=1e-3
|
||||
)
|
||||
|
||||
# (Optionnel) Jacobian Freezing pour aller plus vite
|
||||
freezing = entropyk.JacobianFreezingConfig(
|
||||
max_frozen_iters=4,
|
||||
threshold=0.1
|
||||
)
|
||||
|
||||
# Configuration Newton avec tolérances avancées
|
||||
newton_config = entropyk.NewtonConfig(
|
||||
max_iterations=150,
|
||||
tolerance=1e-5,
|
||||
line_search=True,
|
||||
use_numerical_jacobian=True,
|
||||
jacobian_freezing=freezing,
|
||||
convergence_criteria=convergence,
|
||||
initial_state=[1000000.0, 450000.0] * 17
|
||||
)
|
||||
|
||||
# Configuration Picard robuste en cas d'échec de Newton
|
||||
picard_config = entropyk.PicardConfig(
|
||||
max_iterations=500,
|
||||
tolerance=1e-4,
|
||||
relaxation=0.4,
|
||||
convergence_criteria=convergence
|
||||
)
|
||||
|
||||
# ── 6. Lancement du calcul ──
|
||||
print("Lancement de la simulation (Newton uniquement)...")
|
||||
try:
|
||||
result = newton_config.solve(system)
|
||||
|
||||
status = result.status
|
||||
print(f"\n✅ Simulation terminée avec succès !")
|
||||
print(f"Statut : {status}")
|
||||
print(f"Itérations : {result.iterations}")
|
||||
print(f"Résidu final : {result.final_residual:.2e}")
|
||||
|
||||
# Le résultat contient le vecteur d'état complet
|
||||
state_vec = result.state_vector
|
||||
print(f"Aperçu des 5 premières variables d'état : {state_vec[:5]}")
|
||||
|
||||
except entropyk.TimeoutError:
|
||||
print("\n❌ Le solveur a dépassé le temps imparti (Timeout).")
|
||||
except entropyk.SolverError as e:
|
||||
print(f"\n❌ Erreur du solveur : {e}")
|
||||
print("Note: Ce comportement peut arriver si les paramètres (taille des tuyaux, coeffs, températures)")
|
||||
print("dépassent le domaine thermodynamique du fluide ou si le graphe manque de contraintes aux limites.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
system = build_complete_system()
|
||||
solve_system(system)
|
||||
87
bindings/python/examples/simple_thermodynamic_loop.py
Normal file
87
bindings/python/examples/simple_thermodynamic_loop.py
Normal file
@@ -0,0 +1,87 @@
|
||||
"""
|
||||
Cycle frigorifique simple R134a - 4 composants
|
||||
Compresseur → Condenseur → Détendeur → Évaporateur → (retour)
|
||||
|
||||
Équations des composants mock (python_components.rs) :
|
||||
Compresseur : r[0] = p_disc - (p_suc + 1 MPa) r[1] = h_disc - (h_suc + power/m_dot)
|
||||
Condenseur : r[0] = p_out - p_in r[1] = h_out - (h_in - 225 kJ/kg)
|
||||
Détendeur : r[0] = p_out - (p_in - 1 MPa) r[1] = h_out - h_in
|
||||
Évaporateur : r[0] = p_out - p_in r[1] = h_out - (h_in + 150 kJ/kg)
|
||||
|
||||
État initial cohérent : P_HP - P_LP = 1 MPa → tous les résidus de pression valent 0 au départ.
|
||||
"""
|
||||
import entropyk
|
||||
import time
|
||||
|
||||
def main():
|
||||
system = entropyk.System()
|
||||
print("Construction du système simple (R134a)...")
|
||||
|
||||
fluid = "R134a"
|
||||
|
||||
comp = system.add_component(entropyk.Compressor(
|
||||
m1=0.85, m2=2.5, m3=500.0, m4=1500.0, m5=-2.5, m6=1.8,
|
||||
m7=600.0, m8=1600.0, m9=-3.0, m10=2.0,
|
||||
speed_rpm=3600.0, displacement=0.00008, efficiency=0.88, fluid=fluid
|
||||
))
|
||||
cond = system.add_component(entropyk.Condenser(
|
||||
ua=5000.0, fluid=fluid, water_temp=30.0, water_flow=2.0
|
||||
))
|
||||
valve = system.add_component(entropyk.ExpansionValve(
|
||||
fluid=fluid, opening=0.5 # target_dp = 2e6*(1-0.5) = 1 MPa
|
||||
))
|
||||
evap = system.add_component(entropyk.Evaporator(
|
||||
ua=3000.0, fluid=fluid, water_temp=10.0, water_flow=2.0
|
||||
))
|
||||
|
||||
system.add_edge(comp, cond) # edge 0 : comp → cond
|
||||
system.add_edge(cond, valve) # edge 1 : cond → valve
|
||||
system.add_edge(valve, evap) # edge 2 : valve → evap
|
||||
system.add_edge(evap, comp) # edge 3 : evap → comp
|
||||
|
||||
system.finalize()
|
||||
print(f"Propriétés: {system.node_count} composants, {system.edge_count} connexions, "
|
||||
f"{system.state_vector_len} variables d'état.")
|
||||
|
||||
# ─── État initial cohérent avec les équations mock ───────────────────────
|
||||
# Valve et Comp utilisent tous les deux target_dp = 1 MPa
|
||||
# → P_HP - P_LP = 1 MPa ⇒ résidus de pression = 0 dès le départ
|
||||
# Enthalpies choisies proches de l'équilibre attendu :
|
||||
# Cond : h_in - 225 kJ/kg = h_out_cond (225 000 J/kg)
|
||||
# Evap : h_in + 150 kJ/kg = h_out_evap (150 000 J/kg)
|
||||
# Comp : h_in + w_sp ≈ h_in + 75 kJ/kg (AHRI 540)
|
||||
P_LP = 350_000.0 # Pa — basse pression (R134a ~1.5°C sat)
|
||||
P_HP = 1_350_000.0 # Pa — haute pression = P_LP + 1 MPa ✓
|
||||
initial_state = [
|
||||
P_HP, 485_000.0, # edge0 comp→cond : vapeur surchauffée HP (≈h_suc + 75 kJ/kg)
|
||||
P_HP, 260_000.0, # edge1 cond→valve : liquide HP (≈485-225)
|
||||
P_LP, 260_000.0, # edge2 valve→evap : biphasique BP (isenthalpique)
|
||||
P_LP, 410_000.0, # edge3 evap→comp : vapeur surchauffée BP (≈260+150)
|
||||
]
|
||||
|
||||
config = entropyk.NewtonConfig(
|
||||
max_iterations=150,
|
||||
tolerance=1e-4,
|
||||
line_search=True,
|
||||
use_numerical_jacobian=True,
|
||||
initial_state=initial_state
|
||||
)
|
||||
|
||||
print("Lancement du Newton Solver...")
|
||||
t0 = time.time()
|
||||
try:
|
||||
res = config.solve(system)
|
||||
elapsed = time.time() - t0
|
||||
print(f"\n✅ Convergé en {res.iterations} itérations ({elapsed*1000:.1f} ms)")
|
||||
sv = res.state_vector
|
||||
print(f"\nÉtat final du cycle R134a :")
|
||||
print(f" comp → cond : P={sv[0]/1e5:.2f} bar, h={sv[1]/1e3:.1f} kJ/kg")
|
||||
print(f" cond → valve : P={sv[2]/1e5:.2f} bar, h={sv[3]/1e3:.1f} kJ/kg")
|
||||
print(f" valve → evap : P={sv[4]/1e5:.2f} bar, h={sv[5]/1e3:.1f} kJ/kg")
|
||||
print(f" evap → comp : P={sv[6]/1e5:.2f} bar, h={sv[7]/1e3:.1f} kJ/kg")
|
||||
except Exception as e:
|
||||
elapsed = time.time() - t0
|
||||
print(f"\n❌ Échec après {elapsed*1000:.1f} ms : {e}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user