Spaces:
Sleeping
Sleeping
Sync server/reactor_sim.py
Browse files- server/reactor_sim.py +46 -2
server/reactor_sim.py
CHANGED
|
@@ -86,15 +86,59 @@ _ACT = _CFG.get("actuator_limits", {})
|
|
| 86 |
# ---------------------------------------------------------------------------
|
| 87 |
R_GAS = 8.314 # J/(mol*K), universal gas constant
|
| 88 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 89 |
|
| 90 |
def _fugacity_coefficient(T_K: float, P_bar: float, species: str = "CO") -> float:
|
| 91 |
"""SRK fugacity coefficient for key species at reactor conditions.
|
| 92 |
|
| 93 |
-
|
| 94 |
-
|
| 95 |
|
| 96 |
Returns phi (fugacity coefficient, 0 < phi < 1 at high pressure).
|
| 97 |
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 98 |
# Critical properties for key species
|
| 99 |
Tc_K = {"H2": 33.2, "CO": 132.9, "CO2": 304.2, "CH3OH": 512.6, "H2O": 647.1}.get(species, 132.9)
|
| 100 |
Pc_bar = {"H2": 13.0, "CO": 35.0, "CO2": 73.8, "CH3OH": 80.9, "H2O": 220.6}.get(species, 35.0)
|
|
|
|
| 86 |
# ---------------------------------------------------------------------------
|
| 87 |
R_GAS = 8.314 # J/(mol*K), universal gas constant
|
| 88 |
|
| 89 |
+
# ---------------------------------------------------------------------------
|
| 90 |
+
# Optional DWSIM backend — when available, fugacity coefficients come from
|
| 91 |
+
# DWSIM's industrial SRK solver instead of our internal approximation.
|
| 92 |
+
# Set DWSIM_PATH env var to enable. Falls back silently if unavailable.
|
| 93 |
+
# ---------------------------------------------------------------------------
|
| 94 |
+
_dwsim_backend = None
|
| 95 |
+
_dwsim_cache = {} # (T_K_rounded, P_bar_rounded) → {species: phi}
|
| 96 |
+
|
| 97 |
+
def _init_dwsim():
|
| 98 |
+
global _dwsim_backend
|
| 99 |
+
if _dwsim_backend is not None:
|
| 100 |
+
return
|
| 101 |
+
try:
|
| 102 |
+
import sys, os
|
| 103 |
+
# Add integration path
|
| 104 |
+
_int_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), "integrations")
|
| 105 |
+
if _int_dir not in sys.path:
|
| 106 |
+
sys.path.insert(0, _int_dir)
|
| 107 |
+
from dwsim import DWSIMIntegration
|
| 108 |
+
d = DWSIMIntegration()
|
| 109 |
+
if d.is_available:
|
| 110 |
+
_dwsim_backend = d
|
| 111 |
+
except Exception:
|
| 112 |
+
pass
|
| 113 |
+
|
| 114 |
+
_init_dwsim()
|
| 115 |
+
|
| 116 |
|
| 117 |
def _fugacity_coefficient(T_K: float, P_bar: float, species: str = "CO") -> float:
|
| 118 |
"""SRK fugacity coefficient for key species at reactor conditions.
|
| 119 |
|
| 120 |
+
When DWSIM is available (DWSIM_PATH set), uses DWSIM's industrial SRK
|
| 121 |
+
solver via .NET interop. Falls back to internal SRK implementation.
|
| 122 |
|
| 123 |
Returns phi (fugacity coefficient, 0 < phi < 1 at high pressure).
|
| 124 |
"""
|
| 125 |
+
# Try DWSIM backend first (cached per T,P to avoid repeated .NET calls)
|
| 126 |
+
if _dwsim_backend is not None:
|
| 127 |
+
cache_key = (round(T_K, 1), round(P_bar, 1))
|
| 128 |
+
if cache_key not in _dwsim_cache:
|
| 129 |
+
try:
|
| 130 |
+
comp = {"H2": 0.6, "CO": 0.1, "CO2": 0.05, "CH3OH": 0.02,
|
| 131 |
+
"H2O": 0.01, "CH4": 0.15, "N2": 0.07}
|
| 132 |
+
result = _dwsim_backend.get_thermodynamic_properties(
|
| 133 |
+
T_K, P_bar * 1e5, comp)
|
| 134 |
+
_dwsim_cache[cache_key] = result.fugacity_coefficients
|
| 135 |
+
except Exception:
|
| 136 |
+
_dwsim_cache[cache_key] = None
|
| 137 |
+
cached = _dwsim_cache.get(cache_key)
|
| 138 |
+
if cached and species in cached:
|
| 139 |
+
return cached[species]
|
| 140 |
+
|
| 141 |
+
# Internal SRK fallback
|
| 142 |
# Critical properties for key species
|
| 143 |
Tc_K = {"H2": 33.2, "CO": 132.9, "CO2": 304.2, "CH3OH": 512.6, "H2O": 647.1}.get(species, 132.9)
|
| 144 |
Pc_bar = {"H2": 13.0, "CO": 35.0, "CO2": 73.8, "CH3OH": 80.9, "H2O": 220.6}.get(species, 35.0)
|