#[cfg(test)]
mod tests {
use crate::Thermodynamics::User_PhaseOrSolution::{
PhaseOrSolution, SubstanceSystemFactory, SubstancesContainer, SubstancePhaseMapping, CustomSubstance
};
use crate::Thermodynamics::User_PhaseOrSolution2::OnePhase;
use crate::Thermodynamics::User_substances::{LibraryPriority, Phases, SubsData};
use RustedSciThe::symbolic::symbolic_engine::Expr;
use nalgebra::DMatrix;
use approx::assert_relative_eq;
use std::collections::HashMap;
use crate::Thermodynamics::User_PhaseOrSolution::ThermodynamicsCalculatorTrait;
#[test]
fn test_substance_phase_mapping_basic() {
let subs = vec!["A".to_string(), "B".to_string()];
let phases = vec![Some("p1".to_string()), Some("p2".to_string())];
let mapping = SubstancePhaseMapping::new(subs.clone(), phases.clone());
assert_eq!(mapping.all_substances, subs);
assert_eq!(mapping.substance_to_phase, phases);
assert_eq!(mapping.get_phase_for_substance(0).unwrap(), &Some("p1".to_string()));
}
#[test]
fn test_create_system_single_and_multi_phase() {
let subs = vec!["CO".to_string(), "CO2".to_string()];
let container = SubstancesContainer::SinglePhase(subs.clone());
let res = SubstanceSystemFactory::create_system(
container,
None,
vec!["NASA_gas".to_string()],
vec!["NIST".to_string()],
None,
false,
);
assert!(res.is_ok());
match res.unwrap() {
crate::Thermodynamics::User_PhaseOrSolution::CustomSubstance::OnePhase(op) => {
assert_eq!(op.subs_data.substances, subs);
}
_ => panic!("expected one phase"),
}
let mut phases = HashMap::new();
phases.insert("gas".to_string(), vec!["H2".to_string(), "O2".to_string()]);
phases.insert("liquid".to_string(), vec!["H2O".to_string()]);
let container = SubstancesContainer::MultiPhase(phases);
let res = SubstanceSystemFactory::create_system(
container,
None,
vec!["NASA_gas".to_string()],
vec!["NIST".to_string()],
None,
false,
);
assert!(res.is_ok());
match res.unwrap() {
crate::Thermodynamics::User_PhaseOrSolution::CustomSubstance::PhaseOrSolution(p) => {
assert!(p.subs_data.contains_key(&Some("gas".to_string())));
assert!(p.subs_data.contains_key(&Some("liquid".to_string())));
}
_ => panic!("expected phase or solution"),
}
}
#[test]
fn test_create_full_map_of_mole_numbers_phase_or_solution() {
let mut pos = PhaseOrSolution::new();
let mut s1 = SubsData::new();
s1.substances = vec!["A".to_string(), "B".to_string()];
let mut s2 = SubsData::new();
s2.substances = vec!["B".to_string(), "C".to_string()];
pos.subs_data.insert(Some("p1".to_string()), s1);
pos.subs_data.insert(Some("p2".to_string()), s2);
let mut input: HashMap<Option<String>, (Option<f64>, Option<HashMap<String, f64>>)> =
HashMap::new();
input.insert(
Some("p1".to_string()),
(
Some(1.0),
Some(HashMap::from([("A".to_string(), 0.3)])),
),
);
let (full_map, vec_map, summed) = pos
.create_full_map_of_mole_numbers(input.clone())
.unwrap();
let p1_inner = full_map.get(&Some("p1".to_string())).unwrap();
assert!(p1_inner.1.as_ref().unwrap().contains_key("B"));
assert_eq!(p1_inner.1.as_ref().unwrap().get("B").unwrap(), &0.0);
let p1_vec = vec_map.get(&Some("p1".to_string())).unwrap();
assert!(p1_vec.1.as_ref().unwrap().len() == 2);
assert!(summed.contains_key("A"));
assert_eq!(summed.get("A").unwrap(), &0.3);
}
#[test]
fn test_indexed_moles_variables_and_symbolic_vars() {
let mut pos = PhaseOrSolution::new();
let mut s1 = SubsData::new();
s1.substances = vec!["X".to_string(), "Y".to_string()];
let mut s2 = SubsData::new();
s2.substances = vec!["Z".to_string()];
pos.subs_data.insert(Some("p1".to_string()), s1);
pos.subs_data.insert(Some("p2".to_string()), s2);
let (_map_indexed, vec_of_n_vars, np_vec, map_of_var_each) =
pos.indexed_moles_variables().unwrap();
assert_eq!(np_vec.len(), 2);
assert_eq!(vec_of_n_vars.len(), 3);
let p1_map = map_of_var_each.get(&Some("p1".to_string()));
assert!(p1_map.is_some());
assert!(p1_map.unwrap().contains_key("X"));
assert!(p1_map.unwrap().contains_key("Y"));
}
#[test]
fn test_calculate_lagrange_equations_sym_and_fun() {
let mut pos = PhaseOrSolution::new();
let mut s = SubsData::new();
s.substances = vec!["A".to_string(), "B".to_string()];
pos.subs_data.insert(Some("mix".to_string()), s);
let mut inner = HashMap::new();
inner.insert("A".to_string(), Expr::Const(1.0));
inner.insert("B".to_string(), Expr::Const(2.0));
let mut outer = HashMap::new();
outer.insert(Some("mix".to_string()), inner);
pos.dG_sym = outer;
let A = DMatrix::from_vec(2, 1, vec![1.0, 1.0]);
let eqs = pos.calculate_Lagrange_equations_sym(A.clone(), 300.0).unwrap();
assert_eq!(eqs.len(), 2);
let mut gfun_phase = HashMap::new();
gfun_phase.insert(
"A".to_string(),
Box::new(|_T: f64, _n: Option<Vec<f64>>, _Np: Option<f64>| 1.0f64) as Box<dyn Fn(f64, Option<Vec<f64>>, Option<f64>) -> f64>,
);
gfun_phase.insert(
"B".to_string(),
Box::new(|_T: f64, _n: Option<Vec<f64>>, _Np: Option<f64>| 2.0f64) as Box<dyn Fn(f64, Option<Vec<f64>>, Option<f64>) -> f64>,
);
let mut G_fun = HashMap::new();
G_fun.insert(Some("mix".to_string()), gfun_phase);
let f = pos.calculate_Lagrange_equations_fun(A.clone(), G_fun, 300.0).unwrap();
let vals = f(300.0, None, None, vec![0.5]);
assert_eq!(vals.len(), 2);
let expected_a = 0.5 + 1.0f64 / (crate::Thermodynamics::User_PhaseOrSolution::R * 300.0);
assert_relative_eq!(vals[0], expected_a, epsilon = 1e-12);
}
#[test]
fn test_set_T_and_P_in_G_sym() {
let mut pos = PhaseOrSolution::new();
let mut s = SubsData::new();
s.substances = vec!["A".to_string()];
pos.subs_data.insert(Some("p".to_string()), s);
let mut inner = HashMap::new();
inner.insert("A".to_string(), Expr::Var("T".to_string()) + Expr::Var("P".to_string()));
let mut outer = HashMap::new();
outer.insert(Some("p".to_string()), inner);
pos.dG_sym = outer;
pos.set_P_to_sym_in_G_sym(101325.0);
pos.set_T_to_sym_in_G_sym(298.15);
let v = pos.dG_sym.get(&Some("p".to_string())).unwrap();
let expr = v.get("A").unwrap();
let expected = Expr::Const(298.15 + 101325.0);
assert_eq!(format!("{}", expr.simplify()), format!("{}", expected.simplify()));
}
#[test]
fn test_substance_system_factory_multi_phase() {
let mut phase_substances = HashMap::new();
phase_substances.insert("gas".to_string(), vec!["N2".to_string(), "O2".to_string()]);
phase_substances.insert("gas2".to_string(), vec!["H2O".to_string()]);
let container = SubstancesContainer::MultiPhase(phase_substances);
let result = SubstanceSystemFactory::create_system(
container,
None,
vec!["NASA_gas".to_string()],
vec!["NIST".to_string()],
None,
false,
);
assert!(result.is_ok());
let mut pos = match result.unwrap() {
CustomSubstance::PhaseOrSolution(pos) => pos,
_ => panic!("Expected PhaseOrSolution"),
};
let thermal_result = pos.extract_all_thermal_coeffs(400.0);
assert!(thermal_result.is_ok());
let therm_props_result = pos.calculate_therm_map_of_properties(400.0);
assert!(therm_props_result.is_ok());
let therm_sym_result = pos.calculate_therm_map_of_sym();
assert!(therm_sym_result.is_ok());
let all_subs = pos.get_all_substances();
assert_eq!(all_subs.len(), 3);
assert!(all_subs.contains(&"N2".to_string()));
assert!(all_subs.contains(&"O2".to_string()));
assert!(all_subs.contains(&"H2O".to_string()));
let container_result = pos.extract_SubstancesContainer();
assert!(container_result.is_ok());
match container_result.unwrap() {
SubstancesContainer::MultiPhase(phases) => {
assert!(phases.contains_key("gas"));
assert!(phases.contains_key("gas2"));
assert_eq!(phases["gas"].len(), 2);
assert_eq!(phases["gas2"].len(), 1);
}
_ => panic!("Expected MultiPhase container"),
}
let elem_comp_result = pos.calculate_elem_composition_and_molar_mass(None);
assert!(elem_comp_result.is_ok());
let (matrix, molar_masses, elements) = elem_comp_result.unwrap();
assert_eq!(matrix.nrows(), 3); assert!(matrix.ncols() >= 2); assert!(molar_masses.contains_key("N2"));
assert!(molar_masses.contains_key("O2"));
assert!(molar_masses.contains_key("H2O"));
assert!(elements.contains(&"N".to_string()));
assert!(elements.contains(&"O".to_string()));
assert!(elements.contains(&"H".to_string()));
let indexed_vars_result = pos.indexed_moles_variables();
assert!(indexed_vars_result.is_ok());
let (map_indexed, vec_of_n_vars, np_vec, map_of_var_each) = indexed_vars_result.unwrap();
assert_eq!(vec_of_n_vars.len(), 3); assert_eq!(np_vec.len(), 2); assert!(map_indexed.contains_key(&Some("gas".to_string())));
assert!(map_indexed.contains_key(&Some("gas2".to_string())));
assert!(map_of_var_each.contains_key(&Some("gas".to_string())));
assert!(map_of_var_each.contains_key(&Some("gas2".to_string())));
let gibbs_sym_result = pos.calculate_Gibbs_sym(400.0);
assert!(gibbs_sym_result.is_ok());
assert!(!pos.dG_sym.is_empty());
pos.calculate_Gibbs_fun(400.0, 101325.0);
assert!(!pos.dG_fun.is_empty());
let entropy_sym_result = pos.calculate_S_sym(400.0);
assert!(entropy_sym_result.is_ok());
assert!(!pos.dS_sym.is_empty());
pos.calculate_S_fun(400.0, 101325.0);
assert!(!pos.dS_fun.is_empty());
let mut n = HashMap::new();
let gas_moles = vec![0.4, 0.2];
let gas2_moles = vec![0.4];
n.insert(Some("gas".to_string()), (Some(0.6), Some(gas_moles)));
n.insert(Some("gas2".to_string()), (Some(0.4), Some(gas2_moles)));
let gibbs_energy_result = pos.calcutate_Gibbs_free_energy(400.0, 101325.0, n.clone());
assert!(gibbs_energy_result.is_ok());
let gibbs_map = gibbs_energy_result.unwrap();
assert!(gibbs_map.contains_key(&Some("gas".to_string())));
assert!(gibbs_map.contains_key(&Some("gas2".to_string())));
let entropy_result = pos.calculate_S(400.0, 101325.0, n);
assert!(entropy_result.is_ok());
assert!(!pos.dS.is_empty());
let molar_masses = HashMap::from([
("N2".to_string(), 28.014),
("O2".to_string(), 31.998),
("H2O".to_string(), 18.015),
]);
let config_result = pos.configure_system_properties(101325.0, Some("Pa".to_string()), molar_masses, Some("g/mol".to_string()));
assert!(config_result.is_ok());
let nist_result = pos.if_not_found_go_NIST();
assert!(nist_result.is_ok());
let coeffs_result = pos.extract_coeffs_if_current_coeffs_not_valid(400.0);
assert!(coeffs_result.is_ok());
let mut partial_n = HashMap::new();
let partial_gas_moles = HashMap::from([
("N2".to_string(), 0.5),
]);
partial_n.insert(Some("gas".to_string()), (Some(0.6), Some(partial_gas_moles)));
partial_n.insert(Some("gas2".to_string()), (Some(0.4), Some(HashMap::from([("H2O".to_string(), 0.4)]))));
let full_map_result = pos.create_full_map_of_mole_numbers(partial_n);
assert!(full_map_result.is_ok());
let (full_map, vec_map, summed) = full_map_result.unwrap();
let gas_data = full_map.get(&Some("gas".to_string())).unwrap();
let gas_moles = gas_data.1.as_ref().unwrap();
assert!(gas_moles.contains_key("O2"));
assert_relative_eq!(*gas_moles.get("O2").unwrap(), 0.0, epsilon = 1e-10);
assert!(summed.contains_key("N2"));
assert!(summed.contains_key("O2"));
assert!(summed.contains_key("H2O"));
assert_relative_eq!(*summed.get("N2").unwrap(), 0.5, epsilon = 1e-10);
assert_relative_eq!(*summed.get("O2").unwrap(), 0.0, epsilon = 1e-10);
assert_relative_eq!(*summed.get("H2O").unwrap(), 0.4, epsilon = 1e-10);
pos.set_P_to_sym_in_G_sym(200000.0);
pos.set_T_to_sym_in_G_sym(350.0);
assert!(!pos.dG_sym.is_empty());
let gas_sym = pos.dG_sym.get(&Some("gas".to_string())).unwrap();
let n2_expr = gas_sym.get("N2").unwrap();
assert!(!format!("{}", n2_expr).contains("T"));
assert!(!format!("{}", n2_expr).contains("P"));
let _ = pos.indexed_moles_variables();
let _ = pos.calculate_Gibbs_sym(400.0);
let A = DMatrix::from_vec(3, 2, vec![2.0, 0.0, 0.0, 2.0, 1.0, 0.0]); let lagrange_sym_result = pos.calculate_Lagrange_equations_sym(A.clone(), 400.0);
assert!(lagrange_sym_result.is_ok());
let lagrange_eqs = lagrange_sym_result.unwrap();
assert_eq!(lagrange_eqs.len(), 3);
let lagrange_fun2_result = pos.calculate_Lagrange_equations_fun2(A, 400.0, 101325.0, 400.0);
assert!(lagrange_fun2_result.is_ok());
let lagrange_fun2 = lagrange_fun2_result.unwrap();
let test_vals2 = lagrange_fun2(400.0, None, None, vec![0.5, 1.5]);
assert_eq!(test_vals2.len(), 3);
}
}