ExponentialGrid
Exponential vertical grid discretization for pervious and impervious road columns in the urban canopy thermal solver. Computes node depths (Oleson Eq. 4.8), layer thicknesses (Eq. 4.6), and interface depths (Eq. 4.7) with a scaling factor f_s = 0.025 m that produces finer resolution near the surface — a requirement because urban roads overlie real soil and the near-surface diurnal cycle dominates thermal exchange. Migrated from UrbanCanopy.jl@9200edd4 src/roof_wall_road_snow_temperatures.jl:890 (`ExponentialGrid` @component). Implements Oleson et al. (2010, CLM Tech Note Ch. 4 §4.1, Eqs. 4.6-4.8). Parameterized as observed-only: f_s is the only input parameter; z_node_i, dz_layer_i, z_interface_j are algebraic outputs. Upstream `N` (number of layers) is fixed to its canonical default 15 for serialization (per-N templating lives outside the ESM scalar schema and is not needed for the urban-canopy use case).
Description
Exponential vertical grid discretization for pervious and impervious road columns in the urban canopy thermal solver. Computes node depths (Oleson Eq. 4.8), layer thicknesses (Eq. 4.6), and interface depths (Eq. 4.7) with a scaling factor f_s = 0.025 m that produces finer resolution near the surface — a requirement because urban roads overlie real soil and the near-surface diurnal cycle dominates thermal exchange. Migrated from UrbanCanopy.jl@9200edd4 src/roof_wall_road_snow_temperatures.jl:890 (ExponentialGrid @component). Implements Oleson et al. (2010, CLM Tech Note Ch. 4 §4.1, Eqs. 4.6-4.8). Parameterized as observed-only: f_s is the only input parameter; z_node_i, dz_layer_i, z_interface_j are algebraic outputs. Upstream N (number of layers) is fixed to its canonical default 15 for serialization (per-N templating lives outside the ESM scalar schema and is not needed for the urban-canopy use case).
Reference
_source_ref: UrbanCanopy.jl@9200edd4f15609f20339d3a7d104de8064544310:src/roof_wall_road_snow_temperatures.jl:890
Upstream ExponentialGrid is an MTK @component parameterized by N (default 15) declaring three arrays of @variables: z_node(t)[1:N], Δz_layer(t)[1:N], z_interface(t)[1:N+1] (with N+1 entries where index j maps to paper i=j-1). The single @constants declaration is f_s = 0.025 m, the scaling factor of Oleson Eq. 4.8.
For ESM serialization N is fixed to the canonical upstream default of 15; the .esm encodes the full unfolded scalar system: 15 z_node states, 15 dz_layer states, 16 z_interface states (46 algebraic equations total). This matches the unfold-to-scalar convention adopted by the other urban-canopy temps migrations in this rig (e.g. snow_melt_no_layers.esm, total_phase_change_energy.esm). The upstream Julia tests (roof_wall_road_snow_temperatures_test.jl:978-1036) exercise multiple N values (3, 5, 15); the inner-layer formulas are identical for any N (only dz_layer_15 and z_interface_16 depend explicitly on N), so the assertion values pinned here at N=15 are also exact for any larger N choice — i.e. moving to a templated representation in the future will not invalidate the per-layer reference values, only extend them.
Unicode Δ in Δz_layer is renamed dz_layer for ASCII identifier names per the urban-canopy convention (matches snow_density.esm renaming ρ → rho); the ESM identifier-pattern allows unicode but the rig-wide ASCII convention keeps editor and tooling support uniform.
Observability classification: this component is functionally observed-only — every output state is given by a single algebraic equation in terms of the parameter f_s and other state outputs (the (t) time index has no role since there is no derivative anywhere). Test scenarios use time_span: [0, 1] and sample at t=0 to mirror the convention used by sibling observed-only files (snow_melt_no_layers.esm, total_phase_change_energy.esm, snow_density.esm).
Tolerance rationale (model-level rel=1e-9): observed-only algebraic system (no ODE integration); the only non-trivial roundoff path is the chain exp(0.5*(i-0.5)) → subtraction by 1 → multiplication by f_s → linear combination — IEEE-754 ULP precision throughout. 1e-9 leaves comfortable headroom above ULP roundoff and matches the convention used by sibling observed-only files in this rig (total_phase_change_energy.esm, etc.). The deepest layer (z_node_15 = ~35.18 m) carries the largest absolute roundoff but the relative error stays well below 1e-9. Tighter abs: 1.0e-12 is asserted on z_interface_1 = 0 (exactly zero by construction) so the assertion does not silently accept a stuck-at-1e-3 regression._
Parameters
| Name | Units | Default | Description |
|---|---|---|---|
f_s | m | 0.025 | Scaling factor for road grid (Oleson et al. 2010 Eq. 4.8) |
Observed
| Name | Units | Default | Description |
|---|---|---|---|
z_node_1 | m | Node depth of layer 1 (Oleson Eq. 4.8): z_1 = f_s * (exp(0.5*(1 - 0.5)) - 1) | |
z_node_2 | m | Node depth of layer 2 (Oleson Eq. 4.8): z_2 = f_s * (exp(0.5*(2 - 0.5)) - 1) | |
z_node_3 | m | Node depth of layer 3 (Oleson Eq. 4.8): z_3 = f_s * (exp(0.5*(3 - 0.5)) - 1) | |
z_node_4 | m | Node depth of layer 4 (Oleson Eq. 4.8): z_4 = f_s * (exp(0.5*(4 - 0.5)) - 1) | |
z_node_5 | m | Node depth of layer 5 (Oleson Eq. 4.8): z_5 = f_s * (exp(0.5*(5 - 0.5)) - 1) | |
z_node_6 | m | Node depth of layer 6 (Oleson Eq. 4.8): z_6 = f_s * (exp(0.5*(6 - 0.5)) - 1) | |
z_node_7 | m | Node depth of layer 7 (Oleson Eq. 4.8): z_7 = f_s * (exp(0.5*(7 - 0.5)) - 1) | |
z_node_8 | m | Node depth of layer 8 (Oleson Eq. 4.8): z_8 = f_s * (exp(0.5*(8 - 0.5)) - 1) | |
z_node_9 | m | Node depth of layer 9 (Oleson Eq. 4.8): z_9 = f_s * (exp(0.5*(9 - 0.5)) - 1) | |
z_node_10 | m | Node depth of layer 10 (Oleson Eq. 4.8): z_10 = f_s * (exp(0.5*(10 - 0.5)) - 1) | |
z_node_11 | m | Node depth of layer 11 (Oleson Eq. 4.8): z_11 = f_s * (exp(0.5*(11 - 0.5)) - 1) | |
z_node_12 | m | Node depth of layer 12 (Oleson Eq. 4.8): z_12 = f_s * (exp(0.5*(12 - 0.5)) - 1) | |
z_node_13 | m | Node depth of layer 13 (Oleson Eq. 4.8): z_13 = f_s * (exp(0.5*(13 - 0.5)) - 1) | |
z_node_14 | m | Node depth of layer 14 (Oleson Eq. 4.8): z_14 = f_s * (exp(0.5*(14 - 0.5)) - 1) | |
z_node_15 | m | Node depth of layer 15 (Oleson Eq. 4.8): z_15 = f_s * (exp(0.5*(15 - 0.5)) - 1) | |
dz_layer_1 | m | Layer thickness 1 (Oleson Eq. 4.6, top): 0.5 * (z_node_1 + z_node_2) | |
dz_layer_2 | m | Layer thickness 2 (Oleson Eq. 4.6, interior): 0.5 * (z_node_3 - z_node_1) | |
dz_layer_3 | m | Layer thickness 3 (Oleson Eq. 4.6, interior): 0.5 * (z_node_4 - z_node_2) | |
dz_layer_4 | m | Layer thickness 4 (Oleson Eq. 4.6, interior): 0.5 * (z_node_5 - z_node_3) | |
dz_layer_5 | m | Layer thickness 5 (Oleson Eq. 4.6, interior): 0.5 * (z_node_6 - z_node_4) | |
dz_layer_6 | m | Layer thickness 6 (Oleson Eq. 4.6, interior): 0.5 * (z_node_7 - z_node_5) | |
dz_layer_7 | m | Layer thickness 7 (Oleson Eq. 4.6, interior): 0.5 * (z_node_8 - z_node_6) | |
dz_layer_8 | m | Layer thickness 8 (Oleson Eq. 4.6, interior): 0.5 * (z_node_9 - z_node_7) | |
dz_layer_9 | m | Layer thickness 9 (Oleson Eq. 4.6, interior): 0.5 * (z_node_10 - z_node_8) | |
dz_layer_10 | m | Layer thickness 10 (Oleson Eq. 4.6, interior): 0.5 * (z_node_11 - z_node_9) | |
dz_layer_11 | m | Layer thickness 11 (Oleson Eq. 4.6, interior): 0.5 * (z_node_12 - z_node_10) | |
dz_layer_12 | m | Layer thickness 12 (Oleson Eq. 4.6, interior): 0.5 * (z_node_13 - z_node_11) | |
dz_layer_13 | m | Layer thickness 13 (Oleson Eq. 4.6, interior): 0.5 * (z_node_14 - z_node_12) | |
dz_layer_14 | m | Layer thickness 14 (Oleson Eq. 4.6, interior): 0.5 * (z_node_15 - z_node_13) | |
dz_layer_15 | m | Layer thickness 15 (Oleson Eq. 4.6, bottom): z_node_15 - z_node_14 | |
z_interface_1 | m | Interface depth z_{h,0} = 0 (Oleson Eq. 4.7, surface) | |
z_interface_2 | m | Interface depth z_{h,1} = 0.5 * (z_node_1 + z_node_2) (Oleson Eq. 4.7) | |
z_interface_3 | m | Interface depth z_{h,2} = 0.5 * (z_node_2 + z_node_3) (Oleson Eq. 4.7) | |
z_interface_4 | m | Interface depth z_{h,3} = 0.5 * (z_node_3 + z_node_4) (Oleson Eq. 4.7) | |
z_interface_5 | m | Interface depth z_{h,4} = 0.5 * (z_node_4 + z_node_5) (Oleson Eq. 4.7) | |
z_interface_6 | m | Interface depth z_{h,5} = 0.5 * (z_node_5 + z_node_6) (Oleson Eq. 4.7) | |
z_interface_7 | m | Interface depth z_{h,6} = 0.5 * (z_node_6 + z_node_7) (Oleson Eq. 4.7) | |
z_interface_8 | m | Interface depth z_{h,7} = 0.5 * (z_node_7 + z_node_8) (Oleson Eq. 4.7) | |
z_interface_9 | m | Interface depth z_{h,8} = 0.5 * (z_node_8 + z_node_9) (Oleson Eq. 4.7) | |
z_interface_10 | m | Interface depth z_{h,9} = 0.5 * (z_node_9 + z_node_10) (Oleson Eq. 4.7) | |
z_interface_11 | m | Interface depth z_{h,10} = 0.5 * (z_node_10 + z_node_11) (Oleson Eq. 4.7) | |
z_interface_12 | m | Interface depth z_{h,11} = 0.5 * (z_node_11 + z_node_12) (Oleson Eq. 4.7) | |
z_interface_13 | m | Interface depth z_{h,12} = 0.5 * (z_node_12 + z_node_13) (Oleson Eq. 4.7) | |
z_interface_14 | m | Interface depth z_{h,13} = 0.5 * (z_node_13 + z_node_14) (Oleson Eq. 4.7) | |
z_interface_15 | m | Interface depth z_{h,14} = 0.5 * (z_node_14 + z_node_15) (Oleson Eq. 4.7) | |
z_interface_16 | m | Interface depth z_{h,15} = z_node_15 + 0.5 * dz_layer_15 (Oleson Eq. 4.7, bottom) |
Observed expressions
$$ z_{node\,1} = f_{s} \cdot \left(e^{0.25} - 1.0\right) $$Node depth of layer 1 (Oleson Eq. 4.8): z_1 = f_s * (exp(0.5*(1 - 0.5)) - 1)
$$ z_{node\,2} = f_{s} \cdot \left(e^{0.75} - 1.0\right) $$Node depth of layer 2 (Oleson Eq. 4.8): z_2 = f_s * (exp(0.5*(2 - 0.5)) - 1)
$$ z_{node\,3} = f_{s} \cdot \left(e^{1.25} - 1.0\right) $$Node depth of layer 3 (Oleson Eq. 4.8): z_3 = f_s * (exp(0.5*(3 - 0.5)) - 1)
$$ z_{node\,4} = f_{s} \cdot \left(e^{1.75} - 1.0\right) $$Node depth of layer 4 (Oleson Eq. 4.8): z_4 = f_s * (exp(0.5*(4 - 0.5)) - 1)
$$ z_{node\,5} = f_{s} \cdot \left(e^{2.25} - 1.0\right) $$Node depth of layer 5 (Oleson Eq. 4.8): z_5 = f_s * (exp(0.5*(5 - 0.5)) - 1)
$$ z_{node\,6} = f_{s} \cdot \left(e^{2.75} - 1.0\right) $$Node depth of layer 6 (Oleson Eq. 4.8): z_6 = f_s * (exp(0.5*(6 - 0.5)) - 1)
$$ z_{node\,7} = f_{s} \cdot \left(e^{3.25} - 1.0\right) $$Node depth of layer 7 (Oleson Eq. 4.8): z_7 = f_s * (exp(0.5*(7 - 0.5)) - 1)
$$ z_{node\,8} = f_{s} \cdot \left(e^{3.75} - 1.0\right) $$Node depth of layer 8 (Oleson Eq. 4.8): z_8 = f_s * (exp(0.5*(8 - 0.5)) - 1)
$$ z_{node\,9} = f_{s} \cdot \left(e^{4.25} - 1.0\right) $$Node depth of layer 9 (Oleson Eq. 4.8): z_9 = f_s * (exp(0.5*(9 - 0.5)) - 1)
$$ z_{node\,10} = f_{s} \cdot \left(e^{4.75} - 1.0\right) $$Node depth of layer 10 (Oleson Eq. 4.8): z_10 = f_s * (exp(0.5*(10 - 0.5)) - 1)
$$ z_{node\,11} = f_{s} \cdot \left(e^{5.25} - 1.0\right) $$Node depth of layer 11 (Oleson Eq. 4.8): z_11 = f_s * (exp(0.5*(11 - 0.5)) - 1)
$$ z_{node\,12} = f_{s} \cdot \left(e^{5.75} - 1.0\right) $$Node depth of layer 12 (Oleson Eq. 4.8): z_12 = f_s * (exp(0.5*(12 - 0.5)) - 1)
$$ z_{node\,13} = f_{s} \cdot \left(e^{6.25} - 1.0\right) $$Node depth of layer 13 (Oleson Eq. 4.8): z_13 = f_s * (exp(0.5*(13 - 0.5)) - 1)
$$ z_{node\,14} = f_{s} \cdot \left(e^{6.75} - 1.0\right) $$Node depth of layer 14 (Oleson Eq. 4.8): z_14 = f_s * (exp(0.5*(14 - 0.5)) - 1)
$$ z_{node\,15} = f_{s} \cdot \left(e^{7.25} - 1.0\right) $$Node depth of layer 15 (Oleson Eq. 4.8): z_15 = f_s * (exp(0.5*(15 - 0.5)) - 1)
$$ dz_{layer\,1} = 0.5 \cdot \left(z_{node\,1} + z_{node\,2}\right) $$Layer thickness 1 (Oleson Eq. 4.6, top): 0.5 * (z_node_1 + z_node_2)
$$ dz_{layer\,2} = 0.5 \cdot \left(z_{node\,3} - z_{node\,1}\right) $$Layer thickness 2 (Oleson Eq. 4.6, interior): 0.5 * (z_node_3 - z_node_1)
$$ dz_{layer\,3} = 0.5 \cdot \left(z_{node\,4} - z_{node\,2}\right) $$Layer thickness 3 (Oleson Eq. 4.6, interior): 0.5 * (z_node_4 - z_node_2)
$$ dz_{layer\,4} = 0.5 \cdot \left(z_{node\,5} - z_{node\,3}\right) $$Layer thickness 4 (Oleson Eq. 4.6, interior): 0.5 * (z_node_5 - z_node_3)
$$ dz_{layer\,5} = 0.5 \cdot \left(z_{node\,6} - z_{node\,4}\right) $$Layer thickness 5 (Oleson Eq. 4.6, interior): 0.5 * (z_node_6 - z_node_4)
$$ dz_{layer\,6} = 0.5 \cdot \left(z_{node\,7} - z_{node\,5}\right) $$Layer thickness 6 (Oleson Eq. 4.6, interior): 0.5 * (z_node_7 - z_node_5)
$$ dz_{layer\,7} = 0.5 \cdot \left(z_{node\,8} - z_{node\,6}\right) $$Layer thickness 7 (Oleson Eq. 4.6, interior): 0.5 * (z_node_8 - z_node_6)
$$ dz_{layer\,8} = 0.5 \cdot \left(z_{node\,9} - z_{node\,7}\right) $$Layer thickness 8 (Oleson Eq. 4.6, interior): 0.5 * (z_node_9 - z_node_7)
$$ dz_{layer\,9} = 0.5 \cdot \left(z_{node\,10} - z_{node\,8}\right) $$Layer thickness 9 (Oleson Eq. 4.6, interior): 0.5 * (z_node_10 - z_node_8)
$$ dz_{layer\,10} = 0.5 \cdot \left(z_{node\,11} - z_{node\,9}\right) $$Layer thickness 10 (Oleson Eq. 4.6, interior): 0.5 * (z_node_11 - z_node_9)
$$ dz_{layer\,11} = 0.5 \cdot \left(z_{node\,12} - z_{node\,10}\right) $$Layer thickness 11 (Oleson Eq. 4.6, interior): 0.5 * (z_node_12 - z_node_10)
$$ dz_{layer\,12} = 0.5 \cdot \left(z_{node\,13} - z_{node\,11}\right) $$Layer thickness 12 (Oleson Eq. 4.6, interior): 0.5 * (z_node_13 - z_node_11)
$$ dz_{layer\,13} = 0.5 \cdot \left(z_{node\,14} - z_{node\,12}\right) $$Layer thickness 13 (Oleson Eq. 4.6, interior): 0.5 * (z_node_14 - z_node_12)
$$ dz_{layer\,14} = 0.5 \cdot \left(z_{node\,15} - z_{node\,13}\right) $$Layer thickness 14 (Oleson Eq. 4.6, interior): 0.5 * (z_node_15 - z_node_13)
$$ dz_{layer\,15} = z_{node\,15} - z_{node\,14} $$Layer thickness 15 (Oleson Eq. 4.6, bottom): z_node_15 - z_node_14
$$ z_{interface\,1} = 0.0 $$Interface depth z{h,0} = 0 (Oleson Eq. 4.7, surface)_
$$ z_{interface\,2} = 0.5 \cdot \left(z_{node\,1} + z_{node\,2}\right) $$Interface depth z{h,1} = 0.5 * (z_node_1 + z_node_2) (Oleson Eq. 4.7)_
$$ z_{interface\,3} = 0.5 \cdot \left(z_{node\,2} + z_{node\,3}\right) $$Interface depth z{h,2} = 0.5 * (z_node_2 + z_node_3) (Oleson Eq. 4.7)_
$$ z_{interface\,4} = 0.5 \cdot \left(z_{node\,3} + z_{node\,4}\right) $$Interface depth z{h,3} = 0.5 * (z_node_3 + z_node_4) (Oleson Eq. 4.7)_
$$ z_{interface\,5} = 0.5 \cdot \left(z_{node\,4} + z_{node\,5}\right) $$Interface depth z{h,4} = 0.5 * (z_node_4 + z_node_5) (Oleson Eq. 4.7)_
$$ z_{interface\,6} = 0.5 \cdot \left(z_{node\,5} + z_{node\,6}\right) $$Interface depth z{h,5} = 0.5 * (z_node_5 + z_node_6) (Oleson Eq. 4.7)_
$$ z_{interface\,7} = 0.5 \cdot \left(z_{node\,6} + z_{node\,7}\right) $$Interface depth z{h,6} = 0.5 * (z_node_6 + z_node_7) (Oleson Eq. 4.7)_
$$ z_{interface\,8} = 0.5 \cdot \left(z_{node\,7} + z_{node\,8}\right) $$Interface depth z{h,7} = 0.5 * (z_node_7 + z_node_8) (Oleson Eq. 4.7)_
$$ z_{interface\,9} = 0.5 \cdot \left(z_{node\,8} + z_{node\,9}\right) $$Interface depth z{h,8} = 0.5 * (z_node_8 + z_node_9) (Oleson Eq. 4.7)_
$$ z_{interface\,10} = 0.5 \cdot \left(z_{node\,9} + z_{node\,10}\right) $$Interface depth z{h,9} = 0.5 * (z_node_9 + z_node_10) (Oleson Eq. 4.7)_
$$ z_{interface\,11} = 0.5 \cdot \left(z_{node\,10} + z_{node\,11}\right) $$Interface depth z{h,10} = 0.5 * (z_node_10 + z_node_11) (Oleson Eq. 4.7)_
$$ z_{interface\,12} = 0.5 \cdot \left(z_{node\,11} + z_{node\,12}\right) $$Interface depth z{h,11} = 0.5 * (z_node_11 + z_node_12) (Oleson Eq. 4.7)_
$$ z_{interface\,13} = 0.5 \cdot \left(z_{node\,12} + z_{node\,13}\right) $$Interface depth z{h,12} = 0.5 * (z_node_12 + z_node_13) (Oleson Eq. 4.7)_
$$ z_{interface\,14} = 0.5 \cdot \left(z_{node\,13} + z_{node\,14}\right) $$Interface depth z{h,13} = 0.5 * (z_node_13 + z_node_14) (Oleson Eq. 4.7)_
$$ z_{interface\,15} = 0.5 \cdot \left(z_{node\,14} + z_{node\,15}\right) $$Interface depth z{h,14} = 0.5 * (z_node_14 + z_node_15) (Oleson Eq. 4.7)_
$$ z_{interface\,16} = z_{node\,15} + 0.5 \cdot dz_{layer\,15} $$Interface depth z{h,15} = z_node_15 + 0.5 * dz_layer_15 (Oleson Eq. 4.7, bottom)_
Raw .esm
Raw .esm JSON (this component)
{
"reference": {
"notes": "source_ref: UrbanCanopy.jl@9200edd4f15609f20339d3a7d104de8064544310:src/roof_wall_road_snow_temperatures.jl:890\nUpstream `ExponentialGrid` is an MTK `@component` parameterized by N (default 15) declaring three arrays of `@variables`: z_node(t)[1:N], Δz_layer(t)[1:N], z_interface(t)[1:N+1] (with N+1 entries where index j maps to paper i=j-1). The single `@constants` declaration is f_s = 0.025 m, the scaling factor of Oleson Eq. 4.8.\n\nFor ESM serialization N is fixed to the canonical upstream default of 15; the .esm encodes the full unfolded scalar system: 15 z_node states, 15 dz_layer states, 16 z_interface states (46 algebraic equations total). This matches the unfold-to-scalar convention adopted by the other urban-canopy temps migrations in this rig (e.g. snow_melt_no_layers.esm, total_phase_change_energy.esm). The upstream Julia tests (roof_wall_road_snow_temperatures_test.jl:978-1036) exercise multiple N values (3, 5, 15); the inner-layer formulas are identical for any N (only dz_layer_15 and z_interface_16 depend explicitly on N), so the assertion values pinned here at N=15 are also exact for any larger N choice — i.e. moving to a templated representation in the future will not invalidate the per-layer reference values, only extend them.\n\nUnicode `Δ` in `Δz_layer` is renamed `dz_layer` for ASCII identifier names per the urban-canopy convention (matches snow_density.esm renaming `ρ` → `rho`); the ESM identifier-pattern allows unicode but the rig-wide ASCII convention keeps editor and tooling support uniform.\n\nObservability classification: this component is functionally observed-only — every output state is given by a single algebraic equation in terms of the parameter f_s and other state outputs (the `(t)` time index has no role since there is no derivative anywhere). Test scenarios use `time_span: [0, 1]` and sample at t=0 to mirror the convention used by sibling observed-only files (snow_melt_no_layers.esm, total_phase_change_energy.esm, snow_density.esm).\n\nTolerance rationale (model-level rel=1e-9): observed-only algebraic system (no ODE integration); the only non-trivial roundoff path is the chain `exp(0.5*(i-0.5))` → subtraction by 1 → multiplication by f_s → linear combination — IEEE-754 ULP precision throughout. 1e-9 leaves comfortable headroom above ULP roundoff and matches the convention used by sibling observed-only files in this rig (total_phase_change_energy.esm, etc.). The deepest layer (z_node_15 = ~35.18 m) carries the largest absolute roundoff but the relative error stays well below 1e-9. Tighter `abs: 1.0e-12` is asserted on z_interface_1 = 0 (exactly zero by construction) so the assertion does not silently accept a stuck-at-1e-3 regression."
},
"tolerance": {
"rel": 1e-09
},
"variables": {
"f_s": {
"type": "parameter",
"units": "m",
"default": 0.025,
"description": "Scaling factor for road grid (Oleson et al. 2010 Eq. 4.8)"
},
"z_node_1": {
"type": "unknown",
"units": "m",
"description": "Node depth of layer 1 (Oleson Eq. 4.8): z_1 = f_s * (exp(0.5*(1 - 0.5)) - 1)"
},
"z_node_2": {
"type": "unknown",
"units": "m",
"description": "Node depth of layer 2 (Oleson Eq. 4.8): z_2 = f_s * (exp(0.5*(2 - 0.5)) - 1)"
},
"z_node_3": {
"type": "unknown",
"units": "m",
"description": "Node depth of layer 3 (Oleson Eq. 4.8): z_3 = f_s * (exp(0.5*(3 - 0.5)) - 1)"
},
"z_node_4": {
"type": "unknown",
"units": "m",
"description": "Node depth of layer 4 (Oleson Eq. 4.8): z_4 = f_s * (exp(0.5*(4 - 0.5)) - 1)"
},
"z_node_5": {
"type": "unknown",
"units": "m",
"description": "Node depth of layer 5 (Oleson Eq. 4.8): z_5 = f_s * (exp(0.5*(5 - 0.5)) - 1)"
},
"z_node_6": {
"type": "unknown",
"units": "m",
"description": "Node depth of layer 6 (Oleson Eq. 4.8): z_6 = f_s * (exp(0.5*(6 - 0.5)) - 1)"
},
"z_node_7": {
"type": "unknown",
"units": "m",
"description": "Node depth of layer 7 (Oleson Eq. 4.8): z_7 = f_s * (exp(0.5*(7 - 0.5)) - 1)"
},
"z_node_8": {
"type": "unknown",
"units": "m",
"description": "Node depth of layer 8 (Oleson Eq. 4.8): z_8 = f_s * (exp(0.5*(8 - 0.5)) - 1)"
},
"z_node_9": {
"type": "unknown",
"units": "m",
"description": "Node depth of layer 9 (Oleson Eq. 4.8): z_9 = f_s * (exp(0.5*(9 - 0.5)) - 1)"
},
"z_node_10": {
"type": "unknown",
"units": "m",
"description": "Node depth of layer 10 (Oleson Eq. 4.8): z_10 = f_s * (exp(0.5*(10 - 0.5)) - 1)"
},
"z_node_11": {
"type": "unknown",
"units": "m",
"description": "Node depth of layer 11 (Oleson Eq. 4.8): z_11 = f_s * (exp(0.5*(11 - 0.5)) - 1)"
},
"z_node_12": {
"type": "unknown",
"units": "m",
"description": "Node depth of layer 12 (Oleson Eq. 4.8): z_12 = f_s * (exp(0.5*(12 - 0.5)) - 1)"
},
"z_node_13": {
"type": "unknown",
"units": "m",
"description": "Node depth of layer 13 (Oleson Eq. 4.8): z_13 = f_s * (exp(0.5*(13 - 0.5)) - 1)"
},
"z_node_14": {
"type": "unknown",
"units": "m",
"description": "Node depth of layer 14 (Oleson Eq. 4.8): z_14 = f_s * (exp(0.5*(14 - 0.5)) - 1)"
},
"z_node_15": {
"type": "unknown",
"units": "m",
"description": "Node depth of layer 15 (Oleson Eq. 4.8): z_15 = f_s * (exp(0.5*(15 - 0.5)) - 1)"
},
"dz_layer_1": {
"type": "unknown",
"units": "m",
"description": "Layer thickness 1 (Oleson Eq. 4.6, top): 0.5 * (z_node_1 + z_node_2)"
},
"dz_layer_2": {
"type": "unknown",
"units": "m",
"description": "Layer thickness 2 (Oleson Eq. 4.6, interior): 0.5 * (z_node_3 - z_node_1)"
},
"dz_layer_3": {
"type": "unknown",
"units": "m",
"description": "Layer thickness 3 (Oleson Eq. 4.6, interior): 0.5 * (z_node_4 - z_node_2)"
},
"dz_layer_4": {
"type": "unknown",
"units": "m",
"description": "Layer thickness 4 (Oleson Eq. 4.6, interior): 0.5 * (z_node_5 - z_node_3)"
},
"dz_layer_5": {
"type": "unknown",
"units": "m",
"description": "Layer thickness 5 (Oleson Eq. 4.6, interior): 0.5 * (z_node_6 - z_node_4)"
},
"dz_layer_6": {
"type": "unknown",
"units": "m",
"description": "Layer thickness 6 (Oleson Eq. 4.6, interior): 0.5 * (z_node_7 - z_node_5)"
},
"dz_layer_7": {
"type": "unknown",
"units": "m",
"description": "Layer thickness 7 (Oleson Eq. 4.6, interior): 0.5 * (z_node_8 - z_node_6)"
},
"dz_layer_8": {
"type": "unknown",
"units": "m",
"description": "Layer thickness 8 (Oleson Eq. 4.6, interior): 0.5 * (z_node_9 - z_node_7)"
},
"dz_layer_9": {
"type": "unknown",
"units": "m",
"description": "Layer thickness 9 (Oleson Eq. 4.6, interior): 0.5 * (z_node_10 - z_node_8)"
},
"dz_layer_10": {
"type": "unknown",
"units": "m",
"description": "Layer thickness 10 (Oleson Eq. 4.6, interior): 0.5 * (z_node_11 - z_node_9)"
},
"dz_layer_11": {
"type": "unknown",
"units": "m",
"description": "Layer thickness 11 (Oleson Eq. 4.6, interior): 0.5 * (z_node_12 - z_node_10)"
},
"dz_layer_12": {
"type": "unknown",
"units": "m",
"description": "Layer thickness 12 (Oleson Eq. 4.6, interior): 0.5 * (z_node_13 - z_node_11)"
},
"dz_layer_13": {
"type": "unknown",
"units": "m",
"description": "Layer thickness 13 (Oleson Eq. 4.6, interior): 0.5 * (z_node_14 - z_node_12)"
},
"dz_layer_14": {
"type": "unknown",
"units": "m",
"description": "Layer thickness 14 (Oleson Eq. 4.6, interior): 0.5 * (z_node_15 - z_node_13)"
},
"dz_layer_15": {
"type": "unknown",
"units": "m",
"description": "Layer thickness 15 (Oleson Eq. 4.6, bottom): z_node_15 - z_node_14"
},
"z_interface_1": {
"type": "unknown",
"units": "m",
"description": "Interface depth z_{h,0} = 0 (Oleson Eq. 4.7, surface)"
},
"z_interface_2": {
"type": "unknown",
"units": "m",
"description": "Interface depth z_{h,1} = 0.5 * (z_node_1 + z_node_2) (Oleson Eq. 4.7)"
},
"z_interface_3": {
"type": "unknown",
"units": "m",
"description": "Interface depth z_{h,2} = 0.5 * (z_node_2 + z_node_3) (Oleson Eq. 4.7)"
},
"z_interface_4": {
"type": "unknown",
"units": "m",
"description": "Interface depth z_{h,3} = 0.5 * (z_node_3 + z_node_4) (Oleson Eq. 4.7)"
},
"z_interface_5": {
"type": "unknown",
"units": "m",
"description": "Interface depth z_{h,4} = 0.5 * (z_node_4 + z_node_5) (Oleson Eq. 4.7)"
},
"z_interface_6": {
"type": "unknown",
"units": "m",
"description": "Interface depth z_{h,5} = 0.5 * (z_node_5 + z_node_6) (Oleson Eq. 4.7)"
},
"z_interface_7": {
"type": "unknown",
"units": "m",
"description": "Interface depth z_{h,6} = 0.5 * (z_node_6 + z_node_7) (Oleson Eq. 4.7)"
},
"z_interface_8": {
"type": "unknown",
"units": "m",
"description": "Interface depth z_{h,7} = 0.5 * (z_node_7 + z_node_8) (Oleson Eq. 4.7)"
},
"z_interface_9": {
"type": "unknown",
"units": "m",
"description": "Interface depth z_{h,8} = 0.5 * (z_node_8 + z_node_9) (Oleson Eq. 4.7)"
},
"z_interface_10": {
"type": "unknown",
"units": "m",
"description": "Interface depth z_{h,9} = 0.5 * (z_node_9 + z_node_10) (Oleson Eq. 4.7)"
},
"z_interface_11": {
"type": "unknown",
"units": "m",
"description": "Interface depth z_{h,10} = 0.5 * (z_node_10 + z_node_11) (Oleson Eq. 4.7)"
},
"z_interface_12": {
"type": "unknown",
"units": "m",
"description": "Interface depth z_{h,11} = 0.5 * (z_node_11 + z_node_12) (Oleson Eq. 4.7)"
},
"z_interface_13": {
"type": "unknown",
"units": "m",
"description": "Interface depth z_{h,12} = 0.5 * (z_node_12 + z_node_13) (Oleson Eq. 4.7)"
},
"z_interface_14": {
"type": "unknown",
"units": "m",
"description": "Interface depth z_{h,13} = 0.5 * (z_node_13 + z_node_14) (Oleson Eq. 4.7)"
},
"z_interface_15": {
"type": "unknown",
"units": "m",
"description": "Interface depth z_{h,14} = 0.5 * (z_node_14 + z_node_15) (Oleson Eq. 4.7)"
},
"z_interface_16": {
"type": "unknown",
"units": "m",
"description": "Interface depth z_{h,15} = z_node_15 + 0.5 * dz_layer_15 (Oleson Eq. 4.7, bottom)"
}
},
"equations": [
{
"lhs": "z_node_1",
"rhs": {
"op": "*",
"args": [
"f_s",
{
"op": "-",
"args": [
{
"op": "exp",
"args": [
0.25
]
},
1.0
]
}
]
}
},
{
"lhs": "z_node_2",
"rhs": {
"op": "*",
"args": [
"f_s",
{
"op": "-",
"args": [
{
"op": "exp",
"args": [
0.75
]
},
1.0
]
}
]
}
},
{
"lhs": "z_node_3",
"rhs": {
"op": "*",
"args": [
"f_s",
{
"op": "-",
"args": [
{
"op": "exp",
"args": [
1.25
]
},
1.0
]
}
]
}
},
{
"lhs": "z_node_4",
"rhs": {
"op": "*",
"args": [
"f_s",
{
"op": "-",
"args": [
{
"op": "exp",
"args": [
1.75
]
},
1.0
]
}
]
}
},
{
"lhs": "z_node_5",
"rhs": {
"op": "*",
"args": [
"f_s",
{
"op": "-",
"args": [
{
"op": "exp",
"args": [
2.25
]
},
1.0
]
}
]
}
},
{
"lhs": "z_node_6",
"rhs": {
"op": "*",
"args": [
"f_s",
{
"op": "-",
"args": [
{
"op": "exp",
"args": [
2.75
]
},
1.0
]
}
]
}
},
{
"lhs": "z_node_7",
"rhs": {
"op": "*",
"args": [
"f_s",
{
"op": "-",
"args": [
{
"op": "exp",
"args": [
3.25
]
},
1.0
]
}
]
}
},
{
"lhs": "z_node_8",
"rhs": {
"op": "*",
"args": [
"f_s",
{
"op": "-",
"args": [
{
"op": "exp",
"args": [
3.75
]
},
1.0
]
}
]
}
},
{
"lhs": "z_node_9",
"rhs": {
"op": "*",
"args": [
"f_s",
{
"op": "-",
"args": [
{
"op": "exp",
"args": [
4.25
]
},
1.0
]
}
]
}
},
{
"lhs": "z_node_10",
"rhs": {
"op": "*",
"args": [
"f_s",
{
"op": "-",
"args": [
{
"op": "exp",
"args": [
4.75
]
},
1.0
]
}
]
}
},
{
"lhs": "z_node_11",
"rhs": {
"op": "*",
"args": [
"f_s",
{
"op": "-",
"args": [
{
"op": "exp",
"args": [
5.25
]
},
1.0
]
}
]
}
},
{
"lhs": "z_node_12",
"rhs": {
"op": "*",
"args": [
"f_s",
{
"op": "-",
"args": [
{
"op": "exp",
"args": [
5.75
]
},
1.0
]
}
]
}
},
{
"lhs": "z_node_13",
"rhs": {
"op": "*",
"args": [
"f_s",
{
"op": "-",
"args": [
{
"op": "exp",
"args": [
6.25
]
},
1.0
]
}
]
}
},
{
"lhs": "z_node_14",
"rhs": {
"op": "*",
"args": [
"f_s",
{
"op": "-",
"args": [
{
"op": "exp",
"args": [
6.75
]
},
1.0
]
}
]
}
},
{
"lhs": "z_node_15",
"rhs": {
"op": "*",
"args": [
"f_s",
{
"op": "-",
"args": [
{
"op": "exp",
"args": [
7.25
]
},
1.0
]
}
]
}
},
{
"lhs": "dz_layer_1",
"rhs": {
"op": "*",
"args": [
0.5,
{
"op": "+",
"args": [
"z_node_1",
"z_node_2"
]
}
]
}
},
{
"lhs": "dz_layer_2",
"rhs": {
"op": "*",
"args": [
0.5,
{
"op": "-",
"args": [
"z_node_3",
"z_node_1"
]
}
]
}
},
{
"lhs": "dz_layer_3",
"rhs": {
"op": "*",
"args": [
0.5,
{
"op": "-",
"args": [
"z_node_4",
"z_node_2"
]
}
]
}
},
{
"lhs": "dz_layer_4",
"rhs": {
"op": "*",
"args": [
0.5,
{
"op": "-",
"args": [
"z_node_5",
"z_node_3"
]
}
]
}
},
{
"lhs": "dz_layer_5",
"rhs": {
"op": "*",
"args": [
0.5,
{
"op": "-",
"args": [
"z_node_6",
"z_node_4"
]
}
]
}
},
{
"lhs": "dz_layer_6",
"rhs": {
"op": "*",
"args": [
0.5,
{
"op": "-",
"args": [
"z_node_7",
"z_node_5"
]
}
]
}
},
{
"lhs": "dz_layer_7",
"rhs": {
"op": "*",
"args": [
0.5,
{
"op": "-",
"args": [
"z_node_8",
"z_node_6"
]
}
]
}
},
{
"lhs": "dz_layer_8",
"rhs": {
"op": "*",
"args": [
0.5,
{
"op": "-",
"args": [
"z_node_9",
"z_node_7"
]
}
]
}
},
{
"lhs": "dz_layer_9",
"rhs": {
"op": "*",
"args": [
0.5,
{
"op": "-",
"args": [
"z_node_10",
"z_node_8"
]
}
]
}
},
{
"lhs": "dz_layer_10",
"rhs": {
"op": "*",
"args": [
0.5,
{
"op": "-",
"args": [
"z_node_11",
"z_node_9"
]
}
]
}
},
{
"lhs": "dz_layer_11",
"rhs": {
"op": "*",
"args": [
0.5,
{
"op": "-",
"args": [
"z_node_12",
"z_node_10"
]
}
]
}
},
{
"lhs": "dz_layer_12",
"rhs": {
"op": "*",
"args": [
0.5,
{
"op": "-",
"args": [
"z_node_13",
"z_node_11"
]
}
]
}
},
{
"lhs": "dz_layer_13",
"rhs": {
"op": "*",
"args": [
0.5,
{
"op": "-",
"args": [
"z_node_14",
"z_node_12"
]
}
]
}
},
{
"lhs": "dz_layer_14",
"rhs": {
"op": "*",
"args": [
0.5,
{
"op": "-",
"args": [
"z_node_15",
"z_node_13"
]
}
]
}
},
{
"lhs": "dz_layer_15",
"rhs": {
"op": "-",
"args": [
"z_node_15",
"z_node_14"
]
}
},
{
"lhs": "z_interface_1",
"rhs": 0.0
},
{
"lhs": "z_interface_2",
"rhs": {
"op": "*",
"args": [
0.5,
{
"op": "+",
"args": [
"z_node_1",
"z_node_2"
]
}
]
}
},
{
"lhs": "z_interface_3",
"rhs": {
"op": "*",
"args": [
0.5,
{
"op": "+",
"args": [
"z_node_2",
"z_node_3"
]
}
]
}
},
{
"lhs": "z_interface_4",
"rhs": {
"op": "*",
"args": [
0.5,
{
"op": "+",
"args": [
"z_node_3",
"z_node_4"
]
}
]
}
},
{
"lhs": "z_interface_5",
"rhs": {
"op": "*",
"args": [
0.5,
{
"op": "+",
"args": [
"z_node_4",
"z_node_5"
]
}
]
}
},
{
"lhs": "z_interface_6",
"rhs": {
"op": "*",
"args": [
0.5,
{
"op": "+",
"args": [
"z_node_5",
"z_node_6"
]
}
]
}
},
{
"lhs": "z_interface_7",
"rhs": {
"op": "*",
"args": [
0.5,
{
"op": "+",
"args": [
"z_node_6",
"z_node_7"
]
}
]
}
},
{
"lhs": "z_interface_8",
"rhs": {
"op": "*",
"args": [
0.5,
{
"op": "+",
"args": [
"z_node_7",
"z_node_8"
]
}
]
}
},
{
"lhs": "z_interface_9",
"rhs": {
"op": "*",
"args": [
0.5,
{
"op": "+",
"args": [
"z_node_8",
"z_node_9"
]
}
]
}
},
{
"lhs": "z_interface_10",
"rhs": {
"op": "*",
"args": [
0.5,
{
"op": "+",
"args": [
"z_node_9",
"z_node_10"
]
}
]
}
},
{
"lhs": "z_interface_11",
"rhs": {
"op": "*",
"args": [
0.5,
{
"op": "+",
"args": [
"z_node_10",
"z_node_11"
]
}
]
}
},
{
"lhs": "z_interface_12",
"rhs": {
"op": "*",
"args": [
0.5,
{
"op": "+",
"args": [
"z_node_11",
"z_node_12"
]
}
]
}
},
{
"lhs": "z_interface_13",
"rhs": {
"op": "*",
"args": [
0.5,
{
"op": "+",
"args": [
"z_node_12",
"z_node_13"
]
}
]
}
},
{
"lhs": "z_interface_14",
"rhs": {
"op": "*",
"args": [
0.5,
{
"op": "+",
"args": [
"z_node_13",
"z_node_14"
]
}
]
}
},
{
"lhs": "z_interface_15",
"rhs": {
"op": "*",
"args": [
0.5,
{
"op": "+",
"args": [
"z_node_14",
"z_node_15"
]
}
]
}
},
{
"lhs": "z_interface_16",
"rhs": {
"op": "+",
"args": [
"z_node_15",
{
"op": "*",
"args": [
0.5,
"dz_layer_15"
]
}
]
}
}
],
"tests": [
{
"id": "z_node_full_column",
"description": "Verifies Oleson Eq. 4.8 across all 15 grid layers: z_i = f_s * (exp(0.5*(i-0.5)) - 1) with f_s = 0.025 m. Reference values computed directly from the closed-form expression and matched to the upstream Julia component which integrates the same equation symbolically. This anchors the layer-node depth profile that drives the road-soil thermal grid in CLMU.",
"parameter_overrides": {},
"time_span": {
"start": 0.0,
"end": 1.0
},
"assertions": [
{
"variable": "z_node_1",
"time": 0.0,
"expected": 0.007100635417193535
},
{
"variable": "z_node_2",
"time": 0.0,
"expected": 0.02792500041531687
},
{
"variable": "z_node_3",
"time": 0.0,
"expected": 0.06225857393654604
},
{
"variable": "z_node_4",
"time": 0.0,
"expected": 0.11886506690014327
},
{
"variable": "z_node_5",
"time": 0.0,
"expected": 0.21219339590896316
},
{
"variable": "z_node_6",
"time": 0.0,
"expected": 0.3660657971047043
},
{
"variable": "z_node_7",
"time": 0.0,
"expected": 0.6197584979298266
},
{
"variable": "z_node_8",
"time": 0.0,
"expected": 1.0380270500015696
},
{
"variable": "z_node_9",
"time": 0.0,
"expected": 1.7276353086671965
},
{
"variable": "z_node_10",
"time": 0.0,
"expected": 2.8646071131796917
},
{
"variable": "z_node_11",
"time": 0.0,
"expected": 4.73915671146575
},
{
"variable": "z_node_12",
"time": 0.0,
"expected": 7.829766507142356
},
{
"variable": "z_node_13",
"time": 0.0,
"expected": 12.92532061670855
},
{
"variable": "z_node_14",
"time": 0.0,
"expected": 21.32646906315379
},
{
"variable": "z_node_15",
"time": 0.0,
"expected": 35.17762120511739
}
]
},
{
"id": "z_interface_surface_boundary",
"description": "Verifies the surface boundary condition: z_interface_1 = z_{h,0} = 0 m exactly (Oleson Eq. 4.7, paper index i=0). Tightened absolute tolerance to catch any stuck-at-nonzero regression in the boundary equation.",
"parameter_overrides": {},
"time_span": {
"start": 0.0,
"end": 1.0
},
"assertions": [
{
"variable": "z_interface_1",
"time": 0.0,
"expected": 0.0,
"tolerance": {
"abs": 1e-12
}
}
]
},
{
"id": "dz_layer_full_column",
"description": "Verifies Oleson Eq. 4.6 layer-thickness recurrence across all 15 layers: top layer dz_layer_1 = 0.5 * (z_node_1 + z_node_2), interior layers dz_layer_i = 0.5 * (z_node_{i+1} - z_node_{i-1}), bottom layer dz_layer_15 = z_node_15 - z_node_14. Anchors the layer-thickness profile that feeds heat-flux divergence and phase-change accounting in the urban canopy thermal solver.",
"parameter_overrides": {},
"time_span": {
"start": 0.0,
"end": 1.0
},
"assertions": [
{
"variable": "dz_layer_1",
"time": 0.0,
"expected": 0.017512817916255204
},
{
"variable": "dz_layer_2",
"time": 0.0,
"expected": 0.02757896925967625
},
{
"variable": "dz_layer_3",
"time": 0.0,
"expected": 0.0454700332424132
},
{
"variable": "dz_layer_4",
"time": 0.0,
"expected": 0.07496741098620856
},
{
"variable": "dz_layer_5",
"time": 0.0,
"expected": 0.12360036510228053
},
{
"variable": "dz_layer_6",
"time": 0.0,
"expected": 0.20378255101043175
},
{
"variable": "dz_layer_7",
"time": 0.0,
"expected": 0.33598062644843263
},
{
"variable": "dz_layer_8",
"time": 0.0,
"expected": 0.5539384053686849
},
{
"variable": "dz_layer_9",
"time": 0.0,
"expected": 0.9132900315890611
},
{
"variable": "dz_layer_10",
"time": 0.0,
"expected": 1.5057607013992766
},
{
"variable": "dz_layer_11",
"time": 0.0,
"expected": 2.482579696981332
},
{
"variable": "dz_layer_12",
"time": 0.0,
"expected": 4.0930819526214
},
{
"variable": "dz_layer_13",
"time": 0.0,
"expected": 6.7483512780057175
},
{
"variable": "dz_layer_14",
"time": 0.0,
"expected": 11.12615029420442
},
{
"variable": "dz_layer_15",
"time": 0.0,
"expected": 13.851152141963599
}
]
},
{
"id": "z_interface_full_column",
"description": "Verifies Oleson Eq. 4.7 interface-depth recurrence across all 16 interfaces: surface z_interface_1 = 0, interior z_interface_{i+1} = 0.5 * (z_node_i + z_node_{i+1}) for i = 1..14, and bottom z_interface_16 = z_node_15 + 0.5 * dz_layer_15. Anchors the interface positions used for inter-layer thermal-conductivity coupling.",
"parameter_overrides": {},
"time_span": {
"start": 0.0,
"end": 1.0
},
"assertions": [
{
"variable": "z_interface_1",
"time": 0.0,
"expected": 0.0,
"tolerance": {
"abs": 1e-12
}
},
{
"variable": "z_interface_2",
"time": 0.0,
"expected": 0.017512817916255204
},
{
"variable": "z_interface_3",
"time": 0.0,
"expected": 0.04509178717593146
},
{
"variable": "z_interface_4",
"time": 0.0,
"expected": 0.09056182041834465
},
{
"variable": "z_interface_5",
"time": 0.0,
"expected": 0.16552923140455322
},
{
"variable": "z_interface_6",
"time": 0.0,
"expected": 0.28912959650683373
},
{
"variable": "z_interface_7",
"time": 0.0,
"expected": 0.4929121475172655
},
{
"variable": "z_interface_8",
"time": 0.0,
"expected": 0.8288927739656982
},
{
"variable": "z_interface_9",
"time": 0.0,
"expected": 1.382831179334383
},
{
"variable": "z_interface_10",
"time": 0.0,
"expected": 2.2961212109234443
},
{
"variable": "z_interface_11",
"time": 0.0,
"expected": 3.8018819123227208
},
{
"variable": "z_interface_12",
"time": 0.0,
"expected": 6.284461609304053
},
{
"variable": "z_interface_13",
"time": 0.0,
"expected": 10.377543561925453
},
{
"variable": "z_interface_14",
"time": 0.0,
"expected": 17.12589483993117
},
{
"variable": "z_interface_15",
"time": 0.0,
"expected": 28.252045134135592
},
{
"variable": "z_interface_16",
"time": 0.0,
"expected": 42.10319727609919
}
]
},
{
"id": "monotonic_increasing_depths",
"description": "Spot-checks the monotonic-increasing-with-depth invariant of the exponential grid (upstream `ExponentialGrid - Increasing Depth` test, roof_wall_road_snow_temperatures_test.jl:1016): z_node_1 < z_node_7 < z_node_15 and z_interface_1 < z_interface_8 < z_interface_16. Asserted via the spot values at three depths each — the full-column tests above already pin every layer, this test documents the monotonicity contract for downstream consumers.",
"parameter_overrides": {},
"time_span": {
"start": 0.0,
"end": 1.0
},
"assertions": [
{
"variable": "z_node_1",
"time": 0.0,
"expected": 0.007100635417193535
},
{
"variable": "z_node_7",
"time": 0.0,
"expected": 0.6197584979298266
},
{
"variable": "z_node_15",
"time": 0.0,
"expected": 35.17762120511739
},
{
"variable": "z_interface_1",
"time": 0.0,
"expected": 0.0,
"tolerance": {
"abs": 1e-12
}
},
{
"variable": "z_interface_8",
"time": 0.0,
"expected": 0.8288927739656982
},
{
"variable": "z_interface_16",
"time": 0.0,
"expected": 42.10319727609919
}
]
},
{
"id": "f_s_doubled_scales_linearly",
"description": "Verifies the linear scaling of the grid with the f_s parameter: doubling f_s from 0.025 m to 0.05 m doubles every z_node value, since z_i = f_s * (exp(0.5*(i-0.5)) - 1) is linear in f_s. Spot-checks layers 1, 8, and 15 (top, middle, and bottom). Guards against regressions that pin the constant or break the linear coupling.",
"parameter_overrides": {
"f_s": 0.05
},
"time_span": {
"start": 0.0,
"end": 1.0
},
"assertions": [
{
"variable": "z_node_1",
"time": 0.0,
"expected": 0.01420127083438707
},
{
"variable": "z_node_8",
"time": 0.0,
"expected": 2.076054100003139
},
{
"variable": "z_node_15",
"time": 0.0,
"expected": 70.35524241023478
}
]
}
]
}