Skip to content

Commit

Permalink
implement reactive equilibrium
Browse files Browse the repository at this point in the history
  • Loading branch information
yoelcortes committed May 26, 2024
1 parent 5a6809a commit da4a613
Show file tree
Hide file tree
Showing 8 changed files with 808 additions and 510 deletions.
157 changes: 154 additions & 3 deletions tests/test_reaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"""
import pytest
import thermosteam as tmo
import numpy as np
from thermosteam.reaction import (
Reaction, ParallelReaction, SeriesReaction, ReactionSystem, ReactionItem
)
Expand Down Expand Up @@ -213,8 +214,10 @@ def test_reaction_enthalpy_with_phases():
reactant='Glucose', X=1,
correct_atomic_balance=True)
assert_allclose(combustion.dH, -2787650.3239119546, rtol=1e-3)

def test_reactive_phase_equilibrium():

def test_reactive_phase_equilibrium_no_kinetics():
import thermosteam as tmo
from numpy.testing import assert_allclose
tmo.settings.set_thermo(['EthylLactate', 'LacticAcid', 'H2O', 'Ethanol'], cache=True)
rxn = tmo.Reaction('LacticAcid + Ethanol -> H2O + EthylLactate', reactant='LacticAcid', X=0.2)
stream = tmo.Stream(
Expand All @@ -236,6 +239,153 @@ def test_reactive_phase_equilibrium():
1.8234109156732896]
)

stream.vle(T=340, P=101325, liquid_reaction=rxn)
assert_allclose(
stream.imol['l'],
stream.mol
)
assert_allclose(
stream.imol['g'],
0
)
stream.vle(T=450, P=101325, liquid_reaction=rxn)
assert_allclose(
stream.imol['g'],
stream.mol
)
assert_allclose(
stream.imol['l'],
0
)

def test_reactive_phase_equilibrium_with_kinetics():
import thermosteam as tmo
from math import exp
from numpy.testing import assert_allclose
tmo.settings.set_thermo(['EthylLactate', 'LacticAcid', 'H2O', 'Ethanol'], cache=True)

class Esterification(tmo.Reaction):
__slots__ = ('mcat',)

def __init__(self):
super().__init__(
'LacticAcid + Ethanol -> H2O + EthylLactate',
reactant='LacticAcid', X=0.2
)
self.mcat = 0.01

def _rate(self, stream):
R = tmo.constants.R
T = stream.T
kf = 6.52e3 * exp(-4.8e4 / (R * T))
kr = 2.72e3 * exp(-4.8e4 / (R * T))
LaEt, La, H2O, EtOH = stream.mol / stream.F_mol
return self.mcat * (kf * La * EtOH - kr * LaEt * H2O)

rxn = Esterification()
stream = tmo.Stream(
H2O=2, Ethanol=5, LacticAcid=1, T=355,
)
rxn(stream)
assert_allclose(
stream.mol,
[0.7998037291462218, 0.20019627085377822,
2.799803729146222, 4.200196270853779]
)
stream = tmo.Stream(
H2O=2, Ethanol=5, LacticAcid=1, T=355,
)
T = 360
P = 101325
stream.vle(T=T, P=P, liquid_reaction=rxn)
assert_allclose(
stream.imol['l'],
[0.35781246995914223,
0.28312078337665264,
1.291316286965713,
1.3287108564655643],
rtol=1e-6,
atol=1e-6,
)
assert_allclose(
stream.imol['g'],
[0.0,
0.35906674666420507,
1.0664961829934292,
3.313476673575294],
rtol=1e-6,
atol=1e-6,
)
V = stream.vapor_fraction
H = stream.H + stream.Hf
stream = tmo.Stream(
H2O=2, Ethanol=5, LacticAcid=1, T=355,
)
stream.vle(V=V, P=P, liquid_reaction=rxn)
assert_allclose(
stream.imol['l'],
[0.35781246995914223,
0.28312078337665264,
1.291316286965713,
1.3287108564655643],
rtol=1e-6,
atol=1e-6,
)
assert_allclose(
stream.imol['g'],
[0.0,
0.35906674666420507,
1.0664961829934292,
3.313476673575294],
rtol=1e-6,
atol=1e-6,
)
stream = tmo.Stream(
H2O=2, Ethanol=5, LacticAcid=1, T=355,
)
stream.vle(V=V, T=T, liquid_reaction=rxn)
assert_allclose(
stream.imol['l'],
[0.35781246995914223,
0.28312078337665264,
1.291316286965713,
1.3287108564655643],
rtol=1e-6,
atol=1e-6,
)
assert_allclose(
stream.imol['g'],
[0.0,
0.35906674666420507,
1.0664961829934292,
3.313476673575294],
rtol=1e-6,
atol=1e-6,
)
stream = tmo.Stream(
H2O=2, Ethanol=5, LacticAcid=1, T=355,
)
stream.vle(H=H, P=P, liquid_reaction=rxn)
assert_allclose(
stream.imol['l'],
[0.35781246995914223,
0.28312078337665264,
1.291316286965713,
1.3287108564655643],
rtol=1e-6,
atol=1e-6,
)
assert_allclose(
stream.imol['g'],
[0.0,
0.35906674666420507,
1.0664961829934292,
3.313476673575294],
rtol=1e-6,
atol=1e-6,
)


def test_repr():
cal2joule = 4.184
Glucan = tmo.Chemical('Glucan', search_db=False, formula='C6H10O5', Hf=-233200*cal2joule, phase='s', default=True)
Expand Down Expand Up @@ -264,5 +414,6 @@ def test_repr():
test_reaction()
test_reaction_enthalpy_balance()
test_reaction_enthalpy_with_phases()
test_reactive_phase_equilibrium()
test_reactive_phase_equilibrium_no_kinetics()
test_reactive_phase_equilibrium_with_kinetics()
test_repr()
6 changes: 1 addition & 5 deletions thermosteam/_multi_stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -361,9 +361,7 @@ def reset_cache(self):
self._streams = {}
self._vle_cache = eq.VLECache(self._imol,
self._thermal_condition,
self._thermo,
self._bubble_point_cache,
self._dew_point_cache)
self._thermo)
self._lle_cache = eq.LLECache(self._imol,
self._thermal_condition,
self._thermo)
Expand All @@ -381,8 +379,6 @@ def __getitem__(self, phase):
stream._imol = self._imol.get_phase(phase)
stream._thermal_condition = self._thermal_condition
stream._thermo = self._thermo
stream._bubble_point_cache = self._bubble_point_cache
stream._dew_point_cache = self._dew_point_cache
stream._property_cache = {}
stream.characterization_factors = {}
stream._property_cache_key = None, None
Expand Down
22 changes: 4 additions & 18 deletions thermosteam/_stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
from .base import SparseVector, SparseArray
from numpy.typing import NDArray
from typing import Optional, Sequence, Callable
import biosteam as bst
# from .constants import g

MaterialIndexer = tmo.indexer.MaterialIndexer
Expand Down Expand Up @@ -274,7 +273,6 @@ class Stream(AbstractStream):
"""
__slots__ = (
'_imol', '_thermal_condition', '_streams',
'_bubble_point_cache', '_dew_point_cache',
'_vle_cache', '_lle_cache', '_sle_cache',
'_price', '_property_cache_key',
'_property_cache', 'characterization_factors', 'equations',
Expand Down Expand Up @@ -767,8 +765,6 @@ def _init_indexer(self, flow, phase, chemicals, chemical_flows):

def reset_cache(self):
"""Reset cache regarding equilibrium methods."""
self._bubble_point_cache = eq.BubblePointCache()
self._dew_point_cache = eq.DewPointCache()
self._property_cache_key = None, None
self._property_cache = {}

Expand Down Expand Up @@ -1965,8 +1961,6 @@ def proxy(self, ID=None):
new._thermal_condition = self._thermal_condition
new._property_cache = self._property_cache
new._property_cache_key = self._property_cache_key
new._bubble_point_cache = self._bubble_point_cache
new._dew_point_cache = self._dew_point_cache
new.equations = self.equations
new.characterization_factors = self.characterization_factors
return new
Expand Down Expand Up @@ -2022,9 +2016,7 @@ def vlle(self, T, P):
imol = self.imol
vle = eq.VLE(imol,
self._thermal_condition,
self._thermo,
self._bubble_point_cache,
self._dew_point_cache)
self._thermo)
lle = eq.LLE(imol,
self._thermal_condition,
self._thermo)
Expand Down Expand Up @@ -2094,9 +2086,7 @@ def get_bubble_point(self, IDs: Optional[Sequence[str]]=None):
BubblePoint([Water, Ethanol])
"""
chemicals = self.chemicals[IDs] if IDs else self.vle_chemicals
bp = self._bubble_point_cache(chemicals, self._thermo)
return bp
return eq.BubblePoint(self.chemicals[IDs] if IDs else self.vle_chemicals, self._thermo)

def get_dew_point(self, IDs: Optional[Sequence[str]]=None):
"""
Expand All @@ -2116,9 +2106,7 @@ def get_dew_point(self, IDs: Optional[Sequence[str]]=None):
DewPoint([Water, Ethanol])
"""
chemicals = self.chemicals[IDs] if IDs else self.vle_chemicals
dp = self._dew_point_cache(chemicals, self._thermo)
return dp
return eq.DewPoint(self.chemicals[IDs] if IDs else self.vle_chemicals, self._thermo)

def bubble_point_at_T(self, T: Optional[float]=None, IDs: Optional[Sequence[str]]=None):
"""
Expand Down Expand Up @@ -2502,9 +2490,7 @@ def phases(self, phases):
self._streams = {}
self._vle_cache = eq.VLECache(self._imol,
self._thermal_condition,
self._thermo,
self._bubble_point_cache,
self._dew_point_cache)
self._thermo)
self._lle_cache = eq.LLECache(self._imol,
self._thermal_condition,
self._thermo)
Expand Down
Loading

0 comments on commit da4a613

Please sign in to comment.