Concepts¶
What the pieces of moraine are and how they fit together. Ten minutes here save hours in the reference.
A collection of functions, not a workflow¶
There is no workflow that always gives a satisfactory InSAR result: decorrelation, atmosphere and strong deformation gradients defeat every fixed chain somewhere. moraine therefore is a collection of functions that each implement one technique (an amplitude dispersion index, a statistical test for homogeneous pixels, EMI phase linking, a deep learning filter, minimum cost flow unwrapping, ...) and the data infrastructure around them. You compose the chain for your case; the verified example pipelines are a starting point, not the only way.
The data stay simple on purpose: numpy or cupy arrays in memory, zarr arrays on disk. No containers, no project files; every result is an array you can open with any tool.
Three layers¶
| layer | namespace | data | one call processes |
|---|---|---|---|
| API | moraine.* (import moraine as mr) |
numpy (CPU, numba) or cupy (GPU) arrays in memory; the result is the same kind as the input | one unit: one image or image pair of the scene, or one block of pixels / points with its whole time series |
| CLI | moraine.cli.* (import moraine.cli as mc) |
zarr datasets on disk, larger than memory; processed chunk by chunk by moraine's own workers, threads on the CPU or one process per GPU | a whole data set |
| command | moraine COMMAND ..., moraine run FILE |
the same zarr datasets | a whole data set, from the shell or a pipeline file |
The CLI functions are not wrappers of the API functions: they cut the data into the units the API functions
take, run them as the tasks of an executor (threads on the CPU, one process per GPU; decisions 0033, 0034), and write zarr. Every moraine.cli function is a
command of the moraine executable, with its help generated from the docstring (decision 0005), so the three
layers always agree. help(mr.emi), help(mc.emi) and moraine emi --help describe the same thing.
import moraine as mr
import moraine.cli as mc
ph = mr.emi(coh) # a block of points, in memory
mc.emi('ds/ds_can_coh.zarr', 'ds/ds_can_ph.zarr', cuda=True) # a whole data set, on the GPUs
Rasters and point clouds¶
Two kinds of data sets run through a processing chain (the full conventions are in the data contract):
- Rasters on the radar grid: shape
(nlines, width[, n]), azimuth first, range second, stacks last. The rslc stack is(nlines, width, nimages)complex64;nanmarks missing data. - Point clouds of selected pixels (PS, DS): arrays
(n_points, ...). A point is addressed by its grid indexgix(n_points, 2)(azimuth, range) or by its hilbert indexhix(n_points,), and point clouds are kept in hilbert order, so that points close in the array are close on the ground.pc-union,pc-intersect,pc-diffandpc-select-dataare set operations on sorted indices;ras2pcandpc2rasmove data between the two kinds.
Interferometric data are complex: the interferogram of the image pair (ref, sec) is ref * conj(sec), phase
linked histories and filtered interferograms have unit amplitude, coherence of point clouds is stored
compressed (the upper triangle of the coherence matrix, (n_points, n_pairs)), unwrapped phase is float32
radians (n_points, n_pairs).
Chunks¶
zarr arrays are stored in chunks, the workers process them in parallel; the chunk layout decides the memory and the
speed. moraine's convention (decision 0019): blocks in space, one image (or image pair) per chunk,
e.g. (lines_block, width_block, 1) for a raster stack and (points_block, 1) for a point cloud stack. A step per
image then reads whole chunks, and a step per block reads one chunk of every image, both without rechunking.
Commands take chunks (processing) and out_chunks (storage) arguments; too small chunks spend the time in
scheduling, too large ones run out of memory. Divide rasters along azimuth rather than range.
The processing chain¶
The example pipelines implement one common chain; every step is a command and can be replaced:
- Load GAMMA results into zarr: flattened rslc stack, coordinates, look vector, metadata (01).
- PS candidates: amplitude dispersion index and the temporal coherence of Noise2Fringe filtered interferograms (02).
- DS: statistically homogeneous pixels (KS test), DS candidates, coherence matrices, EMI phase linking with an adaptive regularization, DS selection by the weighted temporal coherence and the connectivity of the coherent image pairs (03).
- Merge and refine: PS and DS together, filtered with the Noise2Fringe Transformer, kept by temporal coherence (04).
- Unwrap: minimum cost flow on a Delaunay network of the points, every interferogram alone (
mcf-pc) or a redundant network together (emcf-pc), unwrapping errors corrected by phase closure (05).
Pipelines, resuming and JSON¶
A chain is a TOML file of steps run by moraine run FILE (pipeline files).
A step is skipped when it ran before with the same arguments and its inputs did not change, so after a failure
or a changed parameter you simply run the file again. moraine run FILE --dry-run shows what would run,
moraine status FILE the state. With --json every command prints one JSON object on stdout and logs on
stderr (JSON output): this is what scripts and AI agents
read.
GPU or CPU¶
API functions accept numpy or cupy arrays and dispatch on the type (moraine.api.utils_.get_array_module);
CLI functions and commands take cuda (one worker process per GPU, allocating from cupy's memory pool). A GPU is used only when
CUDA_VISIBLE_DEVICES names one. The phase linking of many images (more than about 100) can be faster on a
machine with many CPU cores than on one GPU; the guides give the numbers.