Version: dev

WetDeposition

EMEP-formulation wet deposition model for PM2.5, SO2, and other gases. Computes three first-order wet deposition rate coefficients (k_particle, k_SO2, k_othergas [1/s]) from cloud fraction (cloudFrac), rain mixing ratio (qrain), air density (rho_air), and the atmospheric level index (lev). Subcloud scavenging rates scale as qrain*rho_air/Dz times a species-specific washout coefficient; in-cloud scavenging additionally scales with cloudFrac; the particle subcloud term uses A_wd*E*qrain*rho_air without the 1/Dz factor. The layer depth Dz is looked up from a 72-entry constant table (GEOS-Chem-derived model-level thicknesses in metres) indexed by lev. The gt-p3ep blocking gap (get_lev_depth is @register_symbolic) is resolved by expressing the lookup as an interp.linear AST composition over the 72-entry integer-axis table — matching the FastJX_interpolation_troposphere precedent. Migrated from AtmosphericDeposition.jl@e4468c79 src/wet_deposition.jl:147 (the WetDeposition builder) and src/wet_deposition.jl:82 (_WetDeposition helper). Purely algebraic: no differential states; k_particle, k_SO2, k_othergas are observed variables.

Domain
atmospheric_deposition
Type
model
.esm schema
1.0.0
Source
components/atmospheric_deposition/wet_deposition.esm
Tags
#atmospheric_deposition #model #emep #wet-deposition #scavenging #observed-only

Description

EMEP-formulation wet deposition model for PM2.5, SO2, and other gases. Computes three first-order wet deposition rate coefficients (k_particle, k_SO2, k_othergas [1/s]) from cloud fraction (cloudFrac), rain mixing ratio (qrain), air density (rho_air), and the atmospheric level index (lev). Subcloud scavenging rates scale as qrainrho_air/Dz times a species-specific washout coefficient; in-cloud scavenging additionally scales with cloudFrac; the particle subcloud term uses A_wdEqrainrho_air without the 1/Dz factor. The layer depth Dz is looked up from a 72-entry constant table (GEOS-Chem-derived model-level thicknesses in metres) indexed by lev. The gt-p3ep blocking gap (get_lev_depth is @register_symbolic) is resolved by expressing the lookup as an interp.linear AST composition over the 72-entry integer-axis table — matching the FastJX_interpolation_troposphere precedent. Migrated from AtmosphericDeposition.jl@e4468c79 src/wet_deposition.jl:147 (the WetDeposition builder) and src/wet_deposition.jl:82 (_WetDeposition helper). Purely algebraic: no differential states; k_particle, k_SO2, k_othergas are observed variables.

Reference

EMEP (2003). EMEP MSC-W Status Report 2003: Transboundary Acidification, Eutrophication and Ground Level Ozone in Europe. EMEP Report 1/2003, Part I. https://www.emep.int/publ/reports/2003/emep_report_1_part1_2003.pdf .

_source_ref: AtmosphericDeposition.jl@e4468c79c8dd4aae88646cd16d6bcf290874742c:src/wet_deposition.jl:147

Upstream WetDeposition is an MTK builder — System(eqs, t, vars, params; name) — with four @parameters (cloudFrac, qrain, ρ_air, lev) and three @variables (k_particle, k_SO2, k_othergas [1/s]), related by three algebraic equations built from the _WetDeposition helper (src/wet_deposition.jl:101). The helper is a plain Julia function computing subcloud and in-cloud scavenging rates using six local constants (E=0.1, wSubSO2=0.15, wSubOther=0.5, wInSO2=0.3, wInParticle=1.0, wInOther=1.4) and three module-level @constants (A_wd=5.2, ρwater=1000.0, Vdr=5.0). These local constants are folded into the inline expression arithmetic as fixed numeric literals; the module @constants become fixed-default parameters per the rig convention.

The gt-p3ep blocking gap: get_lev_depth(lev) (src/wet_deposition.jl:82) is a @register_symbolic wrapper around a 72-entry constant Julia array lev_depth (src/wet_deposition.jl:7-80) indexed by lev. The registered-symbolic call get_lev_depth(lev) * Δz_unit supplies the layer depth Dz to the _WetDeposition helper. Resolution: exactly as done for FastJX_interpolation_troposphere (components/gaschem/fastjx/fastjx_interp_troposphere.esm, esm-09u), the registered function is replaced by an interp.linear AST expression over the full 72-entry table on a 1-indexed integer axis. For integer lev in 1..72 the query always lands exactly on an axis knot, so interp.linear returns the exact table entry with zero blend weight, reproducing the upstream direct array indexing. The Δz_unit @constant equals 1 m and folds away, so the looked-up value is already in metres.

The _WetDeposition helper logic verbatim: i = ifelse(qrain > 0, 1, 0) – guard against non-positive qrain AE = A_wd * E = 5.2 * 0.1 = 0.52 – precombined constant wInParticleVdrPerrhowater = 1.05.0/1000.0 = 0.005 wSubSO2VdrPerrhowater = 0.155.0/1000.0 = 7.5e-4 wSubOtherVdrPerrhowater = 0.5*5.0/1000.0 = 2.5e-3 k_particle = i * qrain * rho_air * (AE + cloudFrac * (wInParticleVdrPerrhowater / Dz)) k_SO2 = i * (wSubSO2VdrPerrhowater + cloudFrac * wSubSO2VdrPerrhowater) * qrain * rho_air / Dz k_othergas = i * (wSubOtherVdrPerrhowater + cloudFrac * wSubOtherVdrPerrhowater) * qrain * rho_air / Dz Note: the upstream wdSO2 formula uses (wSubSO2VdrPerrhowater + cloudFrac * wSubSO2VdrPerrhowater) = wSubSO2VdrPerrhowater * (1 + cloudFrac). The wInSO2VdrPerrhowater constant appears in the precombinations block of _WetDeposition but is not referenced in any of the three output expressions (verified by inspection of src/wet_deposition.jl:123-128); it is therefore omitted from the ESM.

All three output variables (k_particle, k_SO2, k_othergas) are expressed as type: observed with inline expression trees. No time derivative exists anywhere; system_kind is left unset (observed-only algebraic, matching dry_aerosol.esm and WetDepositionFlux.esm siblings).

The ρ_air Julia parameter name is migrated as rho_air (ASCII) for JSON compatibility. The upstream coupler metadata (WetDepositionCoupler) is informational only and is not carried into the ESM per rig convention.

Inputs and defaults: cloudFrac (default 0.5, dimensionless), qrain (default 0.5, dimensionless rain mixing ratio), rho_air (default 1.204 kg/m^3, upstream default), lev (default 1, level index 1-72). Module @constants become fixed-default parameters: A_wd=5.2 m^3/(kg*s), rho_water=1000.0 kg/m^3, Vdr=5.0 m/s.

Tolerance rationale (model-level rel=1e-9): a closed-form algebraic system evaluated by topological substitution of the interp.linear lookup and arithmetic on float64 constants. The interp.linear query lands on integer knots, returning exact table entries; subsequent arithmetic (+, *, /, ifelse) accumulates float64 round-off ~1e-15 per op, ~1e-13 for the full cascade. rel=1e-9 gives comfortable headroom._

Parameters

NameUnitsDefaultDescription
cloudFrac10.5Fraction of the grid cell covered by clouds (dimensionless, upstream cloudFrac @parameter).
qrain10.5Rain mixing ratio (dimensionless, upstream qrain @parameter).
rho_airkg/m^31.204Air density (upstream ρ_air @parameter, migrated as ASCII rho_air).
lev11Atmospheric level index (1-indexed integer, 1 = surface, up to 72); used to look up layer depth from the 72-entry lev_depth table.
A_wdm^3/(kg*s)5.2Empirical wet deposition coefficient (upstream module @constant A_wd).
rho_waterkg/m^31000.0Water density (upstream module @constant ρwater).
Vdrm/s5.0Raindrop fall speed (upstream module @constant Vdr).

Observed

NameUnitsDefaultDescription
DzmLayer depth at level lev, looked up from the 72-entry GEOS-Chem model-level thickness table (lev_depth [m]) via interp.linear on the integer axis 1..72. Resolves the gt-p3ep gap: the upstream @register_symbolic get_lev_depth(lev) is expressed as an AST interp.linear composition, matching the FastJX_interpolation_troposphere precedent (esm-09u). For integer lev the query lands exactly on an axis knot (zero blend weight), reproducing the direct array indexing of the upstream Julia code.
i_rain1Rain presence indicator: 1 if qrain > 0, else 0. Guards against negative qrain (upstream i = ifelse(qrain > 0, 1, 0), src/wet_deposition.jl:109).
k_particle1/sFirst-order wet deposition rate for PM2.5 (aerosol particles). Subcloud term: A_wdEqrainrho_air (no 1/Dz); in-cloud term: wInParticle(Vdr/rho_water)cloudFracqrainrho_air/Dz. With E=0.1, wInParticle=1.0 folded in (src/wet_deposition.jl:123): k_particle = i * qrain * rho_air * (A_wd0.1 + cloudFrac*(1.0*Vdr/rho_water/Dz)).
k_SO21/sFirst-order wet deposition rate for SO2. Both subcloud and in-cloud terms use wSubSO2=0.15; combined: (wSubSO2Vdr/rho_water)(1+cloudFrac)qrainrho_air/Dz (src/wet_deposition.jl:124).
k_othergas1/sFirst-order wet deposition rate for other gases (not SO2). Both subcloud and in-cloud terms use wSubOther=0.5; combined: (wSubOtherVdr/rho_water)(1+cloudFrac)qrainrho_air/Dz (src/wet_deposition.jl:125-126).

Observed expressions

$$ Dz = \mathrm{fn}\left(\mathrm{const}\left(\right), \mathrm{const}\left(\right), lev\right) $$

Layer depth at level lev, looked up from the 72-entry GEOS-Chem model-level thickness table (lev_depth [m]) via interp.linear on the integer axis 1..72. Resolves the gt-p3ep gap: the upstream @register_symbolic get_lev_depth(lev) is expressed as an AST interp.linear composition, matching the FastJX_interpolation_troposphere precedent (esm-09u). For integer lev the query lands exactly on an axis knot (zero blend weight), reproducing the direct array indexing of the upstream Julia code.

$$ i_{rain} = \mathrm{ifelse}\left(\mathrm{>}\left(qrain, 0\right), 1, 0\right) $$

Rain presence indicator: 1 if qrain > 0, else 0. Guards against negative qrain (upstream i = ifelse(qrain > 0, 1, 0), src/wet_deposition.jl:109).

$$ k_{particle} = i_{rain} \cdot qrain \cdot rho_{air} \cdot \left(A_{wd} \cdot 0.1 + cloudFrac \cdot \frac{Vdr}{rho_{water} \cdot Dz}\right) $$

First-order wet deposition rate for PM2.5 (aerosol particles). Subcloud term: A_wdEqrainrho_air (no 1/Dz); in-cloud term: wInParticle(Vdr/rho_water)cloudFracqrainrho_air/Dz. With E=0.1, wInParticle=1.0 folded in (src/wet_deposition.jl:123): k_particle = i * qrain * rho_air * (A_wd0.1 + cloudFrac*(1.0*Vdr/rho_water/Dz)).

$$ k_{SO2} = i_{rain} \cdot \left(\frac{0.15 \cdot Vdr}{rho_{water}} + cloudFrac \cdot \frac{0.15 \cdot Vdr}{rho_{water}}\right) \cdot qrain \cdot rho_{air} \cdot \frac{1}{Dz} $$

First-order wet deposition rate for SO2. Both subcloud and in-cloud terms use wSubSO2=0.15; combined: (wSubSO2Vdr/rho_water)(1+cloudFrac)qrainrho_air/Dz (src/wet_deposition.jl:124).

$$ k_{othergas} = i_{rain} \cdot \left(\frac{0.5 \cdot Vdr}{rho_{water}} + cloudFrac \cdot \frac{0.5 \cdot Vdr}{rho_{water}}\right) \cdot qrain \cdot rho_{air} \cdot \frac{1}{Dz} $$

First-order wet deposition rate for other gases (not SO2). Both subcloud and in-cloud terms use wSubOther=0.5; combined: (wSubOtherVdr/rho_water)(1+cloudFrac)qrainrho_air/Dz (src/wet_deposition.jl:125-126).

Analyses

deposition_rates_vs_lev

Wet deposition rates k_particle, k_SO2, and k_othergas as a function of atmospheric level (lev 1-72). Higher levels have greater Dz, reducing the 1/Dz scavenging terms while leaving the subcloud particle term (no 1/Dz) approximately constant.

Time span: 0.0 → 1.0

Swept over: lev

PM2.5 wet deposition rate k_particle versus model level.

SO2 and other-gas wet deposition rates versus model level.

deposition_rates_vs_qrain_and_cloudFrac

Wet deposition rates as a joint function of rain mixing ratio (qrain) and cloud fraction (cloudFrac) at lev=1. All three rates scale linearly with qrain; the gas rates additionally scale with (1 + cloudFrac) and the particle in-cloud term scales with cloudFrac.

Time span: 0.0 → 1.0

Swept over: qrain, cloudFrac

PM2.5 wet deposition rate k_particle as a function of qrain and cloudFrac.

Raw .esm

Raw .esm JSON (this component)
{
  "reference": {
    "citation": "EMEP (2003). EMEP MSC-W Status Report 2003: Transboundary Acidification, Eutrophication and Ground Level Ozone in Europe. EMEP Report 1/2003, Part I. https://www.emep.int/publ/reports/2003/emep_report_1_part1_2003.pdf.",
    "notes": "source_ref: AtmosphericDeposition.jl@e4468c79c8dd4aae88646cd16d6bcf290874742c:src/wet_deposition.jl:147\n\nUpstream `WetDeposition` is an MTK builder — `System(eqs, t, vars, params; name)` — with four @parameters (cloudFrac, qrain, ρ_air, lev) and three @variables (k_particle, k_SO2, k_othergas [1/s]), related by three algebraic equations built from the `_WetDeposition` helper (src/wet_deposition.jl:101). The helper is a plain Julia function computing subcloud and in-cloud scavenging rates using six local constants (E=0.1, wSubSO2=0.15, wSubOther=0.5, wInSO2=0.3, wInParticle=1.0, wInOther=1.4) and three module-level @constants (A_wd=5.2, ρwater=1000.0, Vdr=5.0). These local constants are folded into the inline expression arithmetic as fixed numeric literals; the module @constants become fixed-default parameters per the rig convention.\n\nThe gt-p3ep blocking gap: `get_lev_depth(lev)` (src/wet_deposition.jl:82) is a `@register_symbolic` wrapper around a 72-entry constant Julia array `lev_depth` (src/wet_deposition.jl:7-80) indexed by lev. The registered-symbolic call `get_lev_depth(lev) * Δz_unit` supplies the layer depth Dz to the _WetDeposition helper. Resolution: exactly as done for FastJX_interpolation_troposphere (components/gaschem/fastjx/fastjx_interp_troposphere.esm, esm-09u), the registered function is replaced by an `interp.linear` AST expression over the full 72-entry table on a 1-indexed integer axis. For integer lev in 1..72 the query always lands exactly on an axis knot, so interp.linear returns the exact table entry with zero blend weight, reproducing the upstream direct array indexing. The Δz_unit @constant equals 1 m and folds away, so the looked-up value is already in metres.\n\nThe `_WetDeposition` helper logic verbatim:\n  i = ifelse(qrain > 0, 1, 0)                  -- guard against non-positive qrain\n  AE = A_wd * E = 5.2 * 0.1 = 0.52             -- precombined constant\n  wInParticleVdrPerrhowater = 1.0*5.0/1000.0 = 0.005\n  wSubSO2VdrPerrhowater = 0.15*5.0/1000.0 = 7.5e-4\n  wSubOtherVdrPerrhowater = 0.5*5.0/1000.0 = 2.5e-3\n  k_particle = i * qrain * rho_air * (AE + cloudFrac * (wInParticleVdrPerrhowater / Dz))\n  k_SO2      = i * (wSubSO2VdrPerrhowater + cloudFrac * wSubSO2VdrPerrhowater) * qrain * rho_air / Dz\n  k_othergas = i * (wSubOtherVdrPerrhowater + cloudFrac * wSubOtherVdrPerrhowater) * qrain * rho_air / Dz\nNote: the upstream `wdSO2` formula uses (wSubSO2VdrPerrhowater + cloudFrac * wSubSO2VdrPerrhowater) = wSubSO2VdrPerrhowater * (1 + cloudFrac). The wInSO2VdrPerrhowater constant appears in the precombinations block of _WetDeposition but is not referenced in any of the three output expressions (verified by inspection of src/wet_deposition.jl:123-128); it is therefore omitted from the ESM.\n\nAll three output variables (k_particle, k_SO2, k_othergas) are expressed as `type: observed` with inline expression trees. No time derivative exists anywhere; `system_kind` is left unset (observed-only algebraic, matching dry_aerosol.esm and WetDepositionFlux.esm siblings).\n\nThe `ρ_air` Julia parameter name is migrated as `rho_air` (ASCII) for JSON compatibility. The upstream coupler metadata (WetDepositionCoupler) is informational only and is not carried into the ESM per rig convention.\n\nInputs and defaults: cloudFrac (default 0.5, dimensionless), qrain (default 0.5, dimensionless rain mixing ratio), rho_air (default 1.204 kg/m^3, upstream default), lev (default 1, level index 1-72). Module @constants become fixed-default parameters: A_wd=5.2 m^3/(kg*s), rho_water=1000.0 kg/m^3, Vdr=5.0 m/s.\n\nTolerance rationale (model-level rel=1e-9): a closed-form algebraic system evaluated by topological substitution of the interp.linear lookup and arithmetic on float64 constants. The interp.linear query lands on integer knots, returning exact table entries; subsequent arithmetic (+, *, /, ifelse) accumulates float64 round-off ~1e-15 per op, ~1e-13 for the full cascade. rel=1e-9 gives comfortable headroom."
  },
  "tolerance": {
    "rel": 1e-09
  },
  "variables": {
    "cloudFrac": {
      "type": "parameter",
      "units": "1",
      "default": 0.5,
      "description": "Fraction of the grid cell covered by clouds (dimensionless, upstream cloudFrac @parameter)."
    },
    "qrain": {
      "type": "parameter",
      "units": "1",
      "default": 0.5,
      "description": "Rain mixing ratio (dimensionless, upstream qrain @parameter)."
    },
    "rho_air": {
      "type": "parameter",
      "units": "kg/m^3",
      "default": 1.204,
      "description": "Air density (upstream ρ_air @parameter, migrated as ASCII rho_air)."
    },
    "lev": {
      "type": "parameter",
      "units": "1",
      "default": 1,
      "description": "Atmospheric level index (1-indexed integer, 1 = surface, up to 72); used to look up layer depth from the 72-entry lev_depth table."
    },
    "A_wd": {
      "type": "parameter",
      "units": "m^3/(kg*s)",
      "default": 5.2,
      "description": "Empirical wet deposition coefficient (upstream module @constant A_wd)."
    },
    "rho_water": {
      "type": "parameter",
      "units": "kg/m^3",
      "default": 1000.0,
      "description": "Water density (upstream module @constant ρwater)."
    },
    "Vdr": {
      "type": "parameter",
      "units": "m/s",
      "default": 5.0,
      "description": "Raindrop fall speed (upstream module @constant Vdr)."
    },
    "Dz": {
      "type": "unknown",
      "units": "m",
      "description": "Layer depth at level lev, looked up from the 72-entry GEOS-Chem model-level thickness table (lev_depth [m]) via interp.linear on the integer axis 1..72. Resolves the gt-p3ep gap: the upstream @register_symbolic get_lev_depth(lev) is expressed as an AST interp.linear composition, matching the FastJX_interpolation_troposphere precedent (esm-09u). For integer lev the query lands exactly on an axis knot (zero blend weight), reproducing the direct array indexing of the upstream Julia code."
    },
    "i_rain": {
      "type": "unknown",
      "units": "1",
      "description": "Rain presence indicator: 1 if qrain > 0, else 0. Guards against negative qrain (upstream `i = ifelse(qrain > 0, 1, 0)`, src/wet_deposition.jl:109)."
    },
    "k_particle": {
      "type": "unknown",
      "units": "1/s",
      "description": "First-order wet deposition rate for PM2.5 (aerosol particles). Subcloud term: A_wd*E*qrain*rho_air (no 1/Dz); in-cloud term: wInParticle*(Vdr/rho_water)*cloudFrac*qrain*rho_air/Dz. With E=0.1, wInParticle=1.0 folded in (src/wet_deposition.jl:123): k_particle = i * qrain * rho_air * (A_wd*0.1 + cloudFrac*(1.0*Vdr/rho_water/Dz))."
    },
    "k_SO2": {
      "type": "unknown",
      "units": "1/s",
      "description": "First-order wet deposition rate for SO2. Both subcloud and in-cloud terms use wSubSO2=0.15; combined: (wSubSO2*Vdr/rho_water)*(1+cloudFrac)*qrain*rho_air/Dz (src/wet_deposition.jl:124)."
    },
    "k_othergas": {
      "type": "unknown",
      "units": "1/s",
      "description": "First-order wet deposition rate for other gases (not SO2). Both subcloud and in-cloud terms use wSubOther=0.5; combined: (wSubOther*Vdr/rho_water)*(1+cloudFrac)*qrain*rho_air/Dz (src/wet_deposition.jl:125-126)."
    }
  },
  "equations": [
    {
      "lhs": "Dz",
      "rhs": {
        "op": "fn",
        "name": "interp.linear",
        "args": [
          {
            "op": "const",
            "args": [],
            "value": [
              123.66503647136699,
              126.1276322862293,
              127.81793001768432,
              129.5320284164788,
              131.3096296124803,
              133.16517799136489,
              135.08768602272573,
              137.10796269057562,
              139.21228482592755,
              141.44376989951024,
              143.7574669454459,
              146.11933204200864,
              198.54224783503264,
              254.42969509717796,
              261.67340274464914,
              269.231033059717,
              277.3039413513152,
              285.9069077030176,
              446.4439568700527,
              469.32492993415644,
              494.6124439883338,
              522.6842502004765,
              554.6091144685597,
              591.0927240282208,
              633.2768512023067,
              682.3924743496791,
              741.7294428383548,
              1090.491426716162,
              1091.224127316289,
              1063.1347680566032,
              1038.8233086979671,
              1024.2528747829,
              1011.555297383451,
              1001.2550381718829,
              993.8747259925203,
              988.6668674973989,
              1000.6772919922369,
              1018.1853036083521,
              1038.4077259678052,
              1060.279636055635,
              1080.0011699235038,
              1105.2749220476362,
              1128.8308686418932,
              1150.9605352645412,
              1174.281709164923,
              1196.5658056986103,
              1220.477376106457,
              1248.055139801716,
              1289.3240338666546,
              1330.1699211514533,
              1371.1351955508508,
              1418.9073193940494,
              1469.6721949144776,
              1524.1720211194188,
              1589.3067557895556,
              1669.0982349095284,
              1748.6026372218985,
              1819.7984799666592,
              1873.109532132221,
              1911.520986089934,
              1927.4499053974941,
              1929.2166042272438,
              1929.6506325142327,
              1932.4995109991505,
              1946.1510743334002,
              1971.4849133077078,
              1995.6526762815556,
              2040.0593226684432,
              2158.2645757768187,
              2421.761343639795,
              3116.2739840471622,
              4343.478215407085
            ]
          },
          {
            "op": "const",
            "args": [],
            "value": [
              1,
              2,
              3,
              4,
              5,
              6,
              7,
              8,
              9,
              10,
              11,
              12,
              13,
              14,
              15,
              16,
              17,
              18,
              19,
              20,
              21,
              22,
              23,
              24,
              25,
              26,
              27,
              28,
              29,
              30,
              31,
              32,
              33,
              34,
              35,
              36,
              37,
              38,
              39,
              40,
              41,
              42,
              43,
              44,
              45,
              46,
              47,
              48,
              49,
              50,
              51,
              52,
              53,
              54,
              55,
              56,
              57,
              58,
              59,
              60,
              61,
              62,
              63,
              64,
              65,
              66,
              67,
              68,
              69,
              70,
              71,
              72
            ]
          },
          "lev"
        ]
      }
    },
    {
      "lhs": "i_rain",
      "rhs": {
        "op": "ifelse",
        "args": [
          {
            "op": ">",
            "args": [
              "qrain",
              0
            ]
          },
          1,
          0
        ]
      }
    },
    {
      "lhs": "k_particle",
      "rhs": {
        "op": "*",
        "args": [
          "i_rain",
          "qrain",
          "rho_air",
          {
            "op": "+",
            "args": [
              {
                "op": "*",
                "args": [
                  "A_wd",
                  0.1
                ]
              },
              {
                "op": "*",
                "args": [
                  "cloudFrac",
                  {
                    "op": "/",
                    "args": [
                      "Vdr",
                      {
                        "op": "*",
                        "args": [
                          "rho_water",
                          "Dz"
                        ]
                      }
                    ]
                  }
                ]
              }
            ]
          }
        ]
      }
    },
    {
      "lhs": "k_SO2",
      "rhs": {
        "op": "*",
        "args": [
          "i_rain",
          {
            "op": "+",
            "args": [
              {
                "op": "/",
                "args": [
                  {
                    "op": "*",
                    "args": [
                      0.15,
                      "Vdr"
                    ]
                  },
                  "rho_water"
                ]
              },
              {
                "op": "*",
                "args": [
                  "cloudFrac",
                  {
                    "op": "/",
                    "args": [
                      {
                        "op": "*",
                        "args": [
                          0.15,
                          "Vdr"
                        ]
                      },
                      "rho_water"
                    ]
                  }
                ]
              }
            ]
          },
          "qrain",
          "rho_air",
          {
            "op": "/",
            "args": [
              1,
              "Dz"
            ]
          }
        ]
      }
    },
    {
      "lhs": "k_othergas",
      "rhs": {
        "op": "*",
        "args": [
          "i_rain",
          {
            "op": "+",
            "args": [
              {
                "op": "/",
                "args": [
                  {
                    "op": "*",
                    "args": [
                      0.5,
                      "Vdr"
                    ]
                  },
                  "rho_water"
                ]
              },
              {
                "op": "*",
                "args": [
                  "cloudFrac",
                  {
                    "op": "/",
                    "args": [
                      {
                        "op": "*",
                        "args": [
                          0.5,
                          "Vdr"
                        ]
                      },
                      "rho_water"
                    ]
                  }
                ]
              }
            ]
          },
          "qrain",
          "rho_air",
          {
            "op": "/",
            "args": [
              1,
              "Dz"
            ]
          }
        ]
      }
    }
  ],
  "tests": [
    {
      "id": "default_params_lev1",
      "description": "Default parameters (cloudFrac=0.5, qrain=0.5, rho_air=1.204, lev=1). Level 1 Dz=123.66503647136699 m from the lev_depth table. Pins all three deposition rate outputs and intermediate observed quantities. Re-asserts k_particle at t=1 to confirm time-invariance (purely algebraic).",
      "parameter_overrides": {
        "cloudFrac": 0.5,
        "qrain": 0.5,
        "rho_air": 1.204,
        "lev": 1,
        "A_wd": 5.2,
        "rho_water": 1000.0,
        "Vdr": 5.0
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "Dz",
          "time": 0.0,
          "expected": 123.66503647136699
        },
        {
          "variable": "i_rain",
          "time": 0.0,
          "expected": 1.0
        },
        {
          "variable": "k_particle",
          "time": 0.0,
          "expected": 0.3130521699717474
        },
        {
          "variable": "k_SO2",
          "time": 0.0,
          "expected": 5.476487286338272e-06
        },
        {
          "variable": "k_othergas",
          "time": 0.0,
          "expected": 1.8254957621127573e-05
        },
        {
          "variable": "k_particle",
          "time": 1.0,
          "expected": 0.3130521699717474
        }
      ]
    },
    {
      "id": "lev3_anchor",
      "description": "Level 3 (Dz=127.81793001768432 m). Anchors the lev_depth lookup at a different level. The upstream Julia test (test/wetdep_test.jl:48) asserts get_lev_depth(3) ≈ 127.81793001768432, which is the exact interp.linear table entry at knot 3.",
      "parameter_overrides": {
        "cloudFrac": 0.5,
        "qrain": 0.5,
        "rho_air": 1.204,
        "lev": 3,
        "A_wd": 5.2,
        "rho_water": 1000.0,
        "Vdr": 5.0
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "Dz",
          "time": 0.0,
          "expected": 127.81793001768432
        },
        {
          "variable": "k_particle",
          "time": 0.0,
          "expected": 0.31305177456089134
        },
        {
          "variable": "k_SO2",
          "time": 0.0,
          "expected": 5.29855240110913e-06
        },
        {
          "variable": "k_othergas",
          "time": 0.0,
          "expected": 1.7661841337030432e-05
        }
      ]
    },
    {
      "id": "no_rain_zero_rates",
      "description": "qrain=0: the i_rain guard sets all three rates to zero regardless of cloudFrac, rho_air, and Dz.",
      "parameter_overrides": {
        "cloudFrac": 0.5,
        "qrain": 0.0,
        "rho_air": 1.204,
        "lev": 1,
        "A_wd": 5.2,
        "rho_water": 1000.0,
        "Vdr": 5.0
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "i_rain",
          "time": 0.0,
          "expected": 0.0
        },
        {
          "variable": "k_particle",
          "time": 0.0,
          "expected": 0.0,
          "tolerance": {
            "abs": 1e-15
          }
        },
        {
          "variable": "k_SO2",
          "time": 0.0,
          "expected": 0.0,
          "tolerance": {
            "abs": 1e-15
          }
        },
        {
          "variable": "k_othergas",
          "time": 0.0,
          "expected": 0.0,
          "tolerance": {
            "abs": 1e-15
          }
        }
      ]
    },
    {
      "id": "no_clouds_subcloud_only",
      "description": "cloudFrac=0: only the subcloud terms contribute. k_particle = qrain*rho_air*A_wd*E; k_SO2 and k_othergas use wSub*Vdr/rho_water*qrain*rho_air/Dz without the in-cloud addend.",
      "parameter_overrides": {
        "cloudFrac": 0.0,
        "qrain": 0.5,
        "rho_air": 1.204,
        "lev": 1,
        "A_wd": 5.2,
        "rho_water": 1000.0,
        "Vdr": 5.0
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "k_particle",
          "time": 0.0,
          "expected": 0.31304
        },
        {
          "variable": "k_SO2",
          "time": 0.0,
          "expected": 3.650991524225514e-06
        },
        {
          "variable": "k_othergas",
          "time": 0.0,
          "expected": 1.2169971747418382e-05
        }
      ]
    },
    {
      "id": "full_cloud_cover",
      "description": "cloudFrac=1.0: both subcloud and in-cloud terms contribute at full strength.",
      "parameter_overrides": {
        "cloudFrac": 1.0,
        "qrain": 0.5,
        "rho_air": 1.204,
        "lev": 1,
        "A_wd": 5.2,
        "rho_water": 1000.0,
        "Vdr": 5.0
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "k_particle",
          "time": 0.0,
          "expected": 0.3130643399434948
        },
        {
          "variable": "k_SO2",
          "time": 0.0,
          "expected": 7.301983048451028e-06
        },
        {
          "variable": "k_othergas",
          "time": 0.0,
          "expected": 2.4339943494836764e-05
        }
      ]
    },
    {
      "id": "heavy_rain_lev1",
      "description": "qrain=1.0: all rates scale linearly with qrain. Doubles all outputs relative to the default qrain=0.5 case at lev=1.",
      "parameter_overrides": {
        "cloudFrac": 0.5,
        "qrain": 1.0,
        "rho_air": 1.204,
        "lev": 1,
        "A_wd": 5.2,
        "rho_water": 1000.0,
        "Vdr": 5.0
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "k_particle",
          "time": 0.0,
          "expected": 0.6261043399434948
        },
        {
          "variable": "k_SO2",
          "time": 0.0,
          "expected": 1.0952974572676544e-05
        },
        {
          "variable": "k_othergas",
          "time": 0.0,
          "expected": 3.6509915242255145e-05
        }
      ]
    },
    {
      "id": "lev72_deep_layer",
      "description": "lev=72 (deepest level, Dz=4343.478215407085 m): the 1/Dz terms in k_SO2 and k_othergas are smallest; the subcloud k_particle term (no 1/Dz) is unchanged from lev=1.",
      "parameter_overrides": {
        "cloudFrac": 0.5,
        "qrain": 0.5,
        "rho_air": 1.204,
        "lev": 72,
        "A_wd": 5.2,
        "rho_water": 1000.0,
        "Vdr": 5.0
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "Dz",
          "time": 0.0,
          "expected": 4343.478215407085
        },
        {
          "variable": "k_particle",
          "time": 0.0,
          "expected": 0.31304034649650014
        },
        {
          "variable": "k_SO2",
          "time": 0.0,
          "expected": 1.5592342505544854e-07
        },
        {
          "variable": "k_othergas",
          "time": 0.0,
          "expected": 5.197447501848284e-07
        }
      ]
    }
  ],
  "analyses": [
    {
      "id": "deposition_rates_vs_lev",
      "description": "Wet deposition rates k_particle, k_SO2, and k_othergas as a function of atmospheric level (lev 1-72). Higher levels have greater Dz, reducing the 1/Dz scavenging terms while leaving the subcloud particle term (no 1/Dz) approximately constant.",
      "initial_state": {},
      "parameters": {
        "cloudFrac": 0.5,
        "qrain": 0.5,
        "rho_air": 1.204,
        "A_wd": 5.2,
        "rho_water": 1000.0,
        "Vdr": 5.0
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "parameter_sweep": {
        "type": "cartesian",
        "dimensions": [
          {
            "parameter": "lev",
            "range": {
              "start": 1,
              "stop": 72,
              "count": 72,
              "scale": "linear"
            }
          }
        ]
      },
      "plots": [
        {
          "id": "particle_rate_vs_lev",
          "type": "line",
          "description": "PM2.5 wet deposition rate k_particle versus model level.",
          "x": {
            "variable": "lev",
            "label": "Level index"
          },
          "y": {
            "variable": "k_particle",
            "label": "k_particle (1/s)"
          }
        },
        {
          "id": "gas_rates_vs_lev",
          "type": "line",
          "description": "SO2 and other-gas wet deposition rates versus model level.",
          "x": {
            "variable": "lev",
            "label": "Level index"
          },
          "y": {
            "variable": "k_SO2",
            "label": "k_SO2 (1/s)"
          }
        }
      ]
    },
    {
      "id": "deposition_rates_vs_qrain_and_cloudFrac",
      "description": "Wet deposition rates as a joint function of rain mixing ratio (qrain) and cloud fraction (cloudFrac) at lev=1. All three rates scale linearly with qrain; the gas rates additionally scale with (1 + cloudFrac) and the particle in-cloud term scales with cloudFrac.",
      "initial_state": {},
      "parameters": {
        "rho_air": 1.204,
        "lev": 1,
        "A_wd": 5.2,
        "rho_water": 1000.0,
        "Vdr": 5.0
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "parameter_sweep": {
        "type": "cartesian",
        "dimensions": [
          {
            "parameter": "qrain",
            "range": {
              "start": 0.0,
              "stop": 1.0,
              "count": 11,
              "scale": "linear"
            }
          },
          {
            "parameter": "cloudFrac",
            "range": {
              "start": 0.0,
              "stop": 1.0,
              "count": 6,
              "scale": "linear"
            }
          }
        ]
      },
      "plots": [
        {
          "id": "particle_heatmap",
          "type": "heatmap",
          "description": "PM2.5 wet deposition rate k_particle as a function of qrain and cloudFrac.",
          "x": {
            "variable": "qrain",
            "label": "Rain mixing ratio"
          },
          "y": {
            "variable": "cloudFrac",
            "label": "Cloud fraction"
          },
          "value": {
            "variable": "k_particle",
            "reduce": "final"
          }
        }
      ]
    }
  ]
}