///|
pub(all) struct GridDescriptor {
grid : Grid1D
cell_centers : Array[Double]
cell_edges : Array[Double]
} derive(Debug, ToJson)
///|
pub fn describe_grid(grid : Grid1D) -> GridDescriptor {
{
grid,
cell_centers: grid_coordinates(grid),
cell_edges: Array::makei(grid.cells + 1, fn(i) { i.to_double() * grid.dx }),
}
}
///|
pub fn grid_coordinates(grid : Grid1D) -> Array[Double] {
Array::makei(grid.cells, fn(i) { grid.position(i) })
}
///|
pub fn grid_cell_edges(grid : Grid1D) -> Array[Double] {
Array::makei(grid.cells + 1, fn(i) { i.to_double() * grid.dx })
}
///|
pub fn grid_cell_volume(grid : Grid1D) -> Double {
grid.dx
}
///|
pub fn grid_index_at(grid : Grid1D, x : Double) -> Int {
nearest_index(grid, x)
}
///|
pub fn grid_neighbor_indices(grid : Grid1D, index : Int) -> (Int, Int) {
(modulo_index(index - 1, grid.cells), modulo_index(index + 1, grid.cells))
}
///|
pub fn grid_distance(grid : Grid1D, first : Double, second : Double) -> Double {
let raw = (grid.wrap(first) - grid.wrap(second)).abs()
raw.min(grid.length - raw)
}
///|
pub fn grid_interpolate_coordinates(
grid : Grid1D,
count : Int,
) -> Array[Double] {
linspace(0.0, grid.length, count).map(fn(x) { grid.wrap(x) })
}
///|
pub fn grid_periodic_copy(
grid : Grid1D,
values : ArrayView[Double],
shift : Int,
) -> Array[Double] {
Array::makei(grid.cells, fn(i) {
if values.length() == 0 {
0.0
} else {
values[modulo_index(i - shift, values.length())]
}
})
}
///|
pub fn grid_roll(
grid : Grid1D,
values : ArrayView[Double],
shift : Int,
) -> Array[Double] {
grid_periodic_copy(grid, values, shift)
}
///|
pub fn grid_integral(grid : Grid1D, values : ArrayView[Double]) -> Double {
sum_values(values) * grid.dx
}
///|
pub fn grid_weighted_integral(
grid : Grid1D,
values : ArrayView[Double],
weight : ArrayView[Double],
) -> Double {
weighted_sum(values, weight) * grid.dx
}
///|
pub fn grid_variance(grid : Grid1D, values : ArrayView[Double]) -> Double {
let average = mean(values)
safe_ratio(
values.fold(init=0.0, fn(acc, value) {
let difference = value - average
acc + difference * difference
}) *
grid.dx,
grid.length,
0.0,
)
}
///|
pub fn grid_center_of_mass(
grid : Grid1D,
density : ArrayView[Double],
) -> Double {
let mut numerator = 0.0
let mut denominator = 0.0
for i in 0.. Double {
mean(values)
}
///|
pub fn grid_smooth(
grid : Grid1D,
values : ArrayView[Double],
passes : Int,
) -> Array[Double] {
let mut output = values.to_owned()
for _ in 0.. Array[Double] {
Array::makei(grid.cells, fn(i) {
if i < values.length() {
clamp(values[i], low, high)
} else {
0.0
}
})
}
///|
pub fn grid_regrid(
source : Grid1D,
values : ArrayView[Double],
target : Grid1D,
) -> Array[Double] {
resample_periodic(source, values, target, Linear)
}
///|
pub fn grid_l2_difference(
grid : Grid1D,
first : ArrayView[Double],
second : ArrayView[Double],
) -> Double {
field_l2_error(first, second) * grid.dx.sqrt()
}