About plMapcalc
plMapcalc is a standalone raster map calculator. It works on Linux, macOS, and Windows. You write a Python expression; plMapcalc executes it independently for every pixel of one or more input raster layers, producing one or more output layers.
The Python edition replaces the original C/TCC runtime compiler with numba JIT, and OpenMP with numba prange, while keeping full compatibility with the original command-line interface.
What plMapcalc can do
- Combine or transform any number of raster layers with arbitrary Python expressions
- Compute statistics (mean, sum, histogram) across the entire raster using memory cells
- Reclassify layers using lookup tables loaded from files
- Compute neighbourhood operators (Laplace, slope, …) via layer shifting
- Perform multi-pass algorithms (histogram equalisation, area assignment, Voronoi) with
RESTART() - Process arbitrarily large rasters using tile-based streaming I/O
C version vs Python version
| Component | Original C edition | Python edition |
|---|---|---|
| Expression language | C (compiled by TCC at runtime) | Python (compiled by numba JIT) |
| Parallel pixel loop | OpenMP #pragma omp parallel for | numba prange over tile |
| I/O granularity | Row by row (GDAL per-row calls) | 256-row tiles, async prefetch + write |
| Thread control | -t N → omp_set_num_threads(N) | -t N → numba.set_num_threads(N) |
| MEM with writes | Serial OpenMP (critical section) | Serial @njit kernel |
| Raster I/O library | GDAL C API (dynamic dlopen) | rasterio |
| Platforms | Linux, Windows | Linux, macOS, Windows (Python ≥ 3.9) |
| GPU acceleration | — | --gpu via numba.cuda (optional, NVIDIA only) |
Three execution modes
Parallel CPU kernel — nogil thread bands
When the cell expression does not write to MEM, the parallel kernel is
selected automatically. The tile is split into horizontal bands; each band runs in its own
Python thread calling an @njit(nogil=True) function. The GIL is released so
threads execute truly in parallel. Use -t N to set the band count.
Serial CPU kernel — sequential @njit
When the expression writes to MEM (detected by scanning for the pattern
MEM[…]), the serial kernel is used. Pixels are processed row by row, left
to right, so a write in pixel k is visible to pixel k+1 — matching the
original C semantics. The loop is still compiled by @njit, so it is much
faster than pure Python.
GPU kernel — numba.cuda
Activated by --gpu. Each CUDA thread handles one pixel; an entire tile
is dispatched to the GPU as a single kernel launch. Thread blocks are
16 × 16 pixels; the grid covers the full tile. Host ↔ device transfers
happen per tile — constant arrays (nodata values, geotransform) are cached on the device
across tiles to minimise PCIe traffic. MEM[] is synchronised back to the
CPU after every tile so --execute-end can read statistics.
Mode selection is automatic. If CUDA is unavailable or the expression
writes to MEM[], --gpu falls back to the CPU parallel kernel
with a warning. You never need to change your expression; only the flag changes.
Tile-based I/O
Instead of reading one row at a time (as in the original C version), the Python edition reads 256 rows per rasterio call. Two input tile buffers alternate (ping-pong): one is being processed by the JIT kernel while the other is being filled by a background I/O thread. Output tiles are written asynchronously after each compute step.
Memory cells (MEM)
An optional float64 array of any size, shared across all pixels and across
iterations. Pre-load from a text file with -r; save after processing with
-s. Used for reclassification tables, statistics accumulators, point
coordinates for Voronoi, and more.
Multi-pass processing
Call RESTART() inside --execute-end to repeat the full scan.
ITERATION() returns the current pass number (starting at 1), enabling
different behaviour on each pass — for example, accumulating a histogram in pass 1 and
applying it in pass 2.
License and authors
plMapcalc is open-source software. Original C version and design by Paweł Netzel. Python port maintains full compatibility with the original CLI.