///|
pub(all) struct GridReduction {
source_cells : Int
target_cells : Int
source_length : Double
values : Array[Double]
} derive(Debug, ToJson)
///|
pub fn reduce_average(
source : Grid1D,
values : ArrayView[Double],
target_cells : Int,
) -> GridReduction {
let count = target_cells.max(1)
let target = zeros(count)
let ratio = source.cells.to_double() / count.to_double()
for i in 0.. Array[Double] {
resample_periodic(source, values, target, Linear)
}
///|
pub fn reduction_error(
source : Grid1D,
values : ArrayView[Double],
reduction : GridReduction,
) -> Double {
let reconstructed = prolongate_linear(
Grid1D::new(reduction.target_cells, source.length),
reduction.values,
source,
)
field_l2_error(values, reconstructed)
}
///|
pub fn reduction_integral(_grid : Grid1D, reduction : GridReduction) -> Double {
integrate_trapezoid(
Grid1D::new(reduction.target_cells, reduction.source_length),
reduction.values,
)
}
///|
pub fn reduction_minimum(reduction : GridReduction) -> Double {
min_value(reduction.values, 0.0)
}
///|
pub fn reduction_maximum(reduction : GridReduction) -> Double {
max_value(reduction.values, 0.0)
}
///|
pub fn reduction_summary(reduction : GridReduction) -> String {
"source_cells=\{reduction.source_cells}\ntarget_cells=\{reduction.target_cells}\nminimum=\{reduction_minimum(reduction)}\nmaximum=\{reduction_maximum(reduction)}\n"
}
///|
pub fn reduction_series(
source : Grid1D,
values : ArrayView[Double],
resolutions : ArrayView[Int],
) -> Array[GridReduction] {
resolutions.map(fn(resolution) { reduce_average(source, values, resolution) })
}
///|
pub fn reduction_errors(
source : Grid1D,
values : ArrayView[Double],
reductions : ArrayView[GridReduction],
) -> Array[Double] {
reductions.map(fn(reduction) { reduction_error(source, values, reduction) })
}
///|
pub fn reduction_to_csv(reduction : GridReduction) -> String {
let output = StringBuilder()
output.write_string("index,value\n")
for i in 0.. Array[Double] {
if reductions.length() == 0 {
[]
} else {
let width = reductions[0].values.length()
Array::makei(width, fn(i) {
mean(reductions.map(fn(reduction) { reduction.values[i] }))
})
}
}
///|
pub fn reduction_converges(
errors : ArrayView[Double],
tolerance : Double,
) -> Bool {
errors.length() > 0 && errors[errors.length() - 1] <= tolerance
}