Large data & batch¶
Many rasters at once, maps larger than memory, and tiled MSPA. Tutorial: large data and batch processing.
Most tools also accept a RasterCollection
or a lazy stack directly (e.g. ls.mspa(ls.load_raster("tiles/*.tif"),
output_dir="out")), and Landscape
reads large maps in blocks (block_rows).
Folders of rasters¶
batch
¶
Parallel processing of many rasters, one thread per raster.
batch() runs any landschaft tool on many rasters (GuidosToolbox's
File -> Batch Process); mspa_batch() is the MSPA-specific version with
GTB's output naming.
BatchResult
dataclass
¶
BatchResult(
input: Path,
output: Path | None,
seconds: float,
error: str | None = None,
outputs: list[Path] = list(),
)
Bases: Saveable
Outcome of one input of batch() / mspa_batch().
Attributes:
| Name | Type | Description |
|---|---|---|
input |
Path
|
The input raster. |
output |
Path | None
|
The main output file ( |
seconds |
float
|
Run time. |
error |
str | None
|
The error message, or |
outputs |
list[Path]
|
Every file written. |
parse_memory
¶
16_000_000_000, "16GB", "500 MiB" -> bytes.
run_parallel
¶
run_parallel(
items: list[T],
work: Callable[[T], object],
*,
pixels: Callable[[T], int],
n_workers: int | None,
threads_per_worker: int,
max_memory: int | str | None,
) -> list
Run work on every item with a thread pool and a memory budget.
Results come back in input order. work must not raise if the caller
wants every item processed.
mspa_batch
¶
mspa_batch(
inputs,
output_dir: PathLike,
*,
connectivity: int = 8,
edge_width: int = 1,
transition: bool = True,
internal: bool = True,
n_workers: int | None = None,
threads_per_worker: int = 1,
max_memory: int | str | None = None,
overwrite: bool = False,
raise_errors: bool = False,
on=None,
) -> list[BatchResult]
Run MSPA on many rasters in parallel and write the results.
Each worker thread loads one raster, runs MSPA and writes
<output_dir>/<name>_<connectivity>_<edge_width>_<transition>_<internal>.tif
(GuidosToolbox naming), then moves to the next one. The C++ core releases
the GIL, so the threads run fully in parallel, and memory stays bounded by
the rasters being processed at the same time.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
inputs
|
A |
required | |
output_dir
|
PathLike
|
Directory for the results (created if needed). |
required |
connectivity
|
int
|
MSPA parameters, see |
8
|
edge_width
|
int
|
MSPA parameters, see |
8
|
transition
|
int
|
MSPA parameters, see |
8
|
internal
|
int
|
MSPA parameters, see |
8
|
n_workers
|
int | None
|
Rasters processed concurrently. Default: all cores but one, divided
by |
None
|
threads_per_worker
|
int
|
Threads inside each raster (default 1: best throughput for many rasters; raise it when processing a few very large ones). |
1
|
max_memory
|
int | str | None
|
Memory budget, e.g. |
None
|
overwrite
|
bool
|
Recompute outputs that already exist. |
False
|
raise_errors
|
bool
|
Raise the first error instead of recording it in the results. |
False
|
on
|
|
None
|
Returns:
| Type | Description |
|---|---|
list of BatchResult
|
One entry per input, in input order. |
Examples:
>>> from pathlib import Path
>>> import landschaft as ls
>>> forest = ls.load_raster(ls.example_data("input"))
>>> Path("tiles").mkdir(exist_ok=True)
>>> for row in (0, 500):
... _ = ls.write_raster(forest[row:row + 500, :500], f"tiles/forest_{row}.tif")
>>> runs = ls.mspa_batch("tiles", "mspa_out", edge_width=1)
>>> [run.output.name for run in runs]
['forest_0_8_1_1_1.tif', 'forest_500_8_1_1_1.tif']
mspa_collection
¶
mspa_collection(
collection: RasterCollection,
*,
output_dir: PathLike | None = None,
n_workers: int | None = None,
threads_per_worker: int = 1,
max_memory: int | str | None = None,
overwrite: bool = False,
**params,
)
mspa() for a RasterCollection.
batch
¶
batch(
tool,
inputs,
output_dir: PathLike,
*,
n_workers: int | None = None,
threads_per_worker: int = 1,
max_memory: int | str | None = None,
overwrite: bool = False,
raise_errors: bool = False,
table_format: str = "csv",
on=None,
**params,
) -> list[BatchResult]
Run a landschaft tool on many rasters in parallel and write its outputs.
GuidosToolbox's Batch Process for every tool: each worker thread loads
one raster, runs tool(data, **params) and writes what it returns to
output_dir, named after the input and the tool:
- maps:
<name>_<tool>[_<field>].tif(GeoTIFF with the input's georeferencing and, for GTB products, GTB's colour table); - tables:
<name>_<tool>_<field>.csv(.parquetwithtable_format="parquet";"landscape_metrics"writes its long table as<name>_landscape_metrics.csv); the text report (summary()):<name>_<tool>.txt; GTB's CSV report when the tool has one:<name>_<tool>_gtb.csv; <name>_<tool>.json: tool, parameters, output files, scalar results and run time. An input whose JSON exists is skipped unlessoverwrite.
MSPA is written with GTB's naming (see mspa_batch()).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tool
|
A name from |
required | |
inputs
|
A |
required | |
output_dir
|
PathLike
|
Directory for the results (created if needed). |
required |
n_workers
|
int | None
|
As in |
None
|
threads_per_worker
|
int | None
|
As in |
None
|
max_memory
|
int | None
|
As in |
None
|
overwrite
|
int | None
|
As in |
None
|
raise_errors
|
int | None
|
As in |
None
|
table_format
|
str
|
"csv" (default) or "parquet" (needs pyarrow) for the tables. |
'csv'
|
on
|
|
None
|
|
**params
|
Parameters of the tool, e.g. |
{}
|
Returns:
| Type | Description |
|---|---|
list of BatchResult
|
One entry per input, in input order; |
Examples:
Accounting of every raster of a folder:
>>> from pathlib import Path
>>> import landschaft as ls
>>> forest = ls.load_raster(ls.example_data("input"))
>>> Path("tiles").mkdir(exist_ok=True)
>>> for row in (0, 500):
... _ = ls.write_raster(forest[row:row + 500, :500], f"tiles/forest_{row}.tif")
>>> runs = ls.batch("accounting", "tiles", "accounting_out")
>>> [run.ok for run in runs]
[True, True]
>>> [path.name for path in runs[0].outputs]
['forest_0_accounting_classes.tif', 'forest_0_accounting_ids.tif',
'forest_0_accounting_area.tif', 'forest_0_accounting_stats.csv',
'forest_0_accounting.txt', 'forest_0_accounting.json']
mspa_batch
¶
mspa_batch(
inputs,
output_dir: PathLike,
*,
connectivity: int = 8,
edge_width: int = 1,
transition: bool = True,
internal: bool = True,
n_workers: int | None = None,
threads_per_worker: int = 1,
max_memory: int | str | None = None,
overwrite: bool = False,
raise_errors: bool = False,
on=None,
) -> list[BatchResult]
Run MSPA on many rasters in parallel and write the results.
Each worker thread loads one raster, runs MSPA and writes
<output_dir>/<name>_<connectivity>_<edge_width>_<transition>_<internal>.tif
(GuidosToolbox naming), then moves to the next one. The C++ core releases
the GIL, so the threads run fully in parallel, and memory stays bounded by
the rasters being processed at the same time.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
inputs
|
A |
required | |
output_dir
|
PathLike
|
Directory for the results (created if needed). |
required |
connectivity
|
int
|
MSPA parameters, see |
8
|
edge_width
|
int
|
MSPA parameters, see |
8
|
transition
|
int
|
MSPA parameters, see |
8
|
internal
|
int
|
MSPA parameters, see |
8
|
n_workers
|
int | None
|
Rasters processed concurrently. Default: all cores but one, divided
by |
None
|
threads_per_worker
|
int
|
Threads inside each raster (default 1: best throughput for many rasters; raise it when processing a few very large ones). |
1
|
max_memory
|
int | str | None
|
Memory budget, e.g. |
None
|
overwrite
|
bool
|
Recompute outputs that already exist. |
False
|
raise_errors
|
bool
|
Raise the first error instead of recording it in the results. |
False
|
on
|
|
None
|
Returns:
| Type | Description |
|---|---|
list of BatchResult
|
One entry per input, in input order. |
Examples:
>>> from pathlib import Path
>>> import landschaft as ls
>>> forest = ls.load_raster(ls.example_data("input"))
>>> Path("tiles").mkdir(exist_ok=True)
>>> for row in (0, 500):
... _ = ls.write_raster(forest[row:row + 500, :500], f"tiles/forest_{row}.tif")
>>> runs = ls.mspa_batch("tiles", "mspa_out", edge_width=1)
>>> [run.output.name for run in runs]
['forest_0_8_1_1_1.tif', 'forest_500_8_1_1_1.tif']
BatchResult
dataclass
¶
BatchResult(
input: Path,
output: Path | None,
seconds: float,
error: str | None = None,
outputs: list[Path] = list(),
)
Bases: Saveable
Outcome of one input of batch() / mspa_batch().
Attributes:
| Name | Type | Description |
|---|---|---|
input |
Path
|
The input raster. |
output |
Path | None
|
The main output file ( |
seconds |
float
|
Run time. |
error |
str | None
|
The error message, or |
outputs |
list[Path]
|
Every file written. |
Tools of batch¶
ls.BATCH_TOOLS lists the names batch accepts; any function taking a raster
as its first argument works too.
accounting, clustering_fac, conefor_inputs, contagion_pff, contortion, distance_to_resistance, euclidean_distance, fad, fad_multiscale, fos, gray_spatial_convolution, gtn_components, gtn_importance, influence_zones, landscape_mosaic, landscape_mosaic_heatmap, landscape_mosaic_stats, mspa, parcellation, proximity, reclassify, restoration_status, spa, spatial_entropy, spatial_entropy_map, landscape_metrics, window_metrics.
Several computers¶
on=ls.helpers() runs the tasks of batch, mspa_batch,
simulate.scenarios, simulate.calibrate, sdm.fit (its cross-validation),
uncertainty.monte_carlo, the trade-off calibrations and replacement importance
of ls.prioritize, parallel.map and parallel.tiled on this computer and on
the computers of its group running landschaft worker. Tutorial:
several computers.
helpers
¶
helpers(
*,
local: bool = True,
local_threads: int | None = None,
port: int = TCP_PORT,
discovery: bool = True,
verbose: bool = True,
) -> Helpers
This computer and the helpers of its group, for on= (see Helpers).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
local
|
bool
|
Run tasks on this computer too ( |
True
|
local_threads
|
int | None
|
Cores of this computer for the tasks (default: all but one). |
None
|
port
|
int
|
TCP port helpers connect to. |
TCP_PORT
|
discovery
|
bool
|
Answer helpers that look for work on the local network. |
True
|
verbose
|
bool
|
Print who joined, the progress and failures. |
True
|
Returns:
| Type | Description |
|---|---|
Helpers
|
|
Examples:
Helpers
¶
Helpers(
*,
local: bool = True,
local_threads: int | None = None,
port: int = TCP_PORT,
discovery: bool = True,
verbose: bool = True,
out: Callable[[str], None] | None = None,
host: str = "",
)
This computer and the helpers of its group, for the on= argument of
landschaft's functions that run many independent tasks.
Give it to batch(), mspa_batch(),
scenarios() or calibrate()
(grid and random searches): their tasks run here and on the computers of this
computer's group running landschaft worker, with the same results as on this
computer alone. Used in a with block, the helpers stay connected from one call
to the next; otherwise each call starts and stops the coordinator.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
local
|
bool
|
Run tasks on this computer too. |
True
|
local_threads
|
int | None
|
Cores of this computer for the tasks (default: all but one). |
None
|
port
|
int
|
TCP port helpers connect to (the discovery broadcasts use UDP 47810); 0 picks a free one. |
TCP_PORT
|
discovery
|
bool
|
Answer the broadcasts of helpers looking for work on the local network. Without
it, helpers connect with |
True
|
verbose
|
bool
|
Print who joined, the progress and failures. |
True
|
Examples:
>>> import landschaft as ls
>>> with ls.helpers() as pool:
... runs = ls.batch("fad", "tiles/", "fad_out/", on=pool)
... ens = ls.simulate.scenarios(model, start, drivers, replicates=100, seed=1, on=pool)
machines
property
¶
The computers working now: [{"name", "cores", "local", "tasks"}].
map
¶
map(
tool,
items,
*,
on=None,
output_dir=None,
threads_per_task: int | None = None,
n_workers: int | None = None,
**common,
) -> list
Run a tool on many inputs, on this computer or on helpers, in parallel.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tool
|
A name of |
required | |
items
|
One call per item: a dict of keyword arguments, a tuple of positional ones, or the first argument alone (a raster). |
required | |
on
|
|
None
|
|
output_dir
|
Save each result there ( |
None
|
|
threads_per_task
|
int | None
|
Threads of each call (default: each computer's cores divided among the calls). |
None
|
n_workers
|
int | None
|
Calls at once on this computer, without |
None
|
**common
|
Keyword arguments of every call. |
{}
|
Returns:
| Type | Description |
|---|---|
list
|
The results (or the paths of the saved results), in the order of |
Examples:
tiled
¶
tiled(
tool,
raster,
*args,
halo: int | None = None,
tile: int = 1024,
on=None,
output=None,
n_workers: int | None = None,
**kwargs,
)
Run a neighbourhood tool on a large raster tile by tile, on this computer or on helpers.
Each tile is cut with a margin (halo) of the cells its edge cells need, the
tool runs on it and its result over the tile proper goes into place: the same
values as on the whole raster, for tools that see only a neighbourhood (moving
windows, lines of sight, slopes). A raster read lazily (ls.load_raster(path,
chunks=...)) is read tile by tile.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tool
|
A name of |
required | |
raster
|
A DataArray (in memory or lazy). |
required | |
*args
|
The tool's other arguments. |
()
|
|
**kwargs
|
The tool's other arguments. |
()
|
|
halo
|
int | None
|
The margin in cells (default: what the tool needs, known for |
None
|
tile
|
int
|
The side of a tile in cells (without its halo). |
1024
|
on
|
|
None
|
|
output
|
Save the result there ( |
None
|
|
n_workers
|
int | None
|
Tiles at once on this computer, without |
None
|
Returns:
| Type | Description |
|---|---|
The tool's result over the whole raster: a DataArray, a Dataset, or the tool's
|
|
result class when every part of it is a map (else a dict of its maps).
|
|
Examples:
call
¶
A registered tool with its arguments, the drawn ones marked by param().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tool
|
A name of |
required | |
*args
|
Its arguments; |
()
|
|
**kwargs
|
Its arguments; |
()
|
Returns:
| Type | Description |
|---|---|
Call
|
|
Examples:
ls.parallel.TOOLS lists the tools map, tiled and monte_carlo can run by name:
the analyses of ls ("fad", "mspa", ...), ls.surface ("surface.geomorphons"),
ls.hydro, ls.services, ls.nlm and ls.circuit.
run_worker
¶
run_worker(
*,
cores: int | None = None,
connect: str | None = None,
join: str | None = None,
maps: Iterable[str] = (),
cache_dir: str | None = None,
cache_gb: float = 20.0,
) -> None
Lend this computer to the group: wait for tasks and run them, until Ctrl+C.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cores
|
int | None
|
Cores to lend (default: all but one). |
None
|
connect
|
str | None
|
The coordinator's address ( |
None
|
join
|
str | None
|
The invitation code shown by |
None
|
maps
|
Iterable[str]
|
Where shared folders are mounted here, as |
()
|
cache_dir
|
str | None
|
Where received input files are kept, and how much space they may take: the same data is not sent again. |
None
|
cache_gb
|
str | None
|
Where received input files are kept, and how much space they may take: the same data is not sent again. |
None
|
invite_helpers
¶
Show an invitation code and let other computers join this one's group with
landschaft worker --join <code>, for minutes. Returns the names of those that
joined.
list_helpers
¶
The helpers of this computer's group waiting for work now (busy ones are not
looking): [{"name", "address", "cores", "version"}].
leave_group
¶
Forget this computer's group (it no longer helps nor uses helpers).
open_firewall
¶
Let helpers reach this computer: the Windows firewall rules for the local network.
The landschaft command¶
| Command | What it does |
|---|---|
landschaft helpers invite [--minutes 10] |
show a code with which other computers join this one's group |
landschaft worker --join CODE |
join a group (the first time) and lend this computer |
landschaft worker [--cores N] [--connect HOST[:PORT]] [--map SRC=DST] [--cache-gb 20] |
lend this computer until Ctrl+C |
landschaft helpers list |
the helpers waiting for work on the local network |
landschaft helpers firewall |
Windows: let helpers reach this computer (TCP 47811, UDP 47810, local subnet) |
landschaft helpers leave |
take this computer out of its group |
Maps larger than memory¶
mspa_tiled
¶
mspa_tiled(
data,
output: PathLike | None = None,
*,
connectivity: int = 8,
edge_width: int = 1,
transition: bool = True,
internal: bool = True,
tile_size: int = 6500,
overlap: int = 2000,
n_workers: int = 1,
n_threads: int | None = None,
overwrite: bool = False,
)
MSPA of a large map by overlapping tiles, identical to GTB's MSPA Tiling.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
MSPA input (0 missing, 1 background, 2 foreground): a 2-D array or
DataArray (processed in memory), or the path of a GeoTIFF (processed
out of core, tile by tile, into |
required | |
output
|
PathLike | None
|
GeoTIFF to write. For a path input it defaults to GTB's name next to
the input, |
None
|
connectivity
|
int
|
MSPA parameters, see |
8
|
edge_width
|
int
|
MSPA parameters, see |
8
|
transition
|
int
|
MSPA parameters, see |
8
|
internal
|
int
|
MSPA parameters, see |
8
|
tile_size
|
int
|
Tile side including the overlap, and the overlap [pixels]. GTB uses 2000 and a tile size of 6500 on MS-Windows (9500 on Linux, 8500 on macOS). |
6500
|
overlap
|
int
|
Tile side including the overlap, and the overlap [pixels]. GTB uses 2000 and a tile size of 6500 on MS-Windows (9500 on Linux, 8500 on macOS). |
6500
|
n_workers
|
int
|
Tiles processed concurrently; each needs about 32 bytes per tile pixel. |
1
|
n_threads
|
int | None
|
Threads per tile (default: all cores but one, shared among the workers). |
None
|
overwrite
|
bool
|
Replace an existing |
False
|
Returns:
| Type | Description |
|---|---|
(ndarray, DataArray or Path)
|
The MSPA map for in-memory input; the path of the written GeoTIFF for a path input. |
Examples:
tile_layout
¶
tile_layout(
size: int, tile_size: int = 6500, overlap: int = 2000
) -> list[tuple[int, int, int, int]]
GTB's tiles along one axis of size pixels.
Returns (read_start, read_stop, keep_start, keep_stop) per tile: the
tile read for MSPA and the part of it kept in the result (map
coordinates). Tiles start every tile_size - overlap pixels; the last
one ends at the map border. Of each overlap, the first overlap // 2
pixels go to the earlier tile.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
size
|
int
|
Pixels along the axis. |
required |
tile_size
|
int
|
As in |
6500
|
overlap
|
int
|
As in |
6500
|
Returns:
| Type | Description |
|---|---|
list of tuple
|
|
Examples: