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

C version vs Python version

ComponentOriginal C editionPython edition
Expression languageC (compiled by TCC at runtime)Python (compiled by numba JIT)
Parallel pixel loopOpenMP #pragma omp parallel fornumba prange over tile
I/O granularityRow by row (GDAL per-row calls)256-row tiles, async prefetch + write
Thread control-t Nomp_set_num_threads(N)-t Nnumba.set_num_threads(N)
MEM with writesSerial OpenMP (critical section)Serial @njit kernel
Raster I/O libraryGDAL C API (dynamic dlopen)rasterio
PlatformsLinux, WindowsLinux, 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.