r"""Fluorescence/phosphorescence quantum yields, and the photochemical quantum yield via Beer-Lambert.
See Lakowicz, *Principles of Fluorescence Spectroscopy*, 3rd ed., Ch. 1,
for the radiative/total-decay-rate quantum yields, and Turro, Ramamurthy
& Scaiano, *Modern Molecular Photochemistry of Organic Molecules* (2010),
Ch. 7, for the photochemical (photon-in, product-out) quantum yield.
"""
from __future__ import annotations
import numpy as np
from chemistrykit.spectro.systems.beer_lambert import transmittance
__all__ = [
"fluorescence_quantum_yield",
"intersystem_crossing_yield",
"phosphorescence_quantum_yield",
"photons_absorbed",
"photochemical_quantum_yield",
]
[docs]
def fluorescence_quantum_yield(kf: float, kic: float, kisc: float) -> float:
r"""Fluorescence quantum yield :math:`\Phi_f = k_f/(k_f+k_{ic}+k_{isc})`.
The fraction of excited :math:`S_1` molecules that relax by emitting
a photon (fluorescence) rather than through either nonradiative decay
channel -- the ratio of the radiative rate constant to the *total*
:math:`S_1` decay rate (Lakowicz, *Principles of Fluorescence
Spectroscopy*, 3rd ed., Ch. 1, eq. 1.1). See
:mod:`chemistrykit.photochem.systems.jablonski` for the underlying
kinetic model this ratio comes from.
Parameters
----------
kf : float
Fluorescence (radiative) rate constant.
kic : float
Internal conversion (nonradiative, :math:`S_1\to S_0`) rate
constant.
kisc : float
Intersystem crossing (:math:`S_1\to T_1`) rate constant.
Returns
-------
float
In :math:`[0, 1]`.
Examples
--------
With no competing nonradiative pathway, every excited molecule
fluoresces:
>>> round(fluorescence_quantum_yield(kf=1.0, kic=0.0, kisc=0.0), 6)
1.0
Adding a nonradiative channel of the same magnitude as `kf` exactly
halves the yield:
>>> round(fluorescence_quantum_yield(kf=1.0, kic=1.0, kisc=0.0), 6)
0.5
"""
return kf / (kf + kic + kisc)
[docs]
def intersystem_crossing_yield(kisc: float, kf: float, kic: float) -> float:
r"""Intersystem-crossing yield :math:`\Phi_{isc} = k_{isc}/(k_f+k_{ic}+k_{isc})`.
The fraction of excited :math:`S_1` population that crosses to the
triplet manifold :math:`T_1` rather than returning directly to
:math:`S_0` (Turro, Ramamurthy & Scaiano, *Modern Molecular
Photochemistry of Organic Molecules*, Ch. 5).
Parameters
----------
kisc : float
Intersystem crossing rate constant.
kf : float
Fluorescence rate constant.
kic : float
Internal conversion rate constant.
Returns
-------
float
In :math:`[0, 1]`.
Examples
--------
Together with :func:`fluorescence_quantum_yield` and the (implicit)
internal-conversion yield, the three :math:`S_1` decay-channel yields
sum to exactly 1:
>>> kf, kic, kisc = 2.0, 1.0, 0.5
>>> phi_f = fluorescence_quantum_yield(kf, kic, kisc)
>>> phi_isc = intersystem_crossing_yield(kisc, kf, kic)
>>> phi_ic = kic / (kf + kic + kisc)
>>> round(phi_f + phi_isc + phi_ic, 9)
1.0
"""
return kisc / (kf + kic + kisc)
[docs]
def phosphorescence_quantum_yield(kisc: float, kf: float, kic: float, kp: float, kic_T: float) -> float:
r"""Phosphorescence quantum yield :math:`\Phi_p = \Phi_{isc}\cdot\frac{k_p}{k_p+k_{ic,T}}`.
Phosphorescence requires *two* successive branching events to
succeed: the molecule must first cross to the triplet manifold
(probability :math:`\Phi_{isc}`), and the resulting triplet must then
decay radiatively rather than nonradiatively (probability
:math:`k_p/(k_p+k_{ic,T})`) -- the product of these two independent
branching ratios (Lakowicz, *Principles of Fluorescence
Spectroscopy*, 3rd ed., Ch. 1; Turro, Ramamurthy & Scaiano, *Modern
Molecular Photochemistry of Organic Molecules*, Ch. 5).
Parameters
----------
kisc : float
Intersystem crossing rate constant.
kf : float
Fluorescence rate constant.
kic : float
:math:`S_1` internal conversion rate constant.
kp : float
Phosphorescence (radiative :math:`T_1\to S_0`) rate constant.
kic_T : float
Triplet nonradiative decay rate constant.
Returns
-------
float
In :math:`[0, 1]`.
Examples
--------
With no intersystem crossing at all, no phosphorescence is possible:
>>> round(phosphorescence_quantum_yield(kisc=0.0, kf=1.0, kic=0.0, kp=1.0, kic_T=0.0), 6)
0.0
With every :math:`S_1` crossing to the triplet, and every triplet
decaying radiatively, the phosphorescence yield is exactly 1:
>>> round(phosphorescence_quantum_yield(kisc=1.0, kf=0.0, kic=0.0, kp=1.0, kic_T=0.0), 6)
1.0
"""
phi_isc = intersystem_crossing_yield(kisc, kf, kic)
return phi_isc * (kp / (kp + kic_T))
[docs]
def photons_absorbed(photon_flux_incident, absorbance):
r"""Photon flux (or count) actually absorbed by a sample, from the Beer-Lambert absorbance.
:math:`I_{abs} = I_0(1-10^{-A}) = I_0(1-T)`, using
:func:`chemistrykit.spectro.systems.beer_lambert.transmittance` for
:math:`T=10^{-A}` -- the fraction of incident light *not*
transmitted is, by energy conservation (neglecting reflection and
scattering losses), the fraction absorbed (Turro, Ramamurthy &
Scaiano, *Modern Molecular Photochemistry of Organic Molecules*, Ch.
7).
Parameters
----------
photon_flux_incident : float or array-like of float
Incident photon flux (or photon count over an exposure time), in
any consistent unit (e.g. mol photons / s, or einstein/s).
absorbance : float or array-like of float
Beer-Lambert absorbance of the sample at the excitation
wavelength (see :mod:`chemistrykit.spectro.systems.beer_lambert`).
Returns
-------
float or ndarray
Absorbed photon flux, same unit as `photon_flux_incident`.
Examples
--------
At zero absorbance, nothing is absorbed:
>>> round(float(photons_absorbed(1.0, absorbance=0.0)), 6)
0.0
At very high absorbance, essentially all incident light is absorbed:
>>> round(float(photons_absorbed(1.0, absorbance=10.0)), 6)
1.0
"""
photon_flux_incident = np.asarray(photon_flux_incident, dtype=np.float64)
result = photon_flux_incident * (1.0 - transmittance(absorbance))
return float(result) if result.ndim == 0 else result
[docs]
def photochemical_quantum_yield(moles_product_formed, moles_photons_absorbed):
r"""Photochemical quantum yield :math:`\Phi = \frac{\text{moles of product formed}}{\text{moles of photons absorbed}}`.
The photochemistry analogue of the excited-state quantum yields
above: the efficiency of converting absorbed photons into chemical
product (Turro, Ramamurthy & Scaiano, *Modern Molecular
Photochemistry of Organic Molecules*, Ch. 7). **Note on range**: for
a simple, non-chain photoreaction :math:`0\le\Phi\le1` (each absorbed
photon produces at most one product molecule), but a radical-chain
photoreaction can propagate after the initiating absorption event and
give :math:`\Phi\gg1` -- this function does not itself enforce an
upper bound, since chain reactions are a real and common exception,
not implemented here.
Parameters
----------
moles_product_formed : float or array-like of float
moles_photons_absorbed : float or array-like of float
Returns
-------
float or ndarray
Examples
--------
One photon absorbed producing exactly one product molecule (a
typical simple photoisomerization) gives :math:`\Phi=1`:
>>> round(float(photochemical_quantum_yield(1.0, 1.0)), 6)
1.0
"""
result = np.asarray(moles_product_formed, dtype=np.float64) / np.asarray(moles_photons_absorbed, dtype=np.float64)
return float(result) if result.ndim == 0 else result