///|
pub(all) struct BenchmarkSample {
  name : String
  cells : Int
  particles : Int
  steps : Int
  energy : Double
} derive(Debug, ToJson)

///|
pub fn two_stream_particles(
  count : Int,
  length : Double,
  speed : Double,
) -> Array[Particle] {
  Array::makei(count, fn(i) {
    let x = (i.to_double() + 0.5) * length / count.to_double()
    let v = if i % 2 == 0 { speed } else { -speed }
    Particle::new(x~, v~)
  })
}

///|
pub fn run_pic_benchmark(
  cells? : Int = 64,
  particles? : Int = 128,
  steps? : Int = 16,
) -> BenchmarkSample {
  let grid = Grid1D::new(cells, 1.0)
  let state = PicState::new(grid, two_stream_particles(particles, 1.0, 1.0e5)).run(
    1.0e-12, steps,
  )
  {
    name: "two-stream-pic",
    cells,
    particles,
    steps,
    energy: kinetic_energy(state.particles) + field_energy(state.field),
  }
}

///|
pub fn benchmark_to_csv(sample : BenchmarkSample) -> String {
  "name,cells,particles,steps,energy\n\{sample.name},\{sample.cells},\{sample.particles},\{sample.steps},\{sample.energy}\n"
}