feat(python): implement python bindings for all components and solvers
This commit is contained in:
157
bindings/python/examples/migration_from_tespy.py
Normal file
157
bindings/python/examples/migration_from_tespy.py
Normal file
@@ -0,0 +1,157 @@
|
||||
"""Entropyk vs TESPy — Migration Guide.
|
||||
|
||||
Side-by-side comparison showing how common TESPy patterns translate
|
||||
to Entropyk's Python API.
|
||||
|
||||
This file is a reference guide, not a runnable script.
|
||||
"""
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────┐
|
||||
# │ 1. Component Construction │
|
||||
# └─────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
# TESPy:
|
||||
# from tespy.components import Compressor
|
||||
# comp = Compressor("compressor")
|
||||
# comp.set_attr(eta_s=0.85)
|
||||
|
||||
# Entropyk:
|
||||
import entropyk
|
||||
|
||||
comp = entropyk.Compressor(
|
||||
speed_rpm=2900.0,
|
||||
efficiency=0.85,
|
||||
fluid="R134a",
|
||||
)
|
||||
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────┐
|
||||
# │ 2. Condenser / Evaporator │
|
||||
# └─────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
# TESPy:
|
||||
# from tespy.components import Condenser
|
||||
# cond = Condenser("condenser")
|
||||
# cond.set_attr(pr=0.98, Q=-50000)
|
||||
|
||||
# Entropyk — UA-based heat exchangers:
|
||||
cond = entropyk.Condenser(ua=5000.0) # W/K
|
||||
evap = entropyk.Evaporator(ua=3000.0) # W/K
|
||||
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────┐
|
||||
# │ 3. Expansion Valve │
|
||||
# └─────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
# TESPy:
|
||||
# from tespy.components import Valve
|
||||
# valve = Valve("expansion_valve")
|
||||
|
||||
# Entropyk:
|
||||
valve = entropyk.ExpansionValve(fluid="R134a", opening=0.8)
|
||||
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────┐
|
||||
# │ 4. Building the Network / System │
|
||||
# └─────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
# TESPy:
|
||||
# from tespy.networks import Network
|
||||
# nw = Network(fluids=["R134a"])
|
||||
# nw.add_conns(c1, c2, c3, c4)
|
||||
# nw.solve("design")
|
||||
|
||||
# Entropyk:
|
||||
system = entropyk.System()
|
||||
c = system.add_component(comp)
|
||||
d = system.add_component(cond)
|
||||
e = system.add_component(valve)
|
||||
v = system.add_component(evap)
|
||||
system.add_edge(c, d)
|
||||
system.add_edge(d, e)
|
||||
system.add_edge(e, v)
|
||||
system.add_edge(v, c)
|
||||
system.finalize()
|
||||
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────┐
|
||||
# │ 5. Solving │
|
||||
# └─────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
# TESPy:
|
||||
# nw.solve("design")
|
||||
# print(nw.res[-1])
|
||||
|
||||
# Entropyk — multiple solver strategies:
|
||||
|
||||
# Option A: Newton-Raphson (fast, may diverge)
|
||||
newton = entropyk.NewtonConfig(max_iterations=200, tolerance=1e-6)
|
||||
|
||||
# Option B: Picard / Sequential Substitution (slower, more robust)
|
||||
picard = entropyk.PicardConfig(max_iterations=500, tolerance=1e-4)
|
||||
|
||||
# Option C: Fallback (Newton first, then Picard if divergence)
|
||||
fallback = entropyk.FallbackConfig(newton=newton, picard=picard)
|
||||
|
||||
try:
|
||||
result = fallback.solve(system)
|
||||
print(f"Converged in {result.iterations} iterations")
|
||||
print(f"State vector: {result.state_vector}")
|
||||
except entropyk.TimeoutError as e:
|
||||
print(f"Solver timed out: {e}")
|
||||
except entropyk.SolverError as e:
|
||||
print(f"Solver failed: {e}")
|
||||
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────┐
|
||||
# │ 6. Physical Units │
|
||||
# └─────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
# TESPy uses raw floats with implicit units.
|
||||
# Entropyk provides type-safe physical quantities:
|
||||
|
||||
p = entropyk.Pressure(bar=12.0)
|
||||
print(f"Pressure: {p.to_pascals()} Pa = {p.to_bar()} bar = {p.to_kpa()} kPa")
|
||||
|
||||
t = entropyk.Temperature(celsius=45.0)
|
||||
print(f"Temperature: {t.to_kelvin()} K = {t.to_celsius()} °C")
|
||||
|
||||
h = entropyk.Enthalpy(kj_per_kg=420.0)
|
||||
print(f"Enthalpy: {h.to_j_per_kg()} J/kg = {h.to_kj_per_kg()} kJ/kg")
|
||||
|
||||
m = entropyk.MassFlow(kg_per_s=0.05)
|
||||
print(f"Mass flow: {m.to_kg_per_s()} kg/s = {m.to_g_per_s()} g/s")
|
||||
|
||||
# Arithmetic on physical types
|
||||
dp = entropyk.Pressure(bar=10.0) - entropyk.Pressure(bar=3.0)
|
||||
print(f"Pressure drop: {dp.to_bar()} bar")
|
||||
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────────────┐
|
||||
# │ 7. Error Handling │
|
||||
# └─────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
# TESPy:
|
||||
# try:
|
||||
# nw.solve("design")
|
||||
# except Exception:
|
||||
# ...
|
||||
|
||||
# Entropyk — typed exception hierarchy:
|
||||
# EntropykError (base)
|
||||
# ├── SolverError
|
||||
# │ ├── TimeoutError
|
||||
# │ └── ControlSaturationError
|
||||
# ├── FluidError
|
||||
# ├── ComponentError
|
||||
# ├── TopologyError
|
||||
# └── ValidationError
|
||||
|
||||
try:
|
||||
result = newton.solve(system)
|
||||
except entropyk.TimeoutError:
|
||||
print("Increase timeout or use fallback solver")
|
||||
except entropyk.SolverError:
|
||||
print("Try different solver config or initial conditions")
|
||||
except entropyk.EntropykError:
|
||||
print("Catch-all for any Entropyk error")
|
||||
149
bindings/python/examples/simple_cycle.py
Normal file
149
bindings/python/examples/simple_cycle.py
Normal file
@@ -0,0 +1,149 @@
|
||||
"""Entropyk — Simple Refrigeration Cycle Example.
|
||||
|
||||
This example demonstrates how to use the Python bindings to build and
|
||||
(eventually) solve a simple vapor-compression refrigeration cycle:
|
||||
|
||||
Compressor → Condenser → Expansion Valve → Evaporator → (loop)
|
||||
|
||||
Usage:
|
||||
python examples/simple_cycle.py
|
||||
"""
|
||||
|
||||
import entropyk
|
||||
|
||||
# ── Step 1: Create physical components ──────────────────────────────────
|
||||
|
||||
print("=" * 60)
|
||||
print(" Entropyk — Simple Refrigeration Cycle")
|
||||
print("=" * 60)
|
||||
|
||||
# Compressor with AHRI 540 coefficients (using defaults)
|
||||
compressor = entropyk.Compressor(
|
||||
speed_rpm=2900.0,
|
||||
displacement=0.0001,
|
||||
efficiency=0.85,
|
||||
fluid="R134a",
|
||||
)
|
||||
print(f"\n {compressor}")
|
||||
|
||||
# Condenser coil: UA = 5 kW/K
|
||||
condenser = entropyk.Condenser(ua=5000.0)
|
||||
print(f" {condenser}")
|
||||
|
||||
# Thermostatic expansion valve
|
||||
expansion_valve = entropyk.ExpansionValve(fluid="R134a", opening=0.8)
|
||||
print(f" {expansion_valve}")
|
||||
|
||||
# Evaporator coil: UA = 3 kW/K
|
||||
evaporator = entropyk.Evaporator(ua=3000.0)
|
||||
print(f" {evaporator}")
|
||||
|
||||
# ── Step 2: Build the system graph ──────────────────────────────────────
|
||||
|
||||
print("\n---")
|
||||
print(" Building system graph...")
|
||||
|
||||
system = entropyk.System()
|
||||
|
||||
# Add components — returns node indices
|
||||
comp_idx = system.add_component(compressor)
|
||||
cond_idx = system.add_component(condenser)
|
||||
exv_idx = system.add_component(expansion_valve)
|
||||
evap_idx = system.add_component(evaporator)
|
||||
|
||||
# Connect them in a cycle
|
||||
system.add_edge(comp_idx, cond_idx) # Compressor → Condenser
|
||||
system.add_edge(cond_idx, exv_idx) # Condenser → EXV
|
||||
system.add_edge(exv_idx, evap_idx) # EXV → Evaporator
|
||||
system.add_edge(evap_idx, comp_idx) # Evaporator → Compressor (loop)
|
||||
|
||||
print(f" {system}")
|
||||
|
||||
# ── Step 3: Finalize the system ─────────────────────────────────────────
|
||||
|
||||
print(" Finalizing system topology...")
|
||||
system.finalize()
|
||||
print(f" State vector length: {system.state_vector_len}")
|
||||
|
||||
# ── Step 4: Configure solver ────────────────────────────────────────────
|
||||
|
||||
print("\n---")
|
||||
print(" Configuring solver...")
|
||||
|
||||
# Newton-Raphson solver with line search
|
||||
newton = entropyk.NewtonConfig(
|
||||
max_iterations=200,
|
||||
tolerance=1e-6,
|
||||
line_search=True,
|
||||
timeout_ms=10000,
|
||||
)
|
||||
print(f" {newton}")
|
||||
|
||||
# Picard solver for backup
|
||||
picard = entropyk.PicardConfig(
|
||||
max_iterations=500,
|
||||
tolerance=1e-4,
|
||||
relaxation=0.5,
|
||||
)
|
||||
print(f" {picard}")
|
||||
|
||||
# Fallback: try Newton first, fall back to Picard
|
||||
fallback = entropyk.FallbackConfig(newton=newton, picard=picard)
|
||||
print(f" {fallback}")
|
||||
|
||||
# ── Step 5: Solve ───────────────────────────────────────────────────────
|
||||
|
||||
print("\n---")
|
||||
print(" Solving... (requires real component implementations)")
|
||||
print(" NOTE: SimpleAdapter placeholders will produce trivial solutions.")
|
||||
|
||||
try:
|
||||
result = fallback.solve(system)
|
||||
print(f"\n ✅ Solution found!")
|
||||
print(f" Status: {result.status}")
|
||||
print(f" Iterations: {result.iterations}")
|
||||
print(f" Residual: {result.final_residual:.2e}")
|
||||
print(f" State vector ({len(result.state_vector)} vars): "
|
||||
f"{result.state_vector[:6]}...")
|
||||
except entropyk.SolverError as e:
|
||||
print(f"\n ❌ Solver error: {e}")
|
||||
except entropyk.EntropykError as e:
|
||||
print(f"\n ❌ Entropyk error: {e}")
|
||||
|
||||
# ── Working with physical types ─────────────────────────────────────────
|
||||
|
||||
print("\n---")
|
||||
print(" Physical types demo:")
|
||||
|
||||
p = entropyk.Pressure(bar=12.0)
|
||||
print(f" {p}")
|
||||
print(f" = {p.to_pascals():.0f} Pa")
|
||||
print(f" = {p.to_kpa():.1f} kPa")
|
||||
print(f" = {p.to_bar():.2f} bar")
|
||||
print(f" float(p) = {float(p)}")
|
||||
|
||||
t = entropyk.Temperature(celsius=45.0)
|
||||
print(f" {t}")
|
||||
print(f" = {t.to_kelvin():.2f} K")
|
||||
print(f" = {t.to_celsius():.2f} °C")
|
||||
print(f" = {t.to_fahrenheit():.2f} °F")
|
||||
|
||||
h = entropyk.Enthalpy(kj_per_kg=420.0)
|
||||
print(f" {h}")
|
||||
print(f" = {h.to_j_per_kg():.0f} J/kg")
|
||||
print(f" = {h.to_kj_per_kg():.1f} kJ/kg")
|
||||
|
||||
m = entropyk.MassFlow(kg_per_s=0.05)
|
||||
print(f" {m}")
|
||||
print(f" = {m.to_kg_per_s():.3f} kg/s")
|
||||
print(f" = {m.to_g_per_s():.1f} g/s")
|
||||
|
||||
# Arithmetic
|
||||
p1 = entropyk.Pressure(bar=10.0)
|
||||
p2 = entropyk.Pressure(bar=2.0)
|
||||
print(f"\n Arithmetic: {p1} + {p2} = {p1 + p2}")
|
||||
print(f" {p1} - {p2} = {p1 - p2}")
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print(" Done!")
|
||||
print("=" * 60)
|
||||
Reference in New Issue
Block a user