Quick Overview#
This section provides a brief end-to-end example of the alsDB workflow: ingesting LAZ files, querying points, and computing a Canopy Height Model. For detailed explanations refer to alsDB Fundamentals.
Setup#
import alsdb
from alsdb import ALSDatabase, ALSProvider
from alsdb.storage import ALSZarrStore
alsdb.setup_logging() # INFO-level logging to stderr
Ingest a LAZ tile#
alsdb.ALSDatabase reads the LAZ header automatically to extract the acquisition year, CRS, and bounding box. The TileDB array is created on first write.
db = ALSDatabase(storage_type="local", uri="my_array")
db.ingest("path/to/tile.laz")
To ingest a full directory in parallel:
from pathlib import Path
paths = sorted(Path("/data/als/").glob("*.laz"))
db.ingest_many(paths, max_workers=8, consolidate_every=50)
Already-ingested files (tracked in the manifest) are skipped automatically.
Query points#
alsdb.ALSProvider queries the TileDB array by bounding box and year.
reader = ALSProvider(storage_type="local", uri="my_array")
# All points in a bounding box (returns pandas DataFrame)
df = reader.query_bbox(308_000, 4_688_000, 310_000, 4_690_000)
# Restrict to a single survey year
df = reader.query_bbox(308_000, 4_688_000, 310_000, 4_690_000, year=2021)
# Which survey years are stored?
print(reader.available_years()) # e.g. [2019, 2021, 2023]
# As xarray Dataset
ds = reader.to_xarray(308_000, 4_688_000, 310_000, 4_690_000, year=2021)
Compute a Canopy Height Model#
All processing functions write directly to an ALSZarrStore: a Zarr v3 hierarchy that holds multiple resolutions and survey years.
from alsdb.processing.chm import compute_chm
store = ALSZarrStore("output/forest.zarr")
compute_chm(
provider=reader,
store=store,
resolution=1.0,
bbox=(308_000, 4_688_000, 310_000, 4_690_000),
year=2021,
)
For a large area, split into sub-tiles with a parallel worker pool:
compute_chm(
provider=reader,
store=store,
resolution=1.0,
year=2021,
tile_size=500.0, # 500 m sub-tiles
tile_buffer=50.0, # 50 m buffer for accurate HAG at tile edges
n_workers=4,
)
Read the result as xarray#
ds = store.to_dataset(resolution=1.0) # coords: time, y, x
chm = ds["chm"].sel(time=2021) # DataArray (ny, nx)
# CRS is attached via rioxarray if available
print(ds.rio.crs)
Compute biomass and structural metrics#
from alsdb.processing.biomass import compute_biomass, compute_metrics
# 16 LiDAR structural metrics at 10 m:
# height percentiles (h50, h75, h95, hmax, hmean), canopy cover (cc),
# point density, FHD, VCI, CRR, and 6 height-stratum proportions (pv_*)
compute_metrics(
provider=reader, store=store, resolution=10.0, year=2021,
min_density=1.0, # mask cells below 1 pt m⁻² (optional guard)
)
# Aboveground biomass using the Næsset (2002) model
# Always calibrate coefficients against field plots before scientific use
compute_biomass(provider=reader, store=store, resolution=10.0, year=2021)
# Read results
ds10 = store.to_dataset(resolution=10.0)
agb = ds10["biomass"].sel(time=2021)
Multi-temporal change detection#
alsdb.processing.change.compute_change computes pixel-wise absolute change,
relative change, and a gain/loss flag between two survey years:
from alsdb.processing.change import compute_change
# Compute CHM change 2017 → 2021, ignoring sub-0.5 m differences
compute_change(store, "chm", year_from=2017, year_to=2021,
resolution=1.0, min_delta=0.5, pct_min_abs=0.5)
# Three products are written: chm_delta, chm_delta_pct, chm_change_flag
ds = store.to_dataset(resolution=1.0)
gain_loss = ds["chm_change_flag"].sel(time=2021) # +1 gain, −1 loss, 0 stable
Simulate large-footprint waveforms#
from alsdb.processing.waveform import simulate_waveform
result = simulate_waveform(
provider=reader,
center_x=308_500.0, center_y=4_689_000.0,
footprint_radius=12.5,
year=2021,
)
print(result.rh[98]) # RH98 height above ground (m)
print(result.cover) # canopy cover fraction
—
For a complete explanation of these concepts, including the two-layer storage architecture, tiling strategy, and overwrite semantics, continue to alsDB Fundamentals.