///|
pub fn Grid::downsample_mean(self : Grid, factor : Int) -> Grid {
let safe = Int::max(1, factor)
let rows = (self.rows + safe - 1) / safe
let cols = (self.cols + safe - 1) / safe
let values : Array[Double] = []
for row in 0.. if is_finite(value) { window.push(value) }
None => ()
}
}
}
values.push(summary(window).mean)
}
}
{
origin_lat: self.origin_lat,
origin_lon: self.origin_lon,
lat_step: self.lat_step * Double::from_int(safe),
lon_step: self.lon_step * Double::from_int(safe),
rows,
cols,
values,
}
}
///|
pub fn Grid::downsample_min(self : Grid, factor : Int) -> Grid {
self.downsample_with(factor, fn(values) { summary(values).minimum })
}
///|
pub fn Grid::downsample_max(self : Grid, factor : Int) -> Grid {
self.downsample_with(factor, fn(values) { summary(values).maximum })
}
///|
pub fn Grid::downsample_with(
self : Grid,
factor : Int,
reducer : (ArrayView[Double]) -> Double,
) -> Grid {
let safe = Int::max(1, factor)
let rows = (self.rows + safe - 1) / safe
let cols = (self.cols + safe - 1) / safe
let values : Array[Double] = []
for row in 0.. if is_finite(value) { window.push(value) }
None => ()
}
}
}
values.push(reducer(window))
}
}
{
origin_lat: self.origin_lat,
origin_lon: self.origin_lon,
lat_step: self.lat_step * Double::from_int(safe),
lon_step: self.lon_step * Double::from_int(safe),
rows,
cols,
values,
}
}
///|
pub fn Grid::pyramid(self : Grid, levels : Int) -> Array[Grid] {
let output : Array[Grid] = [self]
let mut current = self
for _ in 1.. Array[Grid] {
let output : Array[Grid] = []
let safe_rows = Int::max(1, tile_rows)
let safe_cols = Int::max(1, tile_cols)
for row in 0.. Int? {
if row < 0 || col < 0 || row >= self.rows || col >= self.cols {
None
} else {
Some(
row /
Int::max(1, tile_rows) *
((self.cols + Int::max(1, tile_cols) - 1) / Int::max(1, tile_cols)) +
col / Int::max(1, tile_cols),
)
}
}
///|
pub fn Grid::interior(self : Grid, border : Int) -> Grid {
self.crop(
border,
border,
Int::max(0, self.rows - 2 * border),
Int::max(0, self.cols - 2 * border),
)
}
///|
pub fn Grid::boundary(self : Grid, border : Int) -> Grid {
self.pad(border, 0.0).difference(self).unwrap_or(self)
}
///|
pub fn Grid::cell_centres(self : Grid) -> Array[GeoPoint] {
let output : Array[GeoPoint] = []
for row in 0.. output.push(point)
None => ()
}
}
}
output
}
///|
pub fn grid_mosaic(grids : ArrayView[Grid]) -> Grid? {
if grids.length() == 0 {
None
} else {
let first = grids[0]
let mut output = first
for grid in grids[1:] {
match
output.combine(grid, fn(a, b) { if is_finite(b) { b } else { a } }) {
Some(combined) => output = combined
None => ()
}
}
Some(output)
}
}
///|
pub fn grid_match_extent(a : Grid, b : Grid) -> Bool {
a.rows == b.rows &&
a.cols == b.cols &&
a.origin_lat == b.origin_lat &&
a.origin_lon == b.origin_lon &&
a.lat_step == b.lat_step &&
a.lon_step == b.lon_step
}
///|
pub fn grid_residual(a : Grid, b : Grid) -> Grid? {
if grid_match_extent(a, b) {
a.difference(b)
} else {
None
}
}
///|
pub fn grid_rmse(a : Grid, b : Grid) -> Double {
match grid_residual(a, b) {
Some(residual) => rms(residual.values)
None => 0.0
}
}
///|
pub fn grid_mae(a : Grid, b : Grid) -> Double {
match grid_residual(a, b) {
Some(residual) => residual.mean_absolute()
None => 0.0
}
}
///|
pub fn grid_correlation(a : Grid, b : Grid) -> Double {
if grid_match_extent(a, b) {
covariance_summary(a.values, b.values).correlation
} else {
0.0
}
}
///|
pub fn grid_apply_mask(
source : Grid,
mask : Grid,
accepted_value : Double,
) -> Grid {
source
.combine(mask, fn(value, flag) {
if flag == accepted_value {
value
} else {
0.0 / 0.0
}
})
.unwrap_or(source)
}
///|
pub fn grid_percentile(grid : Grid, fraction : Double) -> Double {
percentile(grid.values, fraction)
}
///|
pub fn grid_standardize(grid : Grid) -> Grid {
{ ..grid, values: normalize_values(grid.values) }
}