Use this skill to verify raster processing correctness, check nodata semantics, validate affine transforms, understand neighborhood operations, or answer domain questions about raster algorithms. This is the domain knowledge oracle for autonomous agents working on vibespatial-raster. Trigger on: "is this correct", "should this return", "nodata", "affine", "CRS", "neighborhood", "stencil", "focal", "morphology", "CCL", "connected component", "zonal", "rasterize", "polygonize", "marching squares".
Use this reference to verify whether a raster operation produces the correct result, to understand edge cases, or to validate design decisions.
Question: $ARGUMENTS
data: numpy or CuPy array of shape (height, width) or (bands, height, width)nodata: scalar sentinel value (same dtype as data) or Noneaffine: 6-parameter affine transform (a, b, c, d, e, f) mapping pixel -> worldcrs: coordinate reference system (pyproj.CRS or None)residency: HOST or DEVICEdiagnostics: list of RasterDiagnosticEvent.data.device_data()move_to(Residency.DEVICE, ...) for H->D transfercp.asnumpy() for final D->H at pipeline end.data on a DEVICE-resident raster (will raise or give stale data)add(a, b): if either pixel is nodata -> result is nodatawhere(condition, a, b): condition can reference nodata pixelsclassify(raster, breaks): nodata pixels remain nodata in output# On GPU: nullable mask pointer
d_mask = raster.device_nodata_mask() # CuPy bool array or None
# In kernel: if (nodata_mask != nullptr && nodata_mask[idx]) { output[idx] = nodata_val; return; }
isnan() in kernels, not == comparisonThe affine transform maps pixel coordinates to world coordinates:
world_x = a * col + b * row + c
world_y = d * col + e * row + f
Where:
a = pixel width (x-resolution)b = rotation (usually 0)c = x-coordinate of upper-left cornerd = rotation (usually 0)e = pixel height (negative for north-up, i.e., y decreases downward)f = y-coordinate of upper-left corner(col + 0.5, row + 0.5) in pixel spacec and f (origin shifts)a and esize = ceil(6 * sigma) | 1 (ensure odd)dz/dx = ((c + 2f + i) - (a + 2d + g)) / (8 * cell_size_x)
dz/dy = ((g + 2h + i) - (a + 2b + c)) / (8 * cell_size_y)
slope = arctan(sqrt(dz_dx^2 + dz_dy^2))
aspect = arctan2(-dz_dy, dz_dx)
abs(a) for x, abs(e) for y)(TILE_H + 2*halo, TILE_W + 2*halo)__syncthreads() after loading, before computationchanged flag (atomicOr)open(A) = dilate(erode(A))close(A) = erode(dilate(A))sieve(raster, min_size=10) removes components with < 10 pixels(col + 0.5, row + 0.5) transformed by affineadd(a, b), subtract(a, b), multiply(a, b), divide(a, b)apply(raster, func) — apply a Python function element-wisewhere(condition, true_val, false_val) — conditional selectionclassify(raster, breaks, labels) — reclassify by value ranges