Version: dev

LocalScaleMeteorology

Local-scale boundary-layer meteorology from Seinfeld & Pandis (2006) "Atmospheric Chemistry and Physics", 2nd ed., Chapter 16 "Meteorology of the Local Scale". A flat observed-only algebraic component that combines atmospheric static-stability analysis, Monin-Obukhov surface-layer similarity theory and Pasquill stability-class estimation: from the air temperature and pressure, the surface-layer geometry, the friction velocity u_star and the surface sensible heat flux q_z it computes the potential temperature θ (Eq. 16.14), the actual and potential-temperature lapse rates dT_dz and dθ_dz (Eqs. 16.16-16.18), the Monin-Obukhov length L and its inverse L_inv (Eq. 16.70), the stability parameter ζ = z/L, the Businger-Dyer stability functions φ_m, φ_h and their integrated forms ψ_m, ψ_h (Eqs. 16.75, 16.78-16.79), the stability-corrected mean wind speed ū (Eq. 16.66) and the Pasquill stability class (1=A to 6=F) via the Golder (1972) correlation (Eq. 16.83). Twelve purely-algebraic equations, no time integration. Migrated from AtmosphericDynamics.jl@816cc391 src/local_scale_meteorology.jl:234 (`LocalScaleMeteorology` @component).

Domain
atmospheric_dynamics
Subdomain
local_scale
Type
model
.esm schema
1.0.0
Source
components/atmospheric_dynamics/local_scale/local_scale_met.esm
Tags
#atmospheric_dynamics #local_scale #model #seinfeld-pandis #boundary-layer #monin-obukhov #potential-temperature #pasquill #observed-only #ch16

Description

Local-scale boundary-layer meteorology from Seinfeld & Pandis (2006) “Atmospheric Chemistry and Physics”, 2nd ed., Chapter 16 “Meteorology of the Local Scale”. A flat observed-only algebraic component that combines atmospheric static-stability analysis, Monin-Obukhov surface-layer similarity theory and Pasquill stability-class estimation: from the air temperature and pressure, the surface-layer geometry, the friction velocity u_star and the surface sensible heat flux q_z it computes the potential temperature θ (Eq. 16.14), the actual and potential-temperature lapse rates dT_dz and dθ_dz (Eqs. 16.16-16.18), the Monin-Obukhov length L and its inverse L_inv (Eq. 16.70), the stability parameter ζ = z/L, the Businger-Dyer stability functions φ_m, φ_h and their integrated forms ψ_m, ψ_h (Eqs. 16.75, 16.78-16.79), the stability-corrected mean wind speed ū (Eq. 16.66) and the Pasquill stability class (1=A to 6=F) via the Golder (1972) correlation (Eq. 16.83). Twelve purely-algebraic equations, no time integration. Migrated from AtmosphericDynamics.jl@816cc391 src/local_scale_meteorology.jl:234 (LocalScaleMeteorology @component).

Reference

_source_ref: AtmosphericDynamics.jl@816cc3918e1eef2c2ee6d8fa8dd73c8f13a85a47:src/local_scale_meteorology.jl:234

Upstream LocalScaleMeteorology is a ModelingToolkit @component that combines the atmospheric static-stability diagnostics of the sibling AtmosphericStability component and the Monin-Obukhov surface-layer similarity theory of SurfaceLayerProfile with a Pasquill stability-class estimate, all from Seinfeld & Pandis (2006) Ch. 16 (Meteorology of the Local Scale, pp. 720-760). It declares 18 referenced @constants, 10 @parameters, 12 @variables and 12 equations, returning System(eqs, t; name).

Flat single model – NOT a coupling.couple composition. docs/migration-tracker.md tags this row features: variables, parameters, coupling.couple with depends_on: AtmosphericStability, SurfaceLayerProfile, and the upstream docstring calls it a “composite system”. The upstream code, however, builds a plain System(eqs, t; name) with all 12 equations written inline (src/local_scale_meteorology.jl:308-374): it does NOT call System(...; systems=[...]) and constructs no subcomponents – it re-implements the AtmosphericStability and SurfaceLayerProfile physics directly. The migration therefore represents it as a single flat model with a 12-equation block, not as an ESS subsystem-composed model; the tracker depends_on entries record conceptual provenance (the sibling components whose physics is reused), not a structural dependency. The shared equations are byte-identical to the corresponding equations of the gate-verified sibling migrations stability.esm and surface_layer_profile.esm.

System kind: all 12 equations are explicit algebraic assignments (lhs ~ rhs) with no D(.) operator – every output is a closed-form expression of the inputs. system_kind is left unset (default ‘ode’); the compiled system has zero differential states, exactly as for the siblings stability.esm and surface_layer_profile.esm.

Variable classification. (1) T, T_below, p, z, z₀, Δz, T₀, ρ, u_star, q_z: upstream MTK @parameters – the external inputs – encoded type: parameter with their upstream defaults. (2) θ, dT_dz, dθ_dz, L, ζ, φ_m, φ_h, ψ_m, ψ_h, ū, L_inv, pasquill_class: upstream @variables, each the LHS of exactly one purely-algebraic equation – observed algebraic outputs with no time derivative and hence no initial condition – encoded type: state with no default. (3) g, κ, ĉ_p, R_air, p₀, Γ_d, ε_q, z₀_ref and the 10 Golder coefficients: upstream MTK @constants; the ESS schema has no constant variable type, so each is encoded type: parameter carrying its upstream value as default, exactly as in stability.esm and surface_layer_profile.esm.

Omitted constants a_D, b_D. Upstream declares 12 Golder (1972) coefficient @constants a_A, b_A, …, a_F, b_F (src lines 251-262). The pasquill_class equation (src lines 358-373) is a 5-level nested ifelse; its fourth branch – the class-D / neutral boundary – is compared against the class-E coefficients a_E + b_E*log10(z₀/z₀_ref) (src line 365), so a_D and b_D (both declared 0.0) appear in no equation. An unreferenced MTK @constant is not collected into the built System (the same reason g is omitted from stability.esm), so a_D and b_D are omitted here; the remaining 10 Golder coefficients are all referenced and retained. The upstream LocalScaleMeteorology structure testitem checks only length(equations(sys)) == 12 and a handful of named parameters, consistent with this.

κ_exp local. Upstream binds a plain Julia local κ_exp = R_air / ĉ_p (~ 0.286, the Poisson exponent R/c_p) and uses it as the exponent of the potential-temperature equation (Eq. 16.14). MTK inlines it when System(eqs, t) is built; the .esm mirrors this, writing equation 1’s exponent as the sub-expression R_air / ĉ_p.

Equation faithfulness. The 12 upstream equations (src lines 308-374) are preserved in upstream order: θ (Eq. 16.14), dT_dz (finite-difference actual lapse rate), dθ_dz (Eqs. 16.16-16.18), L (Eq. 16.70), L_inv = 1/L, ζ = z/L, φ_m and φ_h (Eq. 16.75 Businger-Dyer), ψ_m and ψ_h (Eqs. 16.78-16.79), ū (Eq. 16.66 with the Eq. 16.77 correction), and pasquill_class (Eq. 16.83 Golder correlation). The L, ζ, φ_m, φ_h, ψ_m, ψ_h and ū equation trees are copied verbatim from the sibling surface_layer_profile.esm, where mtk2esm reordered the commutative */+ operands of L, rewrote x^(-n) as 1/x^n in φ_m/φ_h, folded ((1-15ζ)^0.25)^2 to (1-15ζ)^0.5 in ψ_m/ψ_h, and folded the π/2 term of ψ_m to the float literal 1.5707963267948966. The θ, dT_dz and dθ_dz trees match the corresponding stability.esm equations.

Identifiers. Upstream Unicode identifiers are kept verbatim (θ, dθ_dz, Γ_d, p₀, Δz, ĉ_p, κ, ε_q, z₀, z₀_ref, T₀, ρ, ζ, φ_m, φ_h, ψ_m, ψ_h, ū), matching surface_layer_profile.esm. R_air is the dry-air specific gas constant in J/(kgK); it is named R_air rather than the schema-reserved bare name R, correct since it is dimensionally J/(kgK), not the universal gas constant in J/(mol*K).

Units are SI-coherent and carried verbatim from the upstream declarations; they are descriptive metadata (the ESS runners perform no dimensional analysis).

Tolerance rationale (model-level rel=1.0e-6). The system is a closed-form algebraic evaluation – no ODE integration, no implicit solve – so there is no integrator error to bound; rel=1.0e-6 covers float64 round-off and cross-runner libm differences in the ^/log/log10/atan chain, matching the siblings. Near-zero outputs in the neutral regime – ζ, L_inv, ψ_m, ψ_h ~ 1e-12..1e-14 at the default q_z = 0, where the ε_q heat-flux regularization makes |L| enormous – carry a per-assertion abs=1.0e-6; the exact-zero actual lapse rate dT_dz (T = T_below) carries abs=1.0e-12.

Test reproduction. The 10 inline tests reproduce every LocalScaleMeteorology scenario of test/local_scale_meteorology_test.jl plus the AtmosphericDynamics.jl docs “Complete Boundary Layer Analysis” example: defaults_baseline exercises all 12 outputs at the declared defaults (the upstream LocalScaleMeteorology structure testitem); potential_temp_850hPa and potential_temp_cold_low_pressure reproduce the Potential temperature and Physical constraints θ checks; pasquill_unstable_class_C and pasquill_stable_class_F reproduce the two Pasquill stability classification testitems (the upstream <= 3 / >= 4 assertions become the exact classes 3 and 6); physical_constraints_wind_class_D reproduces the Physical constraints ū > 0 check. The added scenarios light_wind_strong_heating_class_A, moderately_unstable_class_B and inversion_stable_class_E extend Pasquill coverage to classes 1, 2 and 5 (the suite spans the full A-F range) and exercise the inversion (dT_dz > 0) and stable-branch (ζ > 0) cases; summer_afternoon_boundary_layer reproduces the docs composite example. Expected values are the float64 results of the upstream formulas; the L/ζ/φ/ψ/ū values of the default and summer-afternoon scenarios agree with the corresponding surface_layer_profile.esm tests, as those equations are shared verbatim.

Examples. The 3 examples reproduce AtmosphericDynamics.jl docs figures (docs/src/local_scale_meteorology.md): potential_temperature_profile sweeps pressure p (the Potential Temperature Profile figure); monin_obukhov_length_vs_heat_flux sweeps the surface heat flux q_z over the unstable regime (the Monin-Obukhov Length vs Heat Flux figure); pasquill_class_vs_roughness_length sweeps the roughness length z₀ at a fixed unstable heat flux to trace the discrete Pasquill A-F classification against the Golder (1972) z₀ correlation (the Monin-Obukhov Length vs Roughness Length for Pasquill Stability Classes figure), the diagnostic distinctive to this composite component. All three example sweeps stay in the unstable / neutral regime (ζ <= 0); the example renderer eagerly evaluates both ifelse branches, and the Businger-Dyer unstable branch (1-15ζ)^(-1/4) is real-valued only for ζ <= 0._

Parameters

NameUnitsDefaultDescription
TK288.15Air temperature at height z
T_belowK288.15Air temperature at height z - Δz
pPa101325.0Pressure at height z
zm10.0Height above ground
z₀m0.1Roughness length (Table 16.1)
Δzm100.0Vertical spacing for gradient calculation
T₀K288.15Reference temperature (surface)
ρkg/m^31.225Air density
u_starm/s0.3Friction velocity
q_zW/m^20.0Surface sensible heat flux (positive upward)
gm/s^29.807Gravitational acceleration
κ10.4von Karman constant (dimensionless)
ĉ_pJ/(kg*K)1005.0Specific heat of air at constant pressure
R_airJ/(kg*K)287.0Gas constant for dry air
p₀Pa101325.0Reference pressure (sea level)
Γ_dK/m0.00976Dry adiabatic lapse rate (Eq. 16.8: g/c_p = 9.807/1005 ≈ 9.76 K/km)
ε_qW/m^21e-10Small regularization for heat flux
z₀_refm1.0Reference length for dimensionless log
a_Am^-1-0.096Golder (1972) coefficient a for Pasquill class A (Eq. 16.83: 1/L = a + b·log₁₀(z₀))
b_Am^-10.029Golder (1972) coefficient b for Pasquill class A (Eq. 16.83: 1/L = a + b·log₁₀(z₀))
a_Bm^-1-0.037Golder (1972) coefficient a for Pasquill class B (Eq. 16.83: 1/L = a + b·log₁₀(z₀))
b_Bm^-10.029Golder (1972) coefficient b for Pasquill class B (Eq. 16.83: 1/L = a + b·log₁₀(z₀))
a_Cm^-1-0.002Golder (1972) coefficient a for Pasquill class C (Eq. 16.83: 1/L = a + b·log₁₀(z₀))
b_Cm^-10.018Golder (1972) coefficient b for Pasquill class C (Eq. 16.83: 1/L = a + b·log₁₀(z₀))
a_Em^-10.004Golder (1972) coefficient a for Pasquill class E (Eq. 16.83: 1/L = a + b·log₁₀(z₀))
b_Em^-1-0.018Golder (1972) coefficient b for Pasquill class E (Eq. 16.83: 1/L = a + b·log₁₀(z₀))
a_Fm^-10.035Golder (1972) coefficient a for Pasquill class F (Eq. 16.83: 1/L = a + b·log₁₀(z₀))
b_Fm^-1-0.036Golder (1972) coefficient b for Pasquill class F (Eq. 16.83: 1/L = a + b·log₁₀(z₀))

Observed

NameUnitsDefaultDescription
θKPotential temperature (Eq. 16.14)
dT_dzK/mActual temperature lapse rate
dθ_dzK/mPotential temperature gradient
LmMonin-Obukhov length (Eq. 16.70)
ζ1Stability parameter z/L (dimensionless)
φ_m1Momentum stability function (Eq. 16.75) (dimensionless)
φ_h1Heat stability function (Eq. 16.75) (dimensionless)
ψ_m1Integrated momentum stability function (dimensionless)
ψ_h1Integrated heat stability function (dimensionless)
ūm/sMean wind speed at height z (Eq. 16.66)
L_invm^-1Inverse Monin-Obukhov length
pasquill_class1Pasquill stability class (1=A to 6=F) (dimensionless)

Observed expressions

$$ θ = T \cdot \frac{p₀}{p}^{\frac{R_{air}}{ĉ_{p}}} $$

Potential temperature (Eq. 16.14)

$$ dT_{dz} = \frac{T - T_{below}}{Δz} $$

Actual temperature lapse rate

$$ dθ_{dz} = dT_{dz} + Γ_{d} $$

Potential temperature gradient

$$ L = \frac{\left(-1\right) \cdot ĉ_{p} \cdot ρ \cdot u_{star}^{3} \cdot T₀}{κ \cdot g \cdot \left(q_{z} + ε_{q}\right)} $$

Monin-Obukhov length (Eq. 16.70)

$$ ζ = \frac{z}{L} $$

Stability parameter z/L (dimensionless)

$$ φ_{m} = \mathrm{ifelse}\left(\mathrm{<}\left(ζ, 0\right), \frac{1}{\left(1 + \left(-15\right) \cdot ζ\right)^{0.25}}, 1 + 4.7 \cdot ζ\right) $$

Momentum stability function (Eq. 16.75) (dimensionless)

$$ φ_{h} = \mathrm{ifelse}\left(\mathrm{<}\left(ζ, 0\right), \frac{1}{\left(1 + \left(-15\right) \cdot ζ\right)^{0.5}}, 1 + 4.7 \cdot ζ\right) $$

Heat stability function (Eq. 16.75) (dimensionless)

$$ ψ_{m} = \mathrm{ifelse}\left(\mathrm{<}\left(ζ, 0\right), 1.5707963267948966 + \left(-2\right) \cdot \mathrm{atan}\left(\left(1 + \left(-15\right) \cdot ζ\right)^{0.25}\right) + 2 \cdot \ln\left(\frac{1 + \left(1 + \left(-15\right) \cdot ζ\right)^{0.25}}{2}\right) + \ln\left(\frac{1 + \left(1 + \left(-15\right) \cdot ζ\right)^{0.5}}{2}\right), \left(-4.7\right) \cdot ζ\right) $$

Integrated momentum stability function (dimensionless)

$$ ψ_{h} = \mathrm{ifelse}\left(\mathrm{<}\left(ζ, 0\right), 2 \cdot \ln\left(\frac{1 + \left(1 + \left(-15\right) \cdot ζ\right)^{0.5}}{2}\right), \left(-4.7\right) \cdot ζ\right) $$

Integrated heat stability function (dimensionless)

$$ ū = \frac{\left(\left(-1\right) \cdot ψ_{m} + \ln\left(\frac{z}{z₀}\right)\right) \cdot u_{star}}{κ} $$

Mean wind speed at height z (Eq. 16.66)

$$ L_{inv} = \frac{1}{L} $$

Inverse Monin-Obukhov length

$$ pasquill_{class} = \mathrm{ifelse}\left(\mathrm{<}\left(L_{inv}, a_{A} + b_{A} \cdot \log_{10}\left(\frac{z₀}{z₀_{ref}}\right)\right), 1, \mathrm{ifelse}\left(\mathrm{<}\left(L_{inv}, a_{B} + b_{B} \cdot \log_{10}\left(\frac{z₀}{z₀_{ref}}\right)\right), 2, \mathrm{ifelse}\left(\mathrm{<}\left(L_{inv}, a_{C} + b_{C} \cdot \log_{10}\left(\frac{z₀}{z₀_{ref}}\right)\right), 3, \mathrm{ifelse}\left(\mathrm{<}\left(L_{inv}, a_{E} + b_{E} \cdot \log_{10}\left(\frac{z₀}{z₀_{ref}}\right)\right), 4, \mathrm{ifelse}\left(\mathrm{<}\left(L_{inv}, a_{F} + b_{F} \cdot \log_{10}\left(\frac{z₀}{z₀_{ref}}\right)\right), 5, 6\right)\right)\right)\right)\right) $$

Pasquill stability class (1=A to 6=F) (dimensionless)

Analyses

potential_temperature_profile

Potential temperature θ = T·(p₀/p)^(R_air/ĉ_p) (Eq. 16.14) swept over pressure p from 50000 to 101325 Pa at the default temperature T = 288.15 K. Reproduces the AtmosphericDynamics.jl docs Potential Temperature Profile figure — at fixed temperature θ rises as pressure falls, equalling the actual temperature at the sea-level reference pressure p₀ and exceeding it aloft where the (p₀/p) adiabatic-compression factor is greater than one.

Time span: 0.0 → 1.0

Swept over: p

Potential temperature θ as a function of pressure p (Eq. 16.14).

monin_obukhov_length_vs_heat_flux

Monin-Obukhov length L (Eq. 16.70) as a function of the surface sensible heat flux q_z over the unstable regime (q_z > 0, surface heating), at the default u_star = 0.3 m/s. Reproduces the unstable branch of the AtmosphericDynamics.jl docs Monin-Obukhov Length vs Heat Flux figure: L is negative and grows toward 0 as the heat flux increases.

Time span: 0.0 → 1.0

Swept over: q_z

Monin-Obukhov length L vs surface heat flux q_z (Eq. 16.70).

pasquill_class_vs_roughness_length

Pasquill stability class (1=A to 6=F) as a function of the surface roughness length z₀, swept from 0.001 to 2 m (Table 16.1, snow through low-density residential terrain) at a fixed moderately unstable surface heat flux q_z = 120 W/m^2 and the default u_star = 0.3 m/s. The Monin-Obukhov length L (and hence L_inv) is independent of z₀, so this example isolates the z₀ dependence of the Golder (1972) correlation (Eq. 16.83, 1/L = a + b·log₁₀(z₀)): as the surface roughens the class boundaries shift and the diagnosed Pasquill class steps between the unstable categories. Reproduces the AtmosphericDynamics.jl docs Monin-Obukhov Length vs Roughness Length for Pasquill Stability Classes figure.

Time span: 0.0 → 1.0

Swept over: z₀

Pasquill stability class as a function of the surface roughness length z₀ (Eq. 16.83, Golder correlation).

Raw .esm

Raw .esm JSON (this component)
{
  "reference": {
    "notes": "source_ref: AtmosphericDynamics.jl@816cc3918e1eef2c2ee6d8fa8dd73c8f13a85a47:src/local_scale_meteorology.jl:234\n\nUpstream `LocalScaleMeteorology` is a ModelingToolkit `@component` that combines the atmospheric static-stability diagnostics of the sibling `AtmosphericStability` component and the Monin-Obukhov surface-layer similarity theory of `SurfaceLayerProfile` with a Pasquill stability-class estimate, all from Seinfeld & Pandis (2006) Ch. 16 (Meteorology of the Local Scale, pp. 720-760). It declares 18 referenced `@constants`, 10 `@parameters`, 12 `@variables` and 12 equations, returning `System(eqs, t; name)`.\n\nFlat single model -- NOT a coupling.couple composition. docs/migration-tracker.md tags this row `features: variables, parameters, coupling.couple` with `depends_on: AtmosphericStability, SurfaceLayerProfile`, and the upstream docstring calls it a \"composite system\". The upstream code, however, builds a plain `System(eqs, t; name)` with all 12 equations written inline (src/local_scale_meteorology.jl:308-374): it does NOT call `System(...; systems=[...])` and constructs no subcomponents -- it re-implements the AtmosphericStability and SurfaceLayerProfile physics directly. The migration therefore represents it as a single flat model with a 12-equation block, not as an ESS subsystem-composed model; the tracker `depends_on` entries record conceptual provenance (the sibling components whose physics is reused), not a structural dependency. The shared equations are byte-identical to the corresponding equations of the gate-verified sibling migrations stability.esm and surface_layer_profile.esm.\n\nSystem kind: all 12 equations are explicit algebraic assignments (lhs ~ rhs) with no `D(.)` operator -- every output is a closed-form expression of the inputs. `system_kind` is left unset (default 'ode'); the compiled system has zero differential states, exactly as for the siblings stability.esm and surface_layer_profile.esm.\n\nVariable classification. (1) T, T_below, p, z, z₀, Δz, T₀, ρ, u_star, q_z: upstream MTK `@parameters` -- the external inputs -- encoded type: parameter with their upstream defaults. (2) θ, dT_dz, dθ_dz, L, ζ, φ_m, φ_h, ψ_m, ψ_h, ū, L_inv, pasquill_class: upstream `@variables`, each the LHS of exactly one purely-algebraic equation -- observed algebraic outputs with no time derivative and hence no initial condition -- encoded type: state with no default. (3) g, κ, ĉ_p, R_air, p₀, Γ_d, ε_q, z₀_ref and the 10 Golder coefficients: upstream MTK `@constants`; the ESS schema has no `constant` variable type, so each is encoded type: parameter carrying its upstream value as default, exactly as in stability.esm and surface_layer_profile.esm.\n\nOmitted constants a_D, b_D. Upstream declares 12 Golder (1972) coefficient `@constants` a_A, b_A, ..., a_F, b_F (src lines 251-262). The pasquill_class equation (src lines 358-373) is a 5-level nested `ifelse`; its fourth branch -- the class-D / neutral boundary -- is compared against the class-E coefficients a_E + b_E*log10(z₀/z₀_ref) (src line 365), so a_D and b_D (both declared 0.0) appear in no equation. An unreferenced MTK `@constant` is not collected into the built `System` (the same reason g is omitted from stability.esm), so a_D and b_D are omitted here; the remaining 10 Golder coefficients are all referenced and retained. The upstream `LocalScaleMeteorology structure` testitem checks only `length(equations(sys)) == 12` and a handful of named parameters, consistent with this.\n\nκ_exp local. Upstream binds a plain Julia local `κ_exp = R_air / ĉ_p` (~ 0.286, the Poisson exponent R/c_p) and uses it as the exponent of the potential-temperature equation (Eq. 16.14). MTK inlines it when `System(eqs, t)` is built; the .esm mirrors this, writing equation 1's exponent as the sub-expression R_air / ĉ_p.\n\nEquation faithfulness. The 12 upstream equations (src lines 308-374) are preserved in upstream order: θ (Eq. 16.14), dT_dz (finite-difference actual lapse rate), dθ_dz (Eqs. 16.16-16.18), L (Eq. 16.70), L_inv = 1/L, ζ = z/L, φ_m and φ_h (Eq. 16.75 Businger-Dyer), ψ_m and ψ_h (Eqs. 16.78-16.79), ū (Eq. 16.66 with the Eq. 16.77 correction), and pasquill_class (Eq. 16.83 Golder correlation). The L, ζ, φ_m, φ_h, ψ_m, ψ_h and ū equation trees are copied verbatim from the sibling surface_layer_profile.esm, where `mtk2esm` reordered the commutative */+ operands of L, rewrote x^(-n) as 1/x^n in φ_m/φ_h, folded ((1-15ζ)^0.25)^2 to (1-15ζ)^0.5 in ψ_m/ψ_h, and folded the π/2 term of ψ_m to the float literal 1.5707963267948966. The θ, dT_dz and dθ_dz trees match the corresponding stability.esm equations.\n\nIdentifiers. Upstream Unicode identifiers are kept verbatim (θ, dθ_dz, Γ_d, p₀, Δz, ĉ_p, κ, ε_q, z₀, z₀_ref, T₀, ρ, ζ, φ_m, φ_h, ψ_m, ψ_h, ū), matching surface_layer_profile.esm. R_air is the dry-air specific gas constant in J/(kg*K); it is named R_air rather than the schema-reserved bare name R, correct since it is dimensionally J/(kg*K), not the universal gas constant in J/(mol*K).\n\nUnits are SI-coherent and carried verbatim from the upstream declarations; they are descriptive metadata (the ESS runners perform no dimensional analysis).\n\nTolerance rationale (model-level rel=1.0e-6). The system is a closed-form algebraic evaluation -- no ODE integration, no implicit solve -- so there is no integrator error to bound; rel=1.0e-6 covers float64 round-off and cross-runner libm differences in the ^/log/log10/atan chain, matching the siblings. Near-zero outputs in the neutral regime -- ζ, L_inv, ψ_m, ψ_h ~ 1e-12..1e-14 at the default q_z = 0, where the ε_q heat-flux regularization makes |L| enormous -- carry a per-assertion abs=1.0e-6; the exact-zero actual lapse rate dT_dz (T = T_below) carries abs=1.0e-12.\n\nTest reproduction. The 10 inline tests reproduce every LocalScaleMeteorology scenario of test/local_scale_meteorology_test.jl plus the AtmosphericDynamics.jl docs \"Complete Boundary Layer Analysis\" example: `defaults_baseline` exercises all 12 outputs at the declared defaults (the upstream `LocalScaleMeteorology structure` testitem); `potential_temp_850hPa` and `potential_temp_cold_low_pressure` reproduce the `Potential temperature` and `Physical constraints` θ checks; `pasquill_unstable_class_C` and `pasquill_stable_class_F` reproduce the two `Pasquill stability classification` testitems (the upstream <= 3 / >= 4 assertions become the exact classes 3 and 6); `physical_constraints_wind_class_D` reproduces the `Physical constraints` ū > 0 check. The added scenarios `light_wind_strong_heating_class_A`, `moderately_unstable_class_B` and `inversion_stable_class_E` extend Pasquill coverage to classes 1, 2 and 5 (the suite spans the full A-F range) and exercise the inversion (dT_dz > 0) and stable-branch (ζ > 0) cases; `summer_afternoon_boundary_layer` reproduces the docs composite example. Expected values are the float64 results of the upstream formulas; the L/ζ/φ/ψ/ū values of the default and summer-afternoon scenarios agree with the corresponding surface_layer_profile.esm tests, as those equations are shared verbatim.\n\nExamples. The 3 examples reproduce AtmosphericDynamics.jl docs figures (docs/src/local_scale_meteorology.md): `potential_temperature_profile` sweeps pressure p (the `Potential Temperature Profile` figure); `monin_obukhov_length_vs_heat_flux` sweeps the surface heat flux q_z over the unstable regime (the `Monin-Obukhov Length vs Heat Flux` figure); `pasquill_class_vs_roughness_length` sweeps the roughness length z₀ at a fixed unstable heat flux to trace the discrete Pasquill A-F classification against the Golder (1972) z₀ correlation (the `Monin-Obukhov Length vs Roughness Length for Pasquill Stability Classes` figure), the diagnostic distinctive to this composite component. All three example sweeps stay in the unstable / neutral regime (ζ <= 0); the example renderer eagerly evaluates both `ifelse` branches, and the Businger-Dyer unstable branch (1-15ζ)^(-1/4) is real-valued only for ζ <= 0."
  },
  "tolerance": {
    "rel": 1e-06
  },
  "variables": {
    "T": {
      "type": "parameter",
      "units": "K",
      "default": 288.15,
      "description": "Air temperature at height z"
    },
    "T_below": {
      "type": "parameter",
      "units": "K",
      "default": 288.15,
      "description": "Air temperature at height z - Δz"
    },
    "p": {
      "type": "parameter",
      "units": "Pa",
      "default": 101325.0,
      "description": "Pressure at height z"
    },
    "z": {
      "type": "parameter",
      "units": "m",
      "default": 10.0,
      "description": "Height above ground"
    },
    "z₀": {
      "type": "parameter",
      "units": "m",
      "default": 0.1,
      "description": "Roughness length (Table 16.1)"
    },
    "Δz": {
      "type": "parameter",
      "units": "m",
      "default": 100.0,
      "description": "Vertical spacing for gradient calculation"
    },
    "T₀": {
      "type": "parameter",
      "units": "K",
      "default": 288.15,
      "description": "Reference temperature (surface)"
    },
    "ρ": {
      "type": "parameter",
      "units": "kg/m^3",
      "default": 1.225,
      "description": "Air density"
    },
    "u_star": {
      "type": "parameter",
      "units": "m/s",
      "default": 0.3,
      "description": "Friction velocity"
    },
    "q_z": {
      "type": "parameter",
      "units": "W/m^2",
      "default": 0.0,
      "description": "Surface sensible heat flux (positive upward)"
    },
    "g": {
      "type": "parameter",
      "units": "m/s^2",
      "default": 9.807,
      "description": "Gravitational acceleration"
    },
    "κ": {
      "type": "parameter",
      "units": "1",
      "default": 0.4,
      "description": "von Karman constant (dimensionless)"
    },
    "ĉ_p": {
      "type": "parameter",
      "units": "J/(kg*K)",
      "default": 1005.0,
      "description": "Specific heat of air at constant pressure"
    },
    "R_air": {
      "type": "parameter",
      "units": "J/(kg*K)",
      "default": 287.0,
      "description": "Gas constant for dry air"
    },
    "p₀": {
      "type": "parameter",
      "units": "Pa",
      "default": 101325.0,
      "description": "Reference pressure (sea level)"
    },
    "Γ_d": {
      "type": "parameter",
      "units": "K/m",
      "default": 0.00976,
      "description": "Dry adiabatic lapse rate (Eq. 16.8: g/c_p = 9.807/1005 ≈ 9.76 K/km)"
    },
    "ε_q": {
      "type": "parameter",
      "units": "W/m^2",
      "default": 1e-10,
      "description": "Small regularization for heat flux"
    },
    "z₀_ref": {
      "type": "parameter",
      "units": "m",
      "default": 1.0,
      "description": "Reference length for dimensionless log"
    },
    "a_A": {
      "type": "parameter",
      "units": "m^-1",
      "default": -0.096,
      "description": "Golder (1972) coefficient a for Pasquill class A (Eq. 16.83: 1/L = a + b·log₁₀(z₀))"
    },
    "b_A": {
      "type": "parameter",
      "units": "m^-1",
      "default": 0.029,
      "description": "Golder (1972) coefficient b for Pasquill class A (Eq. 16.83: 1/L = a + b·log₁₀(z₀))"
    },
    "a_B": {
      "type": "parameter",
      "units": "m^-1",
      "default": -0.037,
      "description": "Golder (1972) coefficient a for Pasquill class B (Eq. 16.83: 1/L = a + b·log₁₀(z₀))"
    },
    "b_B": {
      "type": "parameter",
      "units": "m^-1",
      "default": 0.029,
      "description": "Golder (1972) coefficient b for Pasquill class B (Eq. 16.83: 1/L = a + b·log₁₀(z₀))"
    },
    "a_C": {
      "type": "parameter",
      "units": "m^-1",
      "default": -0.002,
      "description": "Golder (1972) coefficient a for Pasquill class C (Eq. 16.83: 1/L = a + b·log₁₀(z₀))"
    },
    "b_C": {
      "type": "parameter",
      "units": "m^-1",
      "default": 0.018,
      "description": "Golder (1972) coefficient b for Pasquill class C (Eq. 16.83: 1/L = a + b·log₁₀(z₀))"
    },
    "a_E": {
      "type": "parameter",
      "units": "m^-1",
      "default": 0.004,
      "description": "Golder (1972) coefficient a for Pasquill class E (Eq. 16.83: 1/L = a + b·log₁₀(z₀))"
    },
    "b_E": {
      "type": "parameter",
      "units": "m^-1",
      "default": -0.018,
      "description": "Golder (1972) coefficient b for Pasquill class E (Eq. 16.83: 1/L = a + b·log₁₀(z₀))"
    },
    "a_F": {
      "type": "parameter",
      "units": "m^-1",
      "default": 0.035,
      "description": "Golder (1972) coefficient a for Pasquill class F (Eq. 16.83: 1/L = a + b·log₁₀(z₀))"
    },
    "b_F": {
      "type": "parameter",
      "units": "m^-1",
      "default": -0.036,
      "description": "Golder (1972) coefficient b for Pasquill class F (Eq. 16.83: 1/L = a + b·log₁₀(z₀))"
    },
    "θ": {
      "type": "unknown",
      "units": "K",
      "description": "Potential temperature (Eq. 16.14)"
    },
    "dT_dz": {
      "type": "unknown",
      "units": "K/m",
      "description": "Actual temperature lapse rate"
    },
    "dθ_dz": {
      "type": "unknown",
      "units": "K/m",
      "description": "Potential temperature gradient"
    },
    "L": {
      "type": "unknown",
      "units": "m",
      "description": "Monin-Obukhov length (Eq. 16.70)"
    },
    "ζ": {
      "type": "unknown",
      "units": "1",
      "description": "Stability parameter z/L (dimensionless)"
    },
    "φ_m": {
      "type": "unknown",
      "units": "1",
      "description": "Momentum stability function (Eq. 16.75) (dimensionless)"
    },
    "φ_h": {
      "type": "unknown",
      "units": "1",
      "description": "Heat stability function (Eq. 16.75) (dimensionless)"
    },
    "ψ_m": {
      "type": "unknown",
      "units": "1",
      "description": "Integrated momentum stability function (dimensionless)"
    },
    "ψ_h": {
      "type": "unknown",
      "units": "1",
      "description": "Integrated heat stability function (dimensionless)"
    },
    "ū": {
      "type": "unknown",
      "units": "m/s",
      "description": "Mean wind speed at height z (Eq. 16.66)"
    },
    "L_inv": {
      "type": "unknown",
      "units": "m^-1",
      "description": "Inverse Monin-Obukhov length"
    },
    "pasquill_class": {
      "type": "unknown",
      "units": "1",
      "description": "Pasquill stability class (1=A to 6=F) (dimensionless)"
    }
  },
  "equations": [
    {
      "lhs": "θ",
      "rhs": {
        "op": "*",
        "args": [
          "T",
          {
            "op": "^",
            "args": [
              {
                "op": "/",
                "args": [
                  "p₀",
                  "p"
                ]
              },
              {
                "op": "/",
                "args": [
                  "R_air",
                  "ĉ_p"
                ]
              }
            ]
          }
        ]
      }
    },
    {
      "lhs": "dT_dz",
      "rhs": {
        "op": "/",
        "args": [
          {
            "op": "-",
            "args": [
              "T",
              "T_below"
            ]
          },
          "Δz"
        ]
      }
    },
    {
      "lhs": "dθ_dz",
      "rhs": {
        "op": "+",
        "args": [
          "dT_dz",
          "Γ_d"
        ]
      }
    },
    {
      "lhs": "L",
      "rhs": {
        "op": "/",
        "args": [
          {
            "op": "*",
            "args": [
              -1,
              "ĉ_p",
              "ρ",
              {
                "op": "^",
                "args": [
                  "u_star",
                  3
                ]
              },
              "T₀"
            ]
          },
          {
            "op": "*",
            "args": [
              "κ",
              "g",
              {
                "op": "+",
                "args": [
                  "q_z",
                  "ε_q"
                ]
              }
            ]
          }
        ]
      }
    },
    {
      "lhs": "L_inv",
      "rhs": {
        "op": "/",
        "args": [
          1,
          "L"
        ]
      }
    },
    {
      "lhs": "ζ",
      "rhs": {
        "op": "/",
        "args": [
          "z",
          "L"
        ]
      }
    },
    {
      "lhs": "φ_m",
      "rhs": {
        "op": "ifelse",
        "args": [
          {
            "op": "<",
            "args": [
              "ζ",
              0
            ]
          },
          {
            "op": "/",
            "args": [
              1,
              {
                "op": "^",
                "args": [
                  {
                    "op": "+",
                    "args": [
                      1,
                      {
                        "op": "*",
                        "args": [
                          -15,
                          "ζ"
                        ]
                      }
                    ]
                  },
                  0.25
                ]
              }
            ]
          },
          {
            "op": "+",
            "args": [
              1,
              {
                "op": "*",
                "args": [
                  4.7,
                  "ζ"
                ]
              }
            ]
          }
        ]
      }
    },
    {
      "lhs": "φ_h",
      "rhs": {
        "op": "ifelse",
        "args": [
          {
            "op": "<",
            "args": [
              "ζ",
              0
            ]
          },
          {
            "op": "/",
            "args": [
              1,
              {
                "op": "^",
                "args": [
                  {
                    "op": "+",
                    "args": [
                      1,
                      {
                        "op": "*",
                        "args": [
                          -15,
                          "ζ"
                        ]
                      }
                    ]
                  },
                  0.5
                ]
              }
            ]
          },
          {
            "op": "+",
            "args": [
              1,
              {
                "op": "*",
                "args": [
                  4.7,
                  "ζ"
                ]
              }
            ]
          }
        ]
      }
    },
    {
      "lhs": "ψ_m",
      "rhs": {
        "op": "ifelse",
        "args": [
          {
            "op": "<",
            "args": [
              "ζ",
              0
            ]
          },
          {
            "op": "+",
            "args": [
              1.5707963267948966,
              {
                "op": "*",
                "args": [
                  -2,
                  {
                    "op": "atan",
                    "args": [
                      {
                        "op": "^",
                        "args": [
                          {
                            "op": "+",
                            "args": [
                              1,
                              {
                                "op": "*",
                                "args": [
                                  -15,
                                  "ζ"
                                ]
                              }
                            ]
                          },
                          0.25
                        ]
                      }
                    ]
                  }
                ]
              },
              {
                "op": "*",
                "args": [
                  2,
                  {
                    "op": "log",
                    "args": [
                      {
                        "op": "/",
                        "args": [
                          {
                            "op": "+",
                            "args": [
                              1,
                              {
                                "op": "^",
                                "args": [
                                  {
                                    "op": "+",
                                    "args": [
                                      1,
                                      {
                                        "op": "*",
                                        "args": [
                                          -15,
                                          "ζ"
                                        ]
                                      }
                                    ]
                                  },
                                  0.25
                                ]
                              }
                            ]
                          },
                          2
                        ]
                      }
                    ]
                  }
                ]
              },
              {
                "op": "log",
                "args": [
                  {
                    "op": "/",
                    "args": [
                      {
                        "op": "+",
                        "args": [
                          1,
                          {
                            "op": "^",
                            "args": [
                              {
                                "op": "+",
                                "args": [
                                  1,
                                  {
                                    "op": "*",
                                    "args": [
                                      -15,
                                      "ζ"
                                    ]
                                  }
                                ]
                              },
                              0.5
                            ]
                          }
                        ]
                      },
                      2
                    ]
                  }
                ]
              }
            ]
          },
          {
            "op": "*",
            "args": [
              -4.7,
              "ζ"
            ]
          }
        ]
      }
    },
    {
      "lhs": "ψ_h",
      "rhs": {
        "op": "ifelse",
        "args": [
          {
            "op": "<",
            "args": [
              "ζ",
              0
            ]
          },
          {
            "op": "*",
            "args": [
              2,
              {
                "op": "log",
                "args": [
                  {
                    "op": "/",
                    "args": [
                      {
                        "op": "+",
                        "args": [
                          1,
                          {
                            "op": "^",
                            "args": [
                              {
                                "op": "+",
                                "args": [
                                  1,
                                  {
                                    "op": "*",
                                    "args": [
                                      -15,
                                      "ζ"
                                    ]
                                  }
                                ]
                              },
                              0.5
                            ]
                          }
                        ]
                      },
                      2
                    ]
                  }
                ]
              }
            ]
          },
          {
            "op": "*",
            "args": [
              -4.7,
              "ζ"
            ]
          }
        ]
      }
    },
    {
      "lhs": "ū",
      "rhs": {
        "op": "/",
        "args": [
          {
            "op": "*",
            "args": [
              {
                "op": "+",
                "args": [
                  {
                    "op": "*",
                    "args": [
                      -1,
                      "ψ_m"
                    ]
                  },
                  {
                    "op": "log",
                    "args": [
                      {
                        "op": "/",
                        "args": [
                          "z",
                          "z₀"
                        ]
                      }
                    ]
                  }
                ]
              },
              "u_star"
            ]
          },
          "κ"
        ]
      }
    },
    {
      "lhs": "pasquill_class",
      "rhs": {
        "op": "ifelse",
        "args": [
          {
            "op": "<",
            "args": [
              "L_inv",
              {
                "op": "+",
                "args": [
                  "a_A",
                  {
                    "op": "*",
                    "args": [
                      "b_A",
                      {
                        "op": "log10",
                        "args": [
                          {
                            "op": "/",
                            "args": [
                              "z₀",
                              "z₀_ref"
                            ]
                          }
                        ]
                      }
                    ]
                  }
                ]
              }
            ]
          },
          1,
          {
            "op": "ifelse",
            "args": [
              {
                "op": "<",
                "args": [
                  "L_inv",
                  {
                    "op": "+",
                    "args": [
                      "a_B",
                      {
                        "op": "*",
                        "args": [
                          "b_B",
                          {
                            "op": "log10",
                            "args": [
                              {
                                "op": "/",
                                "args": [
                                  "z₀",
                                  "z₀_ref"
                                ]
                              }
                            ]
                          }
                        ]
                      }
                    ]
                  }
                ]
              },
              2,
              {
                "op": "ifelse",
                "args": [
                  {
                    "op": "<",
                    "args": [
                      "L_inv",
                      {
                        "op": "+",
                        "args": [
                          "a_C",
                          {
                            "op": "*",
                            "args": [
                              "b_C",
                              {
                                "op": "log10",
                                "args": [
                                  {
                                    "op": "/",
                                    "args": [
                                      "z₀",
                                      "z₀_ref"
                                    ]
                                  }
                                ]
                              }
                            ]
                          }
                        ]
                      }
                    ]
                  },
                  3,
                  {
                    "op": "ifelse",
                    "args": [
                      {
                        "op": "<",
                        "args": [
                          "L_inv",
                          {
                            "op": "+",
                            "args": [
                              "a_E",
                              {
                                "op": "*",
                                "args": [
                                  "b_E",
                                  {
                                    "op": "log10",
                                    "args": [
                                      {
                                        "op": "/",
                                        "args": [
                                          "z₀",
                                          "z₀_ref"
                                        ]
                                      }
                                    ]
                                  }
                                ]
                              }
                            ]
                          }
                        ]
                      },
                      4,
                      {
                        "op": "ifelse",
                        "args": [
                          {
                            "op": "<",
                            "args": [
                              "L_inv",
                              {
                                "op": "+",
                                "args": [
                                  "a_F",
                                  {
                                    "op": "*",
                                    "args": [
                                      "b_F",
                                      {
                                        "op": "log10",
                                        "args": [
                                          {
                                            "op": "/",
                                            "args": [
                                              "z₀",
                                              "z₀_ref"
                                            ]
                                          }
                                        ]
                                      }
                                    ]
                                  }
                                ]
                              }
                            ]
                          },
                          5,
                          6
                        ]
                      }
                    ]
                  }
                ]
              }
            ]
          }
        ]
      }
    }
  ],
  "tests": [
    {
      "id": "defaults_baseline",
      "description": "Baseline run at the declared defaults (T = T_below = 288.15 K, p = 101325 Pa, z = 10 m, z₀ = 0.1 m, Δz = 100 m, T₀ = 288.15 K, ρ = 1.225 kg/m^3, u_star = 0.3 m/s, q_z = 0). Pins all 12 outputs at once, reproducing the upstream `LocalScaleMeteorology structure` testitem. At sea level (p = p₀) θ = T = 288.15 K; with T = T_below the actual lapse rate dT_dz is exactly zero and dθ_dz collapses to the dry adiabatic lapse rate Γ_d = 9.76e-3 K/m. With q_z = 0 the ε_q heat-flux regularization makes |L| enormous, so the surface layer is effectively neutral: ζ ≈ 0, φ_m = φ_h → 1, ψ_m = ψ_h → 0, ū reduces to the pure logarithmic profile, and the near-zero L_inv places the atmosphere in Pasquill class D (4, neutral).",
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "θ",
          "time": 0.0,
          "expected": 288.15
        },
        {
          "variable": "dT_dz",
          "time": 0.0,
          "expected": 0.0,
          "tolerance": {
            "abs": 1e-12
          }
        },
        {
          "variable": "dθ_dz",
          "time": 0.0,
          "expected": 0.00976
        },
        {
          "variable": "L",
          "time": 0.0,
          "expected": -24416778974839.39
        },
        {
          "variable": "L_inv",
          "time": 0.0,
          "expected": -4.095544301852689e-14,
          "tolerance": {
            "abs": 1e-06
          }
        },
        {
          "variable": "ζ",
          "time": 0.0,
          "expected": -4.0955443018526885e-13,
          "tolerance": {
            "abs": 1e-06
          }
        },
        {
          "variable": "φ_m",
          "time": 0.0,
          "expected": 0.9999999999984641
        },
        {
          "variable": "φ_h",
          "time": 0.0,
          "expected": 0.9999999999969285
        },
        {
          "variable": "ψ_m",
          "time": 0.0,
          "expected": 1.5354384430548228e-12,
          "tolerance": {
            "abs": 1e-06
          }
        },
        {
          "variable": "ψ_h",
          "time": 0.0,
          "expected": 3.0713209753206747e-12,
          "tolerance": {
            "abs": 1e-06
          }
        },
        {
          "variable": "ū",
          "time": 0.0,
          "expected": 3.4538776394899164
        },
        {
          "variable": "pasquill_class",
          "time": 0.0,
          "expected": 4
        }
      ]
    },
    {
      "id": "potential_temp_850hPa",
      "description": "Potential temperature at the 850 hPa level (p = 85000 Pa, T = 280 K): θ = 280·(101325/85000)^(287/1005) ≈ 294.4 K. Because p < p₀ the (p₀/p) adiabatic-compression factor exceeds 1, so θ > T. Reproduces the lower-pressure assertion of the upstream `Potential temperature` testitem; θ matches the sibling stability.esm potential_temp_850hPa test (shared Eq. 16.14).",
      "parameter_overrides": {
        "T": 280.0,
        "p": 85000.0
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "θ",
          "time": 0.0,
          "expected": 294.40591070177146
        }
      ]
    },
    {
      "id": "potential_temp_cold_low_pressure",
      "description": "Potential temperature for cold air at low pressure (T = 200 K, p = 50000 Pa): θ = 200·(101325/50000)^(287/1005) ≈ 244.7 K, which stays strictly positive. Reproduces the upstream `Physical constraints` testitem assertion that the potential temperature is always positive.",
      "parameter_overrides": {
        "T": 200.0,
        "p": 50000.0
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "θ",
          "time": 0.0,
          "expected": 244.6967948244097
        }
      ]
    },
    {
      "id": "light_wind_strong_heating_class_A",
      "description": "Light winds with strong surface heating (u_star = 0.2 m/s, q_z = 110 W/m^2) — the very-unstable regime. The small friction velocity and large upward heat flux give a small-magnitude negative Monin-Obukhov length L ≈ -6.6 m, so L_inv ≈ -0.152 m^-1 falls below the Golder class-A threshold and the Pasquill class is 1 (A, very unstable). Covers the most-unstable end of the classification.",
      "parameter_overrides": {
        "u_star": 0.2,
        "q_z": 110.0
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "L",
          "time": 0.0,
          "expected": -6.576910161566923
        },
        {
          "variable": "L_inv",
          "time": 0.0,
          "expected": -0.15204708220641924
        },
        {
          "variable": "ζ",
          "time": 0.0,
          "expected": -1.5204708220641923
        },
        {
          "variable": "ū",
          "time": 0.0,
          "expected": 1.6509524855067808
        },
        {
          "variable": "pasquill_class",
          "time": 0.0,
          "expected": 1
        }
      ]
    },
    {
      "id": "moderately_unstable_class_B",
      "description": "Moderately unstable surface layer (u_star = 0.3 m/s, q_z = 240 W/m^2): L ≈ -10.2 m, L_inv ≈ -0.098 m^-1, which lands between the Golder class-A and class-B thresholds, giving Pasquill class 2 (B, moderately unstable).",
      "parameter_overrides": {
        "u_star": 0.3,
        "q_z": 240.0
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "L",
          "time": 0.0,
          "expected": -10.17365790617884
        },
        {
          "variable": "L_inv",
          "time": 0.0,
          "expected": -0.09829306324450549
        },
        {
          "variable": "ū",
          "time": 0.0,
          "expected": 2.6475309942972105
        },
        {
          "variable": "pasquill_class",
          "time": 0.0,
          "expected": 2
        }
      ]
    },
    {
      "id": "pasquill_unstable_class_C",
      "description": "Unstable surface layer — reproduces the first `Pasquill stability classification` testitem (u_star = 0.5 m/s, q_z = 300 W/m^2, z₀ = 0.1 m, T₀ = 300 K, ρ = 1.225 kg/m^3). The Monin-Obukhov length L ≈ -39.2 m is negative (the upstream `L < 0` assertion) and the Pasquill class is 3 (C, slightly unstable) — the upstream test asserts `pasquill_class ≤ 3`. ζ < 0 selects the Businger-Dyer unstable branch of φ_m and ψ_m.",
      "parameter_overrides": {
        "u_star": 0.5,
        "q_z": 300.0,
        "z₀": 0.1,
        "T₀": 300.0,
        "ρ": 1.225
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "L",
          "time": 0.0,
          "expected": -39.22979122054367
        },
        {
          "variable": "L_inv",
          "time": 0.0,
          "expected": -0.025490831556511696
        },
        {
          "variable": "ζ",
          "time": 0.0,
          "expected": -0.25490831556511695
        },
        {
          "variable": "φ_m",
          "time": 0.0,
          "expected": 0.6747713297758686
        },
        {
          "variable": "ψ_m",
          "time": 0.0,
          "expected": 0.5170494788751416
        },
        {
          "variable": "ū",
          "time": 0.0,
          "expected": 5.110150883891188
        },
        {
          "variable": "pasquill_class",
          "time": 0.0,
          "expected": 3
        }
      ]
    },
    {
      "id": "physical_constraints_wind_class_D",
      "description": "Physical constraints — reproduces the second `Physical constraints` testitem (u_star = 0.5 m/s, z = 10 m, z₀ = 0.1 m, q_z = 50 W/m^2, T₀ = 288.15 K, ρ = 1.225 kg/m^3): the mean wind speed ū ≈ 5.58 m/s is positive. The weak heat flux gives a large-magnitude L ≈ -226 m, so L_inv ≈ -0.0044 m^-1 places the atmosphere in Pasquill class 4 (D, near-neutral). The unstable-branch stability functions φ_m and φ_h are positive (the upstream `Physical constraints` φ > 0 check).",
      "parameter_overrides": {
        "u_star": 0.5,
        "z": 10.0,
        "z₀": 0.1,
        "q_z": 50.0,
        "T₀": 288.15,
        "ρ": 1.225
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "L",
          "time": 0.0,
          "expected": -226.08128680361628
        },
        {
          "variable": "L_inv",
          "time": 0.0,
          "expected": -0.0044231878460097495
        },
        {
          "variable": "φ_m",
          "time": 0.0,
          "expected": 0.8805331749104327
        },
        {
          "variable": "φ_h",
          "time": 0.0,
          "expected": 0.7753386721178468
        },
        {
          "variable": "ū",
          "time": 0.0,
          "expected": 5.581856204835306
        },
        {
          "variable": "pasquill_class",
          "time": 0.0,
          "expected": 4
        }
      ]
    },
    {
      "id": "inversion_stable_class_E",
      "description": "Surface temperature inversion with surface cooling (T = 290.15 K above T_below = 288.15 K over Δz = 100 m, u_star = 0.25 m/s, q_z = -60 W/m^2). Temperature increasing with height gives a positive actual lapse rate dT_dz = 0.02 K/m and a strongly positive potential-temperature gradient dθ_dz = 0.02976 K/m (stable stratification). The downward heat flux gives a positive Monin-Obukhov length L ≈ 23.6 m, so ζ > 0 selects the stable branch where φ_m = φ_h = 1 + 4.7ζ and ψ_m = ψ_h = -4.7ζ; L_inv ≈ 0.042 m^-1 gives Pasquill class 5 (E, slightly stable).",
      "parameter_overrides": {
        "T": 290.15,
        "T_below": 288.15,
        "Δz": 100.0,
        "u_star": 0.25,
        "q_z": -60.0
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "θ",
          "time": 0.0,
          "expected": 290.15
        },
        {
          "variable": "dT_dz",
          "time": 0.0,
          "expected": 0.02
        },
        {
          "variable": "dθ_dz",
          "time": 0.0,
          "expected": 0.02976
        },
        {
          "variable": "L",
          "time": 0.0,
          "expected": 23.550134042129717
        },
        {
          "variable": "L_inv",
          "time": 0.0,
          "expected": 0.042462603321537895
        },
        {
          "variable": "ζ",
          "time": 0.0,
          "expected": 0.42462603321537895
        },
        {
          "variable": "φ_m",
          "time": 0.0,
          "expected": 2.995742356112281
        },
        {
          "variable": "φ_h",
          "time": 0.0,
          "expected": 2.995742356112281
        },
        {
          "variable": "ψ_m",
          "time": 0.0,
          "expected": -1.9957423561122811
        },
        {
          "variable": "ū",
          "time": 0.0,
          "expected": 4.125570338812733
        },
        {
          "variable": "pasquill_class",
          "time": 0.0,
          "expected": 5
        }
      ]
    },
    {
      "id": "pasquill_stable_class_F",
      "description": "Stable surface layer — reproduces the second `Pasquill stability classification` testitem (u_star = 0.2 m/s, q_z = -100 W/m^2, z₀ = 0.1 m, T₀ = 280 K, ρ = 1.225 kg/m^3). The strong downward (surface-cooling) heat flux gives a positive Monin-Obukhov length L ≈ 7.0 m (the upstream `L > 0` assertion) and the Pasquill class is 6 (F, moderately stable) — the upstream test asserts `pasquill_class ≥ 4`. ζ > 0 selects the stable branch of φ_m and ψ_m.",
      "parameter_overrides": {
        "u_star": 0.2,
        "q_z": -100.0,
        "z₀": 0.1,
        "T₀": 280.0,
        "ρ": 1.225
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "L",
          "time": 0.0,
          "expected": 7.0299785867308
        },
        {
          "variable": "L_inv",
          "time": 0.0,
          "expected": 0.1422479439535586
        },
        {
          "variable": "ζ",
          "time": 0.0,
          "expected": 1.4224794395355862
        },
        {
          "variable": "φ_m",
          "time": 0.0,
          "expected": 7.685653365817255
        },
        {
          "variable": "ψ_m",
          "time": 0.0,
          "expected": -6.685653365817255
        },
        {
          "variable": "ū",
          "time": 0.0,
          "expected": 5.645411775902673
        },
        {
          "variable": "pasquill_class",
          "time": 0.0,
          "expected": 6
        }
      ]
    },
    {
      "id": "summer_afternoon_boundary_layer",
      "description": "Summer-afternoon boundary layer from the AtmosphericDynamics.jl docs \"Complete Boundary Layer Analysis\" example (T = 298.15 K at 10 m, T_below = 300.15 K at the surface — superadiabatic, p = 100000 Pa, z = 10 m, z₀ = 0.1 m, Δz = 10 m, T₀ = 300.15 K, ρ = 1.18 kg/m^3, u_star = 0.35 m/s, q_z = 150 W/m^2). A strongly unstable surface layer: θ ≈ 299.3 K, dθ_dz ≈ -0.190 K/m (unstable), L ≈ -25.9 m, ζ ≈ -0.386, ū ≈ 3.45 m/s, Pasquill class 3 (C). Touches all 12 outputs; the L/ζ/φ/ψ/ū values agree with the surface_layer_profile.esm summer_afternoon_boundary_layer test (shared equations).",
      "parameter_overrides": {
        "T": 298.15,
        "T_below": 300.15,
        "p": 100000.0,
        "z": 10.0,
        "z₀": 0.1,
        "Δz": 10.0,
        "T₀": 300.15,
        "ρ": 1.18,
        "u_star": 0.35,
        "q_z": 150.0
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "θ",
          "time": 0.0,
          "expected": 299.272849613186
        },
        {
          "variable": "dT_dz",
          "time": 0.0,
          "expected": -0.2
        },
        {
          "variable": "dθ_dz",
          "time": 0.0,
          "expected": -0.19024000000000002
        },
        {
          "variable": "L",
          "time": 0.0,
          "expected": -25.936007561545868
        },
        {
          "variable": "L_inv",
          "time": 0.0,
          "expected": -0.03855643539689024
        },
        {
          "variable": "ζ",
          "time": 0.0,
          "expected": -0.3855643539689024
        },
        {
          "variable": "φ_m",
          "time": 0.0,
          "expected": 0.6196366508538875
        },
        {
          "variable": "φ_h",
          "time": 0.0,
          "expected": 0.3839495790814225
        },
        {
          "variable": "ψ_m",
          "time": 0.0,
          "expected": 0.663061754670419
        },
        {
          "variable": "ψ_h",
          "time": 0.0,
          "expected": 1.1780765683268122
        },
        {
          "variable": "ū",
          "time": 0.0,
          "expected": 3.449344877402963
        },
        {
          "variable": "pasquill_class",
          "time": 0.0,
          "expected": 3
        }
      ]
    }
  ],
  "analyses": [
    {
      "id": "potential_temperature_profile",
      "description": "Potential temperature θ = T·(p₀/p)^(R_air/ĉ_p) (Eq. 16.14) swept over pressure p from 50000 to 101325 Pa at the default temperature T = 288.15 K. Reproduces the AtmosphericDynamics.jl docs `Potential Temperature Profile` figure — at fixed temperature θ rises as pressure falls, equalling the actual temperature at the sea-level reference pressure p₀ and exceeding it aloft where the (p₀/p) adiabatic-compression factor is greater than one.",
      "initial_state": {},
      "parameters": {},
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "parameter_sweep": {
        "type": "cartesian",
        "dimensions": [
          {
            "parameter": "p",
            "range": {
              "start": 50000.0,
              "stop": 101325.0,
              "count": 31,
              "scale": "linear"
            }
          }
        ]
      },
      "plots": [
        {
          "id": "theta_vs_p",
          "type": "line",
          "description": "Potential temperature θ as a function of pressure p (Eq. 16.14).",
          "x": {
            "variable": "p",
            "label": "Pressure p (Pa)"
          },
          "y": {
            "variable": "θ",
            "label": "Potential temperature θ (K)"
          }
        }
      ]
    },
    {
      "id": "monin_obukhov_length_vs_heat_flux",
      "description": "Monin-Obukhov length L (Eq. 16.70) as a function of the surface sensible heat flux q_z over the unstable regime (q_z > 0, surface heating), at the default u_star = 0.3 m/s. Reproduces the unstable branch of the AtmosphericDynamics.jl docs `Monin-Obukhov Length vs Heat Flux` figure: L is negative and grows toward 0 as the heat flux increases.",
      "initial_state": {},
      "parameters": {},
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "parameter_sweep": {
        "type": "cartesian",
        "dimensions": [
          {
            "parameter": "q_z",
            "range": {
              "start": 10.0,
              "stop": 300.0,
              "count": 30,
              "scale": "linear"
            }
          }
        ]
      },
      "plots": [
        {
          "id": "L_vs_q_z",
          "type": "line",
          "description": "Monin-Obukhov length L vs surface heat flux q_z (Eq. 16.70).",
          "x": {
            "variable": "q_z",
            "label": "Surface sensible heat flux q_z (W/m^2)"
          },
          "y": {
            "variable": "L",
            "label": "Monin-Obukhov length L (m)"
          }
        }
      ]
    },
    {
      "id": "pasquill_class_vs_roughness_length",
      "description": "Pasquill stability class (1=A to 6=F) as a function of the surface roughness length z₀, swept from 0.001 to 2 m (Table 16.1, snow through low-density residential terrain) at a fixed moderately unstable surface heat flux q_z = 120 W/m^2 and the default u_star = 0.3 m/s. The Monin-Obukhov length L (and hence L_inv) is independent of z₀, so this example isolates the z₀ dependence of the Golder (1972) correlation (Eq. 16.83, 1/L = a + b·log₁₀(z₀)): as the surface roughens the class boundaries shift and the diagnosed Pasquill class steps between the unstable categories. Reproduces the AtmosphericDynamics.jl docs `Monin-Obukhov Length vs Roughness Length for Pasquill Stability Classes` figure.",
      "initial_state": {},
      "parameters": {
        "q_z": 120.0
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "parameter_sweep": {
        "type": "cartesian",
        "dimensions": [
          {
            "parameter": "z₀",
            "range": {
              "start": 0.001,
              "stop": 2.0,
              "count": 31,
              "scale": "linear"
            }
          }
        ]
      },
      "plots": [
        {
          "id": "pasquill_vs_z0",
          "type": "line",
          "description": "Pasquill stability class as a function of the surface roughness length z₀ (Eq. 16.83, Golder correlation).",
          "x": {
            "variable": "z₀",
            "label": "Roughness length z₀ (m)"
          },
          "y": {
            "variable": "pasquill_class",
            "label": "Pasquill stability class (1=A to 6=F)"
          }
        }
      ]
    }
  ]
}