///|
pub struct TieLine {
  temperature_k : Double
  phase_a : Array[Double]
  phase_b : Array[Double]
  source : String
} derive(Debug)

///|
pub fn TieLine::new(
  temperature_k~ : Double,
  phase_a~ : Array[Double],
  phase_b~ : Array[Double],
  source~ : String,
) -> TieLine raise VleError {
  assert_temperature(temperature_k)
  {
    temperature_k,
    phase_a: normalize(phase_a),
    phase_b: normalize(phase_b),
    source,
  }
}

///|
pub fn distribution_ratio(line : TieLine, component_index : Int) -> Double {
  line.phase_a[component_index] / line.phase_b[component_index]
}

///|
pub fn lever_rule_fraction(
  feed : Double,
  raffinate : Double,
  extract : Double,
) -> Double {
  (feed - raffinate) / (extract - raffinate)
}

///|
pub fn van_t_hoff_solid_solubility(
  melting_temperature_k~ : Double,
  fusion_enthalpy_j_per_mol~ : Double,
  temperature_k~ : Double,
) -> Double raise VleError {
  assert_temperature(melting_temperature_k)
  assert_temperature(temperature_k)
  @math.exp(
    0.0 -
    fusion_enthalpy_j_per_mol /
    gas_constant_j_per_mol_k *
    (1.0 / temperature_k - 1.0 / melting_temperature_k),
  )
}