///|
pub fn Antoine::is_in_range(self : Antoine, temperature_k : Double) -> Bool {
  temperature_k >= self.t_min_k && temperature_k <= self.t_max_k
}

///|
pub fn Antoine::pressure_bar(
  self : Antoine,
  temperature_k : Double,
) -> Double raise VleError {
  assert_temperature(temperature_k)
  let temperature_c = temperature_k - 273.15
  let pressure_mmhg = @math.pow(
    10.0,
    self.a - self.b / (temperature_c + self.c),
  )
  pressure_mmhg * 0.001333223684
}

///|
pub fn Antoine::pressure_bar_checked(
  self : Antoine,
  temperature_k : Double,
) -> Double raise VleError {
  if !self.is_in_range(temperature_k) {
    raise VleError::InvalidParameter(
      "temperature is outside the Antoine correlation range",
    )
  }
  self.pressure_bar(temperature_k)
}

///|
pub fn Dippr101::pressure_bar(
  self : Dippr101,
  temperature_k : Double,
) -> Double raise VleError {
  if temperature_k <= 0.0 {
    raise VleError::NonPositiveTemperature(temperature_k)
  }
  if !(temperature_k >= self.t_min_k && temperature_k <= self.t_max_k) {
    raise VleError::InvalidParameter(
      "temperature is outside the DIPPR-101 correlation range",
    )
  }
  let log_pressure = self.a +
    self.b / temperature_k +
    self.c * @math.ln(temperature_k) +
    self.d * @math.pow(temperature_k, self.e)
  @math.exp(log_pressure)
}

///|
pub fn Wagner::pressure_bar(
  self : Wagner,
  temperature_k : Double,
) -> Double raise VleError {
  if temperature_k <= 0.0 {
    raise VleError::NonPositiveTemperature(temperature_k)
  }
  if !(temperature_k >= self.t_min_k && temperature_k <= self.t_max_k) {
    raise VleError::InvalidParameter(
      "temperature is outside the Wagner correlation range",
    )
  }
  let theta = 1.0 - temperature_k / self.critical_temperature_k
  let reduced_log = (
      self.a * theta +
      self.b * @math.pow(theta, 1.5) +
      self.c * @math.pow(theta, 3.0) +
      self.d * @math.pow(theta, 6.0)
    ) /
    (1.0 - theta)
  self.critical_pressure_bar * @math.exp(reduced_log)
}

///|
pub fn Component::saturation_pressure_bar(
  self : Component,
  temperature_k : Double,
) -> Double raise VleError {
  self.antoine.pressure_bar(temperature_k)
}

///|
pub fn saturation_pressures_bar(
  components : Array[Component],
  temperature_k : Double,
) -> Array[Double] raise VleError {
  if components.length() == 0 {
    raise VleError::EmptyMixture
  }
  [
    for component in components => {
      component.saturation_pressure_bar(temperature_k)
    }
  ]
}

///|
pub fn henry_k_value(
  henry_constant_bar : Double,
  pressure_bar : Double,
) -> Double raise VleError {
  assert_pressure(henry_constant_bar)
  assert_pressure(pressure_bar)
  henry_constant_bar / pressure_bar
}

///|
pub fn raoult_k_value(
  component : Component,
  temperature_k : Double,
  pressure_bar : Double,
) -> Double raise VleError {
  assert_pressure(pressure_bar)
  component.saturation_pressure_bar(temperature_k) / pressure_bar
}

///|
pub fn k_values(
  components : Array[Component],
  temperature_k : Double,
  pressure_bar : Double,
) -> Array[Double] raise VleError {
  assert_pressure(pressure_bar)
  [
    for component in components => {
      component.saturation_pressure_bar(temperature_k) / pressure_bar
    }
  ]
}