use std::sync::Arc;
use crate::symbolic::calculus::differentiate;
use crate::symbolic::core::Expr;
use crate::symbolic::simplify_dag::simplify;
#[must_use]
pub fn first_law_thermodynamics(
internal_energy_change: &Expr,
heat_added: &Expr,
work_done: &Expr,
) -> Expr {
simplify(&Expr::new_sub(
internal_energy_change.clone(),
Expr::new_sub(heat_added.clone(), work_done.clone()),
))
}
#[must_use]
pub fn ideal_gas_law(
p: &Expr,
v: &Expr,
n: &Expr,
r: &Expr,
t: &Expr,
) -> Expr {
simplify(&Expr::new_sub(
Expr::new_mul(p.clone(), v.clone()),
Expr::new_mul(n.clone(), Expr::new_mul(r.clone(), t.clone())),
))
}
#[must_use]
pub fn enthalpy(
internal_energy: &Expr,
pressure: &Expr,
volume: &Expr,
) -> Expr {
simplify(&Expr::new_add(
internal_energy.clone(),
Expr::new_mul(pressure.clone(), volume.clone()),
))
}
#[must_use]
pub fn helmholtz_free_energy(
internal_energy: &Expr,
temperature: &Expr,
entropy: &Expr,
) -> Expr {
simplify(&Expr::new_sub(
internal_energy.clone(),
Expr::new_mul(temperature.clone(), entropy.clone()),
))
}
#[must_use]
pub fn gibbs_free_energy(
enthalpy: &Expr,
temperature: &Expr,
entropy: &Expr,
) -> Expr {
simplify(&Expr::new_sub(
enthalpy.clone(),
Expr::new_mul(temperature.clone(), entropy.clone()),
))
}
#[must_use]
pub fn boltzmann_entropy(omega: &Expr) -> Expr {
let k_b = Expr::new_variable("k_B");
simplify(&Expr::new_mul(k_b, Expr::new_log(omega.clone())))
}
#[must_use]
pub fn carnot_efficiency(
t_cold: &Expr,
t_hot: &Expr,
) -> Expr {
simplify(&Expr::new_sub(
Expr::Constant(1.0),
Expr::new_div(t_cold.clone(), t_hot.clone()),
))
}
#[must_use]
pub fn boltzmann_distribution(
energy: &Expr,
temperature: &Expr,
partition_function: &Expr,
) -> Expr {
let k_b = Expr::new_variable("k_B");
let exponent = Expr::new_neg(Arc::new(Expr::new_div(
energy.clone(),
Expr::new_mul(k_b, temperature.clone()),
)));
simplify(&Expr::new_div(
Expr::new_exp(exponent),
partition_function.clone(),
))
}
#[must_use]
pub fn partition_function(
energies: &[Expr],
temperature: &Expr,
) -> Expr {
let k_b = Expr::new_variable("k_B");
let mut z = Expr::Constant(0.0);
for e in energies {
let exponent = Expr::new_neg(Arc::new(Expr::new_div(
e.clone(),
Expr::new_mul(k_b.clone(), temperature.clone()),
)));
z = Expr::new_add(z, Expr::new_exp(exponent));
}
simplify(&z)
}
#[must_use]
pub fn fermi_dirac_distribution(
energy: &Expr,
chemical_potential: &Expr,
temperature: &Expr,
) -> Expr {
let k_b = Expr::new_variable("k_B");
let exponent = Expr::new_div(
Expr::new_sub(energy.clone(), chemical_potential.clone()),
Expr::new_mul(k_b, temperature.clone()),
);
simplify(&Expr::new_div(
Expr::Constant(1.0),
Expr::new_add(Expr::new_exp(exponent), Expr::Constant(1.0)),
))
}
#[must_use]
pub fn bose_einstein_distribution(
energy: &Expr,
chemical_potential: &Expr,
temperature: &Expr,
) -> Expr {
let k_b = Expr::new_variable("k_B");
let exponent = Expr::new_div(
Expr::new_sub(energy.clone(), chemical_potential.clone()),
Expr::new_mul(k_b, temperature.clone()),
);
simplify(&Expr::new_div(
Expr::Constant(1.0),
Expr::new_sub(Expr::new_exp(exponent), Expr::Constant(1.0)),
))
}
#[must_use]
pub fn work_isothermal_expansion(
n: &Expr,
r: &Expr,
t: &Expr,
v1: &Expr,
v2: &Expr,
) -> Expr {
simplify(&Expr::new_mul(
Expr::new_mul(n.clone(), Expr::new_mul(r.clone(), t.clone())),
Expr::new_log(Expr::new_div(v2.clone(), v1.clone())),
))
}
#[must_use]
pub fn verify_maxwell_relation_helmholtz(
a: &Expr,
t_var: &str,
v_var: &str,
) -> Expr {
let da_dt = differentiate(a, t_var);
let d2a_dt_dv = differentiate(&da_dt, v_var);
let da_dv = differentiate(a, v_var);
let d2a_dv_dt = differentiate(&da_dv, t_var);
simplify(&Expr::new_sub(d2a_dt_dv, d2a_dv_dt))
}