Spatial models¶
Estimators with a fit / predict interface for spatial models: trends, the
GNSS tie (T33) will build on them. verde is the design
reference, not a dependency.
from disp_xr import models
flat = ds.disp.deramp(degree=1) # a plane removed from every epoch, lazily
coords = models.coordinates(points) # (easting, northing) of a point table
est = models.Chain([("trend", models.Trend(1)), ("spline", models.Spline(1e-6))])
est.fit(coords, points.velocity.values)
grid = est.grid(like=ds) # on the frame's grid, with its CRS
scores = models.cross_val_score(est, coords, points.velocity.values, spacing=5000)
Estimator base for spatial models (PRD F9, plan task T19).
Spatial models (trends, GNSS ties, gridders) share one shape, after verde (the design reference only, not a dependency; PRD decision):
fit(coords, data, weights=None)estimates the parameters and returns the estimator; fitted attributes end in_;predict(coords)evaluates the model at any coordinates;score(coords, data, weights=None)is the weighted R²;grid(...)predicts on a regular grid as anxr.DataArraywith a CRS;- :class:
Chainfits steps in sequence, each on the residual of the last.
Coordinates are a tuple (easting, northing) of arrays of one shape, in
the CRS of the data (projected, in meters for DISP frames).
:func:coordinates builds them from a raster, a point table or a
DataFrame. :func:cross_val_score scores an estimator with spatial block
k-fold cross-validation, which keeps neighbors out of each other's folds
(Roberts et al. 2017, https://doi.org/10.1111/ecog.02881).
BaseEstimator ¶
Base class of disp-xr spatial estimators.
Subclasses take their parameters as keyword arguments of __init__
(stored under the same names) and implement _fit(easting, northing,
data, weights) and _predict(easting, northing) on 1D arrays
without NaN; the base class checks inputs, drops NaN and reshapes.
Examples:
>>> class Offset(BaseEstimator):
... def fit(self, coords, data, weights=None): ...
... def predict(self, coords): ...
set_params ¶
Set constructor parameters; returns the estimator.
fit ¶
Fit the model; returns the estimator.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
coords
|
(easting, northing)
|
Arrays of one shape. |
required |
data
|
array - like
|
Values at |
required |
weights
|
array - like
|
Non-negative weights (same shape), for example |
None
|
predict ¶
Return the model at coords (same shape; NaN where they are NaN).
score ¶
Return the weighted R² of the predictions at coords.
grid ¶
grid(*, region: Optional[Sequence[float]] = None, spacing: Optional[float] = None, like: Optional[Union[Dataset, DataArray]] = None, crs: Optional[Any] = None, name: str = 'prediction') -> xr.DataArray
Predict on a regular grid.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
region
|
(west, east, south, north)
|
Bounds of the pixel centers; default the fitted data's bounds. |
None
|
spacing
|
float
|
Pixel size, needed unless |
None
|
like
|
Dataset or DataArray
|
Predict on this grid (its |
None
|
crs
|
optional
|
CRS to attach (default: the CRS of |
None
|
name
|
str
|
Name of the returned DataArray. |
'prediction'
|
Returns:
| Type | Description |
|---|---|
DataArray
|
|
Chain ¶
Bases: BaseEstimator
Fit estimators in sequence, each on the residual of the previous ones.
predict sums the steps. For example, a planar trend then a gridder of
what the trend leaves.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
steps
|
sequence of (name, estimator)
|
The estimators, in order. |
required |
Examples:
>>> from disp_xr.models import Chain, Spline, Trend
>>> chain = Chain([("trend", Trend(1)), ("spline", Spline(damping=1e-2))])
>>> chain.fit(coords, data).predict(coords)
Mean ¶
Trends and de-ramping¶
Polynomial trends and per-epoch de-ramping (PRD F9, plan task T24).
:class:Trend fits a 2D polynomial of the coordinates by weighted least
squares, on coordinates centered and scaled for conditioning (the raw UTM
values, near 10⁶, would make the normal matrix singular in float64 from
degree 2). It is the simplest spatial model and a step of the GNSS tie.
:func:deramp removes a polynomial ramp from every epoch of a stack. In
the temporal-denoising study, per-epoch spatial de-ramping cut velocity
scatter by 10 to 24%, more than any temporal filter. The fit only needs
sums over pixels (the normal equations), so it stays lazy and exact; it runs
on every stride-th pixel by default and the ramp is subtracted from the
full grid chunk by chunk. Ramps are long-wavelength by construction: remove
them only when long-wavelength signal (plate motion, large subsidence
bowls) is not wanted, or mask such areas out of the fit.
Trend ¶
Bases: BaseEstimator
A 2D polynomial trend of degree degree, by weighted least squares.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
degree
|
int
|
0 is a constant, 1 a plane, 2 a quadratic surface. |
1
|
Attributes:
| Name | Type | Description |
|---|---|---|
coef_ |
ndarray
|
Coefficients of the terms in :func: |
center_, scale_ |
tuple of float
|
The normalization. |
Examples:
deramp ¶
deramp(ds: Dataset, degree: int = 1, *, layer: str = 'displacement', mask: Optional[DataArray] = None, weights: Optional[DataArray] = None, stride: int = 4) -> xr.Dataset
Remove a polynomial ramp from every epoch of layer, lazily.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ds
|
Dataset
|
Data with |
required |
degree
|
int
|
Degree of the ramp: 1 a plane (default), 2 a quadratic surface. |
1
|
layer
|
str
|
Layer to de-ramp. |
'displacement'
|
mask
|
DataArray
|
Boolean |
None
|
weights
|
DataArray
|
Non-negative weights for the fit, for example quality weights. |
None
|
stride
|
int
|
Fit on every |
4
|
Returns:
| Type | Description |
|---|---|
Dataset
|
|
Examples:
polynomial_terms ¶
Gridders¶
Gridders for point data (PRD F9, plan task T24.4).
:class:Spline is the biharmonic spline of Sandwell (1987,
https://doi.org/10.1029/GL014i002p00139): the field is a sum of Green's
functions g(r) = r² (ln r - 1) centered on the data points, with forces
from weighted least squares and optional damping (verde's Spline is the
design reference, not a dependency). It suits smooth fields from scattered
points (GNSS velocities, downsampled cells). The system is dense, n x n
for n points, so keep n to a few thousand (downsample first).
:class:Nearest copies the value of the nearest point with positive
weight: a fallback with no smoothing.
Spline ¶
Bases: BaseEstimator
Biharmonic spline gridder (Sandwell 1987) with optional damping.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
damping
|
float
|
Regularization of the forces ( |
None
|
Attributes:
| Name | Type | Description |
|---|---|---|
force_coords_ |
tuple of numpy.ndarray
|
The data points, where the forces sit. |
forces_ |
ndarray
|
The force at each point. |
Examples:
Nearest ¶
GNSS tie¶
GNSS tie: remove long-wavelength DISP error with GNSS (PRD F9, plan task T33).
The residual DISP minus GNSS at the stations is fitted with a smooth surface (a polynomial trend, optionally plus a damped spline) and the predicted field is subtracted from DISP, either for the velocity or for every epoch.
What the tie field may hold. Only long-wavelength error: orbits,
long-wavelength troposphere and ionosphere, reference-frame and plate-motion
differences. Local deformation (groundwater subsidence, coseismic steps) must
stay in the calibrated product, so stations in deforming areas are left out of
the fit (exclude) and their signal is restored by construction: the
smooth field does not reach it. A plane (degree=1) is the default; add the
spline only with damping strong enough that its scale stays well above the
station spacing. Leave-one-station-out scores improve as the field gets more
local, partly by construction (a field that bends to each station predicts
its neighbors well), so a better score alone does not show that the signal
was preserved.
fit_tie ¶
fit_tie(comparison: Any, *, mode: Mode = 'velocity', degree: int = 1, damping: Optional[float] = None, exclude: Any = None) -> TieResult
Fit a GNSS tie to the DISP-minus-GNSS residual at the stations.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
comparison
|
Comparison
|
:func: |
required |
mode
|
('velocity', 'epoch')
|
Fit the velocity residual ( |
"velocity"
|
degree
|
int
|
:class: |
1
|
damping
|
int
|
:class: |
1
|
exclude
|
list of station ids, or a lon/lat polygon
|
Stations left out of the fit, for example those in deforming areas (subsidence, coseismic): their signal must stay in the product. |
None
|
Returns:
| Type | Description |
|---|---|
TieResult
|
|
Examples:
apply_tie ¶
cross_validate_tie ¶
cross_validate_tie(comparison: Any, *, mode: Mode = 'velocity', degree: int = 1, damping: Optional[float] = None, exclude: Any = None) -> pd.DataFrame
Leave-one-station-out: residual RMSE at each station before and after.
Each station used in the fit is left out in turn, the tie is fitted on the others and predicted at it. Excluded stations are scored with the tie of all used stations (they never enter the fit).
Returns:
| Type | Description |
|---|---|
DataFrame
|
Per station: |
Examples:
GNSSTie ¶
Bases: BaseEstimator
A polynomial trend, optionally plus a damped spline of what it leaves.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
degree
|
int
|
Degree of the trend (1, a plane, by default). |
1
|
damping
|
float
|
Damping of a biharmonic spline fitted to the trend's residual; None (default) fits the trend alone. Keep it large: the tie field should hold long-wavelength error only. |
None
|
Examples:
TieResult
dataclass
¶
A fitted GNSS tie: one estimator (velocity) or one per epoch.
Examples:
>>> tie = fit_tie(comparison, mode="epoch")
>>> tie.correction(ds).isel(time=-1).plot()
>>> tie.stations
Helpers¶
coordinates ¶
Return (easting, northing) of a raster, a point table or a DataFrame.
A raster with x and y dimensions gives 2D arrays ((y, x)
order); a point table (x and y coordinates along one dimension,
as from :func:disp_xr.to_points) or a DataFrame with x and y
columns gives 1D arrays.
Examples:
cross_val_score ¶
cross_val_score(estimator: BaseEstimator, coords: Coords, data: Any, *, spacing: float, weights: Optional[Any] = None, n_splits: int = 5, seed: int = 0) -> np.ndarray
Score an estimator with spatial block k-fold cross-validation.
Points are grouped into square blocks of side spacing; the blocks are
shuffled and split into n_splits folds. Each fold is predicted by a
copy fitted on the other folds, and scored with the weighted R².
Returns:
| Type | Description |
|---|---|
ndarray
|
One score per fold. |
Examples:
clone ¶
NotFittedError ¶
Bases: RuntimeError
Raised when predict runs before fit.