///|
/// Piecewise-constant cell averages integrate a discontinuity even inside a cell.
pub fn Gas::shock_tube(
  self : Gas,
  mesh : Mesh,
  left : Primitive,
  right : Primitive,
  interface_at : Double,
) -> Array[Conserved] raise GasError {
  if !finite(interface_at) ||
    interface_at < mesh.left ||
    interface_at > mesh.right {
    raise Invalid("interface must lie within mesh")
  }
  let ul = self.conserved(left)
  let ur = self.conserved(right)
  let states = []
  for i in 0.. Array[Primitive] raise GasError {
  let result = []
  for i in 0.. Array[Conserved] raise GasError {
  Array::make(mesh.cells, self.conserved(state))
}

///|
/// A periodic smooth entropy wave: constant pressure and velocity, varying density.
/// Integral cell averages use analytic averaging of the sinusoid.
pub fn Gas::entropy_wave(
  self : Gas,
  mesh : Mesh,
  mean_density : Double,
  amplitude : Double,
  velocity : Double,
  pressure : Double,
  phase : Double,
) -> Array[Conserved] raise GasError {
  let base = Primitive::new(mean_density, velocity, pressure)
  ignore(self.conserved(base))
  if !finite(amplitude) || amplitude.abs() >= mean_density || !finite(phase) {
    raise Invalid("wave amplitude must be finite and smaller than mean density")
  }
  let k = 2.0 * @math.PI / (mesh.right - mesh.left)
  let result = []
  for i in 0.. (Primitive, Primitive) {
  match self {
    Sod =>
      (
        { rho: 1.0, velocity: 0.0, pressure: 1.0, },
        { rho: 0.125, velocity: 0.0, pressure: 0.1, },
      )
    Lax =>
      (
        { rho: 0.445, velocity: 0.698, pressure: 3.528, },
        { rho: 0.5, velocity: 0.0, pressure: 0.571, },
      )
    Contact =>
      (
        { rho: 1.0, velocity: 0.5, pressure: 1.0, },
        { rho: 0.5, velocity: 0.5, pressure: 1.0, },
      )
  }
}

///|
pub extend TubeCase with @debug.Debug::{to_repr}

///|
pub extend TubeCase with Eq::{equal, not_equal}