Source code for chemistrykit.photochem.systems.fluorescence
r"""Steady-state fluorescence observables: the Stokes shift and the Perrin anisotropy equation.
* :func:`stokes_shift` -- the energy gap between absorption and emission
maxima (G. G. Stokes, *Phil. Trans. R. Soc. Lond.* 142, 463 (1852)).
* :func:`perrin_anisotropy` and :func:`rotational_correlation_time` --
the steady-state fluorescence anisotropy of a rotating fluorophore
(F. Perrin, *J. Phys. Radium* 7, 390 (1926)) with the
Stokes-Einstein-Debye rotational correlation time. See Lakowicz,
*Principles of Fluorescence Spectroscopy*, 3rd ed., Chs. 1 and 10.
"""
from __future__ import annotations
import numpy as np
from chemistrykit.constants import K_B
__all__ = ["stokes_shift", "perrin_anisotropy", "rotational_correlation_time"]
[docs]
def stokes_shift(absorption_max_nm, emission_max_nm):
r"""Stokes shift in wavenumbers, :math:`\Delta\tilde\nu = 10^7/\lambda_{abs} - 10^7/\lambda_{em}` (cm\ :sup:`-1`).
Stokes (1852) observed that fluorescence is emitted at longer
wavelength (lower energy) than the light that excites it; the energy
difference is lost to vibrational relaxation and solvent
reorganization in the excited state before emission (Lakowicz, Ch.
1.4).
Parameters
----------
absorption_max_nm : float or array-like of float
Wavelength of the absorption maximum, in nm.
emission_max_nm : float or array-like of float
Wavelength of the emission maximum, in nm.
Returns
-------
float or ndarray
Stokes shift in cm\ :sup:`-1` (positive for red-shifted emission).
Examples
--------
Absorption at 400 nm and emission at 500 nm:
>>> round(stokes_shift(400.0, 500.0), 6)
5000.0
"""
lam_a = np.asarray(absorption_max_nm, dtype=np.float64)
lam_e = np.asarray(emission_max_nm, dtype=np.float64)
result = 1.0e7 / lam_a - 1.0e7 / lam_e
return float(result) if result.ndim == 0 else result
[docs]
def rotational_correlation_time(viscosity, volume, T):
r"""Stokes-Einstein-Debye rotational correlation time :math:`\theta = \eta V/(k_B T)`.
Parameters
----------
viscosity : float or array-like of float
Solvent viscosity :math:`\eta`, in Pa*s.
volume : float
Hydrodynamic volume of the rotating molecule, in m\ :sup:`3`.
T : float or array-like of float
Temperature, in K.
Returns
-------
float or ndarray
:math:`\theta`, in s.
Examples
--------
A ~1 nm\ :sup:`3` fluorophore in water (1 mPa*s) at 298 K rotates in
about a quarter of a nanosecond:
>>> round(rotational_correlation_time(1.0e-3, 1.0e-27, 298.15) * 1e9, 3)
0.243
"""
result = np.asarray(viscosity, dtype=np.float64) * volume / (K_B * np.asarray(T, dtype=np.float64))
return float(result) if result.ndim == 0 else result
[docs]
def perrin_anisotropy(r0: float, tau, theta):
r"""Perrin equation for steady-state fluorescence anisotropy, :math:`r = r_0/(1+\tau/\theta)`.
A fluorophore excited by polarized light emits polarized light, but
rotational diffusion during the excited-state lifetime :math:`\tau`
scrambles the orientation; for a spherical rotor with rotational
correlation time :math:`\theta` the time-averaged anisotropy is
:math:`r_0/r = 1+\tau/\theta` (Perrin 1926; Lakowicz, Ch. 10, eq.
10.45). :math:`r_0` (at most 0.4 for one-photon excitation) is the
anisotropy in the absence of rotation.
Parameters
----------
r0 : float
Fundamental (rotation-free) anisotropy.
tau : float or array-like of float
Fluorescence lifetime.
theta : float or array-like of float
Rotational correlation time (same unit as `tau`).
Returns
-------
float or ndarray
Examples
--------
When the lifetime equals the correlation time, the anisotropy is
halved:
>>> round(perrin_anisotropy(0.4, tau=4.0, theta=4.0), 6)
0.2
"""
result = r0 / (1.0 + np.asarray(tau, dtype=np.float64) / np.asarray(theta, dtype=np.float64))
return float(result) if result.ndim == 0 else result