Source code for microscopic_gating.adsorption

r"""
Adsorption isotherms for surface occupancy modeling.

This module implements adsorption isotherms that describe how surface
occupancy depends on bulk concentration. These form the foundation for
the gating function calculations.

Theoretical Foundation
----------------------
Derived from grand canonical ensemble for a single binding site with
two states (empty/occupied):

.. math::

    Z = 1 + z e^{\beta\epsilon}

where :math:`z \simeq \phi/\phi^\circ` is the fugacity and :math:`\epsilon`
is the binding energy. The occupancy fraction is:

.. math::

    \theta(\phi) = \frac{z e^{\beta\epsilon}}{1 + z e^{\beta\epsilon}}
                 = \frac{\phi/K_d}{1 + \phi/K_d}

with dissociation constant :math:`K_d = \phi^\circ e^{-\beta\epsilon}`.

Key Properties
--------------
- **Low concentration** (:math:`\phi \ll K_d`): :math:`\theta \approx \phi/K_d` (linear)
- **High concentration** (:math:`\phi \gg K_d`): :math:`\theta \to 1` (saturation)
- **Half-occupancy**: :math:`\theta = 0.5` at :math:`\phi = K_d`

References
----------
- Eq. (S3)-(S4): Langmuir isotherm derivation
- Eq. (S6)-(S7): Symmetric gating function
"""

from __future__ import annotations

from dataclasses import dataclass

import numpy as np

from .types import ArrayLike


[docs]@dataclass(frozen=True) class LangmuirIsotherm: r""" Langmuir isotherm from grand canonical two-state site model. Implements the standard Langmuir adsorption model (Eq. S3-S4): .. math:: \theta(\phi) = \frac{\phi/K}{1+\phi/K} This corresponds to a single-site partition function :math:`Z = 1 + z e^{\beta \epsilon}`, with :math:`z \simeq \phi/\phi^\circ` and :math:`K = \phi^\circ e^{-\beta\epsilon}`. Parameters ---------- K : float Dissociation constant (same unit as :math:`\phi`). Smaller K indicates stronger binding. See Also -------- HillIsotherm : Extended isotherm with cooperativity parameter. Examples -------- >>> isotherm = LangmuirIsotherm(K=1.0) >>> isotherm.theta(1.0) 0.5 >>> isotherm.theta([0.1, 1.0, 10.0]) array([0.0909..., 0.5, 0.9090...]) References ---------- - Eq. (S3)-(S4): Grand canonical two-state site model """ K: float
[docs] def theta(self, phi: ArrayLike) -> ArrayLike: r""" Calculate occupancy fraction. Parameters ---------- phi : ArrayLike Bulk concentration (same unit as K). Returns ------- theta : ArrayLike Occupancy fraction in [0, 1], same shape as `phi`. Notes ----- At :math:`\phi = K`, the occupancy is exactly 0.5. """ phi = np.asarray(phi, dtype=float) x = phi / self.K return x / (1.0 + x)
[docs]@dataclass(frozen=True) class HillIsotherm: r""" Hill isotherm with effective cooperativity. Extends the Langmuir model with a Hill coefficient to capture cooperative or multi-body effects: .. math:: \theta(\phi) = \frac{(\phi/K)^n}{1+(\phi/K)^n} Parameters ---------- K : float Effective dissociation constant (same unit as :math:`\phi`). n : float, optional Hill coefficient (default: 1.0). - n = 1: Reduces to Langmuir isotherm - n > 1: Positive cooperativity (steeper transition) - n < 1: Negative cooperativity (shallower transition) See Also -------- LangmuirIsotherm : Special case with n=1. Notes ----- Hill behavior is not required by the minimal model, but can represent effective multi-body or cooperative binding effects. Examples -------- >>> isotherm = HillIsotherm(K=1.0, n=2.0) >>> isotherm.theta(1.0) 0.5 >>> isotherm.theta([0.5, 1.0, 2.0]) array([0.2, 0.5, 0.8]) """ K: float n: float = 1.0
[docs] def theta(self, phi: ArrayLike) -> ArrayLike: r""" Calculate occupancy fraction with cooperativity. Parameters ---------- phi : ArrayLike Bulk concentration (same unit as K). Returns ------- theta : ArrayLike Occupancy fraction in [0, 1], same shape as `phi`. Notes ----- The Hill coefficient :math:`n` controls the steepness of the transition around :math:`\phi = K`. """ phi = np.asarray(phi, dtype=float) x = (phi / self.K) ** self.n return x / (1.0 + x)