Skip to content

Leaflux surface irradiance fails when terrain grid dimensions differ from the LAD grid #547

Description

@amarcozzi

Summary

irradiance.surface.relative grids fail in treevox whenever the supplied terrain/DEM grid does not have the exact same pixel dimensions as the source leaf-area-density (LAD) grid. The surface path assumes the DEM and LAD grids are already cell-for-cell aligned and passes the raw DEM array straight into leaflux, which rejects the shape mismatch.

Error (from treevox-v2-prod logs)

ValueError: Terrain dimensions must match leaf area grid dimensions.
Leaf area is (715, 703) and terrain is (173, 141)

Raised in leaflux/environment.py:318 (Environment.__init__Terrain(...)), reached via:

treevox/handlers/leaflux.py:442  run_leaflux -> _write_tiles
treevox/handlers/leaflux.py:331  _write_tiles -> _write_tile
treevox/handlers/leaflux.py:301  _write_tile -> _surface_irradiance
treevox/handlers/leaflux.py:232  _surface_irradiance -> Environment(..., terrain=Terrain(terrain), ...)

Root cause

_write_tile (want_surface=True) calls _read_terrain, which reads the DEM tile directly:

elev = dem_ds[ELEVATION_KEY][tile.pad_yx].values.astype(np.float32)
return (elev - job.z_origin) / job.vr

tile.pad_yx indexes the DEM with the LAD tile's padded (y, x) window, so the returned terrain only has the LAD's shape when the two grids share a resolution/extent. When they don't (the common case — e.g. a 2 m LAD grid voxelized from an inventory paired with a coarser topography grid), the DEM slice comes back at the DEM's own resolution and leaflux's Environment raises.

The canopy-only path (irradiance.canopy.relative, no terrain) is unaffected because it never touches _read_terrain/_surface_irradiance.

Suggested fix

In _read_terrain (or upstream in run_leaflux), resample/reproject the DEM onto the LAD grid so terrain is returned on the LAD grid's transform and shape before Terrain(...) is built — rather than assuming matching dimensions. Add a treevox integration test that pairs a fine LAD grid with a coarser DEM.

Repro

  1. Voxelize a tree inventory to a leaf_area_density grid at 2 m horizontal resolution.
  2. Create a topography grid in the same domain at a different resolution (e.g. 30 m native).
  3. Request a leaflux irradiance grid with bands=["irradiance.surface.relative"] and that terrain grid as the source terrain.
  4. The grid job fails with UNEXPECTED_FAILURE; treevox logs show the ValueError above.

Impact

Blocks end-to-end validation of the Fosberg 1-hr dead fuel moisture grid (#540), which consumes an irradiance.surface.relative grid. Tracked downstream in the SDK by silvxlabs/fastfuels-sdk-python#197 (held pending this fix).

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions