///|
/// Limited piecewise linear primitive reconstruction, or piecewise constant.
#derive(Debug, Eq)
pub(all) enum Reconstruction {
Constant
Minmod
MonotonizedCentral
}
///|
fn limited(a : Double, b : Double, mode : Reconstruction) -> Double {
if a == 0.0 || b == 0.0 || (a > 0.0) != (b > 0.0) {
return 0.0
}
let sign = if a > 0.0 { 1.0 } else { -1.0 }
match mode {
Constant => 0.0
Minmod => sign * a.abs().min(b.abs())
MonotonizedCentral =>
sign * (0.5 * (a + b)).abs().min(2.0 * a.abs()).min(2.0 * b.abs())
}
}
///|
/// Returns left and right face traces for each cell. Density/pressure positivity
/// follows from limiting between neighboring positive cell primitive values.
pub fn reconstruct(
states : Array[Primitive],
boundaries : Boundaries,
mode : Reconstruction,
) -> (Array[Primitive], Array[Primitive]) raise GasError {
if states.length() < 2 || states.length() > 1000000 {
raise Invalid("reconstruction needs 2..1000000 cells")
}
for q in states {
q.validate()
}
let low = []
let high = []
let n = states.length()
for i in 0.. Array[Conserved] raise GasError {
self.validate_cells(mesh, states)
let primitives = []
for u in states {
primitives.push(self.primitive(u))
}
let (low, high) = reconstruct(primitives, boundaries, mode)
let fluxes = []
let n = mesh.cells
match boundaries {
Periodic => fluxes.push(self.numerical_flux(high[n - 1], low[0], scheme))
Ends(left, _) => {
let outside = match left {
Outflow => low[0]
Wall => reflected(low[0])
}
fluxes.push(self.numerical_flux(outside, low[0], scheme))
}
}
for i in 1.. fluxes.push(fluxes[0])
Ends(_, right) => {
let outside = match right {
Outflow => high[n - 1]
Wall => reflected(high[n - 1])
}
fluxes.push(self.numerical_flux(high[n - 1], outside, scheme))
}
}
fluxes
}
///|
pub extend Reconstruction with @debug.Debug::{to_repr}
///|
pub extend Reconstruction with Eq::{equal, not_equal}