Skip to content

Activation

JAX-native implementations of the Abdul-Razzak & Ghan (2000) and Morales Betancourt & Nenes (2014) activation parameterizations, wrapped as callable classes that are compatible with jax.grad and jax.vmap.

Callable classes

ARG2000

ARG2000(accom: float = c.ac)

Abdul-Razzak & Ghan (2000) activation scheme.

A thin callable wrapper around arg2000 that satisfies the ActivationScheme interface. Instantiate once; call repeatedly.

Parameters:

Name Type Description Default
accom float

Condensation accommodation coefficient (forwarded to every call).

ac
Source code in pyrcel/activation/_arg2000.py
def __init__(self, accom: float = c.ac) -> None:
    self.accom = accom

MBN2014

MBN2014(accom: float = c.ac)

Morales Betancourt & Nenes (2014) activation scheme.

A thin callable wrapper around mbn2014 satisfying the ActivationScheme interface.

Parameters:

Name Type Description Default
accom float

Condensation accommodation coefficient forwarded to every call.

ac
Source code in pyrcel/activation/_mbn2014.py
def __init__(self, accom: float = c.ac) -> None:
    self.accom = accom

ActivationScheme

Bases: ABC

Interface for droplet activation parameterizations.

All schemes accept lognormal aerosol parameters and updraft conditions and return the maximum parcel supersaturation plus per-mode activated fractions. JAX-native subclasses (e.g. ARG2000) are fully differentiable via jax.grad.

Helper functions

lognormal_activation

lognormal_activation(
    smax: ArrayLike,
    mu: ArrayLike,
    sigma: ArrayLike,
    N: ArrayLike,
    kappa: ArrayLike,
    T: ArrayLike | None = None,
    sgi: ArrayLike | None = None,
) -> tuple[Array, Array]

Activated number and fraction for one or more lognormal modes.

At least one of T or sgi must be supplied. If sgi is given it is used directly; otherwise the modal critical supersaturation is computed from T, mu, and kappa via the approximate κ-Köhler formula.

All scalar arguments broadcast naturally, so the function handles both single-mode scalars and multi-mode arrays in one call.

Parameters:

Name Type Description Default
smax float

Maximum parcel supersaturation (decimal).

required
mu float or array - like

Geometric mean dry radius of the mode(s), m.

required
sigma float or array - like

Geometric standard deviation(s).

required
N float or array - like

Total number concentration(s) (cm⁻³ or any consistent unit).

required
kappa float or array - like

Hygroscopicity parameter(s).

required
T float

Parcel temperature (K). Required when sgi is not supplied.

None
sgi float or array - like

Pre-computed modal critical supersaturation(s). If given, T and mu and kappa are not used for the critical-point calculation.

None

Returns:

Name Type Description
N_act float or array

Activated number concentration (same unit as N).

act_frac float or array

Activated fraction in [0, 1].

Notes

Uses _lognormal_act with the modal critical supersaturation obtained from _kohler_crit_approx.

Source code in pyrcel/activation/_common.py
def lognormal_activation(
    smax: ArrayLike,
    mu: ArrayLike,
    sigma: ArrayLike,
    N: ArrayLike,
    kappa: ArrayLike,
    T: ArrayLike | None = None,
    sgi: ArrayLike | None = None,
) -> tuple[Array, Array]:
    r"""Activated number and fraction for one or more lognormal modes.

    At least one of ``T`` or ``sgi`` must be supplied.  If ``sgi`` is given
    it is used directly; otherwise the modal critical supersaturation is
    computed from ``T``, ``mu``, and ``kappa`` via the approximate κ-Köhler
    formula.

    All scalar arguments broadcast naturally, so the function handles both
    single-mode scalars and multi-mode arrays in one call.

    Parameters
    ----------
    smax : float
        Maximum parcel supersaturation (decimal).
    mu : float or array-like
        Geometric mean dry radius of the mode(s), m.
    sigma : float or array-like
        Geometric standard deviation(s).
    N : float or array-like
        Total number concentration(s) (cm⁻³ or any consistent unit).
    kappa : float or array-like
        Hygroscopicity parameter(s).
    T : float, optional
        Parcel temperature (K).  Required when ``sgi`` is not supplied.
    sgi : float or array-like, optional
        Pre-computed modal critical supersaturation(s).  If given, ``T``
        and ``mu`` and ``kappa`` are not used for the critical-point
        calculation.

    Returns
    -------
    N_act : float or array
        Activated number concentration (same unit as ``N``).
    act_frac : float or array
        Activated fraction in [0, 1].

    Notes
    -----
    Uses `_lognormal_act` with the modal critical supersaturation obtained
    from `_kohler_crit_approx`.

    """
    if sgi is None:
        if T is None:
            raise ValueError("Either T or sgi must be provided.")
        _, sgi = _kohler_crit_approx(T, mu, kappa)
    return _lognormal_act(smax, sigma, N, sgi)

binned_activation

binned_activation(
    Smax: ArrayLike,
    T: ArrayLike,
    rs: ArrayLike,
    r_drys: ArrayLike,
    Nis: ArrayLike,
    kappa: ArrayLike,
) -> tuple[Array, Array, Array, Array]

Equilibrium and kinetic activation statistics for a binned aerosol mode.

A JAX-native re-implementation of pyrcel.legacy.activation.binned_activation that operates on raw arrays (no AerosolSpecies object) and is jax.jit-compatible. Critical radii and supersaturations are computed with the approximate κ-Köhler formula (_kohler_crit_approx).

Parameters:

Name Type Description Default
Smax float

Environmental maximum supersaturation (decimal).

required
T float

Environmental temperature (K).

required
rs (array - like, shape(nr))

Current wet radii of the aerosol/droplet population (m).

required
r_drys (array - like, shape(nr))

Dry particle radii (m).

required
Nis (array - like, shape(nr))

Number concentration per size bin (m⁻³).

required
kappa float

Hygroscopicity parameter for this mode.

required

Returns:

Name Type Description
eq_frac float

Equilibrium-activated fraction: bins with \(S_\text{crit} \le S_\text{max}\).

kn_frac float

Kinetic-activated fraction: bins that have grown past their critical wet radius.

alpha float

Ratio \(N_\text{kn} / N_\text{eq}\) (kinetic limitation factor).

phi float

Fraction of kinetically active bins that are still below their critical wet radius (unactivated tail).

Notes

Follows the approach of Nenes et al. (2001): the equilibrium count includes all bins whose critical supersaturation is below the environmental value; the kinetic count starts at the smallest bin that has already grown past its critical wet radius and includes all larger bins.

References

[Nenes2001] Nenes, A., Ghan, S., Abdul-Razzak, H., Chuang, P. Y., & Seinfeld, J. H. (2001). Kinetic limitations on cloud droplet formation and impact on cloud albedo. Tellus B, 53(2), 133–149. https://doi.org/10.1034/j.1600-0889.2001.d01-12.x

Source code in pyrcel/activation/_common.py
def binned_activation(
    Smax: ArrayLike,
    T: ArrayLike,
    rs: ArrayLike,
    r_drys: ArrayLike,
    Nis: ArrayLike,
    kappa: ArrayLike,
) -> tuple[Array, Array, Array, Array]:
    r"""Equilibrium and kinetic activation statistics for a binned aerosol mode.

    A JAX-native re-implementation of
    `pyrcel.legacy.activation.binned_activation` that operates on raw
    arrays (no `AerosolSpecies` object) and is `jax.jit`-compatible.
    Critical radii and supersaturations are computed with the approximate
    κ-Köhler formula (`_kohler_crit_approx`).

    Parameters
    ----------
    Smax : float
        Environmental maximum supersaturation (decimal).
    T : float
        Environmental temperature (K).
    rs : array-like, shape (nr,)
        Current wet radii of the aerosol/droplet population (m).
    r_drys : array-like, shape (nr,)
        Dry particle radii (m).
    Nis : array-like, shape (nr,)
        Number concentration per size bin (m⁻³).
    kappa : float
        Hygroscopicity parameter for this mode.

    Returns
    -------
    eq_frac : float
        Equilibrium-activated fraction: bins with $S_\text{crit} \le S_\text{max}$.
    kn_frac : float
        Kinetic-activated fraction: bins that have grown past their critical
        wet radius.
    alpha : float
        Ratio $N_\text{kn} / N_\text{eq}$ (kinetic limitation factor).
    phi : float
        Fraction of kinetically active bins that are still below their
        critical wet radius (unactivated tail).

    Notes
    -----
    Follows the approach of Nenes et al. (2001): the equilibrium count includes
    all bins whose critical supersaturation is below the environmental value;
    the kinetic count starts at the smallest bin that has already grown past its
    critical wet radius and includes all larger bins.

    References
    ----------
    **[Nenes2001]** Nenes, A., Ghan, S., Abdul-Razzak, H., Chuang, P. Y., &
    Seinfeld, J. H. (2001). Kinetic limitations on cloud droplet formation
    and impact on cloud albedo. *Tellus B*, **53**(2), 133–149.
    https://doi.org/10.1034/j.1600-0889.2001.d01-12.x

    """
    rs = jnp.asarray(rs, dtype=float)
    r_drys = jnp.asarray(r_drys, dtype=float)
    Nis = jnp.asarray(Nis, dtype=float)

    N_tot = jnp.sum(Nis)
    r_crits, s_crits = _kohler_crit_approx(T, r_drys, kappa)

    # Equilibrium activation: bins whose critical supersaturation is below Smax.
    N_eq = jnp.sum(jnp.where(Smax >= s_crits, Nis, 0.0))
    eq_frac = N_eq / N_tot

    # Kinetic activation: among equilibrium-activated bins only, find the
    # smallest that has grown past its critical wet radius.  Gating on
    # s_crits <= Smax prevents the approximate Köhler formula from triggering
    # false positives for tiny particles near the r_crit ≈ r_dry transition.
    is_r_large = (rs >= r_crits) & (s_crits <= Smax)
    any_large = jnp.any(is_r_large)
    first_large = jnp.argmax(is_r_large)  # 0 when all False (gated by any_large)
    kn_mask = (jnp.arange(Nis.shape[0]) >= first_large) & any_large
    N_kn = jnp.sum(jnp.where(kn_mask, Nis, 0.0))
    kn_frac = N_kn / N_tot

    # Droplets inside the kinetic window that haven't reached critical size.
    N_unact = jnp.sum(jnp.where((rs < r_crits) & kn_mask, Nis, 0.0))
    phi = jnp.where(N_kn > 0.0, N_unact / N_kn, 1.0)
    alpha = jnp.where(N_eq > 0.0, N_kn / N_eq, 0.0)

    return eq_frac, kn_frac, alpha, phi

multi_mode_activation

multi_mode_activation(
    Smax: ArrayLike,
    T: ArrayLike,
    rss: Sequence[ArrayLike],
    r_dryss: Sequence[ArrayLike],
    Niss: Sequence[ArrayLike],
    kappas: ArrayLike,
) -> tuple[list[Array], list[Array]]

Activation statistics for a multi-mode binned aerosol population.

Calls binned_activation for each mode and collects the equilibrium and kinetic activated fractions.

Parameters:

Name Type Description Default
Smax float

Environmental maximum supersaturation (decimal).

required
T float

Environmental temperature (K).

required
rss sequence of array-like

Current wet radii for each mode, each of shape (nr_i,) (m).

required
r_dryss sequence of array-like

Dry radii for each mode, each of shape (nr_i,) (m).

required
Niss sequence of array-like

Number concentrations per bin for each mode, each shape (nr_i,) (m⁻³).

required
kappas (array - like, shape(n_modes))

Hygroscopicity parameter for each mode.

required

Returns:

Name Type Description
eq_fracs list of float

Equilibrium-activated fraction per mode.

kn_fracs list of float

Kinetic-activated fraction per mode.

See Also

pyrcel.activation.binned_activation : Per-mode computation.

Source code in pyrcel/activation/_common.py
def multi_mode_activation(
    Smax: ArrayLike,
    T: ArrayLike,
    rss: Sequence[ArrayLike],
    r_dryss: Sequence[ArrayLike],
    Niss: Sequence[ArrayLike],
    kappas: ArrayLike,
) -> tuple[list[Array], list[Array]]:
    r"""Activation statistics for a multi-mode binned aerosol population.

    Calls [binned_activation][pyrcel.activation.binned_activation] for each
    mode and collects the equilibrium and kinetic activated fractions.

    Parameters
    ----------
    Smax : float
        Environmental maximum supersaturation (decimal).
    T : float
        Environmental temperature (K).
    rss : sequence of array-like
        Current wet radii for each mode, each of shape ``(nr_i,)`` (m).
    r_dryss : sequence of array-like
        Dry radii for each mode, each of shape ``(nr_i,)`` (m).
    Niss : sequence of array-like
        Number concentrations per bin for each mode, each shape ``(nr_i,)``
        (m⁻³).
    kappas : array-like, shape (n_modes,)
        Hygroscopicity parameter for each mode.

    Returns
    -------
    eq_fracs : list of float
        Equilibrium-activated fraction per mode.
    kn_fracs : list of float
        Kinetic-activated fraction per mode.

    See Also
    --------
    pyrcel.activation.binned_activation : Per-mode computation.
    """
    kappas = jnp.asarray(kappas, dtype=float)
    eq_fracs: list[Array] = []
    kn_fracs: list[Array] = []
    for rs, r_drys, Nis, kappa in zip(rss, r_dryss, Niss, kappas):
        eq, kn, _, _ = binned_activation(Smax, T, rs, r_drys, Nis, kappa)
        eq_fracs.append(eq)
        kn_fracs.append(kn)
    return eq_fracs, kn_fracs