///|
/// Count solid cells in an advanced simulation.
pub fn Simulation::solid_count(self : Simulation) -> Int {
  let mut count = 0
  for solid in self.solid {
    if solid {
      count += 1
    }
  }
  count
}

///|
/// Count fluid cells in an advanced simulation.
pub fn Simulation::fluid_count(self : Simulation) -> Int {
  self.size.width.max(0) * self.size.height.max(0) - self.solid_count()
}

///|
/// Apply a reusable geometry mask.
pub fn Simulation::apply_mask(self : Simulation, mask~ : DomainMask) -> Unit {
  for y in 0.. Unit {
  self.apply_mask(
    mask=mask_union(
      self.current_mask(),
      rasterize_shape(size=self.size, shape=Shape::rectangle(bounds~)),
    ),
  )
}

///|
/// Add a circular obstacle.
pub fn Simulation::add_circle(
  self : Simulation,
  center~ : Point,
  radius~ : Double,
) -> Unit {
  self.apply_mask(
    mask=mask_union(
      self.current_mask(),
      rasterize_shape(size=self.size, shape=Shape::circle(center~, radius~)),
    ),
  )
}

///|
/// Copy the current solid geometry.
pub fn Simulation::current_mask(self : Simulation) -> DomainMask {
  let mask = DomainMask::new(size=self.size)
  for y in 0.. Unit {
  if x >= 0 && x < self.size.width {
    for y in 0.. Unit {
  if x >= 0 && x < self.size.width {
    for y in 0.. Unit {
  let denominator = (self.size.height - 1).max(1).to_double()
  for y in 0.. Unit {
  for x in 0.. Field2D {
  self.velocity_field().magnitude_field()
}

///|
/// Return the mean density over fluid cells.
pub fn Simulation::mean_density(self : Simulation) -> Double {
  let density = self.density_field()
  density.statistics_masked(mask=self.current_mask(), include_solid=false).mean
}

///|
/// Add a uniform body force to the current velocity state through options.
pub fn Simulation::forced_copy(
  self : Simulation,
  force_x~ : Double,
  force_y~ : Double,
) -> Simulation {
  let copy = Simulation::new(
    size=self.size,
    options=SimulationOptions::new(
      model=self.options.model,
      boundary=self.options.boundary,
      force_x~,
      force_y~,
    ),
  )
  self.solid[:].blit_to(copy.solid)
  self.f[:].blit_to(copy.f)
  copy.step_count = self.step_count
  copy
}