Iteratively smooths the fine raster while restoring each coarse block's mean at every iteration. The result is a smooth surface whose block means equal the input coarse values exactly — mass preservation is enforced at every iteration by construction, not approximated.
Arguments
- coarse
SpatRaster.
- fact
Integer disagg factor (>= 2).
- cascade
Disaggregation stages. One of: * `NULL` (default): auto-factorize `fact` into prime factors, sorted descending. For example, `fact = 48` becomes `c(3, 2, 2, 2, 2)`. Each stage's per-stage disaggregation is small, keeping the iteration in its comfortable regime where the 3x3 smoother is comparable in bandwidth to the per-stage block size. This is the recommended default. * `fact` (a single integer equal to `fact`): single-stage disaggregation. This is the original Tobler (1979) formulation; at large `fact` it converges slowly and may show within-block flattening (see "Caveat" below). * An integer vector with `prod(cascade) == fact`: explicit factorization. Useful for fine-tuning, e.g. `cascade = c(4, 4, 3)` for `fact = 48`.
- max_iter
Integer, maximum iterations per stage. Default 100.
- tol
Numeric, convergence tolerance as a fraction of the coarse raster's value range. Iteration stops when the largest per-cell change between successive iterations falls below `tol * range`. Default 1e-4. Controls only how close the result is to its smooth fixed point; mass preservation is enforced exactly at every iteration regardless of convergence.
- smoother
Character, smoothing kernel. One of: * `"laplacian_9"` (default): full 3x3 mean, including diagonals. * `"laplacian_5"`: 5-point pattern (cardinal neighbors + center).
- variant
Character, mean-restoration variant. One of: * `"additive"` (default): add a per-block constant. Works for any data. * `"multiplicative"`: scale within-block values. Strictly positive data only; will warn and fall back to additive if any block mean is non-positive.
- init
Character, initial fine raster at each stage. One of: * `"near"` (default): nearest-neighbor disagg. Matches the original Tobler formulation. * `"bilinear"`: standard bilinear disagg. A smoother starting point that typically converges faster.
- na_fill
Character, NA handling. Same semantics as [disagg_bl()]; `"auto"` (default) uses `"fill"` when the coarse raster has NAs, `"reflect"` otherwise.
- verbose
Logical, print iteration progress. Default `FALSE`.
Value
Fine SpatRaster, with attributes `cascade` (the stage sequence actually used), `iterations` (integer vector, one per stage), and `converged` (logical vector, one per stage).
Details
For composite `fact` values, the disaggregation is cascaded through a sequence of smaller stages by default, which is substantially faster than running at the full factor in one shot and produces smoother results.
Compared to the pre-sharpening methods ([disagg_bl()], [disagg_cub()]):
Pycnophylactic and cubic produce smoother output than bilinear (no kinks at cell centers).
Pycnophylactic is *exactly* mass-preserving by construction; the pre-sharpening methods are approximately so, with a small truncation error concentrated near the raster boundary. For small rasters or boundary-sensitive applications, this matters.
Pycnophylactic tends to produce less ringing near sharp coarse-scale gradients than [disagg_cub()].
Pycnophylactic is iterative and substantially slower [disagg_bl()], though cascading is typically much faster than one-shot pycno.
Caveat for single-stage runs
When you explicitly set `cascade = fact` (or `fact` is prime, leaving no cascade options), the algorithm runs as a single pycnophylactic iteration. At large `fact` (> ~20 with the default 3x3 smoother), the single-stage fixed point can show subtle within-block flattening: high-frequency content within a coarse block becomes piecewise-constant at block scale, because the smoother cannot bridge across blocks in a single stage. This is a structural property of the iterative algorithm on regular grids, not a convergence issue — running more iterations doesn't remove it.
The default cascade behavior mostly eliminates this issue by keeping each stage in a regime where the smoother's bandwidth matches the per-stage block size. For `fact` with a large prime factor (e.g. `fact = 22` = 2 x 11), the 11-stage will still exhibit the artifact; consider [disagg_cub()] in that case.
References
Tobler, W. R. (1979). Smooth pycnophylactic interpolation for geographical regions. *J. Am. Stat. Assoc.* 74(367), 519-530.
See also
[disagg_bl()] and [disagg_cub()] for faster, non-iterative pre-sharpening alternatives. The `pycno` package (`pycno::pycno`) implements the polygon-source version of the underlying algorithm.
Examples
library(terra)
coarse <- rast(nrows = 30, ncols = 30, vals = runif(900))
fine_pyc <- disagg_pyc(coarse, fact = 6) # cascade = c(3, 2)
back <- aggregate(fine_pyc, fact = 6, fun = "mean")
max(abs(values(coarse) - values(back))) # ~ tolerance level
#> [1] 4.440892e-16
# Single-stage -- original Tobler 1979 algorithm
fine_tobler <- disagg_pyc(coarse, fact = 6, cascade = 6)