sylva.fusion¶
TLS and ALS together: registration of a plot on a survey, linked trees, merged clouds and profiles, and upscaling of plot values. See TLS and ALS together for the methods and their validation.
sylva.fusion ¶
Terrestrial and airborne lidar together.
A TLS plot measures stems, diameters and the lower canopy in detail; an airborne survey measures the upper canopy and the terrain over the whole landscape. This module puts the two in one frame and combines them:
registerplaces a TLS plot (in a local frame, or georeferenced with a GNSS error of a few metres) on the ALS survey, and reports the residuals and their uncertainty;link_treeslinks TLS stems to ALS trees, reports the stems under another tree's crown, and gives one table of TLS diameters and ALS heights;merge_cloudsandfuse_profilesgive one point cloud and one plant area density profile from both instruments;plot_values,fit_modelandupscalecarry plot values from the TLS over the ALS survey with a regression on area-based metrics;synthetic_scanis a terrestrial scanner for synthetic scenes that sees them assylva.synthetic.als_flightdoes, so both instruments can be checked against one known forest.
The computations are in the Rust core (sylva_rs::fusion).
TreeLinks
dataclass
¶
TLS trees linked to ALS trees, from link_trees.
Attributes:
| Name | Type | Description |
|---|---|---|
tls |
dict
|
The TLS trees as a table: |
als |
dict
|
The ALS trees as a table: |
status |
ndarray
|
Per TLS tree: |
als_index |
ndarray
|
Index into |
distance |
ndarray
|
Stem to that tree's top (m). |
inside |
ndarray
|
Whether the stem is inside that crown. |
als_height |
ndarray
|
That ALS tree's height. |
height |
ndarray
|
Combined height: for a matched tree the ALS height, unless the TLS is known to have seen the top and measured it taller; the TLS height otherwise. |
height_source |
ndarray
|
|
top_seen |
ndarray
|
Whether the TLS saw the top: 1, 0 or NaN (unknown). Given, or for a matched tree inferred from the TLS height reaching the ALS height. |
flag |
ndarray
|
|
cost |
ndarray
|
Assignment cost of each matched tree. |
als_tls |
ndarray
|
Per ALS tree, the index of its matched TLS tree (-1 for none). |
als_stems |
list
|
Per ALS tree, the indices of every TLS tree linked to it or under it. |
settings |
dict
|
The settings of the call. |
counts ¶
counts() -> dict
Numbers of TLS trees by status, of ALS trees with a matched stem and without, and of ALS crowns holding two stems or more.
one_to_many ¶
one_to_many() -> dict
ALS trees with more than one TLS stem under them.
Returns:
| Type | Description |
|---|---|
dict
|
ALS tree id to the TLS tree ids under it, the matched one first. |
table ¶
table() -> dict
One row per TLS tree: its TLS measurements, its link and the combined height.
Returns:
| Type | Description |
|---|---|
dict
|
|
als_table ¶
als_table() -> dict
One row per ALS tree: id, x, y, height,
tls_id (its matched TLS tree, -1 for none), n_stems (TLS
stems linked to it or under it) and stems (their ids).
to_csv ¶
to_csv(path: str | Path) -> None
Write table as CSV (empty cells for NaN).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str | Path
|
Output file. |
required |
FusedProfile
dataclass
¶
A plant area density profile from both instruments, from
fuse_profiles.
Attributes:
| Name | Type | Description |
|---|---|---|
height |
ndarray
|
Bottom of each height bin above ground (m). |
pad |
ndarray
|
Fused plant area density (m² m⁻³); NaN where neither saw the bin. |
weight_tls, weight_als |
Weight of each instrument in each bin (summing to 1). |
|
tls, als |
Each instrument's bins: |
|
split_height |
float
|
Lowest height above which the ALS carries at least half the weight
in every bin: where |
bin_size |
float
|
Bin height (m). |
settings |
dict
|
The settings of the call. |
pai ¶
pai(source: str = 'fused') -> float
Plant area index: the sum of the PAD of the bins times their height.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source
|
('fused', 'tls', 'als')
|
Which profile. Bins without a value count as 0. |
"fused"
|
Returns:
| Type | Description |
|---|---|
float
|
|
table ¶
table() -> dict
The profile as columns: height, pad, weight_tls,
weight_als, pad_tls, pad_als, beams_tls,
beams_als, observed_tls, observed_als.
Registration
dataclass
¶
A TLS plot placed on an ALS survey, from register.
Attributes:
| Name | Type | Description |
|---|---|---|
transform |
ndarray
|
|
search_transform |
ndarray
|
The same after the search, before the ICP refinement: the best peak. |
pivot |
ndarray
|
Centre of the TLS ground after |
heading |
float
|
Rotation about the vertical (degrees, counter-clockwise) added to
|
shift |
ndarray
|
Translation (m) of the pivot added to |
candidates |
dict
|
The peaks of the search, best first, refined: |
ambiguity |
float
|
Misfit (1 - score) of the best peak over that of the second best: 0 for a clear answer, near 1 when another pose fits about as well (NaN with one peak). |
icp |
dict | None
|
Summary of the kept ICP run ( |
covariance |
ndarray | None
|
Formal |
jackknife |
ndarray | None
|
Jackknife standard errors of the pivot's x, y, z (m) and the heading (degrees) over the four quadrants of the plot, or None. |
residuals |
dict
|
|
n_tls, n_als |
Points used (the ALS within reach of the plot). |
|
resolution, coarse_resolution |
Cell sizes (m) of the fine and coarse search, after widening for a sparse survey. |
|
als_density |
float
|
ALS returns per m² near the plot. |
settings |
dict
|
The settings of the call. |
std
property
¶
std: dict
Standard errors of the pivot's x, y, z (m) and the
heading (degrees): the larger of the formal and the jackknife
ones, NaN where neither exists.
apply ¶
apply(cloud: PointCloud) -> PointCloud
The TLS cloud moved into the ALS frame.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cloud
|
PointCloud
|
Points in the TLS frame given to |
required |
Returns:
| Type | Description |
|---|---|
PointCloud
|
|
save ¶
save(path: str | Path) -> None
Write to_dict as JSON (NaN written as null).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str | Path
|
Output file. |
required |
load
classmethod
¶
load(path: str | Path) -> Registration
Read a registration written by save.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str | Path
|
JSON file. |
required |
Returns:
| Type | Description |
|---|---|
Registration
|
|
Model
dataclass
¶
A regression of plot values on ALS metrics, from fit_model.
Attributes:
| Name | Type | Description |
|---|---|---|
form |
str
|
|
names |
list
|
Predictor names, in the order of |
coef, se |
Coefficients (intercept first) and their standard errors, on the model's scale. |
|
sigma, df |
Residual standard error (model scale) and its degrees of freedom. |
|
n |
int
|
Plots. |
r2, adj_r2 |
Coefficient of determination on the model's scale, and adjusted. |
|
xtx_inv |
ndarray
|
|
correction |
float
|
Back-transformation factor |
y, fitted, loo |
Plot values, fitted values and leave-one-out predictions (scale of y). |
|
loo_rmse, loo_bias, loo_r2, loo_rrmse |
Leave-one-out RMSE, mean error (prediction minus observation),
|
|
x_min, x_max |
Range of each predictor over the plots. |
predict ¶
predict(predictors, level: float = 0.95) -> dict
Predict at new predictor values.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
predictors
|
A dict of arrays or of |
required | |
level
|
float
|
Coverage of the prediction interval. |
0.95
|
Returns:
| Type | Description |
|---|---|
dict
|
|
Upscaling
dataclass
¶
A model and its wall-to-wall prediction, from upscale.
Attributes:
| Name | Type | Description |
|---|---|---|
model |
Model
|
The fitted |
mean, se, lower, upper |
Rasters of the prediction, the standard error of a new observation
and the interval at |
|
extrapolated |
Raster
|
Raster: 1 where a predictor lies outside the range of the plots, 0 elsewhere, NaN without a prediction. |
level |
float
|
Coverage of the interval. |
to_ascii_grids ¶
to_ascii_grids(directory: str | Path, prefix: str = '') -> list[str]
Write the rasters as ESRI ASCII grids.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
directory
|
str | Path
|
Output directory (created if needed). |
required |
prefix
|
str
|
Prepended to |
''
|
Returns:
| Type | Description |
|---|---|
list of str
|
The files written. |
link_trees ¶
link_trees(tls_trees, als_trees, transform=None, *, volumes=None, top_seen=None, sampling=None, min_above_observed: float = 0.5, max_distance: float = 3.0, crown_buffer: float = 0.5, height_weight: float = 2.0, dbh_weight: float = 2.0, max_cost: float = 2.0, top_tolerance: float = 1.0) -> TreeLinks
Link TLS stems to ALS trees and combine their measurements.
A TLS tree and an ALS tree can be one tree when the stem lies inside the
ALS crown (or within crown_buffer of its outline) or within
max_distance of its top. Among these pairs an optimal assignment
(Kuhn 1955; Munkres 1957) minimises the total cost, a stem left without
an ALS tree costing max_cost. A pair costs::
(d / D)² + height_weight * dh² + dbh_weight * (1 - dbh / dbh_max)²
with d the stem-to-top distance, D the larger of
max_distance and the crown's equivalent radius, dh = (h_als -
h_tls) / h_als (0.3 for a stem without a TLS height) and dbh_max
the largest DBH among the stems that could be that ALS tree. The stem
that is tallest by the TLS and thickest under a crown is therefore its
tree, as the dominant tree of a crown usually is both. Each ALS tree
gets at most one stem, and the others under its crown are reported with
it as suppressed (shorter by more than top_tolerance and 10 %)
or codominant (about as tall: the ALS saw two canopy trees as one).
TreeLinks.one_to_many lists these crowns.
The combined table keeps the TLS diameter and takes the height from the
instrument that saw the top. Whether the TLS saw a tree's top comes from
top_seen, from sampling (sylva.voxels.tree_sampling:
seen when above_observed_fraction is at least
min_above_observed), or, for a matched tree, from its TLS height
reaching the ALS height within top_tolerance. A matched tree takes
the ALS height unless the TLS is known (from top_seen or
sampling) to have seen the top and measured it taller: both are
lower bounds, the ALS for missing the apex and the TLS for occlusion,
but a TLS height can also be too tall where its segmentation gave the
tree part of a neighbour's crown. Other trees keep the TLS height,
flagged top_not_seen when that is a lower bound.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tls_trees
|
|
required | |
als_trees
|
|
required | |
transform
|
|
None
|
|
volumes
|
Wood volume (m³) per TLS tree: a |
None
|
|
top_seen
|
Per TLS tree, whether its top was seen (booleans, or 1, 0 and NaN). |
None
|
|
sampling
|
Output of |
None
|
|
min_above_observed
|
float
|
|
0.5
|
max_distance
|
float
|
Farthest a stem can be from an ALS top (m) to be its tree outside the crown outline, and the scale of the distance cost. |
3.0
|
crown_buffer
|
float
|
Distance (m) outside a crown outline that still counts as under it. |
0.5
|
height_weight
|
float
|
Weight of the relative height difference in the cost. |
2.0
|
dbh_weight
|
float
|
Weight of the DBH shortfall from the thickest candidate stem. |
2.0
|
max_cost
|
float
|
Cost of leaving a stem without an ALS tree; no pair costing more is made. |
2.0
|
top_tolerance
|
float
|
Height difference (m) within which a TLS tree reaches the ALS height. |
1.0
|
Returns:
| Type | Description |
|---|---|
TreeLinks
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
For a non-finite position, mismatched columns or a setting out of range. |
Examples:
>>> links = fusion.link_trees(stems, als_trees, transform=reg, volumes=qsms)
>>> links.one_to_many() # {als id: [tls ids]}
>>> links.to_csv("trees_fused.csv")
fuse_profiles ¶
fuse_profiles(tls_grid, als_grid, dtm: Raster | None = None, area=None, *, bin_size: float | None = None, min_beams: float = 5.0, estimator: str = 'mean', g: float = 0.5, pad_field: str | None = None, mode: str = 'beams', min_observed: float = 0.0) -> FusedProfile
One plant area density profile from TLS and ALS voxels.
Each grid is summarised per bin of height above dtm over area:
PAD, the mean number of pulses entering a voxel (voxels no pulse
reached count 0, so occlusion lowers it) and the share of voxels crossed
by at least min_beams pulses. Each bin then takes its PAD from both
instruments, weighted by
"beams"(the default): the pulses, since the variance of a gap-fraction estimate falls in proportion to the beams that sampled it. Near the ground the TLS dominates; high in a closed canopy, where its pulses have been stopped, the ALS takes over;"observed": the share of the bin each instrument saw;"best": the one with more pulses alone.
An instrument whose bin is seen less than min_observed gets no
weight there. The weights are reported per bin.
Both grids must be in one frame (move the TLS shots with
sylva.Shots.transform and a Registration before
voxelising) and should share the voxel size.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tls_grid
|
|
required | |
als_grid
|
|
required | |
dtm
|
Raster | None
|
Terrain (e.g. the ALS DTM); heights above the grid floor if None. |
None
|
area
|
|
None
|
|
bin_size
|
float | None
|
Height bin (m); the larger voxel size if None. |
None
|
min_beams
|
float
|
Pulses a voxel needs to count as observed; voxels crossed by fewer give noisy estimates that are biased upwards. |
5.0
|
estimator
|
('mean', 'pooled')
|
|
"mean"
|
g
|
float
|
Leaf projection G of the pooled estimator (0.5: spherical). |
0.5
|
pad_field
|
str | None
|
PAD field of the mean estimator; |
None
|
mode
|
('beams', 'observed', 'best')
|
Weighting. |
"beams"
|
min_observed
|
float
|
Share of a bin an instrument must have seen for its PAD to count. |
0.0
|
Returns:
| Type | Description |
|---|---|
FusedProfile
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
For a grid without the fields asked for, or bad settings. |
merge_clouds ¶
merge_clouds(tls: PointCloud, als: PointCloud, dtm: Raster, split=5.0, transform=None, fallback: float | None = None) -> PointCloud
One cloud from both instruments: TLS below the split, ALS above.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tls
|
PointCloud
|
The TLS points (in the ALS frame, or moved there by |
required |
als
|
PointCloud
|
The ALS returns. |
required |
dtm
|
Raster
|
Terrain for the heights of both, in the ALS frame. |
required |
split
|
Height above ground (m) where the ALS takes over: a number, a
|
5.0
|
|
transform
|
|
None
|
|
fallback
|
float | None
|
Split height where a split raster has no value; the raster's median if None. |
None
|
Returns:
| Type | Description |
|---|---|
PointCloud
|
TLS points lower than the split, then ALS returns at or above it,
with |
Raises:
| Type | Description |
|---|---|
ValueError
|
For a bad split or transform. |
register ¶
register(tls: PointCloud, als, initial=None, *, resolution: float = 0.5, returns_per_cell: float = 10.0, coarse_resolution: float = 2.0, search_radius: float = 10.0, heading_range: float = 180.0, heading_step: float = 3.0, dtm_weight: float = 0.5, min_height: float = 2.0, min_overlap: float = 0.5, n_candidates: int = 3, refine: str = 'all', icp_voxel_sizes=(1.0, 0.5, 0.25), icp_max_distances=(2.0, 1.0, 0.5), min_planarity: float = 0.3, max_refine_shift: float = 3.0, max_refine_turn: float = 8.0, jackknife: bool = True, tls_ground=None, als_ground=None) -> Registration
Register a TLS plot onto an ALS survey.
Search. The canopy height model (CHM) and terrain model (DTM) of
each cloud are made on one grid spacing, from its ground points
(classification 2). The TLS cells are turned by a heading and shifted
over the ALS rasters, and each pose is scored by the correlation
(Pearson's r) of the two CHMs plus dtm_weight times that of the two
DTMs, over the cells both measured. A correlation is blind to a
vertical offset between the terrains and to a TLS canopy that reads low
where the scanner saw less of the crowns. Every heading within
heading_range of the initial one (heading_step apart) and every
shift within search_radius (coarse_resolution apart) is scored;
the n_candidates best separated peaks are searched again at
resolution with bilinear sampling and a parabola through the best
score in heading, x and y, and the vertical offset is the median
difference of the two DTMs. For a sparse survey the fine cells are
widened to hold about returns_per_cell returns each (1 m at 10
returns per m²): a CHM of cells with one or two returns is too ragged
to place a plot by.
Refinement. A robust point-to-plane ICP (Huber weights, trimmed
tail; the ICP of sylva.coreg) moves the TLS points onto the ALS
points (refine="all": ground, stems and crowns; "ground": the
ground alone; "none": no refinement), over the voxel pyramid
icp_voxel_sizes, from each refined peak. A run counts only if it
moves less than max_refine_shift and max_refine_turn from its
peak; of those the best fit is kept (the most TLS points within the
last cut-off of an ALS point; the higher peak when two fit within half
a percent). The 3-D fit of ground and crowns tells apart poses that the
canopy models cannot: the TLS sees the crowns from below and to the
side, so the best correlation of the canopy models can lie a few
degrees or metres off, most of all with one or two scan positions.
Uncertainty. The formal covariance of the ICP (sigma² H⁻¹ of
its point-to-plane information: a lower bound, since the residuals are
not independent) and a jackknife over the four quadrants of the plot
(each left out and the ICP run again). The residuals of the TLS ground
against the ALS DTM and of the TLS canopy against the nearest ALS
returns check the result without any reference.
Everything is computed about a pivot near the plot, so map coordinates of any size lose no precision.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tls
|
PointCloud
|
The TLS plot, with ground classified (or |
required |
als
|
The ALS returns with ground classified (or |
required | |
initial
|
|
None
|
|
resolution
|
float
|
Smallest cell size (m) of the fine search and the residual DTM. |
0.5
|
returns_per_cell
|
float
|
ALS returns a fine cell should hold on average; 0 keeps
|
10.0
|
coarse_resolution
|
float
|
Cell size (m) of the search over the whole window. |
2.0
|
search_radius
|
float
|
Largest horizontal shift (m) searched, from the initial position. A few metres for a GNSS position; the uncertainty of a hand-held position otherwise. |
10.0
|
heading_range
|
float
|
Headings searched either side of the initial one (degrees). 180 (the default) searches the full circle, for a plot in a scanner frame; a few degrees for a georeferenced one. |
180.0
|
heading_step
|
float
|
Heading step (degrees) of the coarse search. |
3.0
|
dtm_weight
|
float
|
Weight of the terrain correlation against the canopy's. Terrain relief constrains a pose where the canopy is uniform. |
0.5
|
min_height
|
float
|
CHM heights below this (m) count as 0. |
2.0
|
min_overlap
|
float
|
Share of the TLS canopy cells that must fall on ALS data for a pose to be scored. |
0.5
|
n_candidates
|
int
|
Peaks of the coarse search refined. |
3
|
refine
|
('all', 'ground', 'none')
|
Points the ICP uses. |
"all"
|
icp_voxel_sizes
|
ICP voxel pyramid and correspondence cut-offs (m), coarse to fine. |
(1.0, 0.5, 0.25)
|
|
icp_max_distances
|
ICP voxel pyramid and correspondence cut-offs (m), coarse to fine. |
(1.0, 0.5, 0.25)
|
|
min_planarity
|
float
|
Planarity an ALS point needs to be an ICP target (0 to 1). |
0.3
|
max_refine_shift
|
float
|
Largest horizontal move (m) and turn (degrees) the ICP may make from the search result. |
3.0
|
max_refine_turn
|
float
|
Largest horizontal move (m) and turn (degrees) the ICP may make from the search result. |
3.0
|
jackknife
|
bool
|
Run the quadrant jackknife (four more ICPs). |
True
|
tls_ground
|
Boolean ground masks, in place of |
None
|
|
als_ground
|
Boolean ground masks, in place of |
None
|
Returns:
| Type | Description |
|---|---|
Registration
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
For bad settings, clouds without ground points, or no pose that puts enough of the TLS canopy on ALS data. |
Examples:
>>> reg = fusion.register(tls, als_catalog, initial=gnss_pose, search_radius=5.0,
... heading_range=5.0)
>>> print(reg.report())
>>> tls_map = reg.apply(tls)
synthetic_scan ¶
synthetic_scan(scene: PointCloud, origins=(10.0, 10.0, 1.5), resolution_deg: float = 0.25, max_zenith_deg: float = 130.0, target_radius: float = 0.03, terrain_slope: float = 0.05, min_range: float = 0.1, max_range: float = 200.0)
Scan a synthetic scene from the ground as sylva.synthetic.als_flight flies it.
Every scene point is a sphere of target_radius (points of class 2,
the scene's ground, are ignored), and the ground is the analytic
terrain of sylva.synthetic.terrain_height. Pulses leave the
scanner on a regular zenith and azimuth grid as thin rays; a ray stops
at the first sphere or the terrain, whichever it meets first, and gives
one echo there, or none if it leaves the scene. A layer of spheres of
n per m³ is then a turbid medium of plant area density 2 π r² n
(spherical leaf angles) for both scanners, so their estimates can be
checked against the same foliage. (sylva.synthetic.scan instead
lets the points in each pulse's angular cell be hit, which suits
geometry but not densities.)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene
|
PointCloud
|
From |
required |
origins
|
One scanner position |
(10.0, 10.0, 1.5)
|
|
resolution_deg
|
float
|
Angular step in zenith and azimuth (degrees). |
0.25
|
max_zenith_deg
|
float
|
Pulses are fired from straight up to this zenith. |
130.0
|
target_radius
|
float
|
Sphere radius (m); use the |
0.03
|
terrain_slope
|
float
|
Slope of the terrain ( |
0.05
|
min_range
|
float
|
Echoes nearer than |
0.1
|
max_range
|
float
|
Echoes nearer than |
0.1
|
Returns:
| Type | Description |
|---|---|
Shots or list of Shots
|
One per origin, every pulse fired (misses included), with the
echo attributes |
Raises:
| Type | Description |
|---|---|
ValueError
|
For settings out of range or an origin below the terrain. |
fit_model ¶
fit_model(y, predictors, model: str = 'loglog', names=None) -> Model
Regress plot values on ALS metrics.
Ordinary least squares, in one of two forms:
"loglog"(the default):ln y = b0 + Σ bk ln xk, the usual form for biomass against canopy height (a power law), with predictions taken back asexp(ŷ + σ²/2)(Baskerville 1972);"linear":y = b0 + Σ bk xk.
Leave-one-out predictions come from the hat matrix in closed form (they
equal refitting without each plot), and with them the RMSE, bias and R²
a new plot can expect. Keep the predictors few (one or two for ten
plots): each costs a degree of freedom, and correlated metrics (zq95
and zmax) add little.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
y
|
Plot values, e.g. the |
required | |
predictors
|
Per plot, the metrics: a dict of arrays, a
|
required | |
model
|
('loglog', 'linear')
|
Model form. |
"loglog"
|
names
|
The predictors to use (keys of |
None
|
Returns:
| Type | Description |
|---|---|
Model
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
With fewer than |
Examples:
>>> m = fusion.fit_model(agb, plot_metrics, "loglog", names=["zq95", "cover"])
>>> print(m.summary())
plot_values ¶
plot_values(trees, area: float, wood_density: float, *, volumes=None, min_dbh: float = 0.0) -> dict
Plot totals per hectare from a plot's TLS trees.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
trees
|
|
required | |
area
|
float
|
Plot area (m²). Give only the trees inside the plot. |
required |
wood_density
|
float
|
Basic wood density (kg/m³), e.g. 500 to 700 for many hardwoods; there is no default, since it depends on the species. |
required |
volumes
|
Wood volume (m³) per tree, as for |
None
|
|
min_dbh
|
float
|
Inventory threshold (m): smaller trees are left out. |
0.0
|
Returns:
| Type | Description |
|---|---|
dict
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
For a non-positive area or wood density. |
upscale ¶
upscale(y, plot_metrics, grid: Mapping, predictors, model: str = 'loglog', level: float = 0.95) -> Upscaling
Fit plot values on ALS metrics and predict them over the ALS grid.
fit_model on the plots, then Model.predict on every cell
of grid. The grid's cells should have the plots' area (e.g. 25 m
cells for 0.06 ha plots), since metrics such as the height percentiles
depend on the area they are computed over.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
y
|
Plot values (e.g. |
required | |
plot_metrics
|
The plots' ALS metrics: |
required | |
grid
|
Mapping
|
The same metrics as rasters on one grid (from
|
required |
predictors
|
Names of the metrics to use. |
required | |
model
|
('loglog', 'linear')
|
Model form. |
"loglog"
|
level
|
float
|
Coverage of the prediction interval. |
0.95
|
Returns:
| Type | Description |
|---|---|
Upscaling
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
As |
Examples:
>>> plots = als.plot_metrics(cat, centres, radius=15.0, metrics=["zq95", "cover"])
>>> grid = als.grid_metrics(cat, 25.0, ["zq95", "cover"])
>>> up = fusion.upscale(agb, plots, grid, ["zq95"], "loglog")
>>> up.mean.to_geotiff("agb.tif")