rast — SIMD raster tile processing for Erlang.
Public façade. Two layers live behind it:
1. Kernels (rast_nif) — bounded, per-tile, binary-first
operations in Rust. Fused and typed: u16 source data is widened to
f32 inside the kernel, and compound indices such as NDVI are computed
in a single pass over the tile.
2. Orchestration (planned: rast_coordinator / rast_worker /
rast_gdal) — bounded-memory, demand-driven tiling of a whole scene,
with GDAL doing the windowed I/O.
Only layer 1 is implemented in this scaffold. Layer 2 functions return
{error, not_implemented} and document the intended contract.
f32_bin() = binary()
little-endian IEEE-754 f32 samples
reason() = length_mismatch | odd_length | empty | not_implemented | term()
u16_bin() = binary()
little-endian uint16 samples
| convolve_f32/6 | Valid 2-D cross-correlation of an f32 tile (SrcW × SrcH) with a
KW × KH f32 kernel. |
| decode_u16/2 | Widen a u16 tile to an f32 tile, scaling each sample by Scale. |
| ndvi_f32/2 | NDVI of two f32 tiles (NIR, Red) → f32 tile, fused single pass. |
| ndvi_u16/2 | NDVI of two u16 tiles (NIR, Red) → f32 tile, fused single pass. |
| pad_replicate_f32/7 | Replicate-pad an f32 tile by Left/Top/Right/Bottom rows/cols. |
| process_band/3 | Process a whole scene through GDAL, tile-by-tile, under a fixed memory budget, writing a GeoTIFF result. |
| process_convolution/5 | Convolve a whole scene with a KW × KH f32 kernel, writing an f32
GeoTIFF. |
| process_tiles/3 | Generic bounded-memory tiling engine. |
| version/0 |
convolve_f32(Src::f32_bin(), SrcW::pos_integer(), SrcH::pos_integer(), Kernel::f32_bin(), KW::pos_integer(), KH::pos_integer()) -> {ok, f32_bin()} | {error, reason()}
Valid 2-D cross-correlation of an f32 tile (SrcW × SrcH) with a
KW × KH f32 kernel. Output (SrcW-KW+1) × (SrcH-KH+1).
Widen a u16 tile to an f32 tile, scaling each sample by Scale.
NDVI of two f32 tiles (NIR, Red) → f32 tile, fused single pass.
NDVI of two u16 tiles (NIR, Red) → f32 tile, fused single pass.
pad_replicate_f32(Src::f32_bin(), W::pos_integer(), H::pos_integer(), L::non_neg_integer(), T::non_neg_integer(), R::non_neg_integer(), B::non_neg_integer()) -> {ok, f32_bin()} | {error, reason()}
Replicate-pad an f32 tile by Left/Top/Right/Bottom rows/cols.
Output (W+Left+Right) × (H+Top+Bottom).
process_band(Sources::[file:filename()], Dst::file:filename(), Opts::map()) -> {ok, file:filename()} | {error, reason()}
Process a whole scene through GDAL, tile-by-tile, under a fixed memory budget, writing a GeoTIFF result.
Sources :: [file:filename()] %% 1 for {decode,_}, 2 (NIR, Red) for ndvi
Dst :: file:filename() %% output GeoTIFF path
Opts :: #{op := ndvi | {decode, Scale :: float()},
tile => {W, H}, %% default {512, 512}
workers => pos_integer()}
workers × tile_bytes
(ARCHITECTURE.md §5). Requires GDAL — see rast_gdal.
process_convolution(Src::file:filename(), Dst::file:filename(), Kernel::f32_bin(), X4::{pos_integer(), pos_integer()}, Opts::map()) -> {ok, file:filename()} | {error, reason()}
Convolve a whole scene with a KW × KH f32 kernel, writing an f32
GeoTIFF. Each output tile reads a source window grown by the halo, so tiles
compose without seams (ARCHITECTURE.md §5).
Src :: file:filename() %% UInt16 or Float32 single band
Kernel :: f32_bin() %% KW*KH little-endian f32, row-major
Opts :: #{tile => {W,H}, workers => pos_integer(),
pad => clamp | valid} %% default clamp
pad => clamp (default): full-size W × H output; the apron at the scene
border is synthesized by edge replication. pad => valid: no border
synthesis, output shrinks to (W-KW+1) × (H-KH+1).
process_tiles(Tiles::[term()], Funs::rast_worker:funs(), Opts::map()) -> {ok, #{tiles := non_neg_integer(), workers := pos_integer()}} | {error, term()}
Generic bounded-memory tiling engine.
Drives a demand-driven worker pool over Tiles: each worker pulls a tile,
reads it, runs the kernel, and writes the result, repeating until the
tiles are exhausted. Peak memory is bounded by Workers × tile_bytes — no
more than one tile is resident per worker (ARCHITECTURE.md §5).
This is the source-agnostic core: Funs injects the I/O so the same engine
serves an in-memory source (tests) or the GDAL bridge (production).
Funs :: #{read := fun((Tile) -> {ok, binary()} | {error, term()}),
kernel := fun((binary()) -> {ok, binary()} | {error, term()}),
write := fun((Tile, binary()) -> ok | {error, term()})}
Opts :: #{workers => pos_integer()} %% default: dirty CPU schedulers
version() -> binary()
Generated by EDoc