import sympy as sm
import matplotlib.pyplot as plt
import numpy as np
from chempy import ReactionSystem
from chempy.units import to_unitless, SI_base_registry as si, default_units as u, default_constants as const
from chempy.kinetics.ode import get_odesys
from chempy.kinetics.integrated import binary_rev
sm.init_printing()
%matplotlib inline
R = 8.314472
T_K = 273.15 + 20 # 20 degree celsius
kB = 1.3806504e-23
h = 6.62606896e-34
dHf = 74e3
dSf = R*np.log(h/kB/T_K*1e16)
dHb = 79e3
dSb = dSf - 23
rsys1 = ReactionSystem.from_string("""
Fe+3 + SCN- -> FeSCN+2; EyringParam(dH={dHf}*J/mol, dS={dSf}*J/K/mol)
FeSCN+2 -> Fe+3 + SCN-; EyringParam(dH={dHb}*J/mol, dS={dSb}*J/K/mol)
""".format(dHf=dHf, dSf=dSf, dHb=dHb, dSb=dSb))
kf_ref = 20836643994.118652*T_K*np.exp(-(dHf - T_K*dSf)/(R*T_K))
kb_ref = 20836643994.118652*T_K*np.exp(-(dHb - T_K*dSb)/(R*T_K))
kf_ref, kb_ref
Fe0 = 6e-3
SCN0 = 2e-3
init_cond = {
'Fe+3': Fe0*u.M,
'SCN-': SCN0*u.M,
'FeSCN+2': 0*u.M
}
t = 3*u.second
def integrate_and_plot(rsys, params):
odes, extra = get_odesys(rsys, include_params=False, unit_registry=si, constants=const)
fig, all_axes = plt.subplots(2, 3, figsize=(14, 6))
for axes, odesys in zip(all_axes, [odes, odes.as_autonomous()]):
res = odesys.integrate(t, init_cond, params, integrator='cvode')
t_sec = to_unitless(res.xout, u.second)
FeSCN_ref = binary_rev(t_sec, kf_ref, kb_ref, 0, Fe0, SCN0)
cmp = to_unitless(res.yout, u.M)
ref = np.empty_like(cmp)
ref[:, odesys.names.index('FeSCN+2')] = FeSCN_ref
ref[:, odesys.names.index('Fe+3')] = Fe0 - FeSCN_ref
ref[:, odesys.names.index('SCN-')] = SCN0 - FeSCN_ref
axes[0].plot(t_sec, cmp)
axes[1].plot(t_sec, cmp - ref)
res.plot_invariant_violations(ax=axes[2])
assert np.allclose(cmp, ref)
print({k: v for k, v in res.info.items() if not k.startswith('internal')})
integrate_and_plot(rsys1, {'temperature': T_K*u.K})
rsys2 = ReactionSystem.from_string("""
Fe+3 + SCN- -> FeSCN+2; MassAction(EyringHS([{dHf}*J/mol, {dSf}*J/K/mol]))
FeSCN+2 -> Fe+3 + SCN-; MassAction(EyringHS([{dHb}*J/mol, {dSb}*J/K/mol]))
""".format(dHf=dHf, dSf=dSf, dHb=dHb, dSb=dSb))
integrate_and_plot(rsys2, {'temperature': T_K*u.K})
rsys3 = ReactionSystem.from_string("""
Fe+3 + SCN- -> FeSCN+2; MassAction(EyringHS.fk('dHf', 'dSf'))
FeSCN+2 -> Fe+3 + SCN-; MassAction(EyringHS.fk('dHb', 'dSb'))
""")
integrate_and_plot(rsys3, dict(temperature=T_K*u.K,
dHf=dHf*u.J/u.mol, dSf=dSf*u.J/u.mol/u.K,
dHb=dHb*u.J/u.mol, dSb=dSb*u.J/u.mol/u.K))