///|
pub(all) enum CycleKind {
V
W
} derive(@debug.Debug, Eq)
///|
pub struct CycleConfig {
kind : CycleKind
smoother : Smoother
sweeps : Int32
}
///|
pub fn CycleConfig::new(
kind~ : CycleKind = V,
smoother~ : Smoother = Jacobi(0.6666666666666666),
sweeps~ : Int32 = 2,
) -> CycleConfig raise SolverError {
if sweeps < 1 || sweeps > 8 {
raise Invalid("cycle smoothing sweeps must be in 1..8")
}
match smoother {
Jacobi(omega) => {
require_finite(omega, "Jacobi weight")
if omega <= 0.0 || omega >= 1.0 {
raise Invalid("cycle Jacobi weight must be in (0,1)")
}
}
SymmetricGaussSeidel => ()
}
{ kind, smoother, sweeps, }
}
///|
pub fn CycleConfig::kind(self : CycleConfig) -> CycleKind {
self.kind
}
///|
pub fn CycleConfig::smoother(self : CycleConfig) -> Smoother {
self.smoother
}
///|
pub fn CycleConfig::sweeps(self : CycleConfig) -> Int32 {
self.sweeps
}
///|
fn Hierarchy::cycle_level(
self : Hierarchy,
level : Int32,
rhs : Field,
initial : Field,
config : CycleConfig,
) -> Field raise SolverError {
if level == self.operators.length() - 1 {
return self.coarse.solve(rhs)
}
let op = self.operators[level]
let pre = config.smoother.apply(op, rhs, initial, config.sweeps)
let residual = op.residual(rhs, pre)
let coarse_rhs = restrict_full(residual)
let mut correction = Field::zeros(coarse_rhs.grid)
let visits = match config.kind {
V => 1
W => 2
}
for _visit in 0.. Field raise SolverError {
let g = self.operators[0].grid
require_same(g, rhs.grid)
require_same(g, initial.grid)
self.cycle_level(0, rhs.zero_boundary(), initial.zero_boundary(), config)
}
///|
/// Linear zero-initialized cycle for reusable preconditioning.
pub fn Hierarchy::precondition(
self : Hierarchy,
rhs : Field,
config~ : CycleConfig = CycleConfig::new(),
) -> Field raise SolverError {
self.cycle(rhs, Field::zeros(rhs.grid), config~)
}
///|
pub extend CycleKind with @debug.Debug::{to_repr}
///|
pub extend CycleKind with Eq::{equal, not_equal}