///|
/// Return the dimensions carried by a vector field.
pub fn VectorField2D::dimensions(self : VectorField2D) -> Size {
self.size
}
///|
/// Copy the horizontal component into a scalar field.
pub fn VectorField2D::horizontal_field(self : VectorField2D) -> Field2D {
{ size: self.size, data: self.ux.copy() }
}
///|
/// Copy the vertical component into a scalar field.
pub fn VectorField2D::vertical_field(self : VectorField2D) -> Field2D {
{ size: self.size, data: self.uy.copy() }
}
///|
/// Clamp a vector coordinate to its nearest valid cell.
fn VectorField2D::clamped_coordinate(
self : VectorField2D,
x : Int,
y : Int,
) -> (Int, Int) {
(
x.clamp(min=0, max=self.size.width - 1),
y.clamp(min=0, max=self.size.height - 1),
)
}
///|
/// Compute a centered finite-difference divergence field.
pub fn VectorField2D::divergence_field(self : VectorField2D) -> Field2D {
let result = Field2D::new(size=self.size)
if self.size.width > 0 && self.size.height > 0 {
for y in 0.. Field2D {
let result = Field2D::new(size=self.size)
if self.size.width > 0 && self.size.height > 0 {
for y in 0.. Double {
let mut maximum = 0.0
for value in self.ux {
maximum = maximum.max(if value < 0.0 { -value } else { value })
}
for value in self.uy {
maximum = maximum.max(if value < 0.0 { -value } else { value })
}
maximum
}
///|
/// Sum one named component, with speed as a useful derived option.
pub fn VectorField2D::component_sum(
self : VectorField2D,
component : String,
) -> Double {
match component {
"ux" => sum_values(self.ux[:])
"uy" => sum_values(self.uy[:])
"speed" => self.magnitude_field().statistics().sum
_ => 0.0
}
}
///|
/// Compute descriptive statistics for vector speed.
pub fn VectorField2D::speed_statistics(self : VectorField2D) -> FieldStatistics {
self.magnitude_field().statistics()
}
///|
/// Scale every vector by one factor.
pub fn VectorField2D::scale(
self : VectorField2D,
factor : Double,
) -> VectorField2D {
let result = VectorField2D::new(size=self.size)
for i in 0.. VectorField2D {
let result = VectorField2D::new(size=self.size)
for y in 0.. VectorField2D {
let result = VectorField2D::new(size=self.size)
for y in 0.. Field2D {
let result = Field2D::new(size=self.size)
for y in 0.. Double {
let mut total = 0.0
for i in 0.. Point {
Point::new(x=sum_values(self.ux[:]), y=sum_values(self.uy[:]))
}
///|
/// Return whether every stored component is finite.
pub fn VectorField2D::is_finite(self : VectorField2D) -> Bool {
let mut result = true
for value in self.ux {
result = result && !value.is_nan() && !value.is_inf()
}
for value in self.uy {
result = result && !value.is_nan() && !value.is_inf()
}
result
}
///|
/// Limit vector magnitude while preserving direction.
pub fn VectorField2D::clamp_speed(
self : VectorField2D,
maximum : Double,
) -> VectorField2D {
let result = VectorField2D::new(size=self.size)
let limit = maximum.max(0.0)
for y in 0.. VectorField2D {
let result = VectorField2D::new(size=self.size)
for y in 0.. VectorField2D {
let t = clamp_double(weight, low=0.0, high=1.0)
self.scale(1.0 - t).add(other.scale(t))
}
///|
/// Return the negative of every vector.
pub fn VectorField2D::negate(self : VectorField2D) -> VectorField2D {
self.scale(-1.0)
}
///|
/// Compute the mean squared magnitude of a vector field.
pub fn VectorField2D::mean_square_speed(self : VectorField2D) -> Double {
if self.ux.length() == 0 {
0.0
} else {
self.kinetic_energy() * 2.0 / self.ux.length().to_double()
}
}
///|
/// Compute the total squared gradient of vector components.
pub fn VectorField2D::gradient_energy(self : VectorField2D) -> Double {
let mut total = 0.0
if self.size.width > 1 && self.size.height > 1 {
for y in 1..<(self.size.height - 1) {
for x in 1..<(self.size.width - 1) {
let left = self.get(x - 1, y)
let right = self.get(x + 1, y)
let bottom = self.get(x, y - 1)
let top = self.get(x, y + 1)
let du_dx = (right.x - left.x) * 0.5
let du_dy = (top.x - bottom.x) * 0.5
let dv_dx = (right.y - left.y) * 0.5
let dv_dy = (top.y - bottom.y) * 0.5
total += du_dx * du_dx + du_dy * du_dy + dv_dx * dv_dx + dv_dy * dv_dy
}
}
}
total
}
///|
/// L1 norm of a derived divergence field.
pub fn VectorField2D::divergence_l1(self : VectorField2D) -> Double {
let mut total = 0.0
for value in self.divergence_field().values() {
total += if value < 0.0 { -value } else { value }
}
total
}
///|
/// L1 norm of a derived curl field.
pub fn VectorField2D::curl_l1(self : VectorField2D) -> Double {
let mut total = 0.0
for value in self.curl_field().values() {
total += if value < 0.0 { -value } else { value }
}
total
}