use crate::Result;
use core::fmt;
use core::fmt::{Display, Formatter};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
pub trait RelativePermittivity {
fn permittivity(&self, temperature: f64) -> Result<f64>;
fn temperature_is_ok(&self, temperature: f64) -> bool {
self.permittivity(temperature).is_ok()
}
fn to_const_permittivity(&self, temperature: f64) -> Result<ConstantPermittivity> {
Ok(ConstantPermittivity::new(self.permittivity(temperature)?))
}
fn set_permittivity(&mut self, permittivity: f64) -> Result<()> {
let _ = permittivity;
Err(crate::Error::Unsupported("setting the permittivity"))
}
}
#[derive(Debug, PartialEq, Clone)]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(deny_unknown_fields)
)]
pub enum Permittivity {
Fixed(f64),
Empirical(EmpiricalPermittivity),
Water,
Ethanol,
Methanol,
Metal,
Vacuum,
Water25,
}
impl RelativePermittivity for Permittivity {
fn permittivity(&self, temperature: f64) -> Result<f64> {
Box::<dyn RelativePermittivity>::from(self.clone()).permittivity(temperature)
}
}
impl From<Permittivity> for Box<dyn RelativePermittivity> {
fn from(model: Permittivity) -> Box<dyn RelativePermittivity> {
match model {
Permittivity::Fixed(d) => Box::new(ConstantPermittivity::from(d)),
Permittivity::Empirical(d) => Box::new(d),
Permittivity::Water => Box::new(WATER),
Permittivity::Ethanol => Box::new(ETHANOL),
Permittivity::Methanol => Box::new(METHANOL),
Permittivity::Metal => Box::new(METAL),
Permittivity::Vacuum => Box::new(VACUUM),
Permittivity::Water25 => Box::new(WATER_25C),
}
}
}
impl Display for Permittivity {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Permittivity::Fixed(d) => write!(f, "{}", d),
Permittivity::Empirical(d) => write!(f, "{}", d),
Permittivity::Water => write!(f, "{}", WATER),
Permittivity::Ethanol => write!(f, "{}", ETHANOL),
Permittivity::Methanol => write!(f, "{}", METHANOL),
Permittivity::Metal => write!(f, "{}", METAL),
Permittivity::Vacuum => write!(f, "{}", VACUUM),
Permittivity::Water25 => write!(f, "{}", WATER_25C),
}
}
}
pub const METAL: ConstantPermittivity = ConstantPermittivity::new(f64::INFINITY);
pub const WATER_25C: ConstantPermittivity = ConstantPermittivity::new(78.4);
pub const VACUUM: ConstantPermittivity = ConstantPermittivity::new(1.0);
pub const WATER: EmpiricalPermittivity = EmpiricalPermittivity::new(
&[-1664.4988, -0.884533, 0.0003635, 64839.1736, 308.3394],
(273.0, 403.0),
);
pub const METHANOL: EmpiricalPermittivity = EmpiricalPermittivity::new(
&[-1750.3069, -0.99026, 0.0004666, 51360.2652, 327.3124],
(176.0, 318.0),
);
pub const ETHANOL: EmpiricalPermittivity = EmpiricalPermittivity::new(
&[-1522.2782, -1.00508, 0.0005211, 38733.9481, 293.1133],
(288.0, 328.0),
);
#[derive(Debug, PartialEq, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ConstantPermittivity {
#[cfg_attr(feature = "serde", serde(rename = "epsr", alias = "εᵣ"))]
permittivity: f64,
}
impl ConstantPermittivity {
pub const fn new(permittivity: f64) -> Self {
Self { permittivity }
}
}
impl From<ConstantPermittivity> for f64 {
fn from(d: ConstantPermittivity) -> f64 {
d.permittivity
}
}
impl From<f64> for ConstantPermittivity {
fn from(d: f64) -> ConstantPermittivity {
ConstantPermittivity::new(d)
}
}
impl RelativePermittivity for ConstantPermittivity {
fn permittivity(&self, _: f64) -> Result<f64> {
Ok(self.permittivity)
}
fn set_permittivity(&mut self, permittivity: f64) -> Result<()> {
self.permittivity = permittivity;
Ok(())
}
}
impl Display for ConstantPermittivity {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"εᵣ = {}",
match self.permittivity.is_infinite() {
true => "∞".to_string(),
false => format!("{:.2}", self.permittivity),
}
)
}
}
#[derive(Debug, PartialEq, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct EmpiricalPermittivity {
coeffs: [f64; 5],
temperature_interval: (f64, f64),
}
impl EmpiricalPermittivity {
pub const fn new(coeffs: &[f64; 5], temperature_interval: (f64, f64)) -> EmpiricalPermittivity {
EmpiricalPermittivity {
coeffs: *coeffs,
temperature_interval,
}
}
}
impl RelativePermittivity for EmpiricalPermittivity {
fn permittivity(&self, temperature: f64) -> Result<f64> {
if temperature < self.temperature_interval.0 || temperature > self.temperature_interval.1 {
Err(crate::Error::TemperatureOutOfRange)
} else {
Ok(self.coeffs[0]
+ self.coeffs[1] * temperature
+ self.coeffs[2] * temperature.powi(2)
+ self.coeffs[3] / temperature
+ self.coeffs[4] * temperature.ln())
}
}
}
impl Display for EmpiricalPermittivity {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"εᵣ(𝑇) = {:.2e} + {:.2e}𝑇 + {:.2e}𝑇² + {:.2e}/𝑇 + {:.2e}㏑(𝑇); 𝑇 = [{:.1}, {:.1}]",
self.coeffs[0],
self.coeffs[1],
self.coeffs[2],
self.coeffs[3],
self.coeffs[4],
self.temperature_interval.0,
self.temperature_interval.1
)
}
}