///|
/// Export a scalar field as row-major CSV.
pub fn Field2D::to_csv(self : Field2D, name? : String = "value") -> String {
  let builder = StringBuilder(
    size_hint=self.size.width * self.size.height * 20 + 32,
  )
  builder.write_string("x,y,\{name}\n")
  for y in 0.. String {
  let builder = StringBuilder(
    size_hint=self.size.width * self.size.height * 8 + 16,
  )
  builder.write_string("x,y,solid\n")
  for y in 0.. String {
  let stats = self.statistics()
  let denominator = if stats.maximum == stats.minimum {
    1.0
  } else {
    stats.maximum - stats.minimum
  }
  let builder = StringBuilder(
    size_hint=(self.size.width + 1) * self.size.height,
  )
  for y in 0.. Option::unwrap)
    }
    builder.write_char('\n')
  }
  builder.to_string()
}

///|
/// Convert a vector field to a scalar magnitude field.
pub fn VectorField2D::magnitude_field(self : VectorField2D) -> Field2D {
  let result = Field2D::new(size=self.size)
  for y in 0.. String {
  let builder = StringBuilder(size_hint=self.size.width * self.size.height * 36)
  for y in 0..