Stratospheric Chemistry

Overview

The stratosphere, extending from approximately 10-50 km altitude, contains the ozone layer that shields the Earth's surface from harmful ultraviolet radiation. This module implements the fundamental chemistry governing stratospheric ozone based on Chapter 5 of Seinfeld & Pandis (2006).

The Chapman Mechanism

The Chapman mechanism (Chapman, 1930) describes the basic photochemical production and destruction of ozone in the stratosphere through four key reactions:

  1. O2 Photolysis: O2 + hv -> O + O (j_O2)
  2. Ozone Formation: O + O2 + M -> O3 + M (k2)
  3. Ozone Photolysis: O3 + hv -> O + O2 (j_O3)
  4. Ozone Destruction: O + O3 -> O2 + O2 (k4)

While the Chapman mechanism predicts the qualitative features of the ozone layer, it overestimates ozone concentrations by roughly a factor of two. This discrepancy is resolved by including catalytic destruction cycles involving NOx, HOx, ClOx, and BrOx species.

Catalytic Ozone Destruction

Catalytic cycles destroy ozone through the general mechanism:

X + O3 -> XO + O2
XO + O -> X + O2
-----------------
Net: O3 + O -> 2 O2

where X represents the catalyst (NO, OH, Cl, Br). These cycles are highly efficient because the catalyst is regenerated and can destroy many ozone molecules before being removed.

N2O as the Primary NOx Source

Nitrous oxide (N2O) transported from the troposphere is the primary source of stratospheric NOx through its reaction with excited atomic oxygen O(1D) (Section 5.3.1):

N2O + O(1D) -> NO + NO    (k = 6.7 × 10⁻¹¹ cm³/molec/s)
N2O + O(1D) -> N2 + O2    (k = 4.9 × 10⁻¹¹ cm³/molec/s)

The NO yield is approximately 58% (6.7/(6.7+4.9)), consistent with Equation 5.18.

Reference: Seinfeld, J.H. and Pandis, S.N. (2006). Atmospheric Chemistry and Physics: From Air Pollution to Climate Change, 2nd Edition. John Wiley & Sons, Chapter 5, pp. 138-203.

Exported Functions

GasChem.ChapmanMechanismFunction
ChapmanMechanism(; name=:ChapmanMechanism)

Create a ModelingToolkit System for the Chapman mechanism.

The Chapman mechanism describes the basic production and destruction of ozone in the stratosphere through photolysis of O2 and subsequent reactions.

Reactions (Section 5.2, Seinfeld & Pandis 2006):

  1. O2 + hν → O + O (j_O2)
  2. O + O2 + M → O3 + M (k2)
  3. O3 + hν → O + O2 (j_O3)
  4. O + O3 → O2 + O2 (k4)

Rate Equations (Equations 5.1-5.2):

d[O]/dt = 2jO2[O2] - k2[O][O2][M] + jO3[O3] - k4[O][O3] d[O3]/dt = k2[O][O2][M] - j_O3[O3] - k4[O][O3]

Steady-State Ozone (Equation 5.13):

[O3]ss = 0.21 × (k2 × jO2 / (k4 × j_O3))^(1/2) × [M]^(3/2)

source
GasChem.NOxCycleFunction
NOxCycle(; name=:NOxCycle)

Create a ModelingToolkit System for the NOx catalytic ozone destruction cycle.

NOx Cycle 1 (Section 5.3.2, Page 154):

NO + O3 → NO2 + O2 (k1 = 3.0 × 10⁻¹² exp(-1500/T) cm³/molec/s) NO2 + O → NO + O2 (k2 = 5.6 × 10⁻¹² exp(180/T) cm³/molec/s) Net: O3 + O → O2 + O2

Steady-State (Equation 5.20):

0 = k1[NO][O3] - j_NO2[NO2] - k2[NO2][O]

Rate of Odd Oxygen Destruction (Equation 5.22):

d[Ox]/dt = -2 k2[NO2][O]

source
GasChem.HOxCycleFunction
HOxCycle(; name=:HOxCycle)

Create a ModelingToolkit System for the HOx catalytic ozone destruction cycle.

HOx Cycle 1 (Page 159):

OH + O3 → HO2 + O2 HO2 + O → OH + O2 Net: O3 + O → O2 + O2

HOx Cycle 2 (Page 159):

OH + O3 → HO2 + O2 HO2 + O3 → OH + O2 + O2 Net: O3 + O3 → O2 + O2 + O2

Steady-State Ratio (Equation 5.28):

[HO2]/[OH] = kOH+O3[O3] / (kHO2+NO[NO])

Rate of Odd Oxygen Destruction (Equation 5.27):

d[Ox]/dt = -2 kHO2+O3[HO2][O3] - 2 kHO2+O[HO2][O]

source
GasChem.ClOxCycleFunction
ClOxCycle(; name=:ClOxCycle)

Create a ModelingToolkit System for the ClOx catalytic ozone destruction cycle.

ClOx Cycle 1 (Section 5.5.1, Page 162):

Cl + O3 → ClO + O2 (k1 = 2.3 × 10⁻¹¹ exp(-200/T) cm³/molec/s) ClO + O → Cl + O2 (k2 = 3.0 × 10⁻¹¹ exp(70/T) cm³/molec/s) Net: O3 + O → O2 + O2

Rate of Odd Oxygen Destruction (Equation 5.29):

d[Ox]/dt = -2 k2[ClO][O]

Steady-State [Cl]/[ClO] Ratio (Equation 5.30):

[Cl]/[ClO] = (kClO+O[O] + kClO+NO[NO]) / (k_Cl+O3[O3])

Reservoir Species (Section 5.6):

  • HCl formed by Cl + CH4 → HCl + CH3
  • ClONO2 formed by ClO + NO2 + M → ClONO2 + M
source
GasChem.BrOxCycleFunction
BrOxCycle(; name=:BrOxCycle)

Create a ModelingToolkit System for the BrOx catalytic ozone destruction cycle.

Bromine is approximately 50 times more effective than chlorine in destroying ozone on an atom-for-atom basis (Page 169).

Key Reactions (Section 5.5.2, Page 166):

Br + O3 → BrO + O2 (k = 1.7 × 10⁻¹¹ exp(-800/T) cm³/molec/s) BrO + O → Br + O2 BrO + ClO → Br + Cl + O2 (or BrCl + O2) BrO + HO2 → HOBr + O2

Note on Reservoir Species (Page 169):

Unlike chlorine, bromine does not form a stable HBr reservoir because Br + CH4 is endothermic and extremely slow.

source
GasChem.StratosphericOzoneSystemFunction
StratosphericOzoneSystem(; name=:StratosphericOzoneSystem)

Create a comprehensive ModelingToolkit System combining all stratospheric ozone chemistry cycles.

This system includes:

  • Chapman mechanism (O, O3 production and loss)
  • O(¹D) photochemistry including O(¹D) + H2O and O(¹D) + CH4
  • N2O + O(¹D) → 2NO as the NOx source (Section 5.3.1)
  • NOx cycle (catalytic O3 destruction)
  • HOx cycle (catalytic O3 destruction)
  • ClOx cycle (catalytic O3 destruction)
  • BrOx cycle (catalytic O3 destruction)

All rate coefficients are temperature-dependent, computed from Arrhenius parameters defined as @constants.

Key Equations from Seinfeld & Pandis Chapter 5:

Odd Oxygen Balance (Equation 5.9):

d[Ox]/dt = 2j_O2[O2] - 2k4[O][O3]

Steady-State O3 (Equation 5.13):

[O3]ss = 0.21 × (k2 × jO2 / (k4 × j_O3))^(1/2) × [M]^(3/2)

[O]/[O3] Ratio (Equation 5.7):

[O]/[O3] = j_O3 / (k2[O2][M])

Time to Steady State (Equation 5.17):

τO3^ss = (1/4) × (k2[M] / (k4 × jO2 × j_O3))^(1/2)

NO Yield from N2O (Equation 5.18, Section 5.3.1):

N2O + O(¹D) → NO + NO (k = 6.7 × 10⁻¹¹ cm³/molec/s) N2O + O(¹D) → N2 + O2 (k = 4.9 × 10⁻¹¹ cm³/molec/s)

source

Implementation

The implementation uses ModelingToolkit.jl to define ODE systems for each chemical cycle. All rate coefficients are embedded as @constants with Arrhenius parameters within each component, ensuring that temperature-dependent rate computation is handled symbolically by ModelingToolkit. This allows for symbolic manipulation of the equations, automatic Jacobian generation, and efficient numerical integration.

Chapman Mechanism System

using GasChem
using ModelingToolkit
using ModelingToolkit: t
using DynamicQuantities
using Symbolics
using DataFrames

sys = ChapmanMechanism()

State Variables

vars = unknowns(sys)
DataFrame(
    :Name => [string(Symbolics.tosymbol(v, escape = false)) for v in vars],
    :Units => [dimension(ModelingToolkit.get_unit(v)) for v in vars],
    :Description => [ModelingToolkit.getdescription(v) for v in vars]
)
3×3 DataFrame
RowNameUnitsDescription
StringDimensio…String
1Om⁻³Atomic oxygen concentration (1e7 molec/cm^3 × 1e6)
2O3m⁻³Ozone concentration (3e12 molec/cm^3 × 1e6)
3Oxm⁻³Odd oxygen = O + O3

Parameters

params = parameters(sys)
DataFrame(
    :Name => [string(Symbolics.tosymbol(p, escape = false)) for p in params],
    :Units => [dimension(ModelingToolkit.get_unit(p)) for p in params],
    :Description => [ModelingToolkit.getdescription(p) for p in params]
)
9×3 DataFrame
RowNameUnitsDescription
StringDimensio…String
1j_O2s⁻¹O2 photolysis rate
2O2_mixO2 mixing ratio (dimensionless)
3Mm⁻³Air number density (3e17 molec/cm^3 × 1e6)
4C_k4KActivation temperature for O + O3
5TKTemperature
6k4_Am³ s⁻¹Pre-factor: O + O3 → 2O2 (8e-12 cm^3/molec/s × 1e-6, Table B.1)
7T_refKReference temperature
8k2_Am⁶ s⁻¹Pre-factor: O + O2 + M → O3 + M (6e-34 cm^6/molec^2/s × 1e-12, Table B.2)
9j_O3s⁻¹O3 photolysis rate

Equations

The Chapman mechanism is governed by coupled differential equations for atomic oxygen O and ozone O3:

equations(sys)

\[ \begin{align} \frac{\mathrm{d} ~ O\left( t \right)}{\mathrm{d}t} &= \mathtt{j\_O3} ~ \mathtt{O3}\left( t \right) + 2 ~ M ~ \mathtt{O2\_mix} ~ \mathtt{j\_O2} - \mathtt{k4\_A} ~ e^{\frac{\mathtt{C\_k4}}{T}} ~ O\left( t \right) ~ \mathtt{O3}\left( t \right) - \left( \frac{\mathtt{T\_ref}}{T} \right)^{2.4} ~ M^{2} ~ \mathtt{O2\_mix} ~ \mathtt{k2\_A} ~ O\left( t \right) \\ \frac{\mathrm{d} ~ \mathtt{O3}\left( t \right)}{\mathrm{d}t} &= - \mathtt{j\_O3} ~ \mathtt{O3}\left( t \right) - \mathtt{k4\_A} ~ e^{\frac{\mathtt{C\_k4}}{T}} ~ O\left( t \right) ~ \mathtt{O3}\left( t \right) + \left( \frac{\mathtt{T\_ref}}{T} \right)^{2.4} ~ M^{2} ~ \mathtt{O2\_mix} ~ \mathtt{k2\_A} ~ O\left( t \right) \\ \mathtt{Ox}\left( t \right) &= O\left( t \right) + \mathtt{O3}\left( t \right) \end{align} \]

Comprehensive Stratospheric System

The full stratospheric system combines all catalytic cycles:

using GasChem
using ModelingToolkit
using ModelingToolkit: t
using DynamicQuantities
using Symbolics
using DataFrames

sys_full = StratosphericOzoneSystem()

All Species

vars = unknowns(sys_full)
DataFrame(
    :Name => [string(Symbolics.tosymbol(v, escape = false)) for v in vars],
    :Units => [dimension(ModelingToolkit.get_unit(v)) for v in vars],
    :Description => [ModelingToolkit.getdescription(v) for v in vars]
)
20×3 DataFrame
RowNameUnitsDescription
StringDimensio…String
1Om⁻³Atomic oxygen O(3P) (1e7 molec/cm^3 × 1e6)
2O1Dm⁻³Excited oxygen O(1D) (50 molec/cm^3 × 1e6)
3O3m⁻³Ozone (3e12 molec/cm^3 × 1e6)
4N2Om⁻³Nitrous oxide (~300 ppb at 30 km)
5NOm⁻³Nitric oxide (1e9 molec/cm^3 × 1e6)
6NO2m⁻³Nitrogen dioxide (1e9 molec/cm^3 × 1e6)
7OHm⁻³Hydroxyl radical (1e6 molec/cm^3 × 1e6)
8HO2m⁻³Hydroperoxyl radical (1e7 molec/cm^3 × 1e6)
9Clm⁻³Chlorine atom (1e4 molec/cm^3 × 1e6)
10ClOm⁻³Chlorine monoxide (1e7 molec/cm^3 × 1e6)
11HClm⁻³Hydrogen chloride (1e9 molec/cm^3 × 1e6)
12ClONO2m⁻³Chlorine nitrate (1e9 molec/cm^3 × 1e6)
13Brm⁻³Bromine atom (1e5 molec/cm^3 × 1e6)
14BrOm⁻³Bromine monoxide (1e6 molec/cm^3 × 1e6)
15HOBrm⁻³Hypobromous acid (1e6 molec/cm^3 × 1e6)
16Oxm⁻³Odd oxygen = O + O3
17NOxm⁻³NOx = NO + NO2
18HOxm⁻³HOx = OH + HO2
19ClOxm⁻³ClOx = Cl + ClO
20BrOxm⁻³BrOx = Br + BrO

Parameters

params = parameters(sys_full)
DataFrame(
    :Name => [string(Symbolics.tosymbol(p, escape = false)) for p in params],
    :Units => [dimension(ModelingToolkit.get_unit(p)) for p in params],
    :Description => [ModelingToolkit.getdescription(p) for p in params]
)
53×3 DataFrame
RowNameUnitsDescription
StringDimensio…String
1j_O2s⁻¹O2 photolysis rate
2O2_mixO2 mixing ratio (dimensionless)
3Mm⁻³Air number density at 30 km (3.1e17 molec/cm^3 × 1e6)
4k_O1D_N2_Am³ s⁻¹Pre-factor: O(1D) + N2 (1.8e-11 cm^3/molec/s × 1e-6, Page 143)
5N2_mixN2 mixing ratio (dimensionless)
6C_O1D_N2Kexp(C/T) factor: O(1D) + N2
7TKTemperature
8C_O1D_O2Kexp(C/T) factor: O(1D) + O2
9k_O1D_O2_Am³ s⁻¹Pre-factor: O(1D) + O2 (3.2e-11 cm^3/molec/s × 1e-6, Page 143)
10j_NO2s⁻¹NO2 photolysis rate
11j_O3_O1Ds⁻¹O3 → O(1D) photolysis rate
12j_O3s⁻¹O3 photolysis rate (total, both channels)
13T_refKReference temperature
14k2_Am⁶ s⁻¹Pre-factor: O + O2 + M → O3 + M (6e-34 cm^6/molec^2/s × 1e-12, Table B.2)
15C_k4Kexp(C/T) factor: O + O3
16k4_Am³ s⁻¹Pre-factor: O + O3 → 2O2 (8e-12 cm^3/molec/s × 1e-6, Table B.1)
17k_ClO_O_Am³ s⁻¹Pre-factor: ClO + O (3e-11 cm^3/molec/s × 1e-6, Page 162)
18C_ClO_OKexp(C/T) factor: ClO + O
19k_BrO_O_cm³ s⁻¹BrO + O rate (5e-11 cm^3/molec/s × 1e-6)
20k_HO2_O_Am³ s⁻¹Pre-factor: HO2 + O (3e-11 cm^3/molec/s × 1e-6, Page 161)
21C_HO2_OKexp(C/T) factor: HO2 + O
22C_NO2_OKexp(C/T) factor: NO2 + O
23k_NO2_O_Am³ s⁻¹Pre-factor: NO2 + O (5.6e-12 cm^3/molec/s × 1e-6, Page 154)
24CH4_mixCH4 mixing ratio (dimensionless)
25k_O1D_CH4_cm³ s⁻¹O(1D) + CH4 → OH + CH3 (1.5e-10 cm^3/molec/s × 1e-6, Page 156)
26H2O_mixH2O mixing ratio (dimensionless)
27k_O1D_H2O_cm³ s⁻¹O(1D) + H2O → 2OH (2.2e-10 cm^3/molec/s × 1e-6, Page 156)
28k_N2O_O1D_NO_cm³ s⁻¹N2O + O(1D) → NO + NO (6.7e-11 cm^3/molec/s × 1e-6, Page 151)
29j_N2Os⁻¹N2O photolysis rate (Section 5.3.1)
30k_N2O_O1D_N2_cm³ s⁻¹N2O + O(1D) → N2 + O2 (4.9e-11 cm^3/molec/s × 1e-6, Page 151)
31C_HO2_O3Kexp(C/T) factor: HO2 + O3
32k_HO2_O3_Am³ s⁻¹Pre-factor: HO2 + O3 (1e-14 cm^3/molec/s × 1e-6, Table B.1)
33k_OH_O3_Am³ s⁻¹Pre-factor: OH + O3 (1.7e-12 cm^3/molec/s × 1e-6, Page 161)
34C_OH_O3Kexp(C/T) factor: OH + O3
35k_Cl_O3_Am³ s⁻¹Pre-factor: Cl + O3 (2.3e-11 cm^3/molec/s × 1e-6, Page 162)
36C_Cl_O3Kexp(C/T) factor: Cl + O3
37C_NO_O3Kexp(C/T) factor: NO + O3
38k_NO_O3_Am³ s⁻¹Pre-factor: NO + O3 (3e-12 cm^3/molec/s × 1e-6, Page 154)
39k_Br_O3_Am³ s⁻¹Pre-factor: Br + O3 (1.7e-11 cm^3/molec/s × 1e-6, Table B.1)
40C_Br_O3Kexp(C/T) factor: Br + O3
41k_ClO_NO_Am³ s⁻¹Pre-factor: ClO + NO (6.4e-12 cm^3/molec/s × 1e-6, Page 163)
42C_ClO_NOKexp(C/T) factor: ClO + NO
43C_HO2_NOKexp(C/T) factor: HO2 + NO
44k_HO2_NO_Am³ s⁻¹Pre-factor: HO2 + NO (3.5e-12 cm^3/molec/s × 1e-6, Page 158)
45k_ClO_NO2_M_Am⁶ s⁻¹Pre-factor: ClO + NO2 + M → ClONO2 (1.8e-31 cm^6/molec^2/s × 1e-12, Page 165)
46k_OH_HCl_Am³ s⁻¹Pre-factor: OH + HCl (2.6e-12 cm^3/molec/s × 1e-6, Page 168)
47C_OH_HClKexp(C/T) factor: OH + HCl
48j_HOBrs⁻¹HOBr photolysis rate
49k_BrO_HO2_cm³ s⁻¹BrO + HO2 rate (4e-11 cm^3/molec/s × 1e-6)
50k_BrO_ClO_cm³ s⁻¹BrO + ClO rate (2e-12 cm^3/molec/s × 1e-6)
51k_Cl_CH4_Am³ s⁻¹Pre-factor: Cl + CH4 (9.6e-12 cm^3/molec/s × 1e-6, Table B.1)
52C_Cl_CH4Kexp(C/T) factor: Cl + CH4
53j_ClONO2s⁻¹ClONO2 photolysis rate

Equations

The full stratospheric system consists of 15 ODEs and 5 algebraic family definitions:

equations(sys_full)

\[ \begin{align} \frac{\mathrm{d} ~ O\left( t \right)}{\mathrm{d}t} &= \mathtt{j\_NO2} ~ \mathtt{NO2}\left( t \right) + \left( \mathtt{j\_O3} - \mathtt{j\_O3\_O1D} \right) ~ \mathtt{O3}\left( t \right) + 2 ~ M ~ \mathtt{O2\_mix} ~ \mathtt{j\_O2} - \mathtt{k\_BrO\_O\_c} ~ \mathtt{BrO}\left( t \right) ~ O\left( t \right) - \mathtt{k4\_A} ~ e^{\frac{\mathtt{C\_k4}}{T}} ~ O\left( t \right) ~ \mathtt{O3}\left( t \right) - \mathtt{k\_ClO\_O\_A} ~ e^{\frac{\mathtt{C\_ClO\_O}}{T}} ~ O\left( t \right) ~ \mathtt{ClO}\left( t \right) - \mathtt{k\_HO2\_O\_A} ~ \mathtt{HO2}\left( t \right) ~ O\left( t \right) ~ e^{\frac{\mathtt{C\_HO2\_O}}{T}} - \mathtt{k\_NO2\_O\_A} ~ e^{\frac{\mathtt{C\_NO2\_O}}{T}} ~ \mathtt{NO2}\left( t \right) ~ O\left( t \right) + M ~ \left( \mathtt{N2\_mix} ~ \mathtt{k\_O1D\_N2\_A} ~ e^{\frac{\mathtt{C\_O1D\_N2}}{T}} + \mathtt{O2\_mix} ~ \mathtt{k\_O1D\_O2\_A} ~ e^{\frac{\mathtt{C\_O1D\_O2}}{T}} \right) ~ \mathtt{O1D}\left( t \right) - \left( \frac{\mathtt{T\_ref}}{T} \right)^{2.4} ~ M^{2} ~ \mathtt{O2\_mix} ~ \mathtt{k2\_A} ~ O\left( t \right) \\ \frac{\mathrm{d} ~ \mathtt{O1D}\left( t \right)}{\mathrm{d}t} &= \mathtt{j\_N2O} ~ \mathtt{N2O}\left( t \right) + \mathtt{j\_O3\_O1D} ~ \mathtt{O3}\left( t \right) - \mathtt{k\_N2O\_O1D\_N2\_c} ~ \mathtt{N2O}\left( t \right) ~ \mathtt{O1D}\left( t \right) - \mathtt{k\_N2O\_O1D\_NO\_c} ~ \mathtt{N2O}\left( t \right) ~ \mathtt{O1D}\left( t \right) - \mathtt{CH4\_mix} ~ M ~ \mathtt{k\_O1D\_CH4\_c} ~ \mathtt{O1D}\left( t \right) - \mathtt{H2O\_mix} ~ M ~ \mathtt{k\_O1D\_H2O\_c} ~ \mathtt{O1D}\left( t \right) - M ~ \left( \mathtt{N2\_mix} ~ \mathtt{k\_O1D\_N2\_A} ~ e^{\frac{\mathtt{C\_O1D\_N2}}{T}} + \mathtt{O2\_mix} ~ \mathtt{k\_O1D\_O2\_A} ~ e^{\frac{\mathtt{C\_O1D\_O2}}{T}} \right) ~ \mathtt{O1D}\left( t \right) \\ \frac{\mathrm{d} ~ \mathtt{O3}\left( t \right)}{\mathrm{d}t} &= - \mathtt{j\_O3} ~ \mathtt{O3}\left( t \right) - \mathtt{k4\_A} ~ e^{\frac{\mathtt{C\_k4}}{T}} ~ O\left( t \right) ~ \mathtt{O3}\left( t \right) - \mathtt{k\_Br\_O3\_A} ~ \mathtt{Br}\left( t \right) ~ e^{\frac{\mathtt{C\_Br\_O3}}{T}} ~ \mathtt{O3}\left( t \right) - \mathtt{k\_Cl\_O3\_A} ~ \mathtt{Cl}\left( t \right) ~ e^{\frac{\mathtt{C\_Cl\_O3}}{T}} ~ \mathtt{O3}\left( t \right) - \mathtt{k\_HO2\_O3\_A} ~ \mathtt{HO2}\left( t \right) ~ e^{\frac{\mathtt{C\_HO2\_O3}}{T}} ~ \mathtt{O3}\left( t \right) - \mathtt{k\_NO\_O3\_A} ~ \mathtt{NO}\left( t \right) ~ e^{\frac{\mathtt{C\_NO\_O3}}{T}} ~ \mathtt{O3}\left( t \right) - \mathtt{k\_OH\_O3\_A} ~ e^{\frac{\mathtt{C\_OH\_O3}}{T}} ~ \mathtt{OH}\left( t \right) ~ \mathtt{O3}\left( t \right) + \left( \frac{\mathtt{T\_ref}}{T} \right)^{2.4} ~ M^{2} ~ \mathtt{O2\_mix} ~ \mathtt{k2\_A} ~ O\left( t \right) \\ \frac{\mathrm{d} ~ \mathtt{N2O}\left( t \right)}{\mathrm{d}t} &= - \mathtt{j\_N2O} ~ \mathtt{N2O}\left( t \right) - \mathtt{k\_N2O\_O1D\_N2\_c} ~ \mathtt{N2O}\left( t \right) ~ \mathtt{O1D}\left( t \right) - \mathtt{k\_N2O\_O1D\_NO\_c} ~ \mathtt{N2O}\left( t \right) ~ \mathtt{O1D}\left( t \right) \\ \frac{\mathrm{d} ~ \mathtt{NO}\left( t \right)}{\mathrm{d}t} &= \mathtt{j\_NO2} ~ \mathtt{NO2}\left( t \right) + 2 ~ \mathtt{k\_N2O\_O1D\_NO\_c} ~ \mathtt{N2O}\left( t \right) ~ \mathtt{O1D}\left( t \right) - \mathtt{k\_ClO\_NO\_A} ~ \mathtt{NO}\left( t \right) ~ e^{\frac{\mathtt{C\_ClO\_NO}}{T}} ~ \mathtt{ClO}\left( t \right) - \mathtt{k\_HO2\_NO\_A} ~ \mathtt{NO}\left( t \right) ~ \mathtt{HO2}\left( t \right) ~ e^{\frac{\mathtt{C\_HO2\_NO}}{T}} + \mathtt{k\_NO2\_O\_A} ~ e^{\frac{\mathtt{C\_NO2\_O}}{T}} ~ \mathtt{NO2}\left( t \right) ~ O\left( t \right) - \mathtt{k\_NO\_O3\_A} ~ \mathtt{NO}\left( t \right) ~ e^{\frac{\mathtt{C\_NO\_O3}}{T}} ~ \mathtt{O3}\left( t \right) \\ \frac{\mathrm{d} ~ \mathtt{NO2}\left( t \right)}{\mathrm{d}t} &= - \mathtt{j\_NO2} ~ \mathtt{NO2}\left( t \right) + \mathtt{k\_ClO\_NO\_A} ~ \mathtt{NO}\left( t \right) ~ e^{\frac{\mathtt{C\_ClO\_NO}}{T}} ~ \mathtt{ClO}\left( t \right) + \mathtt{k\_HO2\_NO\_A} ~ \mathtt{NO}\left( t \right) ~ \mathtt{HO2}\left( t \right) ~ e^{\frac{\mathtt{C\_HO2\_NO}}{T}} - \mathtt{k\_NO2\_O\_A} ~ e^{\frac{\mathtt{C\_NO2\_O}}{T}} ~ \mathtt{NO2}\left( t \right) ~ O\left( t \right) + \mathtt{k\_NO\_O3\_A} ~ \mathtt{NO}\left( t \right) ~ e^{\frac{\mathtt{C\_NO\_O3}}{T}} ~ \mathtt{O3}\left( t \right) - \left( \frac{\mathtt{T\_ref}}{T} \right)^{3.4} ~ M ~ \mathtt{k\_ClO\_NO2\_M\_A} ~ \mathtt{NO2}\left( t \right) ~ \mathtt{ClO}\left( t \right) \\ \frac{\mathrm{d} ~ \mathtt{OH}\left( t \right)}{\mathrm{d}t} &= \mathtt{j\_HOBr} ~ \mathtt{HOBr}\left( t \right) + \mathtt{CH4\_mix} ~ M ~ \mathtt{k\_O1D\_CH4\_c} ~ \mathtt{O1D}\left( t \right) + 2 ~ \mathtt{H2O\_mix} ~ M ~ \mathtt{k\_O1D\_H2O\_c} ~ \mathtt{O1D}\left( t \right) + \mathtt{k\_HO2\_NO\_A} ~ \mathtt{NO}\left( t \right) ~ \mathtt{HO2}\left( t \right) ~ e^{\frac{\mathtt{C\_HO2\_NO}}{T}} + \mathtt{k\_HO2\_O3\_A} ~ \mathtt{HO2}\left( t \right) ~ e^{\frac{\mathtt{C\_HO2\_O3}}{T}} ~ \mathtt{O3}\left( t \right) + \mathtt{k\_HO2\_O\_A} ~ \mathtt{HO2}\left( t \right) ~ O\left( t \right) ~ e^{\frac{\mathtt{C\_HO2\_O}}{T}} - \mathtt{k\_OH\_HCl\_A} ~ \mathtt{HCl}\left( t \right) ~ e^{\frac{\mathtt{C\_OH\_HCl}}{T}} ~ \mathtt{OH}\left( t \right) - \mathtt{k\_OH\_O3\_A} ~ e^{\frac{\mathtt{C\_OH\_O3}}{T}} ~ \mathtt{OH}\left( t \right) ~ \mathtt{O3}\left( t \right) \\ \frac{\mathrm{d} ~ \mathtt{HO2}\left( t \right)}{\mathrm{d}t} &= - \mathtt{k\_BrO\_HO2\_c} ~ \mathtt{HO2}\left( t \right) ~ \mathtt{BrO}\left( t \right) - \mathtt{k\_HO2\_NO\_A} ~ \mathtt{NO}\left( t \right) ~ \mathtt{HO2}\left( t \right) ~ e^{\frac{\mathtt{C\_HO2\_NO}}{T}} - \mathtt{k\_HO2\_O3\_A} ~ \mathtt{HO2}\left( t \right) ~ e^{\frac{\mathtt{C\_HO2\_O3}}{T}} ~ \mathtt{O3}\left( t \right) - \mathtt{k\_HO2\_O\_A} ~ \mathtt{HO2}\left( t \right) ~ O\left( t \right) ~ e^{\frac{\mathtt{C\_HO2\_O}}{T}} + \mathtt{k\_OH\_O3\_A} ~ e^{\frac{\mathtt{C\_OH\_O3}}{T}} ~ \mathtt{OH}\left( t \right) ~ \mathtt{O3}\left( t \right) \\ \frac{\mathrm{d} ~ \mathtt{Cl}\left( t \right)}{\mathrm{d}t} &= \mathtt{j\_ClONO2} ~ \mathtt{ClONO2}\left( t \right) + \mathtt{k\_BrO\_ClO\_c} ~ \mathtt{BrO}\left( t \right) ~ \mathtt{ClO}\left( t \right) + \mathtt{k\_ClO\_NO\_A} ~ \mathtt{NO}\left( t \right) ~ e^{\frac{\mathtt{C\_ClO\_NO}}{T}} ~ \mathtt{ClO}\left( t \right) + \mathtt{k\_ClO\_O\_A} ~ e^{\frac{\mathtt{C\_ClO\_O}}{T}} ~ O\left( t \right) ~ \mathtt{ClO}\left( t \right) - \mathtt{k\_Cl\_O3\_A} ~ \mathtt{Cl}\left( t \right) ~ e^{\frac{\mathtt{C\_Cl\_O3}}{T}} ~ \mathtt{O3}\left( t \right) + \mathtt{k\_OH\_HCl\_A} ~ \mathtt{HCl}\left( t \right) ~ e^{\frac{\mathtt{C\_OH\_HCl}}{T}} ~ \mathtt{OH}\left( t \right) - \mathtt{CH4\_mix} ~ M ~ \mathtt{k\_Cl\_CH4\_A} ~ \mathtt{Cl}\left( t \right) ~ e^{\frac{\mathtt{C\_Cl\_CH4}}{T}} \\ \frac{\mathrm{d} ~ \mathtt{ClO}\left( t \right)}{\mathrm{d}t} &= - \mathtt{k\_BrO\_ClO\_c} ~ \mathtt{BrO}\left( t \right) ~ \mathtt{ClO}\left( t \right) - \mathtt{k\_ClO\_NO\_A} ~ \mathtt{NO}\left( t \right) ~ e^{\frac{\mathtt{C\_ClO\_NO}}{T}} ~ \mathtt{ClO}\left( t \right) - \mathtt{k\_ClO\_O\_A} ~ e^{\frac{\mathtt{C\_ClO\_O}}{T}} ~ O\left( t \right) ~ \mathtt{ClO}\left( t \right) + \mathtt{k\_Cl\_O3\_A} ~ \mathtt{Cl}\left( t \right) ~ e^{\frac{\mathtt{C\_Cl\_O3}}{T}} ~ \mathtt{O3}\left( t \right) - \left( \frac{\mathtt{T\_ref}}{T} \right)^{3.4} ~ M ~ \mathtt{k\_ClO\_NO2\_M\_A} ~ \mathtt{NO2}\left( t \right) ~ \mathtt{ClO}\left( t \right) \\ \frac{\mathrm{d} ~ \mathtt{HCl}\left( t \right)}{\mathrm{d}t} &= - \mathtt{k\_OH\_HCl\_A} ~ \mathtt{HCl}\left( t \right) ~ e^{\frac{\mathtt{C\_OH\_HCl}}{T}} ~ \mathtt{OH}\left( t \right) + \mathtt{CH4\_mix} ~ M ~ \mathtt{k\_Cl\_CH4\_A} ~ \mathtt{Cl}\left( t \right) ~ e^{\frac{\mathtt{C\_Cl\_CH4}}{T}} \\ \frac{\mathrm{d} ~ \mathtt{ClONO2}\left( t \right)}{\mathrm{d}t} &= - \mathtt{j\_ClONO2} ~ \mathtt{ClONO2}\left( t \right) + \left( \frac{\mathtt{T\_ref}}{T} \right)^{3.4} ~ M ~ \mathtt{k\_ClO\_NO2\_M\_A} ~ \mathtt{NO2}\left( t \right) ~ \mathtt{ClO}\left( t \right) \\ \frac{\mathrm{d} ~ \mathtt{Br}\left( t \right)}{\mathrm{d}t} &= \mathtt{j\_HOBr} ~ \mathtt{HOBr}\left( t \right) + \mathtt{k\_BrO\_ClO\_c} ~ \mathtt{BrO}\left( t \right) ~ \mathtt{ClO}\left( t \right) + \mathtt{k\_BrO\_O\_c} ~ \mathtt{BrO}\left( t \right) ~ O\left( t \right) - \mathtt{k\_Br\_O3\_A} ~ \mathtt{Br}\left( t \right) ~ e^{\frac{\mathtt{C\_Br\_O3}}{T}} ~ \mathtt{O3}\left( t \right) \\ \frac{\mathrm{d} ~ \mathtt{BrO}\left( t \right)}{\mathrm{d}t} &= - \mathtt{k\_BrO\_ClO\_c} ~ \mathtt{BrO}\left( t \right) ~ \mathtt{ClO}\left( t \right) - \mathtt{k\_BrO\_HO2\_c} ~ \mathtt{HO2}\left( t \right) ~ \mathtt{BrO}\left( t \right) - \mathtt{k\_BrO\_O\_c} ~ \mathtt{BrO}\left( t \right) ~ O\left( t \right) + \mathtt{k\_Br\_O3\_A} ~ \mathtt{Br}\left( t \right) ~ e^{\frac{\mathtt{C\_Br\_O3}}{T}} ~ \mathtt{O3}\left( t \right) \\ \frac{\mathrm{d} ~ \mathtt{HOBr}\left( t \right)}{\mathrm{d}t} &= - \mathtt{j\_HOBr} ~ \mathtt{HOBr}\left( t \right) + \mathtt{k\_BrO\_HO2\_c} ~ \mathtt{HO2}\left( t \right) ~ \mathtt{BrO}\left( t \right) \\ \mathtt{Ox}\left( t \right) &= O\left( t \right) + \mathtt{O3}\left( t \right) \\ \mathtt{NOx}\left( t \right) &= \mathtt{NO}\left( t \right) + \mathtt{NO2}\left( t \right) \\ \mathtt{HOx}\left( t \right) &= \mathtt{HO2}\left( t \right) + \mathtt{OH}\left( t \right) \\ \mathtt{ClOx}\left( t \right) &= \mathtt{Cl}\left( t \right) + \mathtt{ClO}\left( t \right) \\ \mathtt{BrOx}\left( t \right) &= \mathtt{BrO}\left( t \right) + \mathtt{Br}\left( t \right) \end{align} \]

Analysis

This section demonstrates the behavior of the implemented systems and reproduces key results from Chapter 5 of Seinfeld & Pandis.

Table 5.1: Stratospheric Conditions

The following table reproduces the standard atmospheric conditions used throughout Chapter 5:

using DataFrames

# Table 5.1 from Seinfeld & Pandis (2006), page 142
altitudes = [20, 25, 30, 35, 40, 45]  # km
temperatures = [217, 222, 227, 237, 251, 265]  # K
pressures_hPa = [55, 25, 12, 5.6, 2.8, 1.4]  # hPa
p_over_p0 = [0.054, 0.025, 0.012, 0.0055, 0.0028, 0.0014]
M_values = [1.4e18, 6.4e17, 3.1e17, 1.4e17, 7.1e16, 3.6e16]  # molec/cm^3

# SI number densities for use in later analysis sections
M_SI = M_values .* 1e6  # molec/cm^3 → molec/m^3

# CGS to SI conversion factors
CGS_TO_SI_K2 = 1e-12  # cm^6/molec^2/s → m^6/s
CGS_TO_SI_K = 1e-6    # cm^3/molec/s → m^3/s

# Analytical rate coefficient functions from textbook Tables B.1/B.2 (CGS → SI)
k_O_O2_M_si(T) = 6.0e-34 * (T / 300.0)^(-2.4) * CGS_TO_SI_K2
k_O_O3_si(T) = 8.0e-12 * exp(-2060.0 / T) * CGS_TO_SI_K
k_NO2_O_si(T) = 5.6e-12 * exp(180.0 / T) * CGS_TO_SI_K
k_OH_O3_si(T) = 1.7e-12 * exp(-940.0 / T) * CGS_TO_SI_K
k_ClO_O_si(T) = 3.0e-11 * exp(70.0 / T) * CGS_TO_SI_K
k_Br_O3_si(T) = 1.7e-11 * exp(-800.0 / T) * CGS_TO_SI_K

table51 = DataFrame(
    Symbol("z (km)") => altitudes,
    Symbol("T (K)") => temperatures,
    Symbol("p (hPa)") => pressures_hPa,
    Symbol("p/p₀") => p_over_p0,
    Symbol("[M] (molec/cm³)") => M_values
)
6×5 DataFrame
Rowz (km)T (K)p (hPa)p/p₀[M] (molec/cm³)
Int64Int64Float64Float64Float64
12021755.00.0541.4e18
22522225.00.0256.4e17
33022712.00.0123.1e17
4352375.60.00551.4e17
5402512.80.00287.1e16
6452651.40.00143.6e16

Table 5.2: Chemical Families in Stratospheric Chemistry

Table 5.2 from Seinfeld & Pandis (2006) summarizes the chemical families that are important in stratospheric chemistry:

table52 = DataFrame(
    :Symbol => ["Oₓ", "NOₓ", "NOᵧ", "HOₓ", "Clᵧ", "ClOₓ", "Brᵧ"],
    :Name => ["Odd oxygen", "Nitrogen oxides", "Oxidized nitrogen",
        "Hydrogen radicals", "Inorganic chlorine", "Reactive chlorine",
        "Inorganic bromine"],
    :Components => [
        "O + O3",
        "NO + NO2",
        "NO + NO2 + HNO3 + 2N2O5 + ClONO2 + NO3 + HOONO2 + BrONO2",
        "OH + HO2",
        "Cl + 2Cl2 + ClO + OClO + 2Cl2O2 + HOCl + ClONO2 + HCl + BrCl",
        "Cl + ClO",
        "Br + BrO + HOBr + BrONO2"
    ]
)
7×3 DataFrame
RowSymbolNameComponents
StringStringString
1OₓOdd oxygenO + O3
2NOₓNitrogen oxidesNO + NO2
3NOᵧOxidized nitrogenNO + NO2 + HNO3 + 2N2O5 + ClONO2 + NO3 + HOONO2 + BrONO2
4HOₓHydrogen radicalsOH + HO2
5ClᵧInorganic chlorineCl + 2Cl2 + ClO + OClO + 2Cl2O2 + HOCl + ClONO2 + HCl + BrCl
6ClOₓReactive chlorineCl + ClO
7BrᵧInorganic bromineBr + BrO + HOBr + BrONO2

Rate Coefficients vs Altitude

The rate coefficients for the Chapman mechanism vary with altitude due to their temperature dependence:

using Plots

k2_values = [k_O_O2_M_si(T) for T in temperatures]
k4_values = [k_O_O3_si(T) for T in temperatures]

p1 = plot(altitudes, k2_values,
    xlabel = "Altitude (km)",
    ylabel = "k₂ (m⁶ s⁻¹)",
    label = "k2: O + O2 + M",
    marker = :circle,
    title = "Temperature Dependence of Rate Coefficients",
    legend = :topright)

p2 = plot(altitudes, k4_values,
    xlabel = "Altitude (km)",
    ylabel = "k₄ (m³ s⁻¹)",
    label = "k4: O + O3",
    marker = :square,
    color = :red,
    legend = :topleft)

plot(p1, p2, layout = (1, 2), size = (800, 350))
Example block output

[O]/[O3] Ratio (Equation 5.7)

The steady-state ratio of atomic oxygen to ozone is given by Equation 5.7:

\[\frac{[O]}{[O_3]} = \frac{j_{O_3}}{k_2[O_2][M]}\]

This ratio increases with altitude due to decreasing air density M:

using Plots

j_O3 = 4e-4  # s^-1 (typical midday value around 30 km)
O2_frac = 0.21

O_O3_ratios = Float64[]
for (i, T) in enumerate(temperatures)
    M = M_SI[i]
    k2 = k_O_O2_M_si(T)  # m^6/s (SI)
    O2 = O2_frac * M
    ratio = j_O3 / (k2 * O2 * M)
    push!(O_O3_ratios, ratio)
end

plot(altitudes, O_O3_ratios,
    xlabel = "Altitude (km)",
    ylabel = "[O]/[O3]",
    label = "Equation 5.7",
    marker = :circle,
    yscale = :log10,
    title = "Steady-State [O]/[O3] Ratio vs Altitude",
    legend = :bottomright)
Example block output

The [O]/[O3] ratio increases from approximately 10^-7 at 20 km to 10^-5 at 45 km, consistent with the discussion on page 144 of Seinfeld & Pandis.

Steady-State Ozone (Equation 5.13)

The Chapman mechanism predicts a steady-state ozone concentration given by Equation 5.13:

\[[O_3]_{ss} = 0.21 \times \sqrt{\frac{k_2 \cdot j_{O_2}}{k_4 \cdot j_{O_3}}} \times [M]^{3/2}\]

using Plots

j_O2_values = [1e-12, 5e-12, 1e-11, 2e-11, 3e-11, 4e-11]  # Increases with altitude
j_O3_values = [2e-4, 3e-4, 4e-4, 5e-4, 6e-4, 7e-4]  # s^-1

O3_ss = Float64[]
for (i, T) in enumerate(temperatures)
    M = M_SI[i]  # SI: m^-3
    k2 = k_O_O2_M_si(T)  # SI: m^6/s
    k4 = k_O_O3_si(T)    # SI: m^3/s
    j_O2 = j_O2_values[i]
    j_O3 = j_O3_values[i]

    O3 = 0.21 * sqrt(k2 * j_O2 / (k4 * j_O3)) * M^1.5  # SI: m^-3
    push!(O3_ss, O3)
end

# Convert SI m^-3 to CGS molec/cm^3 for display (÷ 1e6)
plot(O3_ss ./ 1e6 ./ 1e12, altitudes,
    ylabel = "Altitude (km)",
    xlabel = "[O3] (10¹² molec/cm³)",
    label = "Chapman prediction (Eq. 5.13)",
    marker = :circle,
    title = "Steady-State Ozone Profile",
    legend = :topright)
Example block output

Time to Steady State (Equation 5.17)

The characteristic time for ozone to reach steady state is given by Equation 5.17:

\[\tau_{O_3}^{ss} = \frac{1}{4} \sqrt{\frac{k_2[M]}{k_4 \cdot j_{O_2} \cdot j_{O_3}}}\]

using Plots

tau_ss = Float64[]
for (i, T) in enumerate(temperatures)
    M = M_SI[i]  # SI: m^-3
    k2 = k_O_O2_M_si(T)  # SI: m^6/s
    k4 = k_O_O3_si(T)    # SI: m^3/s
    j_O2 = j_O2_values[i]
    j_O3 = j_O3_values[i]

    tau = 0.25 * sqrt(k2 * M / (k4 * j_O2 * j_O3))
    push!(tau_ss, tau)
end

tau_days = tau_ss ./ (24 * 3600)

plot(tau_days, altitudes,
    ylabel = "Altitude (km)",
    xlabel = "Time to steady state (days)",
    label = "Equation 5.17",
    marker = :circle,
    xscale = :log10,
    title = "Ozone Steady-State Timescale",
    legend = :topright)
Example block output

At 40 km, the ozone steady-state timescale is on the order of hours, while at 20 km it can take months to years. This explains why the ozone layer responds quickly to perturbations at higher altitudes but slowly at lower altitudes.

Chapman Mechanism Simulation

We can solve the Chapman mechanism ODE system to observe the approach to steady state:

using GasChem
using ModelingToolkit
using OrdinaryDiffEqDefault
using Plots

chapman = ChapmanMechanism()
sys = mtkcompile(chapman)

# Parameters for 30 km altitude (Table 5.1)
T_val = 227.0  # K
M_30km = 3.1e23  # m^-3 (3.1e17 molec/cm^3 × 1e6)

j_O2_val = 1e-11  # s^-1
j_O3_val = 4e-4   # s^-1

prob = ODEProblem(sys,
    [sys.O => 1e11, sys.O3 => 1e16,  # SI: m^-3
        sys.j_O2 => j_O2_val,
        sys.j_O3 => j_O3_val,
        sys.T => T_val,
        sys.M => M_30km,
        sys.O2_mix => 0.21],
    (0.0, 3600.0 * 24 * 10))  # 10 days

sol = solve(prob, abstol = 1e-8, reltol = 1e-8)

time_hours = sol.t ./ 3600

# Convert SI m^-3 back to CGS molec/cm^3 for display (÷ 1e6)
p1 = plot(time_hours, sol[sys.O3] ./ 1e6 ./ 1e12,
    xlabel = "Time (hours)",
    ylabel = "[O3] (10¹² molec/cm³)",
    label = "O3",
    title = "Chapman Mechanism: Approach to Steady State (30 km)")

p2 = plot(time_hours, sol[sys.O] ./ 1e6,
    xlabel = "Time (hours)",
    ylabel = "[O] (molec/cm³)",
    label = "O",
    color = :red,
    title = "Atomic Oxygen")

plot(p1, p2, layout = (2, 1), size = (700, 500))
Example block output

Catalytic Cycle Contributions to Ozone Loss

The catalytic cycles (NOx, HOx, ClOx, BrOx) each contribute to ozone destruction at different rates depending on altitude. The relative importance of each cycle varies with altitude, as shown in Figure 5.29 of Seinfeld & Pandis.

At lower stratospheric altitudes (15-25 km), the HOx cycle dominates ozone loss. At middle altitudes (25-40 km), the NOx cycle becomes most important. The ClOx cycle contributes significantly at all altitudes and is particularly important in the polar regions where heterogeneous chemistry activates chlorine reservoirs.

The following figure computes the relative destruction rates at each altitude, assuming typical species mixing ratios from the textbook:

using Plots

# Compute catalytic destruction rates
# Using typical stratospheric mixing ratios from Chapter 5
# All concentrations in SI (m^-3)

# Typical mixing ratios (from text)
NO2_vmr = 5e-9   # 5 ppbv
OH_vmr = 5e-7    # 0.5 pptv — very low
ClO_vmr = 1e-10  # ~100 pptv
BrO_vmr = 5e-12  # ~5 pptv

# Reference values in SI for scaling (30 km)
M_ref_si = M_SI[3]

nox_rates = Float64[]
hox_rates = Float64[]
clox_rates = Float64[]
brox_rates = Float64[]
chapman_rates = Float64[]

for (i, T) in enumerate(temperatures)
    M = M_SI[i]  # SI: m^-3
    O_conc = 1e13 * (M_ref_si / M)     # Scale O with inverse density (SI: m^-3)
    O3_conc = 3e18 * (M / M_ref_si)    # Scale O3 with density (SI: m^-3)

    NO2 = NO2_vmr * M
    OH = OH_vmr * M
    ClO = ClO_vmr * M
    BrO = BrO_vmr * M

    # Destruction rates (from Seinfeld & Pandis Eqs. 5.22, 5.25, 5.29)
    k_NO2_O_val = k_NO2_O_si(T)   # SI: m^3/s
    k_OH_O3_val = k_OH_O3_si(T)
    k_ClO_O_val = k_ClO_O_si(T)
    k_Br_O3_val = k_Br_O3_si(T)
    k4 = k_O_O3_si(T)

    R_NOx = 2 * k_NO2_O_val * NO2 * O_conc
    R_HOx = 2 * k_OH_O3_val * OH * O3_conc
    R_ClOx = 2 * k_ClO_O_val * ClO * O_conc
    R_BrOx = 2 * k_Br_O3_val * BrO * O3_conc
    R_chapman = 2 * k4 * O_conc * O3_conc

    total = R_NOx + R_HOx + R_ClOx + R_BrOx + R_chapman
    push!(nox_rates, 100 * R_NOx / total)
    push!(hox_rates, 100 * R_HOx / total)
    push!(clox_rates, 100 * R_ClOx / total)
    push!(brox_rates, 100 * R_BrOx / total)
    push!(chapman_rates, 100 * R_chapman / total)
end

plot(nox_rates, altitudes,
    label = "NOx",
    xlabel = "Contribution to O3 Loss (%)",
    ylabel = "Altitude (km)",
    title = "Catalytic Cycle Contributions (cf. Figure 5.29)",
    linewidth = 2,
    legend = :topright)
plot!(hox_rates, altitudes, label = "HOx", linewidth = 2)
plot!(clox_rates, altitudes, label = "ClOx", linewidth = 2)
plot!(brox_rates, altitudes, label = "BrOx", linewidth = 2)
plot!(chapman_rates, altitudes, label = "Chapman (O+O3)", linewidth = 2, linestyle = :dash)
Example block output

NOx Catalytic Efficiency

The NOx cycle destroys odd oxygen at the rate (Equation 5.22):

\[\frac{d[O_x]}{dt} = -2k_2[NO_2][O]\]

The efficiency of the NOx cycle can be estimated by comparing this destruction rate to the Chapman mechanism rate:

using Plots

NO2_mix = 1e-9  # 1 ppbv
O_mix = 1e-11   # varies strongly with altitude

ratios = Float64[]
for (i, T) in enumerate(temperatures)
    M = M_SI[i]  # SI: m^-3
    k4 = k_O_O3_si(T)      # SI: m^3/s
    k_NO2_O_val = k_NO2_O_si(T)  # SI: m^3/s

    O = O_mix * M
    O3 = 3e18  # SI: m^-3 (3e12 molec/cm^3 × 1e6)
    NO2 = NO2_mix * M

    R_chapman = k4 * O * O3
    R_NOx = k_NO2_O_val * NO2 * O

    push!(ratios, R_NOx / R_chapman)
end

plot(altitudes, ratios,
    xlabel = "Altitude (km)",
    ylabel = "NOx/Chapman Rate Ratio",
    label = "Rate ratio",
    marker = :circle,
    title = "NOx Cycle Efficiency Relative to Chapman",
    legend = :topleft,
    yscale = :log10)
Example block output

Chlorine Reservoir Partitioning

In the stratosphere, most chlorine exists in reservoir species (HCl and ClONO2) rather than reactive forms (Cl and ClO). The partitioning between these species is crucial for understanding ozone depletion.

The following figure uses the ClOx cycle system from the implementation to simulate the approach to steady-state partitioning:

using GasChem
using ModelingToolkit
using OrdinaryDiffEqDefault
using Plots

# Run ClOx system at different altitudes and examine the partitioning
sys = ClOxCycle()
compiled = mtkcompile(sys)

# Compute partitioning at a representative altitude (30 km)
# CGS→SI: 1 cm^-3 = 1e6 m^-3
Cly_total = 2e15  # Total Cly in SI m^-3 (2e9 molec/cm^3 × 1e6)

prob = ODEProblem(compiled,
    [compiled.Cl => 1e10, compiled.ClO => 1e13,
        compiled.HCl => 1e15, compiled.ClONO2 => Cly_total - 1e10 - 1e13 - 1e15],
    (0.0, 3600.0 * 24)  # 1 day
)

sol = solve(prob, abstol = 1e-8, reltol = 1e-8)

time_hours = sol.t ./ 3600

Cly = sol[compiled.Cl] .+ sol[compiled.ClO] .+ sol[compiled.HCl] .+ sol[compiled.ClONO2]
HCl_frac = sol[compiled.HCl] ./ Cly
ClONO2_frac = sol[compiled.ClONO2] ./ Cly
ClOx_frac = (sol[compiled.Cl] .+ sol[compiled.ClO]) ./ Cly

plot(time_hours, HCl_frac, label = "HCl/Cly", linewidth = 2,
    xlabel = "Time (hours)", ylabel = "Fraction of Cly",
    title = "Chlorine Reservoir Partitioning (30 km)",
    legend = :right)
plot!(time_hours, ClONO2_frac, label = "ClONO2/Cly", linewidth = 2)
plot!(time_hours, ClOx_frac, label = "ClOx/Cly", linewidth = 2)
Example block output

The reactive chlorine species (ClOx = Cl + ClO) constitute only a small fraction of total inorganic chlorine (Cly) under normal conditions. However, heterogeneous reactions on polar stratospheric clouds can rapidly convert HCl and ClONO2 to reactive forms, leading to severe ozone depletion in polar regions (the "ozone hole").

Summary

This module provides a comprehensive implementation of stratospheric ozone chemistry based on the well-established theory presented in Seinfeld & Pandis (2006). The key features include:

  1. Chapman Mechanism: Fundamental O2/O3 photochemistry with temperature-dependent rate coefficients
  2. Catalytic Cycles: NOx, HOx, ClOx, and BrOx destruction mechanisms
  3. Chemical Families: Tracking of Ox, NOx, HOx, ClOx, and BrOx families
  4. N2O Source Chemistry: N2O + O(1D) as the primary source of stratospheric NOx (Section 5.3.1)
  5. O(1D) Photochemistry: Including reactions with H2O, CH4, and N2O
  6. Rate Coefficients: All Arrhenius parameters embedded as @constants within ModelingToolkit components