Version: dev

SurfaceLayerProfile

Monin-Obukhov surface-layer similarity theory for the atmospheric surface layer, from Seinfeld & Pandis (2006) "Atmospheric Chemistry and Physics", 2nd ed., Chapter 16 "Meteorology of the Local Scale". Observed-only algebraic component: from the friction velocity u_star, surface sensible heat flux q_z, and surface-layer geometry it computes the Monin-Obukhov length L (Eq. 16.70), the dimensionless stability parameter ζ = z/L, the Businger-Dyer stability functions φ_m and φ_h (Eq. 16.75), their integrated forms ψ_m and ψ_h (Eq. 16.78-16.79), and the stability-corrected mean wind speed ū (Eq. 16.66 with the Eq. 16.77 correction). Migrated from AtmosphericDynamics.jl@816cc391 src/local_scale_meteorology.jl:107 (`SurfaceLayerProfile` @component); the 4 upstream @constants (g, κ, ĉ_p, ε_q) are declared as fixed-default parameters.

.esm schema
1.0.0
Source
components/atmospheric_dynamics/local_scale/surface_layer_profile.esm

Description

Monin-Obukhov surface-layer similarity theory for the atmospheric surface layer, from Seinfeld & Pandis (2006) “Atmospheric Chemistry and Physics”, 2nd ed., Chapter 16 “Meteorology of the Local Scale”. Observed-only algebraic component: from the friction velocity u_star, surface sensible heat flux q_z, and surface-layer geometry it computes the Monin-Obukhov length L (Eq. 16.70), the dimensionless stability parameter ζ = z/L, the Businger-Dyer stability functions φ_m and φ_h (Eq. 16.75), their integrated forms ψ_m and ψ_h (Eq. 16.78-16.79), and the stability-corrected mean wind speed ū (Eq. 16.66 with the Eq. 16.77 correction). Migrated from AtmosphericDynamics.jl@816cc391 src/local_scale_meteorology.jl:107 (SurfaceLayerProfile @component); the 4 upstream @constants (g, κ, ĉ_p, ε_q) are declared as fixed-default parameters.

Reference

source_ref: AtmosphericDynamics.jl@816cc391:src/local_scale_meteorology.jl:107 Upstream SurfaceLayerProfile is a ModelingToolkit @component implementing Monin-Obukhov similarity theory for the atmospheric surface layer. g, κ, ĉ_p, ε_q are upstream @constants; z, z₀, T₀, ρ, u_star, q_z are @parameters; L, ζ, φ_m, φ_h, ψ_m, ψ_h, ū are @variables bound by 7 algebraic equations (no time derivative). For standalone serialization the 4 @constants are declared as fixed-default parameters here, matching the sibling scale_height.esm. The 7 equations are unchanged from upstream; mtk2esm reorders commutative */+ operands, rewrites x^(-n) as 1/x^n, and folds ((1-15ζ)^0.25)^2 to (1-15ζ)^0.5 (algebraically identical). The π/2 term of the ψ_m unstable branch is folded to the float literal 1.5707963267948966. Tolerance rationale (model-level rel=1e-6): observed-only algebraic system (no ODE integration); rel=1e-6 covers float64 roundoff and cross-runner libm differences in the ^/log/atan chain. Near-zero outputs in the neutral regime (ζ, ψ_m, ψ_h ~ 1e-8..1e-13, where π/2 − 2·atan(x≈1) cancels) carry a per-assertion abs=1e-6 — already far tighter than the upstream test suite’s atol=1e-4 for ζ.

Parameters

NameUnitsDefaultDescription
zm10.0Height above ground
z₀m0.1Roughness length (Table 16.1)
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
ε_qW/m^21e-10Small regularization for heat flux

Observed

NameUnitsDefaultDescription
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 with stability)

Observed expressions

$$ 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 with stability)

Analyses

monin_obukhov_length_vs_heat_flux

Monin-Obukhov length L 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 figure “Monin-Obukhov Length vs Heat Flux”: 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).

logarithmic_wind_profile

Mean wind speed ū as a function of height z under neutral conditions (default q_z = 0), with u_star = 0.4 m/s and z₀ = 0.1 m. Reproduces the neutral wind profile of the AtmosphericDynamics.jl docs figure “Wind Profiles for Different Stability Conditions”: ū follows the logarithmic law (u_star/κ)·ln(z/z₀).

Time span: 0.0 → 1.0

Swept over: z

Logarithmic wind profile ū(z) (Eq. 16.66).

businger_dyer_stability_functions

Businger-Dyer stability functions φ_m and φ_h as functions of the stability parameter ζ = z/L, traced by sweeping the surface heat flux q_z over the unstable regime (q_z > 0 -> ζ < 0). Reproduces the unstable branch of the AtmosphericDynamics.jl docs figure “Businger-Dyer Stability Functions”: both functions fall below 1 as the surface layer becomes more unstable.

Time span: 0.0 → 1.0

Swept over: q_z

Momentum stability function φ_m vs ζ (Eq. 16.75, unstable branch).

Heat stability function φ_h vs ζ (Eq. 16.75, unstable branch).

Raw .esm

Raw .esm JSON (this component)
{
  "reference": {
    "notes": "source_ref: AtmosphericDynamics.jl@816cc391:src/local_scale_meteorology.jl:107\nUpstream `SurfaceLayerProfile` is a ModelingToolkit `@component` implementing Monin-Obukhov similarity theory for the atmospheric surface layer. g, κ, ĉ_p, ε_q are upstream `@constants`; z, z₀, T₀, ρ, u_star, q_z are `@parameters`; L, ζ, φ_m, φ_h, ψ_m, ψ_h, ū are `@variables` bound by 7 algebraic equations (no time derivative). For standalone serialization the 4 `@constants` are declared as fixed-default parameters here, matching the sibling scale_height.esm. The 7 equations are unchanged from upstream; `mtk2esm` reorders commutative `*`/`+` operands, rewrites `x^(-n)` as `1/x^n`, and folds `((1-15ζ)^0.25)^2` to `(1-15ζ)^0.5` (algebraically identical). The `π/2` term of the ψ_m unstable branch is folded to the float literal 1.5707963267948966.\nTolerance rationale (model-level rel=1e-6): observed-only algebraic system (no ODE integration); rel=1e-6 covers float64 roundoff and cross-runner libm differences in the `^`/`log`/`atan` chain. Near-zero outputs in the neutral regime (ζ, ψ_m, ψ_h ~ 1e-8..1e-13, where π/2 − 2·atan(x≈1) cancels) carry a per-assertion abs=1e-6 — already far tighter than the upstream test suite's atol=1e-4 for ζ."
  },
  "tolerance": {
    "rel": 1e-06
  },
  "variables": {
    "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)"
    },
    "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"
    },
    "ε_q": {
      "type": "parameter",
      "units": "W/m^2",
      "default": 1e-10,
      "description": "Small regularization for heat flux"
    },
    "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 with stability)"
    }
  },
  "equations": [
    {
      "lhs": "L",
      "rhs": {
        "op": "/",
        "args": [
          {
            "op": "*",
            "args": [
              -1,
              "ĉ_p",
              "ρ",
              {
                "op": "^",
                "args": [
                  "u_star",
                  3
                ]
              },
              "T₀"
            ]
          },
          {
            "op": "*",
            "args": [
              "κ",
              "g",
              {
                "op": "+",
                "args": [
                  "q_z",
                  "ε_q"
                ]
              }
            ]
          }
        ]
      }
    },
    {
      "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"
            ]
          },
          "κ"
        ]
      }
    }
  ],
  "tests": [
    {
      "id": "default_parameters",
      "description": "All parameters at their declared defaults (q_z = 0 -> the ε_q heat-flux regularization makes |L| enormous, so the surface layer is effectively neutral). ζ collapses to ~0, φ_m = φ_h -> 1, ψ_m = ψ_h -> 0, and ū reduces to the pure logarithmic profile (u_star/κ)·ln(z/z₀). Guards the serialized parameter defaults.",
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "L",
          "time": 0.0,
          "expected": -24416778974839.395
        },
        {
          "variable": "ζ",
          "time": 0.0,
          "expected": -4.095544301852688e-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.535438443056002e-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": "ū",
          "time": 1.0,
          "expected": 3.4538776394899164
        }
      ]
    },
    {
      "id": "monin_obukhov_neutral",
      "description": "Monin-Obukhov length under near-neutral conditions (q_z = 1e-6 W/m^2, essentially zero heat flux). Upstream \"Monin-Obukhov length\" test 1: |L| must exceed 1e6 m. Here L = -2.44e9 m.",
      "parameter_overrides": {
        "q_z": 1e-06
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "L",
          "time": 0.0,
          "expected": -2441433754.108529
        },
        {
          "variable": "ζ",
          "time": 0.0,
          "expected": -4.095953856282873e-09,
          "tolerance": {
            "abs": 1e-06
          }
        },
        {
          "variable": "φ_m",
          "time": 0.0,
          "expected": 0.9999999846401737
        },
        {
          "variable": "φ_h",
          "time": 0.0,
          "expected": 0.9999999692803475
        },
        {
          "variable": "ψ_m",
          "time": 0.0,
          "expected": 1.5359826240762353e-08,
          "tolerance": {
            "abs": 1e-06
          }
        },
        {
          "variable": "ψ_h",
          "time": 0.0,
          "expected": 3.071965325174098e-08,
          "tolerance": {
            "abs": 1e-06
          }
        },
        {
          "variable": "ū",
          "time": 0.0,
          "expected": 3.453877627971199
        }
      ]
    },
    {
      "id": "monin_obukhov_unstable",
      "description": "Unstable surface layer: positive (upward) heat flux q_z = 100 W/m^2 with u_star = 0.4 m/s. Upstream \"Monin-Obukhov length\" test 2: L must be negative. ζ < 0 selects the Businger-Dyer unstable branch.",
      "parameter_overrides": {
        "u_star": 0.4,
        "q_z": 100.0
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "L",
          "time": 0.0,
          "expected": -57.876809421783676
        },
        {
          "variable": "ζ",
          "time": 0.0,
          "expected": -0.172780775234583
        },
        {
          "variable": "φ_m",
          "time": 0.0,
          "expected": 0.7263979917166654
        },
        {
          "variable": "φ_h",
          "time": 0.0,
          "expected": 0.5276540423700046
        },
        {
          "variable": "ψ_m",
          "time": 0.0,
          "expected": 0.40064640265675194
        },
        {
          "variable": "ψ_h",
          "time": 0.0,
          "expected": 0.7398010106000124
        },
        {
          "variable": "ū",
          "time": 0.0,
          "expected": 4.20452378333134
        }
      ]
    },
    {
      "id": "monin_obukhov_stable",
      "description": "Stable surface layer: negative (downward) heat flux q_z = -50 W/m^2 (surface cooling). Upstream \"Monin-Obukhov length\" test 3: L must be positive. ζ > 0 selects the stable branch φ_m = φ_h = 1 + 4.7ζ.",
      "parameter_overrides": {
        "q_z": -50.0
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "L",
          "time": 0.0,
          "expected": 48.833557949776456
        },
        {
          "variable": "ζ",
          "time": 0.0,
          "expected": 0.20477721509222482
        },
        {
          "variable": "φ_m",
          "time": 0.0,
          "expected": 1.9624529109334565
        },
        {
          "variable": "φ_h",
          "time": 0.0,
          "expected": 1.9624529109334565
        },
        {
          "variable": "ψ_m",
          "time": 0.0,
          "expected": -0.9624529109334566
        },
        {
          "variable": "ψ_h",
          "time": 0.0,
          "expected": -0.9624529109334566
        },
        {
          "variable": "ū",
          "time": 0.0,
          "expected": 4.175717322691161
        }
      ]
    },
    {
      "id": "businger_dyer_neutral",
      "description": "Businger-Dyer stability functions under near-neutral conditions (q_z = 1e-8 W/m^2). Upstream \"Businger-Dyer stability functions\" test 1: ζ ~ 0 and φ_m = φ_h ~ 1.",
      "parameter_overrides": {
        "q_z": 1e-08
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "L",
          "time": 0.0,
          "expected": -241750286879.598
        },
        {
          "variable": "ζ",
          "time": 0.0,
          "expected": -4.136499744871215e-11,
          "tolerance": {
            "abs": 1e-06
          }
        },
        {
          "variable": "φ_m",
          "time": 0.0,
          "expected": 0.9999999998448812
        },
        {
          "variable": "φ_h",
          "time": 0.0,
          "expected": 0.9999999996897626
        },
        {
          "variable": "ψ_m",
          "time": 0.0,
          "expected": 1.551183625931671e-10,
          "tolerance": {
            "abs": 1e-06
          }
        },
        {
          "variable": "ψ_h",
          "time": 0.0,
          "expected": 3.102371692635132e-10,
          "tolerance": {
            "abs": 1e-06
          }
        },
        {
          "variable": "ū",
          "time": 0.0,
          "expected": 3.45387763937473
        }
      ]
    },
    {
      "id": "businger_dyer_stable",
      "description": "Businger-Dyer stability functions under stable conditions (u_star = 0.2 m/s, q_z = -50 W/m^2). Upstream \"Businger-Dyer stability functions\" test 2: ζ > 0 and φ_m = φ_h = 1 + 4.7ζ. Here 1 + 4.7·0.691123 = 4.248279.",
      "parameter_overrides": {
        "u_star": 0.2,
        "q_z": -50.0
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "L",
          "time": 0.0,
          "expected": 14.469202355489326
        },
        {
          "variable": "ζ",
          "time": 0.0,
          "expected": 0.6911231009362585
        },
        {
          "variable": "φ_m",
          "time": 0.0,
          "expected": 4.248278574400414
        },
        {
          "variable": "φ_h",
          "time": 0.0,
          "expected": 4.248278574400414
        },
        {
          "variable": "ψ_m",
          "time": 0.0,
          "expected": -3.248278574400415
        },
        {
          "variable": "ψ_h",
          "time": 0.0,
          "expected": -3.248278574400415
        },
        {
          "variable": "ū",
          "time": 0.0,
          "expected": 3.926724380194253
        }
      ]
    },
    {
      "id": "businger_dyer_unstable",
      "description": "Businger-Dyer stability functions under unstable conditions (q_z = 100 W/m^2). Upstream \"Businger-Dyer stability functions\" test 3: ζ < 0, φ_m = (1 - 15ζ)^(-1/4), φ_h = (1 - 15ζ)^(-1/2). Same parameters as the upstream \"Physical constraints\" test 3, which checks φ_m, φ_h > 0.",
      "parameter_overrides": {
        "q_z": 100.0
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "L",
          "time": 0.0,
          "expected": -24.416778974814978
        },
        {
          "variable": "ζ",
          "time": 0.0,
          "expected": -0.40955443018567833
        },
        {
          "variable": "φ_m",
          "time": 0.0,
          "expected": 0.6116810518520646
        },
        {
          "variable": "φ_h",
          "time": 0.0,
          "expected": 0.37415370919484814
        },
        {
          "variable": "ψ_m",
          "time": 0.0,
          "expected": 0.6862614089616637
        },
        {
          "variable": "ψ_h",
          "time": 0.0,
          "expected": 1.2155589113923662
        },
        {
          "variable": "ū",
          "time": 0.0,
          "expected": 2.939181582769821
        }
      ]
    },
    {
      "id": "log_wind_profile_neutral",
      "description": "Logarithmic wind profile under neutral conditions (u_star = 0.4 m/s, z₀ = 0.1 m, z = 10 m, q_z = 1e-8 W/m^2). Upstream \"Logarithmic wind profile\" test 1: ū ~ (u_star/κ)·ln(z/z₀) = 1·ln(100) = 4.60517 m/s (ψ_m ~ 0).",
      "parameter_overrides": {
        "u_star": 0.4,
        "q_z": 1e-08
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "L",
          "time": 0.0,
          "expected": -573037717047.9362
        },
        {
          "variable": "ζ",
          "time": 0.0,
          "expected": -1.745085829867543e-11,
          "tolerance": {
            "abs": 1e-06
          }
        },
        {
          "variable": "φ_m",
          "time": 0.0,
          "expected": 0.9999999999345592
        },
        {
          "variable": "φ_h",
          "time": 0.0,
          "expected": 0.9999999998691187
        },
        {
          "variable": "ψ_m",
          "time": 0.0,
          "expected": 6.544076391782967e-11,
          "tolerance": {
            "abs": 1e-06
          }
        },
        {
          "variable": "ψ_h",
          "time": 0.0,
          "expected": 1.3088108374430828e-10,
          "tolerance": {
            "abs": 1e-06
          }
        },
        {
          "variable": "ū",
          "time": 0.0,
          "expected": 4.605170185922651
        }
      ]
    },
    {
      "id": "log_wind_profile_wangara",
      "description": "Logarithmic wind profile with Wangara-experiment roughness (Seinfeld & Pandis p.745: z₀ = 0.0015 m, u_star = 0.4 m/s). Upstream \"Logarithmic wind profile\" test 2: ū ~ (u_star/κ)·ln(z/z₀) = ln(6666.67) = 8.80488 m/s. L/ζ/φ/ψ are independent of z₀, so they match log_wind_profile_neutral exactly.",
      "parameter_overrides": {
        "u_star": 0.4,
        "z₀": 0.0015,
        "q_z": 1e-08
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "L",
          "time": 0.0,
          "expected": -573037717047.9362
        },
        {
          "variable": "ζ",
          "time": 0.0,
          "expected": -1.745085829867543e-11,
          "tolerance": {
            "abs": 1e-06
          }
        },
        {
          "variable": "φ_m",
          "time": 0.0,
          "expected": 0.9999999999345592
        },
        {
          "variable": "φ_h",
          "time": 0.0,
          "expected": 0.9999999998691187
        },
        {
          "variable": "ψ_m",
          "time": 0.0,
          "expected": 6.544076391782967e-11,
          "tolerance": {
            "abs": 1e-06
          }
        },
        {
          "variable": "ψ_h",
          "time": 0.0,
          "expected": 1.3088108374430828e-10,
          "tolerance": {
            "abs": 1e-06
          }
        },
        {
          "variable": "ū",
          "time": 0.0,
          "expected": 8.804875263802577
        }
      ]
    },
    {
      "id": "limiting_neutral_psi_to_zero",
      "description": "Limiting behaviour: as |L| -> infinity (q_z = 1e-10 W/m^2, essentially zero heat flux) the surface layer becomes neutral and the integrated stability function ψ_m -> 0, leaving a purely logarithmic wind profile. Upstream \"Limiting behaviors\" test 1.",
      "parameter_overrides": {
        "q_z": 1e-10
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "L",
          "time": 0.0,
          "expected": -12208389487419.697
        },
        {
          "variable": "ζ",
          "time": 0.0,
          "expected": -8.191088603705376e-13,
          "tolerance": {
            "abs": 1e-06
          }
        },
        {
          "variable": "φ_m",
          "time": 0.0,
          "expected": 0.9999999999969285
        },
        {
          "variable": "φ_h",
          "time": 0.0,
          "expected": 0.9999999999938567
        },
        {
          "variable": "ψ_m",
          "time": 0.0,
          "expected": 3.0715430199255997e-12,
          "tolerance": {
            "abs": 1e-06
          }
        },
        {
          "variable": "ψ_h",
          "time": 0.0,
          "expected": 6.14353012905633e-12,
          "tolerance": {
            "abs": 1e-06
          }
        },
        {
          "variable": "ū",
          "time": 0.0,
          "expected": 3.4538776394887654
        }
      ]
    },
    {
      "id": "wind_profile_z5m",
      "description": "Wind speed at z = 5 m under near-neutral conditions (q_z = 1e-8 W/m^2). Lower half of the upstream \"Limiting behaviors\" test 2 (wind speed increases with height): ū(5 m) = 2.93402 m/s.",
      "parameter_overrides": {
        "z": 5.0,
        "q_z": 1e-08
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "L",
          "time": 0.0,
          "expected": -241750286879.598
        },
        {
          "variable": "ζ",
          "time": 0.0,
          "expected": -2.0682498724356076e-11,
          "tolerance": {
            "abs": 1e-06
          }
        },
        {
          "variable": "φ_m",
          "time": 0.0,
          "expected": 0.9999999999224407
        },
        {
          "variable": "φ_h",
          "time": 0.0,
          "expected": 0.9999999998448814
        },
        {
          "variable": "ψ_m",
          "time": 0.0,
          "expected": 7.755929232038987e-11,
          "tolerance": {
            "abs": 1e-06
          }
        },
        {
          "variable": "ψ_h",
          "time": 0.0,
          "expected": 1.5511858463777203e-10,
          "tolerance": {
            "abs": 1e-06
          }
        },
        {
          "variable": "ū",
          "time": 0.0,
          "expected": 2.93401725401294
        }
      ]
    },
    {
      "id": "wind_profile_z20m",
      "description": "Wind speed at z = 20 m under near-neutral conditions (q_z = 1e-8 W/m^2). Upper half of the upstream \"Limiting behaviors\" test 2: ū(20 m) = 3.97374 m/s > ū(5 m), confirming wind speed increases with height.",
      "parameter_overrides": {
        "z": 20.0,
        "q_z": 1e-08
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "L",
          "time": 0.0,
          "expected": -241750286879.598
        },
        {
          "variable": "ζ",
          "time": 0.0,
          "expected": -8.27299948974243e-11,
          "tolerance": {
            "abs": 1e-06
          }
        },
        {
          "variable": "φ_m",
          "time": 0.0,
          "expected": 0.9999999996897626
        },
        {
          "variable": "φ_h",
          "time": 0.0,
          "expected": 0.999999999379525
        },
        {
          "variable": "ψ_m",
          "time": 0.0,
          "expected": 3.102373913081181e-10,
          "tolerance": {
            "abs": 1e-06
          }
        },
        {
          "variable": "ψ_h",
          "time": 0.0,
          "expected": 6.204752266573222e-10,
          "tolerance": {
            "abs": 1e-06
          }
        },
        {
          "variable": "ū",
          "time": 0.0,
          "expected": 3.973738024678349
        }
      ]
    },
    {
      "id": "summer_afternoon_boundary_layer",
      "description": "Summer-afternoon boundary layer from the AtmosphericDynamics.jl docs \"Complete Boundary Layer Analysis\" example (u_star = 0.35 m/s, q_z = 150 W/m^2 strong upward heat flux, T₀ = 300.15 K, ρ = 1.18 kg/m^3): a strongly unstable surface layer with L = -25.94 m and ζ = -0.386.",
      "parameter_overrides": {
        "u_star": 0.35,
        "q_z": 150.0,
        "T₀": 300.15,
        "ρ": 1.18
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "L",
          "time": 0.0,
          "expected": -25.936007561545868
        },
        {
          "variable": "ζ",
          "time": 0.0,
          "expected": -0.3855643539689024
        },
        {
          "variable": "φ_m",
          "time": 0.0,
          "expected": 0.6196366508538875
        },
        {
          "variable": "φ_h",
          "time": 0.0,
          "expected": 0.38394957908142247
        },
        {
          "variable": "ψ_m",
          "time": 0.0,
          "expected": 0.6630617546704188
        },
        {
          "variable": "ψ_h",
          "time": 0.0,
          "expected": 1.1780765683268124
        },
        {
          "variable": "ū",
          "time": 0.0,
          "expected": 3.449344877402963
        }
      ]
    }
  ],
  "analyses": [
    {
      "id": "monin_obukhov_length_vs_heat_flux",
      "description": "Monin-Obukhov length L 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 figure \"Monin-Obukhov Length vs Heat Flux\": 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": "logarithmic_wind_profile",
      "description": "Mean wind speed ū as a function of height z under neutral conditions (default q_z = 0), with u_star = 0.4 m/s and z₀ = 0.1 m. Reproduces the neutral wind profile of the AtmosphericDynamics.jl docs figure \"Wind Profiles for Different Stability Conditions\": ū follows the logarithmic law (u_star/κ)·ln(z/z₀).",
      "initial_state": {},
      "parameters": {
        "u_star": 0.4
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "parameter_sweep": {
        "type": "cartesian",
        "dimensions": [
          {
            "parameter": "z",
            "range": {
              "start": 1.0,
              "stop": 50.0,
              "count": 30,
              "scale": "linear"
            }
          }
        ]
      },
      "plots": [
        {
          "id": "u_vs_z",
          "type": "line",
          "description": "Logarithmic wind profile ū(z) (Eq. 16.66).",
          "x": {
            "variable": "z",
            "label": "Height z (m)"
          },
          "y": {
            "variable": "ū",
            "label": "Mean wind speed ū (m/s)"
          }
        }
      ]
    },
    {
      "id": "businger_dyer_stability_functions",
      "description": "Businger-Dyer stability functions φ_m and φ_h as functions of the stability parameter ζ = z/L, traced by sweeping the surface heat flux q_z over the unstable regime (q_z > 0 -> ζ < 0). Reproduces the unstable branch of the AtmosphericDynamics.jl docs figure \"Businger-Dyer Stability Functions\": both functions fall below 1 as the surface layer becomes more unstable.",
      "initial_state": {},
      "parameters": {},
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "parameter_sweep": {
        "type": "cartesian",
        "dimensions": [
          {
            "parameter": "q_z",
            "range": {
              "start": 5.0,
              "stop": 250.0,
              "count": 30,
              "scale": "linear"
            }
          }
        ]
      },
      "plots": [
        {
          "id": "phi_m_vs_zeta",
          "type": "line",
          "description": "Momentum stability function φ_m vs ζ (Eq. 16.75, unstable branch).",
          "x": {
            "variable": "ζ",
            "label": "Stability parameter ζ = z/L"
          },
          "y": {
            "variable": "φ_m",
            "label": "Momentum stability function φ_m"
          }
        },
        {
          "id": "phi_h_vs_zeta",
          "type": "line",
          "description": "Heat stability function φ_h vs ζ (Eq. 16.75, unstable branch).",
          "x": {
            "variable": "ζ",
            "label": "Stability parameter ζ = z/L"
          },
          "y": {
            "variable": "φ_h",
            "label": "Heat stability function φ_h"
          }
        }
      ]
    }
  ]
}