r"""The Gibbs adsorption equation, and the Szyszkowski surface-tension equation.
J. W. Gibbs, "On the Equilibrium of Heterogeneous Substances," *Trans.
Connecticut Acad. Arts Sci.* 3 (1875-1878), whose theory of surfaces of
discontinuity gives the surface excess :math:`\Gamma` of a dilute solute
directly from how the liquid's surface tension :math:`\gamma` changes
with the solute's concentration :math:`c`:
.. math::
\Gamma = -\frac{1}{RT}\,\frac{d\gamma}{d\ln c}
(Atkins & de Paula, *Physical Chemistry*, 11th ed.; Adamson &
Gast, *Physical Chemistry of Surfaces*, 6th ed., Ch. III). A solute that
*lowers* the surface tension (a surfactant) is therefore positively
adsorbed at the surface -- measured without ever looking at the surface
directly.
The empirical Szyszkowski (1908) equation for aqueous fatty-acid
solutions,
.. math::
\gamma = \gamma_0 - RT\,\Gamma_{max}\ln(1 + Kc),
turns, under the Gibbs equation, into exactly a Langmuir isotherm for the
surface excess, :math:`\Gamma = \Gamma_{max}Kc/(1+Kc)` -- the link that
:func:`gibbs_surface_excess` recovers numerically from surface-tension
data alone.
"""
from __future__ import annotations
import numpy as np
from chemistrykit.constants import R
__all__ = ["szyszkowski_surface_tension", "gibbs_surface_excess"]
[docs]
def szyszkowski_surface_tension(c, gamma0: float, Gamma_max: float, K: float, T: float, R_gas: float = R):
r"""Szyszkowski surface tension :math:`\gamma = \gamma_0 - RT\Gamma_{max}\ln(1+Kc)`.
Parameters
----------
c : float or array-like of float
Bulk solute concentration (mol/m^3 or any unit consistent with `K`).
gamma0 : float
Surface tension of the pure solvent, in N/m.
Gamma_max : float
Saturation surface excess, in mol/m^2.
K : float
Adsorption constant, inverse to `c`'s units.
T : float
Absolute temperature, in K.
R_gas : float, default :data:`chemistrykit.constants.R`
Gas constant, in J mol^-1 K^-1.
Returns
-------
float or ndarray
Surface tension, in N/m.
Examples
--------
Pure solvent (``c=0``) has surface tension exactly :math:`\gamma_0`:
>>> round(float(szyszkowski_surface_tension(0.0, gamma0=0.072, Gamma_max=5e-6, K=1.0, T=298.15)), 10)
0.072
"""
c = np.asarray(c, dtype=np.float64)
result = gamma0 - R_gas * T * Gamma_max * np.log1p(K * c)
return float(result) if result.ndim == 0 else result
[docs]
def gibbs_surface_excess(c, gamma, T: float, R_gas: float = R):
r"""Surface excess from surface-tension data via the Gibbs equation :math:`\Gamma=-(1/RT)\,d\gamma/d\ln c`.
The derivative is taken numerically (second-order finite differences
in :math:`\ln c`, :func:`numpy.gradient`), so `c` should be sampled
densely enough that :math:`\gamma(\ln c)` is smooth.
Parameters
----------
c : array-like of float
Strictly positive, increasing bulk concentrations.
gamma : array-like of float
Measured surface tensions at those concentrations, in N/m.
T : float
Absolute temperature, in K.
R_gas : float, default :data:`chemistrykit.constants.R`
Gas constant, in J mol^-1 K^-1.
Returns
-------
ndarray
Surface excess :math:`\Gamma`, in mol/m^2 (for `gamma` in N/m).
Examples
--------
Applied to Szyszkowski surface-tension data, the Gibbs equation
recovers a Langmuir isotherm for the surface excess:
>>> c = np.logspace(-3, 2, 2001)
>>> gamma = szyszkowski_surface_tension(c, gamma0=0.072, Gamma_max=5e-6, K=2.0, T=298.15)
>>> Gamma = gibbs_surface_excess(c, gamma, T=298.15)
>>> bool(np.allclose(Gamma[1:-1], 5e-6 * 2.0 * c[1:-1] / (1 + 2.0 * c[1:-1]), rtol=1e-4))
True
"""
c = np.asarray(c, dtype=np.float64)
gamma = np.asarray(gamma, dtype=np.float64)
if np.any(c <= 0):
raise ValueError("concentrations must be strictly positive")
dgamma_dlnc = np.gradient(gamma, np.log(c))
return -dgamma_dlnc / (R_gas * T)