///|
pub(all) struct Field1D {
  grid : Grid1D
  charge_density : Array[Double]
  electric : Array[Double]
  potential : Array[Double]
} derive(Debug, ToJson)

///|
pub fn Field1D::new(grid : Grid1D) -> Field1D {
  {
    grid,
    charge_density: zeros(grid.cells),
    electric: zeros(grid.cells),
    potential: zeros(grid.cells),
  }
}

///|
pub fn Field1D::electric_energy(field : Field1D) -> Double {
  field_energy(field)
}

///|
pub fn Field1D::charge_neutrality_error(field : Field1D) -> Double {
  mean(field.charge_density).abs()
}

///|
pub fn Field1D::potential_range(field : Field1D) -> (Double, Double) {
  (min_value(field.potential), max_value(field.potential))
}

///|
pub fn Field1D::electric_range(field : Field1D) -> (Double, Double) {
  (min_value(field.electric), max_value(field.electric))
}

///|
pub fn solve_periodic_field(
  grid : Grid1D,
  charge_density : ArrayView[Double],
) -> Field1D {
  let rho_mean = mean(charge_density)
  let electric = zeros(grid.cells)
  for i in 1.. Double {
  let y = grid.wrap(x)
  let scaled = y / grid.dx - 0.5
  let i0 = @math.floor(scaled).to_int()
  let frac = scaled - i0.to_double()
  let left = if i0 < 0 { grid.cells - 1 } else { i0 % grid.cells }
  let right = (left + 1) % grid.cells
  values[left] * (1.0 - frac) + values[right] * frac
}