use dyn_quantity::{DynQuantity, Unit, UnitsNotEqual};
#[cfg(feature = "serde")]
use dyn_quantity::serialize_quantity;
use crate::{IsQuantityFunction, filter_unary_function};
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct FirstOrderTaylor {
#[cfg_attr(feature = "serde", serde(serialize_with = "serialize_quantity"))]
base_value: DynQuantity<f64>,
#[cfg_attr(feature = "serde", serde(serialize_with = "serialize_quantity"))]
slope: DynQuantity<f64>,
#[cfg_attr(feature = "serde", serde(serialize_with = "serialize_quantity"))]
expansion_point: DynQuantity<f64>,
}
impl FirstOrderTaylor {
pub fn new(
base_value: DynQuantity<f64>,
slope: DynQuantity<f64>,
expansion_point: DynQuantity<f64>,
) -> Result<Self, UnitsNotEqual> {
let expected = Unit::default();
let found = expansion_point.unit * slope.unit;
if expected == found {
return Ok(Self {
base_value,
slope,
expansion_point,
});
} else {
return Err(UnitsNotEqual(expected, found));
}
}
pub fn base_value(&self) -> &DynQuantity<f64> {
return &self.base_value;
}
pub fn expansion_point(&self) -> &DynQuantity<f64> {
return &self.expansion_point;
}
pub fn slope(&self) -> &DynQuantity<f64> {
return &self.slope;
}
pub fn influencing_factor_unit(&self) -> Unit {
return self.expansion_point.unit;
}
pub fn output_unit(&self) -> Unit {
return self.base_value.unit;
}
}
#[cfg_attr(feature = "serde", typetag::serde)]
impl IsQuantityFunction for FirstOrderTaylor {
fn call(&self, conditions: &[DynQuantity<f64>]) -> DynQuantity<f64> {
return filter_unary_function(
conditions,
self.expansion_point.unit,
|input| {
self.base_value
* (1.0 + self.slope.value * (input.value - self.expansion_point.value))
},
|| self.base_value,
);
}
fn dyn_eq(&self, other: &dyn IsQuantityFunction) -> bool {
(other as &dyn std::any::Any).downcast_ref::<Self>() == Some(self)
}
}
#[cfg(feature = "serde")]
mod serde_impl {
use super::*;
use serde::de::{Deserialize, Deserializer};
impl<'de> Deserialize<'de> for FirstOrderTaylor {
fn deserialize<D>(deserializer: D) -> Result<FirstOrderTaylor, D::Error>
where
D: Deserializer<'de>,
{
#[derive(serde::Deserialize)]
struct FirstOrderTaylorAlias {
base_value: DynQuantity<f64>,
expansion_point: DynQuantity<f64>,
slope: DynQuantity<f64>,
}
let alias = FirstOrderTaylorAlias::deserialize(deserializer)?;
Self::new(alias.base_value, alias.slope, alias.expansion_point)
.map_err(serde::de::Error::custom)
}
}
}
#[cfg(feature = "serde")]
#[cfg_attr(feature = "serde", typetag::serde)]
impl IsQuantityFunction for crate::ClampedQuantity<FirstOrderTaylor> {
fn call(&self, conditions: &[DynQuantity<f64>]) -> DynQuantity<f64> {
return self.call_clamped(conditions);
}
fn dyn_eq(&self, other: &dyn IsQuantityFunction) -> bool {
(other as &dyn std::any::Any).downcast_ref::<Self>() == Some(self)
}
}