///|
/// Rectangular nodal grid; nx/ny are interval counts, not point counts.
pub struct Grid {
nx : Int32
ny : Int32
lx : Double
ly : Double
} derive(@debug.Debug, Eq)
///|
pub fn Grid::new(
nx : Int32,
ny : Int32,
lx~ : Double = 1.0,
ly~ : Double = 1.0,
) -> Grid raise SolverError {
if nx < 2 || ny < 2 {
raise Invalid("grid needs at least two intervals per axis")
}
if nx > 1024 || ny > 1024 {
raise Budget("grid interval limit is 1024 per axis")
}
require_positive(lx, "lx")
require_positive(ly, "ly")
let hx = lx / nx.to_double()
let hy = ly / ny.to_double()
if hx < 1.0e-100 || hy < 1.0e-100 || hx > 1.0e100 || hy > 1.0e100 {
raise Invalid("grid spacing outside supported numerical range")
}
{ nx, ny, lx, ly, }
}
///|
pub fn Grid::shape(self : Grid) -> (Int32, Int32) {
(self.nx + 1, self.ny + 1)
}
///|
pub fn Grid::intervals(self : Grid) -> (Int32, Int32) {
(self.nx, self.ny)
}
///|
pub fn Grid::lengths(self : Grid) -> (Double, Double) {
(self.lx, self.ly)
}
///|
pub fn Grid::spacing(self : Grid) -> (Double, Double) {
(self.lx / self.nx.to_double(), self.ly / self.ny.to_double())
}
///|
pub fn Grid::size(self : Grid) -> Int32 {
(self.nx + 1) * (self.ny + 1)
}
///|
pub fn Grid::unknowns(self : Grid) -> Int32 {
(self.nx - 1) * (self.ny - 1)
}
///|
pub fn Grid::index(
self : Grid,
i : Int32,
j : Int32,
) -> Int32 raise SolverError {
if i < 0 || i > self.nx || j < 0 || j > self.ny {
raise Shape("grid index outside domain")
}
self.at(i, j)
}
///|
pub fn Grid::coordinate(
self : Grid,
i : Int32,
j : Int32,
) -> (Double, Double) raise SolverError {
let _ = self.index(i, j)
let (hx, hy) = self.spacing()
(i.to_double() * hx, j.to_double() * hy)
}
///|
fn Grid::at(self : Grid, i : Int32, j : Int32) -> Int32 {
j * (self.nx + 1) + i
}
///|
pub fn Grid::is_boundary(self : Grid, i : Int32, j : Int32) -> Bool {
i >= 0 &&
i <= self.nx &&
j >= 0 &&
j <= self.ny &&
(i == 0 || j == 0 || i == self.nx || j == self.ny)
}
///|
pub extend Grid with @debug.Debug::{to_repr}
///|
pub extend Grid with Eq::{equal, not_equal}