///|
/// A normalized three-component composition.
///
/// Components are ordered as carrier, solute and solvent. Fractions must be
/// finite, non-negative and sum to one within the supplied tolerance.
pub(all) struct TernaryComposition {
carrier : Double
solute : Double
solvent : Double
} derive(Debug, Eq, ToJson)
///|
pub fn TernaryComposition::new(
carrier~ : Double,
solute~ : Double,
solvent~ : Double,
tolerance? : Double = 1.0e-9,
) -> TernaryComposition raise ExtractionError {
require_fraction("carrier", carrier)
require_fraction("solute", solute)
require_fraction("solvent", solvent)
let total = carrier + solute + solvent
if (total - 1.0).abs() > tolerance {
raise ExtractionError::InvalidComposition(total~)
}
{ carrier, solute, solvent }
}
///|
/// Normalize non-negative component amounts to fractions.
pub fn TernaryComposition::from_amounts(
carrier~ : Double,
solute~ : Double,
solvent~ : Double,
) -> TernaryComposition raise ExtractionError {
require_non_negative("carrier amount", carrier)
require_non_negative("solute amount", solute)
require_non_negative("solvent amount", solvent)
let total = carrier + solute + solvent
if total <= 0.0 {
raise ExtractionError::InvalidComposition(total~)
}
{ carrier: carrier / total, solute: solute / total, solvent: solvent / total }
}
///|
pub fn TernaryComposition::component(
self : TernaryComposition,
index : Int,
) -> Double raise ExtractionError {
match index {
0 => self.carrier
1 => self.solute
2 => self.solvent
_ =>
raise ExtractionError::InvalidArgument(
message="component index must be 0, 1 or 2",
)
}
}
///|
pub fn TernaryComposition::distance_squared(
self : TernaryComposition,
other : TernaryComposition,
) -> Double {
let dc = self.carrier - other.carrier
let du = self.solute - other.solute
let ds = self.solvent - other.solvent
dc * dc + du * du + ds * ds
}
///|
pub fn TernaryComposition::mix(
self : TernaryComposition,
other : TernaryComposition,
self_amount~ : Double,
other_amount~ : Double,
) -> TernaryComposition raise ExtractionError {
require_non_negative("self amount", self_amount)
require_non_negative("other amount", other_amount)
TernaryComposition::from_amounts(
carrier=self.carrier * self_amount + other.carrier * other_amount,
solute=self.solute * self_amount + other.solute * other_amount,
solvent=self.solvent * self_amount + other.solvent * other_amount,
)
}