Skip to content

Commit 4ef519c

Browse files
committed
update
1 parent fbfa7f8 commit 4ef519c

File tree

1 file changed

+61
-10
lines changed

1 file changed

+61
-10
lines changed

devtools/unisim_writer.py

Lines changed: 61 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,23 @@
128128
'c-hexane': 'c-Hexane',
129129
}
130130

131+
# Approximate molar mass (g/mol) for common components, used to convert
132+
# mass flow (kg/h) to molar flow (kgmole/s) for the UniSim COM feed spec.
133+
_COMPONENT_MW = {
134+
'nitrogen': 28.014, 'CO2': 44.010, 'methane': 16.043,
135+
'ethane': 30.070, 'propane': 44.096, 'i-butane': 58.123,
136+
'n-butane': 58.123, 'i-pentane': 72.150, 'n-pentane': 72.150,
137+
'n-hexane': 86.177, 'n-heptane': 100.204, 'n-octane': 114.231,
138+
'n-nonane': 128.258, 'nC10': 142.285, 'water': 18.015,
139+
'hydrogen': 2.016, 'H2S': 34.081, 'oxygen': 31.998,
140+
'argon': 39.948, 'helium': 4.003, 'CO': 28.010,
141+
'methanol': 32.042, 'ethanol': 46.069, 'benzene': 78.114,
142+
'toluene': 92.141, 'cyclohexane': 84.161, 'MEG': 62.068,
143+
'TEG': 150.174, 'DEG': 106.120, 'ammonia': 17.031,
144+
'SO2': 64.066, 'COS': 60.075, 'ethylene': 28.054,
145+
'propene': 42.081,
146+
}
147+
131148
# NeqSim EOS model name -> UniSim property package name
132149
NEQSIM_TO_UNISIM_PROPERTY_PACKAGE = {
133150
'SRK': 'SRK',
@@ -587,6 +604,22 @@ def _to_internal_unit(value, unit_str):
587604
return value
588605
return None # unknown unit — skip Calculate fallback
589606

607+
@staticmethod
608+
def _estimate_molar_mass(fluid: 'ParsedFluid') -> Optional[float]:
609+
"""Estimate mixture molar mass (g/mol) from composition.
610+
611+
Returns None if any component MW is unknown.
612+
"""
613+
if not fluid or not fluid.components:
614+
return None
615+
mw_mix = 0.0
616+
for comp, frac in fluid.components.items():
617+
mw = _COMPONENT_MW.get(comp)
618+
if mw is None:
619+
return None # unknown component — can't compute
620+
mw_mix += frac * mw
621+
return mw_mix if mw_mix > 0 else None
622+
590623
def close(self):
591624
"""Close UniSim application."""
592625
if self._app is not None:
@@ -654,30 +687,48 @@ def build_from_json(self, json_str: str,
654687
except Exception as e:
655688
self._warnings.append("Could not re-enable solver: %s" % e)
656689

657-
# Re-set feed stream flow rates (needs solver active + composition)
690+
# Re-set feed stream flow rates via MolarFlow.Calculate.
691+
# MolarFlow (internal unit: kgmole/s) is the most reliable way
692+
# to set flow in UniSim COM — MassFlow.Calculate persists on the
693+
# feed but doesn't propagate to downstream equipment.
658694
for ps in systems:
695+
mw = self._estimate_molar_mass(ps.fluid)
659696
for feed in ps.feed_streams:
660697
if feed.flow_rate_kghr is not None:
661698
ms = self._stream_objects.get(feed.name)
662-
if ms is not None:
699+
if ms is None:
700+
continue
701+
# Try MolarFlow first (converts kg/h -> kgmole/s)
702+
flow_set = False
703+
if mw and mw > 0:
704+
kgmol_s = feed.flow_rate_kghr / 3600.0 / mw
705+
try:
706+
ms.MolarFlow.Calculate(kgmol_s)
707+
flow_set = True
708+
time.sleep(self.COM_DELAY_MEDIUM)
709+
logger.info(
710+
"Set flow on %s: %.0f kg/h "
711+
"(%.3f kgmol/s, MW=%.1f)",
712+
feed.name, feed.flow_rate_kghr,
713+
kgmol_s, mw)
714+
except Exception:
715+
pass
716+
# Fallback: MassFlow
717+
if not flow_set:
663718
if not self._set_variable(
664719
ms.MassFlow, feed.flow_rate_kghr,
665720
'kg/h', f"{feed.name}.F"):
666721
self._warnings.append(
667-
f"Could not re-set flow on '{feed.name}'")
668-
else:
669-
time.sleep(self.COM_DELAY_MEDIUM)
670-
logger.info("Re-set flow on %s: %.0f kg/h",
671-
feed.name, feed.flow_rate_kghr)
722+
f"Could not set flow on '{feed.name}'")
672723

673724
# Save if requested
674725
if save_path:
675726
abs_path = os.path.abspath(save_path)
676727
try:
677728
self._case.SaveAs(abs_path)
678-
except Exception:
679-
self._case.Save(abs_path)
680-
logger.info(f"Saved UniSim case to: {abs_path}")
729+
logger.info("Saved UniSim case: %s", abs_path)
730+
except Exception as e:
731+
self._warnings.append(f"Could not save: {e}")
681732

682733
return self._case
683734

0 commit comments

Comments
 (0)