use RustedSciThe::symbolic::symbolic_engine::Expr;
use prettytable::{Cell, Row, Table};
use serde::de::Deserializer;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;
use std::error::Error;
use std::fmt;
use std::str::FromStr;
#[allow(non_upper_case_globals)]
const R: f64 = 1.987; #[allow(non_upper_case_globals)]
const Rsym: Expr = Expr::Const(1.987);
use crate::Thermodynamics::DBhandlers::NIST_parser::{Phase, SearchType};
#[derive(Debug)]
pub enum NASAError {
NoCoefficientsFound { temperature: f64, range: String },
InvalidTemperatureRange,
SerdeError(serde_json::Error),
UnsupportedUnit(String),
SymbolicError(String),
FittingError(String),
}
impl fmt::Display for NASAError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
NASAError::NoCoefficientsFound { temperature, range } => {
write!(
f,
"No coefficients found for temperature {} K. Valid range: {}",
temperature, range
)
}
NASAError::InvalidTemperatureRange => {
write!(f, "Invalid temperature range in coefficient data")
}
NASAError::SerdeError(msg) => {
write!(f, "Failed to deserialize NASA data: {}", msg)
}
NASAError::UnsupportedUnit(unit) => {
write!(
f,
"Unsupported unit: {}. Only 'J' and 'cal' are supported",
unit
)
}
NASAError::SymbolicError(msg) => {
write!(f, "Symbolic computation error: {}", msg)
}
NASAError::FittingError(msg) => {
write!(f, "Fitting error: {}", msg)
}
}
}
}
impl Error for NASAError {}
impl From<serde_json::Error> for NASAError {
fn from(err: serde_json::Error) -> Self {
NASAError::SerdeError(err)
}
}
pub fn Cp(t: f64, a: f64, b: f64, c: f64, d: f64, e: f64) -> f64 {
R * (a + b * t + c * t.powi(2) + d * t.powi(3) + e * t.powi(4))
}
pub fn dh(t: f64, a: f64, b: f64, c: f64, d: f64, e: f64, f: f64) -> f64 {
R * t
* (a + b * t / 2.0
+ c * t.powi(2) / 3.0
+ d * t.powi(3) / 4.0
+ e * t.powi(4) / 5.0
+ f / t)
}
pub fn ds(t: f64, a: f64, b: f64, c: f64, d: f64, e: f64, g: f64) -> f64 {
R * (a * t.ln() + b * t + c * t.powi(2) / 2.0 + d * t.powi(3) / 3.0 + e * t.powi(4) / 4.0 + g)
}
pub fn Cp_sym(a: f64, b: f64, c: f64, d: f64, e: f64) -> Expr {
let t = Expr::Var("T".to_owned());
let (a, b, c, d, e) = (
Expr::Const(a),
Expr::Const(b),
Expr::Const(c),
Expr::Const(d),
Expr::Const(e),
);
Rsym * (a
+ b * t.clone()
+ c * t.clone().pow(Expr::Const(2.0))
+ d * t.clone().pow(Expr::Const(3.0))
+ e * t.clone().pow(Expr::Const(4.0)))
}
pub fn dh_sym(a: f64, b: f64, c: f64, d: f64, e: f64, f: f64) -> Expr {
let t = Expr::Var("T".to_owned());
let (a, b, c, d, e, f) = (
Expr::Const(a),
Expr::Const(b),
Expr::Const(c),
Expr::Const(d),
Expr::Const(e),
Expr::Const(f),
);
Rsym * (a * t.clone()
+ b * t.clone().pow(Expr::Const(2.0)) / Expr::Const(2.0)
+ c * t.clone().pow(Expr::Const(3.0)) / Expr::Const(3.0)
+ d * t.clone().pow(Expr::Const(4.0)) / Expr::Const(4.0)
+ e * t.clone().pow(Expr::Const(5.0)) / Expr::Const(5.0)
+ f)
}
pub fn ds_sym(a: f64, b: f64, c: f64, d: f64, e: f64, g: f64) -> Expr {
let t = Expr::Var("T".to_owned());
let (a, b, c, d, e, g) = (
Expr::Const(a),
Expr::Const(b),
Expr::Const(c),
Expr::Const(d),
Expr::Const(e),
Expr::Const(g),
);
Rsym * (a * t.clone().ln()
+ b * t.clone()
+ c * t.clone().pow(Expr::Const(2.0)) / Expr::Const(2.0)
+ d * t.clone().pow(Expr::Const(3.0)) / Expr::Const(3.0)
+ e * t.clone().pow(Expr::Const(4.0)) / Expr::Const(4.0)
+ g)
}
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct NASAinput {
#[serde(deserialize_with = "deserialize_composition")]
pub composition: Option<HashMap<String, f64>>,
pub Cp: Vec<f64>,
pub model: String,
}
fn deserialize_composition<'de, D>(
deserializer: D,
) -> Result<Option<HashMap<String, f64>>, D::Error>
where
D: Deserializer<'de>,
{
let s: String = Deserialize::deserialize(deserializer)?;
if s.is_empty() {
return Ok(None);
}
let s = s.trim_matches(|c| c == '{' || c == '}');
let pairs: Result<HashMap<String, f64>, _> = s
.split(',')
.map(|pair| {
let mut parts = pair.trim().split(':');
let key = parts
.next()
.ok_or("Missing key")
.unwrap()
.trim()
.to_string();
let value = f64::from_str(parts.next().ok_or("Missing value").unwrap().trim())
.map_err(|_| "Invalid float")
.unwrap();
Ok((key, value))
})
.collect();
pairs.map(Some)
}
#[derive(Debug, Clone)]
pub struct Coeffs {
pub T: (f64, f64),
pub coeff: (f64, f64, f64, f64, f64, f64, f64),
}
pub struct NASAdata {
pub input: NASAinput,
pub unit: Option<String>,
pub unit_multiplier: f64,
pub coeffs: (f64, f64, f64, f64, f64, f64, f64),
pub coeffs_map: HashMap<usize, Coeffs>,
pub Cp: f64,
pub dh: f64,
pub ds: f64,
#[allow(clippy::type_complexity)]
pub C_fun: Box<dyn Fn(f64) -> f64 + Send + Sync>,
#[allow(clippy::type_complexity)]
pub dh_fun: Box<dyn Fn(f64) -> f64 + Send + Sync>,
#[allow(clippy::type_complexity)]
pub ds_fun: Box<dyn Fn(f64) -> f64 + Send + Sync>,
pub Cp_sym: Expr,
pub dh_sym: Expr,
pub ds_sym: Expr,
pub norm_threshold: f64,
pub T_interval: Option<(f64, f64)>,
pub fit_point_number: usize,
pub current_T_range: Option<(f64, f64)>,
}
impl NASAdata {
pub fn new() -> Self {
let input = NASAinput {
Cp: Vec::new(),
composition: None,
model: String::new(),
};
Self {
input: input,
unit: None,
unit_multiplier: 4.184,
coeffs: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
coeffs_map: HashMap::new(),
Cp: 0.0,
dh: 0.0,
ds: 0.0,
C_fun: Box::new(|x| x),
dh_fun: Box::new(|x| x),
ds_fun: Box::new(|x| x),
Cp_sym: Expr::Const(0.0),
dh_sym: Expr::Const(0.0),
ds_sym: Expr::Const(0.0),
T_interval: None,
fit_point_number: 1000,
norm_threshold: 0.1,
current_T_range: None,
}
}
pub fn set_unit(&mut self, unit: &str) -> Result<(), NASAError> {
match unit {
"J" => {
self.unit = Some("J".to_string());
self.unit_multiplier = 4.184;
Ok(())
}
"cal" => {
self.unit = Some("cal".to_string());
self.unit_multiplier = 1.0;
Ok(())
}
_ => Err(NASAError::UnsupportedUnit(unit.to_string())),
}
}
pub fn set_T_interval(&mut self, T_min: f64, T_max: f64) {
self.T_interval = Some((T_min, T_max));
}
pub fn from_serde(&mut self, serde: Value) -> Result<(), NASAError> {
self.input = serde_json::from_value(serde).map_err(|e| NASAError::SerdeError(e))?;
Ok(())
}
pub fn parse_coefficients(&mut self) -> Result<(), NASAError> {
let c_data = self.input.Cp.as_slice();
let mut coeffs_map = HashMap::new();
match c_data.len() {
25 => {
let (t1, t2, t3, t4) = (c_data[0], c_data[1], c_data[2], c_data[3]);
coeffs_map.insert(
0,
Coeffs {
T: (t1, t2),
coeff: (
c_data[4], c_data[5], c_data[6], c_data[7], c_data[8], c_data[9],
c_data[10],
),
},
);
coeffs_map.insert(
1,
Coeffs {
T: (t2, t3),
coeff: (
c_data[11], c_data[12], c_data[13], c_data[14], c_data[15], c_data[16],
c_data[17],
),
},
);
coeffs_map.insert(
2,
Coeffs {
T: (t3, t4),
coeff: (
c_data[18], c_data[19], c_data[20], c_data[21], c_data[22], c_data[23],
c_data[24],
),
},
);
}
17 => {
let (t1, t2, t3) = (c_data[0], c_data[1], c_data[2]);
coeffs_map.insert(
0,
Coeffs {
T: (t1, t2),
coeff: (
c_data[3], c_data[4], c_data[5], c_data[6], c_data[7], c_data[8],
c_data[9],
),
},
);
coeffs_map.insert(
1,
Coeffs {
T: (t2, t3),
coeff: (
c_data[10], c_data[11], c_data[12], c_data[13], c_data[14], c_data[15],
c_data[16],
),
},
);
}
9 => {
let (t1, t2) = (c_data[0], c_data[1]);
coeffs_map.insert(
0,
Coeffs {
T: (t1, t2),
coeff: (
c_data[2], c_data[3], c_data[4], c_data[5], c_data[6], c_data[7],
c_data[8],
),
},
);
}
_ => return Err(NASAError::InvalidTemperatureRange),
}
self.coeffs_map = coeffs_map.clone();
Ok(())
}
fn find_coefficients_for_temperature(
&mut self,
t: f64,
) -> Result<(f64, f64, f64, f64, f64, f64, f64), NASAError> {
for coeffs in self.coeffs_map.values() {
if coeffs.T.0 <= t && t <= coeffs.T.1 {
self.current_T_range = Some(coeffs.T.clone());
return Ok(coeffs.coeff);
}
}
let ranges: Vec<String> = self
.coeffs_map
.values()
.map(|c| format!("{}-{}", c.T.0, c.T.1))
.collect();
Err(NASAError::NoCoefficientsFound {
temperature: t,
range: ranges.join(", "),
})
}
pub fn extract_coefficients(&mut self, t: f64) -> Result<(), NASAError> {
if self.coeffs_map.is_empty() {
self.parse_coefficients()?;
}
self.coeffs = self.find_coefficients_for_temperature(t)?;
Ok(())
}
pub fn create_closures_Cp_dH_dS(&mut self) {
let (a, b, c, d, e, f, g) = self.coeffs;
let unit = self.unit_multiplier;
let Cp =
move |t: f64| unit * R * (a + b * t + c * t.powi(2) + d * t.powi(3) + e * t.powi(4));
self.C_fun = Box::new(Cp);
let dh = move |t: f64| {
unit * R
* t
* (a + b * t / 2.0
+ c * t.powi(2) / 3.0
+ d * t.powi(3) / 4.0
+ e * t.powi(4) / 5.0
+ f / t)
};
self.dh_fun = Box::new(dh);
let ds = move |t: f64| {
unit * R
* (a * t.ln()
+ b * t
+ c * t.powi(2) / 2.0
+ d * t.powi(3) / 3.0
+ e * t.powi(4) / 4.0
+ g)
};
self.ds_fun = Box::new(ds);
}
pub fn create_sym_Cp_dH_dS(&mut self) {
let (a, b, c, d, e, f, g) = self.coeffs;
let unit = Expr::Const(self.unit_multiplier);
let C_sym = unit.clone() * Cp_sym(a, b, c, d, e);
self.Cp_sym = C_sym.simplify();
let dh_sym = unit.clone() * dh_sym(a, b, c, d, e, f);
self.dh_sym = dh_sym.simplify();
let ds_sym = unit * ds_sym(a, b, c, d, e, g);
self.ds_sym = ds_sym.simplify();
}
pub fn Taylor_series_Cp_dH_dS(&mut self, T0: f64, n: usize) -> (Expr, Expr, Expr) {
let Cp = self.Cp_sym.clone();
let Cp_taylor = Cp.taylor_series1D("T", T0, n);
let dh = self.dh_sym.clone();
let dh_taylor = dh.taylor_series1D("T", T0, n);
let ds = self.ds_sym.clone();
let ds_taylor = ds.taylor_series1D("T", T0, n);
(Cp_taylor, dh_taylor, ds_taylor)
}
pub fn calculate_Cp_dH_dS(&mut self, t: f64) {
let (a, b, c, d, e, f, g) = self.coeffs;
let unit = self.unit_multiplier;
self.Cp = unit * Cp(t, a, b, c, d, e);
self.dh = unit * dh(t, a, b, c, d, e, f);
self.ds = unit * ds(t, a, b, c, d, e, g);
}
pub fn pretty_print(&self) {
let data = self.input.Cp.clone();
let len = data.len();
let T: Vec<f64> = if len == 25 {
data.clone().into_iter().take(4).collect()
} else if len == 17 {
data.clone().into_iter().take(3).collect()
} else if len == 9 {
data.clone().into_iter().take(2).collect()
} else {
vec![]
};
let coeffs: Vec<Vec<f64>> = if len == 25 {
data[4..].chunks(7).map(|chunk| chunk.to_vec()).collect()
} else if len == 17 {
data[3..].chunks(7).map(|chunk| chunk.to_vec()).collect()
} else if len == 9 {
data[2..].chunks(7).map(|chunk| chunk.to_vec()).collect()
} else {
vec![]
};
let mut table = Table::new();
let mut header_row = vec![Cell::new("Coefficients")];
for pairs in T.windows(2) {
let Tstr = format!("{:} - {:} ", pairs[0], pairs[1]);
header_row.push(Cell::new(&Tstr));
}
table.add_row(Row::new(header_row));
let coeffs_names = ["A", "B", "C", "D", "E", "F", "G"];
for (i, coeff_name) in coeffs_names.iter().enumerate() {
let mut row = vec![Cell::new(coeff_name)];
for coeff_for_every_T in coeffs.iter() {
let coeff = coeff_for_every_T[i].to_string();
row.push(Cell::new(&format!("{:}", coeff)));
}
table.add_row(Row::new(row));
}
table.printstd();
}
fn is_this_T_from_current_T_range(&self, t: f64) -> bool {
if let Some((T_min, T_max)) = self.current_T_range {
T_min <= t && t <= T_max
} else {
false
}
}
pub fn with_T_range<F>(&mut self, T: f64, function: F) -> Result<(), NASAError>
where
F: FnOnce(),
{
let is_this_T_from_current_T_range = self.is_this_T_from_current_T_range(T);
if is_this_T_from_current_T_range {
function();
Ok(())
} else {
self.interval_for_this_T(T)?;
self.extract_coefficients(T)?;
function();
Ok(())
}
}
pub fn with_T_range_mut<F, R>(&mut self, T: f64, function: F) -> Result<R, NASAError>
where
F: FnOnce() -> R,
{
let is_this_T_from_current_T_range = self.is_this_T_from_current_T_range(T);
if is_this_T_from_current_T_range {
Ok(function())
} else {
self.interval_for_this_T(T)?;
self.extract_coefficients(T)?;
Ok(function())
}
}
pub fn create_closures_Cp_dH_dS_with_T_range(&mut self, T: f64) -> Result<(), NASAError> {
let is_this_T_from_current_T_range = self.is_this_T_from_current_T_range(T);
if !is_this_T_from_current_T_range {
self.interval_for_this_T(T)?;
self.extract_coefficients(T)?;
}
self.create_closures_Cp_dH_dS();
Ok(())
}
pub fn calculate_Cp_dH_dS_with_T_range(&mut self, T: f64) -> Result<(), NASAError> {
let is_this_T_from_current_T_range = self.is_this_T_from_current_T_range(T);
if !is_this_T_from_current_T_range {
self.interval_for_this_T(T)?;
self.extract_coefficients(T)?;
}
self.calculate_Cp_dH_dS(T);
Ok(())
}
pub fn create_sym_Cp_dH_dS_with_T_range(&mut self, T: f64) -> Result<(), NASAError> {
let is_this_T_from_current_T_range = self.is_this_T_from_current_T_range(T);
if !is_this_T_from_current_T_range {
self.interval_for_this_T(T)?;
self.extract_coefficients(T)?;
}
self.create_sym_Cp_dH_dS();
Ok(())
}
pub fn interval_for_this_T(&mut self, t: f64) -> Result<(usize, Coeffs), NASAError> {
let intervals = self.coeffs_map.clone();
for (interval_idx, coeffs) in intervals {
if coeffs.T.0 <= t && t <= coeffs.T.1 {
self.current_T_range = Some(coeffs.T);
return Ok((interval_idx, coeffs.clone()));
}
}
Err(NASAError::InvalidTemperatureRange)
}
pub fn fitting_coeffs_for_T_interval(&mut self) -> Result<(), NASAError> {
if let Some((T_min, T_max)) = self.T_interval {
let (i_t_min, coeffs_min) = self.interval_for_this_T(T_min)?;
let (i_t_max, coeffs_max) = self.interval_for_this_T(T_max)?;
if i_t_min == i_t_max {
self.coeffs = coeffs_min.coeff.clone();
} else if (i_t_max as isize - i_t_min as isize).abs() == 1 {
let result =
self.fitting_adjacent2(coeffs_min.clone(), coeffs_max.clone(), T_min, T_max);
match result {
Ok(_) => {
self.current_T_range = self.T_interval;
} _ => {
println!("fitting_adjacent2 failed, falling back to fitting_adjacent");
self.fit_cp_dh_ds(coeffs_min.clone(), coeffs_max.clone(), T_min, T_max)?;
self.current_T_range = self.T_interval;
}
}
} else if (i_t_max as isize - i_t_min as isize).abs() > 1 {
let mut coeffs_in_range = Vec::new();
for (_, coeffs) in &self.coeffs_map {
if coeffs.T.1 > T_min && coeffs.T.0 < T_max {
coeffs_in_range.push(coeffs.clone());
}
}
let result = self.fitting_non_adjacent(coeffs_in_range.clone(), T_min, T_max);
match result {
Ok(_) => {
self.current_T_range = self.T_interval;
} _ => {
self.fitting_cp_dh_ds_non_adjacent(coeffs_in_range, T_min, T_max)?;
self.current_T_range = self.T_interval;
}
}
} else {
return Err(NASAError::InvalidTemperatureRange);
}
Ok(())
} else {
Err(NASAError::InvalidTemperatureRange)
}
}
pub fn integr_mean(&mut self) -> Result<(), NASAError> {
let (T_min, T_max) = self.T_interval.ok_or(NASAError::InvalidTemperatureRange)?;
if T_min >= T_max {
return Err(NASAError::InvalidTemperatureRange);
}
let T_range = T_max - T_min;
let inv_T_range = 1.0 / T_range;
let ds_sym = self.ds_sym.clone();
let ds_integral = ds_sym
.definite_integrate("T", T_min, T_max)
.map_err(|e| NASAError::SymbolicError(format!("Failed to integrate entropy: {}", e)))?;
let ds_mean = inv_T_range * ds_integral;
let dh_sym = self.dh_sym.clone().simplify();
let dh_integral = dh_sym.definite_integrate("T", T_min, T_max).map_err(|e| {
NASAError::SymbolicError(format!("Failed to integrate enthalpy: {}", e))
})?;
let dh_mean = inv_T_range * dh_integral;
let Cp_sym = self.Cp_sym.clone();
let Cp_integral = Cp_sym.definite_integrate("T", T_min, T_max).map_err(|e| {
NASAError::SymbolicError(format!("Failed to integrate heat capacity: {}", e))
})?;
let Cp_mean = inv_T_range * Cp_integral;
self.Cp = Cp_mean;
self.dh = dh_mean;
self.ds = ds_mean;
Ok(())
}
}
impl fmt::Debug for NASAdata {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("NASAdata")
.field("input", &self.input)
.field("unit", &self.unit)
.field("unit_multiplier", &self.unit_multiplier)
.field("coeffs", &self.coeffs)
.field("Cp", &self.Cp)
.field("dh", &self.dh)
.field("ds", &self.ds)
.field("Cp_sym", &self.Cp_sym)
.field("dh_sym", &self.dh_sym)
.field("ds_sym", &self.ds_sym)
.finish_non_exhaustive() }
}
impl Clone for NASAdata {
fn clone(&self) -> Self {
let (a, b, c, d, e, f, g) = self.coeffs;
let unit = self.unit_multiplier;
NASAdata {
input: self.input.clone(),
unit: self.unit.clone(),
unit_multiplier: self.unit_multiplier,
coeffs: self.coeffs,
coeffs_map: self.coeffs_map.clone(),
Cp: self.Cp,
dh: self.dh,
ds: self.ds,
C_fun: Box::new(move |t| {
unit * R * (a + b * t + c * t.powi(2) + d * t.powi(3) + e * t.powi(4))
}),
dh_fun: Box::new(move |t| {
unit * R
* t
* (a + b * t / 2.0
+ c * t.powi(2) / 3.0
+ d * t.powi(3) / 4.0
+ e * t.powi(4) / 5.0
+ f / t)
}),
ds_fun: Box::new(move |t| {
unit * R
* (a * t.ln()
+ b * t
+ c * t.powi(2) / 2.0
+ d * t.powi(3) / 3.0
+ e * t.powi(4) / 4.0
+ g)
}),
Cp_sym: self.Cp_sym.clone(),
dh_sym: self.dh_sym.clone(),
ds_sym: self.ds_sym.clone(),
T_interval: self.T_interval.clone(),
fit_point_number: self.fit_point_number,
norm_threshold: self.norm_threshold.clone(),
current_T_range: self.current_T_range.clone(),
}
}
}
use super::thermo_api::{EnergyUnit, ThermoCalculator, ThermoError, energy_dimension};
impl ThermoCalculator for NASAdata {
fn newinstance(&mut self) -> Result<(), ThermoError> {
*self = NASAdata::new();
Ok(())
}
fn extract_model_coefficients(&mut self, t: f64) -> Result<(), ThermoError> {
self.extract_coefficients(t)?;
Ok(())
}
fn parse_coefficients(&mut self) -> Result<(), ThermoError> {
self.parse_coefficients()?;
Ok(())
}
fn set_unit(&mut self, unit: Option<EnergyUnit>) -> Result<(), ThermoError> {
if let Some(unit) = unit {
self.set_unit(&energy_dimension(unit))
.map_err(|e| ThermoError::UnsupportedUnit(e.to_string()))?;
}
Ok(())
}
fn from_serde(&mut self, serde: Value) -> Result<(), ThermoError> {
self.from_serde(serde)?;
Ok(())
}
fn calculate_Cp_dH_dS(&mut self, temperature: f64) -> Result<(), ThermoError> {
self.calculate_Cp_dH_dS(temperature);
Ok(())
}
fn create_closures_Cp_dH_dS(&mut self) -> Result<(), ThermoError> {
self.create_closures_Cp_dH_dS();
Ok(())
}
fn create_sym_Cp_dH_dS(&mut self) -> Result<(), ThermoError> {
self.create_sym_Cp_dH_dS();
Ok(())
}
fn Taylor_series_cp_dh_ds(
&mut self,
temperature: f64,
order: usize,
) -> Result<(Expr, Expr, Expr), ThermoError> {
let (Cp, dh, ds) = self.Taylor_series_Cp_dH_dS(temperature, order);
Ok((Cp, dh, ds))
}
fn pretty_print_data(&self) -> Result<(), ThermoError> {
self.pretty_print();
Ok(())
}
fn renew_base(
&mut self,
_sub_name: String,
_search_type: SearchType,
_phase: Phase,
) -> Result<(), ThermoError> {
Ok(())
}
fn get_coefficients(&self) -> Result<Vec<f64>, ThermoError> {
let (a, b, c, d, e, f, g) = self.coeffs;
Ok(vec![a, b, c, d, e, f, g])
}
fn print_instance(&self) -> Result<(), ThermoError> {
println!("{:?}", &self);
Ok(())
}
fn get_Cp(&self) -> Result<f64, ThermoError> {
Ok(self.Cp)
}
fn get_dh(&self) -> Result<f64, ThermoError> {
Ok(self.dh)
}
fn get_ds(&self) -> Result<f64, ThermoError> {
Ok(self.ds)
}
fn get_C_fun(&self) -> Result<Box<dyn Fn(f64) -> f64 + Send + Sync>, ThermoError> {
Ok(self.clone().C_fun)
}
fn get_dh_fun(&self) -> Result<Box<dyn Fn(f64) -> f64 + Send + Sync>, ThermoError> {
Ok(self.clone().dh_fun)
}
fn get_ds_fun(&self) -> Result<Box<dyn Fn(f64) -> f64 + Send + Sync>, ThermoError> {
Ok(self.clone().ds_fun)
}
fn get_Cp_sym(&self) -> Result<Expr, ThermoError> {
Ok(self.Cp_sym.clone())
}
fn get_dh_sym(&self) -> Result<Expr, ThermoError> {
Ok(self.dh_sym.clone())
}
fn get_ds_sym(&self) -> Result<Expr, ThermoError> {
Ok(self.ds_sym.clone())
}
fn get_composition(&self) -> Result<Option<HashMap<String, f64>>, ThermoError> {
Ok(self.input.composition.clone())
}
fn fitting_coeffs_for_T_interval(&mut self) -> Result<(), ThermoError> {
self.fitting_coeffs_for_T_interval()?;
Ok(())
}
fn integr_mean(&mut self) -> Result<(), ThermoError> {
self.integr_mean()?;
Ok(())
}
fn set_T_interval(&mut self, T_min: f64, T_max: f64) -> Result<(), ThermoError> {
self.set_T_interval(T_min, T_max);
Ok(())
}
fn calculate_Cp_dH_dS_with_T_range(&mut self, T: f64) -> Result<(), ThermoError> {
self.calculate_Cp_dH_dS_with_T_range(T)?;
Ok(())
}
fn create_closures_Cp_dH_dS_with_T_range(&mut self, T: f64) -> Result<(), ThermoError> {
self.create_closures_Cp_dH_dS_with_T_range(T)?;
Ok(())
}
fn create_sym_Cp_dH_dS_with_T_range(&mut self, T: f64) -> Result<(), ThermoError> {
self.create_sym_Cp_dH_dS_with_T_range(T)?;
Ok(())
}
fn is_coeffs_valid_for_T(&self, T: f64) -> Result<bool, ThermoError> {
let flag = self.is_this_T_from_current_T_range(T);
Ok(flag)
}
}