Version: dev

SnowThermalProperties

Thermal conductivity and volumetric heat capacity of an urban-canopy snow layer. Migrated from UrbanCanopy.jl@9200edd4 src/roof_wall_road_snow_temperatures.jl:190 (`SnowThermalProperties` @component). Implements Oleson et al. (2010, CLM Tech Note Ch. 4 §4.3) Eq. 4.84 for snow bulk density, Eq. 4.83 (Jordan 1991 quadratic) for thermal conductivity, and Eq. 4.87 (additive ice + liquid contributions) for volumetric heat capacity. Parameterized as observed-only: w_ice, w_liq, Δz are inputs (parameters); ρ_sno, λ_snow, c_snow are algebraic outputs.

.esm schema
1.0.0
Source
components/urban_canopy/temps/snow_thermal.esm

Description

Thermal conductivity and volumetric heat capacity of an urban-canopy snow layer. Migrated from UrbanCanopy.jl@9200edd4 src/roof_wall_road_snow_temperatures.jl:190 (SnowThermalProperties @component). Implements Oleson et al. (2010, CLM Tech Note Ch. 4 §4.3) Eq. 4.84 for snow bulk density, Eq. 4.83 (Jordan 1991 quadratic) for thermal conductivity, and Eq. 4.87 (additive ice + liquid contributions) for volumetric heat capacity. Parameterized as observed-only: w_ice, w_liq, Δz are inputs (parameters); ρ_sno, λ_snow, c_snow are algebraic outputs.

Reference

_source_ref: UrbanCanopy.jl@9200edd4f15609f20339d3a7d104de8064544310:src/roof_wall_road_snow_temperatures.jl:190 Upstream SnowThermalProperties is an MTK @component with three @parameters (w_ice, w_liq, Δz), three time-indexed @variables (ρ_sno, λ_snow, c_snow), and three algebraic equations (no derivatives). Identical equation structure preserved here. Upstream structural test (test/roof_wall_road_snow_temperatures_test.jl:154-162) asserts length(equations(sys)) == 3 and length(unknowns(sys)) == 3 — matched here.

The upstream component declares six @constants that participate in the equations: C_liq = 4188.0 J/(kgK), C_ice = 2117.27 J/(kgK), λ_air = 0.023 W/(mK), λ_ice_const = 2.29 W/(mK) (all four are Oleson Table 1.4 physical constants), plus the two Jordan-(1991)-Eq.-4.83 polynomial coefficients jordan_linear_coeff = 7.75e-5 m^3/kg and jordan_quad_coeff = 1.105e-6 m^6/kg^2. They are encoded here as parameters with the upstream values as default, matching the convention used by sibling observed-only ESM files in this rig that translate @constants to fixed-default parameters (snow_soil_blended_heat_capacity.esm encodes C_ice the same way; freezing_point_depression.esm encodes T_f, L_f, g, one_ref the same way). The upstream also declares one_kgm⁻³ = 1.0 kg/m^3 in the second @constants block as a unit-balancing reference for non-dimensionalization; it is unused in the actual equations (the upstream dimensional balance is already implicit in the polynomial coefficient units, see below) — omitted here for fidelity to the equation set rather than to the constant set.

Unit balance of Eq. 4.83 (verified): jordan_linear_coeff [m^3/kg] × ρ_sno [kg/m^3] is dimensionless, and jordan_quad_coeff [m^6/kg^2] × ρ_sno² [kg^2/m^6] is dimensionless, so the bracketed factor in Eq. 4.83 is dimensionless and the outer multiplication by (λ_ice_const - λ_air) [W/(mK)] yields W/(mK) as required.

Unicode Δz (layer thickness) is preserved from upstream — peer ESM components in this rig (snow_soil_blended_heat_capacity.esm uses Δz, freezing_point_depression.esm uses Δz, snow_melt_no_layers.esm uses Δt) already use unicode in identifiers and the schema’s identifier pattern allows it. Unicode ρ_sno and λ_snow are likewise preserved from the upstream output variable names.

Observability classification: this component is functionally observed-only — the three output variables are each given by a single algebraic equation in terms of the parameters (the (t) time index has no role since there are no derivatives). Test scenarios use time_span: [0, 1] and sample at t=0 to mirror the convention used by sibling observed-only ESM files in this rig (snow_soil_blended_heat_capacity.esm, freezing_point_depression.esm, waste_heat_allocation.esm).

Tolerance rationale (model-level rel=1e-9): observed-only algebraic system (no ODE integration); Eqs. 4.84 and 4.87 are one addition + one division each, and Eq. 4.83 evaluates a degree-2 polynomial in ρ_sno followed by one multiplication and one addition — all IEEE-754 ULP-level (~1e-16) roundoff. 1e-9 leaves comfortable headroom above ULP roundoff and matches the convention used by sibling observed-only files (snow_soil_blended_heat_capacity.esm uses 1e-10 for its single-equation case, but waste_heat_allocation.esm and freezing_point_depression.esm both use 1e-9 for multi-equation cases). The upstream test asserts rtol = 1e-10 on ρ_sno (test/roof_wall_road_snow_temperatures_test.jl:182) and rtol = 1e-6 on λ_snow and c_snow (test:189, 194); the walker’s runtime tolerances (reltol=1e-10, abstol=1e-12) comfortably support the tighter 1e-10 we use on the assertion level.

Domain constraint: Δz > 0 is required (the equations have Δz in the denominator). The upstream component does not assert this guard and neither does this .esm — the upstream geometry submodel is responsible for keeping Δz positive. All test fixtures here use Δz ∈ [0.02, 0.5] m, well within the physically meaningful CLMU range. ρ_sno and c_snow are non-negative iff w_ice, w_liq ≥ 0, but the equations do not assert this — the upstream snow-mass tracker is responsible for keeping the masses non-negative; tests here use w_ice, w_liq ≥ 0 throughout._

Parameters

NameUnitsDefaultDescription
w_icekg/m^20.0Ice mass per unit area in the snow layer (Oleson §4.3 input)
w_liqkg/m^20.0Liquid water mass per unit area in the snow layer (Oleson §4.3 input)
Δzm1.0Snow layer thickness (must be > 0; 1.0 m default chosen so divide-by-Δz is well-defined when w_ice and w_liq are at their zero defaults)
C_liqJ/(kg*K)4188.0Specific heat of liquid water (Oleson et al. 2010 Table 1.4 — 4188.0 J/(kg*K))
C_iceJ/(kg*K)2117.27Specific heat of ice (Oleson et al. 2010 Table 1.4 — 2117.27 J/(kg*K))
λ_airW/(m*K)0.023Thermal conductivity of air (Oleson et al. 2010 Table 1.4 — 0.023 W/(m*K); the ρ_sno → 0 limit of Eq. 4.83)
λ_ice_constW/(m*K)2.29Thermal conductivity of ice (Oleson et al. 2010 Table 1.4 — 2.29 W/(m*K); supplies the (λ_ice - λ_air) factor of Eq. 4.83)
jordan_linear_coeffm^3/kg7.75e-05Jordan (1991) linear density coefficient in Eq. 4.83 (7.75e-5 m^3/kg)
jordan_quad_coeffm^6/kg^21.105e-06Jordan (1991) quadratic density coefficient in Eq. 4.83 (1.105e-6 m^6/kg^2)

Observed

NameUnitsDefaultDescription
ρ_snokg/m^3Snow bulk density (Oleson Eq. 4.84): (w_ice + w_liq) / Δz
λ_snowW/(m*K)Snow thermal conductivity (Oleson Eq. 4.83, Jordan 1991): λ_air + (a·ρ + b·ρ²)·(λ_ice - λ_air) with a = 7.75e-5 m^3/kg and b = 1.105e-6 m^6/kg^2
c_snowJ/(m^3*K)Snow volumetric heat capacity (Oleson Eq. 4.87): C_ice · (w_ice/Δz) + C_liq · (w_liq/Δz)

Observed expressions

$$ ρ_{sno} = \frac{w_{ice} + w_{liq}}{Δz} $$

Snow bulk density (Oleson Eq. 4.84): (w_ice + w_liq) / Δz

$$ λ_{snow} = λ_{air} + \left(jordan_{linear\,coeff} \cdot ρ_{sno} + jordan_{quad\,coeff} \cdot ρ_{sno}^{2}\right) \cdot \left(λ_{ice\,const} - λ_{air}\right) $$

Snow thermal conductivity (Oleson Eq. 4.83, Jordan 1991): λ_air + (a·ρ + b·ρ²)·(λ_ice - λ_air) with a = 7.75e-5 m^3/kg and b = 1.105e-6 m^6/kg^2

$$ c_{snow} = C_{ice} \cdot \frac{w_{ice}}{Δz} + C_{liq} \cdot \frac{w_{liq}}{Δz} $$

Snow volumetric heat capacity (Oleson Eq. 4.87): C_ice · (w_ice/Δz) + C_liq · (w_liq/Δz)

Analyses

thermal_properties_vs_density

Sweep snow bulk density via w_ice across the full CLMU range (0-50 kg/m^2 at Δz = 0.1 m → ρ_sno = 0-500 kg/m^3) with w_liq = 0. Surfaces the canonical Jordan (1991) λ-ρ curve (Eq. 4.83): a quadratic in ρ_sno that rises smoothly from λ_air at ρ = 0 to ~1.5 W/(m*K) at firn-like ρ = 500. c_snow rises linearly with w_ice (Eq. 4.87, pure-ice branch). Together these reproduce the two anchor curves used in §4.3 of the CLM Tech Note for snowpack thermal evolution.

Time span: 0.0 → 1.0

Swept over: w_ice

λ_snow vs w_ice (ρ_sno = w_ice / 0.1 at fixed Δz): the Jordan (1991) quadratic curve of Eq. 4.83, rising from λ_air at zero mass to ~1.5 W/(m*K) at the firn limit.

c_snow vs w_ice at w_liq = 0: linear in w_ice with slope C_ice/Δz = 21172.7 per Eq. 4.87 (pure-ice channel only).

heat_capacity_two_d_sweep

Joint sweep over w_ice and w_liq at fixed Δz = 0.1 m. Surfaces the planar additive structure of Eq. 4.87: c_snow is linear in each mass channel with slopes C_ice/Δz = 21172.7 (ice) and C_liq/Δz = 41880.0 (liquid). Iso-c_snow contours are straight lines C_ice·w_ice + C_liq·w_liq = const. The C_liq/C_ice ratio (~1.978) gives liquid water nearly twice the volumetric-heat-capacity-per-unit-mass weight of ice — the basis for the phase-change latent-heat term in §4.3 of the CLM Tech Note.

Time span: 0.0 → 1.0

Swept over: w_ice, w_liq

c_snow as a function of ice and liquid mass at fixed Δz: planar surface with slopes C_ice/Δz and C_liq/Δz per Eq. 4.87. Iso-c_snow contours are straight lines C_ice·w_ice + C_liq·w_liq = const.

Raw .esm

Raw .esm JSON (this component)
{
  "reference": {
    "notes": "source_ref: UrbanCanopy.jl@9200edd4f15609f20339d3a7d104de8064544310:src/roof_wall_road_snow_temperatures.jl:190\nUpstream `SnowThermalProperties` is an MTK `@component` with three `@parameters` (w_ice, w_liq, Δz), three time-indexed `@variables` (ρ_sno, λ_snow, c_snow), and three algebraic equations (no derivatives). Identical equation structure preserved here. Upstream structural test (test/roof_wall_road_snow_temperatures_test.jl:154-162) asserts `length(equations(sys)) == 3` and `length(unknowns(sys)) == 3` — matched here.\n\nThe upstream component declares six `@constants` that participate in the equations: C_liq = 4188.0 J/(kg*K), C_ice = 2117.27 J/(kg*K), λ_air = 0.023 W/(m*K), λ_ice_const = 2.29 W/(m*K) (all four are Oleson Table 1.4 physical constants), plus the two Jordan-(1991)-Eq.-4.83 polynomial coefficients jordan_linear_coeff = 7.75e-5 m^3/kg and jordan_quad_coeff = 1.105e-6 m^6/kg^2. They are encoded here as parameters with the upstream values as `default`, matching the convention used by sibling observed-only ESM files in this rig that translate `@constants` to fixed-default parameters (snow_soil_blended_heat_capacity.esm encodes C_ice the same way; freezing_point_depression.esm encodes T_f, L_f, g, one_ref the same way). The upstream also declares one_kgm⁻³ = 1.0 kg/m^3 in the second @constants block as a unit-balancing reference for non-dimensionalization; it is unused in the actual equations (the upstream dimensional balance is already implicit in the polynomial coefficient units, see below) — omitted here for fidelity to the equation set rather than to the constant set.\n\nUnit balance of Eq. 4.83 (verified): jordan_linear_coeff [m^3/kg] × ρ_sno [kg/m^3] is dimensionless, and jordan_quad_coeff [m^6/kg^2] × ρ_sno² [kg^2/m^6] is dimensionless, so the bracketed factor in Eq. 4.83 is dimensionless and the outer multiplication by (λ_ice_const - λ_air) [W/(m*K)] yields W/(m*K) as required.\n\nUnicode `Δz` (layer thickness) is preserved from upstream — peer ESM components in this rig (snow_soil_blended_heat_capacity.esm uses Δz, freezing_point_depression.esm uses Δz, snow_melt_no_layers.esm uses Δt) already use unicode in identifiers and the schema's identifier pattern allows it. Unicode `ρ_sno` and `λ_snow` are likewise preserved from the upstream output variable names.\n\nObservability classification: this component is functionally observed-only — the three output variables are each given by a single algebraic equation in terms of the parameters (the `(t)` time index has no role since there are no derivatives). Test scenarios use `time_span: [0, 1]` and sample at t=0 to mirror the convention used by sibling observed-only ESM files in this rig (snow_soil_blended_heat_capacity.esm, freezing_point_depression.esm, waste_heat_allocation.esm).\n\nTolerance rationale (model-level rel=1e-9): observed-only algebraic system (no ODE integration); Eqs. 4.84 and 4.87 are one addition + one division each, and Eq. 4.83 evaluates a degree-2 polynomial in ρ_sno followed by one multiplication and one addition — all IEEE-754 ULP-level (~1e-16) roundoff. 1e-9 leaves comfortable headroom above ULP roundoff and matches the convention used by sibling observed-only files (snow_soil_blended_heat_capacity.esm uses 1e-10 for its single-equation case, but waste_heat_allocation.esm and freezing_point_depression.esm both use 1e-9 for multi-equation cases). The upstream test asserts `rtol = 1e-10` on ρ_sno (test/roof_wall_road_snow_temperatures_test.jl:182) and `rtol = 1e-6` on λ_snow and c_snow (test:189, 194); the walker's runtime tolerances (reltol=1e-10, abstol=1e-12) comfortably support the tighter 1e-10 we use on the assertion level.\n\nDomain constraint: Δz > 0 is required (the equations have Δz in the denominator). The upstream component does not assert this guard and neither does this `.esm` — the upstream geometry submodel is responsible for keeping Δz positive. All test fixtures here use Δz ∈ [0.02, 0.5] m, well within the physically meaningful CLMU range. ρ_sno and c_snow are non-negative iff w_ice, w_liq ≥ 0, but the equations do not assert this — the upstream snow-mass tracker is responsible for keeping the masses non-negative; tests here use w_ice, w_liq ≥ 0 throughout."
  },
  "tolerance": {
    "rel": 1e-09
  },
  "variables": {
    "w_ice": {
      "type": "parameter",
      "units": "kg/m^2",
      "default": 0.0,
      "description": "Ice mass per unit area in the snow layer (Oleson §4.3 input)"
    },
    "w_liq": {
      "type": "parameter",
      "units": "kg/m^2",
      "default": 0.0,
      "description": "Liquid water mass per unit area in the snow layer (Oleson §4.3 input)"
    },
    "Δz": {
      "type": "parameter",
      "units": "m",
      "default": 1.0,
      "description": "Snow layer thickness (must be > 0; 1.0 m default chosen so divide-by-Δz is well-defined when w_ice and w_liq are at their zero defaults)"
    },
    "C_liq": {
      "type": "parameter",
      "units": "J/(kg*K)",
      "default": 4188.0,
      "description": "Specific heat of liquid water (Oleson et al. 2010 Table 1.4 — 4188.0 J/(kg*K))"
    },
    "C_ice": {
      "type": "parameter",
      "units": "J/(kg*K)",
      "default": 2117.27,
      "description": "Specific heat of ice (Oleson et al. 2010 Table 1.4 — 2117.27 J/(kg*K))"
    },
    "λ_air": {
      "type": "parameter",
      "units": "W/(m*K)",
      "default": 0.023,
      "description": "Thermal conductivity of air (Oleson et al. 2010 Table 1.4 — 0.023 W/(m*K); the ρ_sno → 0 limit of Eq. 4.83)"
    },
    "λ_ice_const": {
      "type": "parameter",
      "units": "W/(m*K)",
      "default": 2.29,
      "description": "Thermal conductivity of ice (Oleson et al. 2010 Table 1.4 — 2.29 W/(m*K); supplies the (λ_ice - λ_air) factor of Eq. 4.83)"
    },
    "jordan_linear_coeff": {
      "type": "parameter",
      "units": "m^3/kg",
      "default": 7.75e-05,
      "description": "Jordan (1991) linear density coefficient in Eq. 4.83 (7.75e-5 m^3/kg)"
    },
    "jordan_quad_coeff": {
      "type": "parameter",
      "units": "m^6/kg^2",
      "default": 1.105e-06,
      "description": "Jordan (1991) quadratic density coefficient in Eq. 4.83 (1.105e-6 m^6/kg^2)"
    },
    "ρ_sno": {
      "type": "unknown",
      "units": "kg/m^3",
      "description": "Snow bulk density (Oleson Eq. 4.84): (w_ice + w_liq) / Δz"
    },
    "λ_snow": {
      "type": "unknown",
      "units": "W/(m*K)",
      "description": "Snow thermal conductivity (Oleson Eq. 4.83, Jordan 1991): λ_air + (a·ρ + b·ρ²)·(λ_ice - λ_air) with a = 7.75e-5 m^3/kg and b = 1.105e-6 m^6/kg^2"
    },
    "c_snow": {
      "type": "unknown",
      "units": "J/(m^3*K)",
      "description": "Snow volumetric heat capacity (Oleson Eq. 4.87): C_ice · (w_ice/Δz) + C_liq · (w_liq/Δz)"
    }
  },
  "equations": [
    {
      "lhs": "ρ_sno",
      "rhs": {
        "op": "/",
        "args": [
          {
            "op": "+",
            "args": [
              "w_ice",
              "w_liq"
            ]
          },
          "Δz"
        ]
      }
    },
    {
      "lhs": "λ_snow",
      "rhs": {
        "op": "+",
        "args": [
          "λ_air",
          {
            "op": "*",
            "args": [
              {
                "op": "+",
                "args": [
                  {
                    "op": "*",
                    "args": [
                      "jordan_linear_coeff",
                      "ρ_sno"
                    ]
                  },
                  {
                    "op": "*",
                    "args": [
                      "jordan_quad_coeff",
                      {
                        "op": "^",
                        "args": [
                          "ρ_sno",
                          2
                        ]
                      }
                    ]
                  }
                ]
              },
              {
                "op": "-",
                "args": [
                  "λ_ice_const",
                  "λ_air"
                ]
              }
            ]
          }
        ]
      }
    },
    {
      "lhs": "c_snow",
      "rhs": {
        "op": "+",
        "args": [
          {
            "op": "*",
            "args": [
              "C_ice",
              {
                "op": "/",
                "args": [
                  "w_ice",
                  "Δz"
                ]
              }
            ]
          },
          {
            "op": "*",
            "args": [
              "C_liq",
              {
                "op": "/",
                "args": [
                  "w_liq",
                  "Δz"
                ]
              }
            ]
          }
        ]
      }
    }
  ],
  "tests": [
    {
      "id": "upstream_equation_verification",
      "description": "Reproduces upstream `SnowThermalProperties - Equation Verification` test (UrbanCanopy.jl test/roof_wall_road_snow_temperatures_test.jl:164-199). Inputs: w_ice = 10.0 kg/m^2, w_liq = 0.0 kg/m^2, Δz = 0.1 m. Expected ρ_sno = (10 + 0) / 0.1 = 100 kg/m^3, λ_snow = 0.023 + (7.75e-5·100 + 1.105e-6·10000)·(2.29 - 0.023) = 0.023 + 0.0188·2.267 = 0.0656196 W/(m*K), c_snow = (10/0.1)·2117.27 + 0 = 211727.0 J/(m^3*K). Anchors fidelity to the upstream Julia component at the canonical fixture point and exercises all three equations simultaneously.",
      "parameter_overrides": {
        "w_ice": 10.0,
        "w_liq": 0.0,
        "Δz": 0.1
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "ρ_sno",
          "time": 0.0,
          "expected": 100.0
        },
        {
          "variable": "λ_snow",
          "time": 0.0,
          "expected": 0.0656196
        },
        {
          "variable": "c_snow",
          "time": 0.0,
          "expected": 211727.0
        }
      ]
    },
    {
      "id": "upstream_conductivity_in_air_ice_band",
      "description": "Reproduces the bounds-checking assertions of the upstream `Equation Verification` test (test:197-198): for any physically realistic snow density (here ρ_sno = 100 from w_ice=10, w_liq=0, Δz=0.1), λ_snow must satisfy λ_air < λ_snow < λ_ice_const. This is a direct consequence of Eq. 4.83: the polynomial factor in ρ is strictly between 0 and 1 for ρ_sno in [0, ~525] kg/m^3 (the physical range — pure ice density is 917 kg/m^3, but snow bulk densities top out near 500 kg/m^3 in compacted firn). At ρ_sno = 100: λ_snow = 0.0656196 > 0.023 = λ_air and λ_snow = 0.0656196 < 2.29 = λ_ice_const, both strictly. Anchored as an exact-value check on the same fixture.",
      "parameter_overrides": {
        "w_ice": 10.0,
        "w_liq": 0.0,
        "Δz": 0.1
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "λ_snow",
          "time": 0.0,
          "expected": 0.0656196
        }
      ]
    },
    {
      "id": "upstream_density_monotonicity_low",
      "description": "First anchor of the upstream `SnowThermalProperties - Density Monotonicity` test (UrbanCanopy.jl test/roof_wall_road_snow_temperatures_test.jl:201-215). Low-density anchor: w_ice = 5.0 kg/m^2, w_liq = 0.0, Δz = 0.1 m → ρ_sno = 50 kg/m^3, λ_snow = 0.023 + (7.75e-5·50 + 1.105e-6·2500)·2.267 = 0.023 + 0.0066375·2.267 = 0.0380472125 W/(m*K), c_snow = (5/0.1)·2117.27 = 105863.5 J/(m^3*K). Paired with `upstream_density_monotonicity_high` (ρ_sno = 300): low values of λ_snow and c_snow at low density confirm the monotone-in-ρ relation of Eqs. 4.83 and 4.87.",
      "parameter_overrides": {
        "w_ice": 5.0,
        "w_liq": 0.0,
        "Δz": 0.1
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "ρ_sno",
          "time": 0.0,
          "expected": 50.0
        },
        {
          "variable": "λ_snow",
          "time": 0.0,
          "expected": 0.0380472125
        },
        {
          "variable": "c_snow",
          "time": 0.0,
          "expected": 105863.5
        }
      ]
    },
    {
      "id": "upstream_density_monotonicity_high",
      "description": "Second anchor of the upstream `Density Monotonicity` test (UrbanCanopy.jl test/roof_wall_road_snow_temperatures_test.jl:201-215). High-density anchor: w_ice = 30.0 kg/m^2, w_liq = 0.0, Δz = 0.1 m → ρ_sno = 300 kg/m^3, λ_snow = 0.023 + (7.75e-5·300 + 1.105e-6·90000)·2.267 = 0.023 + 0.1227·2.267 = 0.3011609 W/(m*K), c_snow = (30/0.1)·2117.27 = 635181.0 J/(m^3*K). Paired with `upstream_density_monotonicity_low` (ρ_sno = 50): 0.30 > 0.038 and 635181 > 105863.5 anchor the monotone-increasing relation between (λ_snow, c_snow) and ρ_sno mandated by Eqs. 4.83 and 4.87.",
      "parameter_overrides": {
        "w_ice": 30.0,
        "w_liq": 0.0,
        "Δz": 0.1
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "ρ_sno",
          "time": 0.0,
          "expected": 300.0
        },
        {
          "variable": "λ_snow",
          "time": 0.0,
          "expected": 0.3011609
        },
        {
          "variable": "c_snow",
          "time": 0.0,
          "expected": 635181.0
        }
      ]
    },
    {
      "id": "zero_snow_air_limit",
      "description": "Empty snow layer (w_ice = w_liq = 0). With Δz > 0, ρ_sno = 0 and Eq. 4.83 collapses to the pure-air limit λ_snow = λ_air = 0.023 W/(m*K) (the polynomial-in-ρ factor vanishes). c_snow = 0 by Eq. 4.87. Anchors the no-mass limit and verifies no spurious additive constant has been introduced into either of the three equations. Δz is taken at its model default (1.0 m) so the divide-by-Δz term is well-defined.",
      "parameter_overrides": {
        "w_ice": 0.0,
        "w_liq": 0.0,
        "Δz": 1.0
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "ρ_sno",
          "time": 0.0,
          "expected": 0.0,
          "tolerance": {
            "abs": 1e-12
          }
        },
        {
          "variable": "λ_snow",
          "time": 0.0,
          "expected": 0.023
        },
        {
          "variable": "c_snow",
          "time": 0.0,
          "expected": 0.0,
          "tolerance": {
            "abs": 1e-12
          }
        }
      ]
    },
    {
      "id": "mixed_ice_and_liquid",
      "description": "Wet-snow regime: equal masses of ice and liquid water (w_ice = w_liq = 5 kg/m^2) at Δz = 0.1 m. ρ_sno = (5+5)/0.1 = 100 kg/m^3 (same density as `upstream_equation_verification`, so λ_snow is identical — λ_snow depends only on bulk density). c_snow = (5/0.1)·2117.27 + (5/0.1)·4188.0 = 105863.5 + 209400.0 = 315263.5 J/(m^3*K) — exercises both terms of Eq. 4.87 simultaneously and shows that adding liquid at fixed density increases c_snow by the C_liq/C_ice ratio (~1.978) weighted by the liquid fraction.",
      "parameter_overrides": {
        "w_ice": 5.0,
        "w_liq": 5.0,
        "Δz": 0.1
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "ρ_sno",
          "time": 0.0,
          "expected": 100.0
        },
        {
          "variable": "λ_snow",
          "time": 0.0,
          "expected": 0.0656196
        },
        {
          "variable": "c_snow",
          "time": 0.0,
          "expected": 315263.5
        }
      ]
    },
    {
      "id": "all_liquid_no_ice",
      "description": "All-liquid limit (slush): w_ice = 0, w_liq = 10 kg/m^2 at Δz = 0.1 m. ρ_sno = 100 (same as the ice-only fixture — Eq. 4.84 sums ice and liquid symmetrically), so λ_snow = 0.0656196 W/(m*K) again. c_snow = (10/0.1)·4188.0 = 418800.0 J/(m^3*K) — pure C_liq contribution from Eq. 4.87, ~1.978× larger than the ice-only c_snow at the same density (211727.0). Confirms that the C_ice and C_liq terms of Eq. 4.87 are decoupled by their respective mass channels.",
      "parameter_overrides": {
        "w_ice": 0.0,
        "w_liq": 10.0,
        "Δz": 0.1
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "ρ_sno",
          "time": 0.0,
          "expected": 100.0
        },
        {
          "variable": "λ_snow",
          "time": 0.0,
          "expected": 0.0656196
        },
        {
          "variable": "c_snow",
          "time": 0.0,
          "expected": 418800.0
        }
      ]
    },
    {
      "id": "thin_layer_same_density",
      "description": "Thin layer (Δz = 0.02 m) with proportionally lower mass (w_ice = 1.0 kg/m^2): produces the same bulk density (ρ_sno = 50 kg/m^3) as `upstream_density_monotonicity_low` (Δz = 0.1, w_ice = 5.0), hence identical λ_snow and c_snow (the equations depend on the ratios w_ice/Δz and w_liq/Δz, not on the absolute layer thickness). Verifies the Δz scaling property of Eqs. 4.84, 4.83, 4.87 — halving both Δz and w_ice leaves the thermal properties unchanged.",
      "parameter_overrides": {
        "w_ice": 1.0,
        "w_liq": 0.0,
        "Δz": 0.02
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "ρ_sno",
          "time": 0.0,
          "expected": 50.0
        },
        {
          "variable": "λ_snow",
          "time": 0.0,
          "expected": 0.0380472125
        },
        {
          "variable": "c_snow",
          "time": 0.0,
          "expected": 105863.5
        }
      ]
    },
    {
      "id": "thick_layer_high_total_mass",
      "description": "Thick old-snow layer with substantial mass: Δz = 0.5 m, w_ice = 50 kg/m^2, w_liq = 10 kg/m^2 → ρ_sno = 60/0.5 = 120 kg/m^3 (typical of seasonal old snow, between fresh-snow 50 and firn 300). λ_snow = 0.023 + (7.75e-5·120 + 1.105e-6·14400)·2.267 = 0.023 + 0.02491·2.267 = 0.08015560399999999 W/(m*K). c_snow = (50/0.5)·2117.27 + (10/0.5)·4188.0 = 211727 + 83760 = 295487.0 J/(m^3*K). Exercises the model at a thicker, mixed-phase regime where both Eq. 4.83 polynomial terms contribute non-trivially and both Eq. 4.87 mass channels are active.",
      "parameter_overrides": {
        "w_ice": 50.0,
        "w_liq": 10.0,
        "Δz": 0.5
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "assertions": [
        {
          "variable": "ρ_sno",
          "time": 0.0,
          "expected": 120.0
        },
        {
          "variable": "λ_snow",
          "time": 0.0,
          "expected": 0.08015560399999999
        },
        {
          "variable": "c_snow",
          "time": 0.0,
          "expected": 295487.0
        }
      ]
    }
  ],
  "analyses": [
    {
      "id": "thermal_properties_vs_density",
      "description": "Sweep snow bulk density via w_ice across the full CLMU range (0-50 kg/m^2 at Δz = 0.1 m → ρ_sno = 0-500 kg/m^3) with w_liq = 0. Surfaces the canonical Jordan (1991) λ-ρ curve (Eq. 4.83): a quadratic in ρ_sno that rises smoothly from λ_air at ρ = 0 to ~1.5 W/(m*K) at firn-like ρ = 500. c_snow rises linearly with w_ice (Eq. 4.87, pure-ice branch). Together these reproduce the two anchor curves used in §4.3 of the CLM Tech Note for snowpack thermal evolution.",
      "initial_state": {},
      "parameters": {
        "w_liq": 0.0,
        "Δz": 0.1
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "parameter_sweep": {
        "type": "cartesian",
        "dimensions": [
          {
            "parameter": "w_ice",
            "range": {
              "start": 0.0,
              "stop": 50.0,
              "count": 26,
              "scale": "linear"
            }
          }
        ]
      },
      "plots": [
        {
          "id": "lambda_vs_density",
          "type": "line",
          "description": "λ_snow vs w_ice (ρ_sno = w_ice / 0.1 at fixed Δz): the Jordan (1991) quadratic curve of Eq. 4.83, rising from λ_air at zero mass to ~1.5 W/(m*K) at the firn limit.",
          "x": {
            "variable": "w_ice",
            "label": "w_ice (kg/m^2)"
          },
          "y": {
            "variable": "λ_snow",
            "label": "λ_snow (W/(m*K))"
          }
        },
        {
          "id": "c_snow_vs_w_ice",
          "type": "line",
          "description": "c_snow vs w_ice at w_liq = 0: linear in w_ice with slope C_ice/Δz = 21172.7 per Eq. 4.87 (pure-ice channel only).",
          "x": {
            "variable": "w_ice",
            "label": "w_ice (kg/m^2)"
          },
          "y": {
            "variable": "c_snow",
            "label": "c_snow (J/(m^3*K))"
          }
        }
      ]
    },
    {
      "id": "heat_capacity_two_d_sweep",
      "description": "Joint sweep over w_ice and w_liq at fixed Δz = 0.1 m. Surfaces the planar additive structure of Eq. 4.87: c_snow is linear in each mass channel with slopes C_ice/Δz = 21172.7 (ice) and C_liq/Δz = 41880.0 (liquid). Iso-c_snow contours are straight lines C_ice·w_ice + C_liq·w_liq = const. The C_liq/C_ice ratio (~1.978) gives liquid water nearly twice the volumetric-heat-capacity-per-unit-mass weight of ice — the basis for the phase-change latent-heat term in §4.3 of the CLM Tech Note.",
      "initial_state": {},
      "parameters": {
        "Δz": 0.1
      },
      "time_span": {
        "start": 0.0,
        "end": 1.0
      },
      "parameter_sweep": {
        "type": "cartesian",
        "dimensions": [
          {
            "parameter": "w_ice",
            "range": {
              "start": 0.0,
              "stop": 30.0,
              "count": 11,
              "scale": "linear"
            }
          },
          {
            "parameter": "w_liq",
            "range": {
              "start": 0.0,
              "stop": 15.0,
              "count": 11,
              "scale": "linear"
            }
          }
        ]
      },
      "plots": [
        {
          "id": "c_snow_heatmap",
          "type": "heatmap",
          "description": "c_snow as a function of ice and liquid mass at fixed Δz: planar surface with slopes C_ice/Δz and C_liq/Δz per Eq. 4.87. Iso-c_snow contours are straight lines C_ice·w_ice + C_liq·w_liq = const.",
          "x": {
            "variable": "w_ice",
            "label": "w_ice (kg/m^2)"
          },
          "y": {
            "variable": "w_liq",
            "label": "w_liq (kg/m^2)"
          },
          "value": {
            "variable": "c_snow",
            "reduce": "final"
          }
        }
      ]
    }
  ]
}