use serde::Deserialize;
use serde::Serialize;
use crate::symbolic::calculus::differentiate;
use crate::symbolic::core::Expr;
use crate::symbolic::simplify_dag::simplify;
use crate::symbolic::vector::Vector;
use crate::symbolic::vector::curl;
use crate::symbolic::vector::divergence;
use crate::symbolic::vector::gradient;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MaxwellEquations {
pub gauss_law_electric: Expr,
pub gauss_law_magnetic: Expr,
pub faradays_law: Expr,
pub amperes_law: Expr,
}
impl MaxwellEquations {
#[must_use]
pub fn new(
e_field: &Vector,
b_field: &Vector,
rho: &Expr,
j_field: &Vector,
vars: (&str, &str, &str),
t_var: &str,
) -> Self {
let epsilon_0 = Expr::new_variable("epsilon_0");
let mu_0 = Expr::new_variable("mu_0");
let gauss_law_electric = simplify(&Expr::new_sub(
divergence(e_field, vars),
Expr::new_div(rho.clone(), epsilon_0.clone()),
));
let gauss_law_magnetic = simplify(&divergence(b_field, vars));
let faradays_law = {
let lhs = curl(e_field, vars);
let rhs = Vector::new(
differentiate(&b_field.x, t_var),
differentiate(&b_field.y, t_var),
differentiate(&b_field.z, t_var),
)
.scalar_mul(&Expr::Constant(-1.0));
(lhs - rhs).to_expr()
};
let amperes_law = {
let lhs = curl(b_field, vars);
let de_dt = Vector::new(
differentiate(&e_field.x, t_var),
differentiate(&e_field.y, t_var),
differentiate(&e_field.z, t_var),
);
let rhs = (j_field.clone() + de_dt.scalar_mul(&epsilon_0)).scalar_mul(&mu_0);
(lhs - rhs).to_expr()
};
Self {
gauss_law_electric,
gauss_law_magnetic,
faradays_law,
amperes_law,
}
}
}
#[must_use]
pub fn lorentz_force(
charge: &Expr,
e_field: &Vector,
velocity: &Vector,
b_field: &Vector,
) -> Vector {
let v_cross_b = velocity.cross(b_field);
let term = e_field.clone() + v_cross_b;
term.scalar_mul(charge)
}
#[must_use]
pub fn electric_field_from_potentials(
v: &Expr,
a: &Vector,
vars: (&str, &str, &str),
t_var: &str,
) -> Vector {
let grad_v = gradient(v, vars);
let da_dt = Vector::new(
differentiate(&a.x, t_var),
differentiate(&a.y, t_var),
differentiate(&a.z, t_var),
);
(grad_v + da_dt).scalar_mul(&Expr::Constant(-1.0))
}
#[must_use]
pub fn electric_field_from_potential(
v: &Expr,
vars: (&str, &str, &str),
) -> Vector {
gradient(v, vars).scalar_mul(&Expr::Constant(-1.0))
}
#[must_use]
pub fn magnetic_field_from_vector_potential(
a: &Vector,
vars: (&str, &str, &str),
) -> Vector {
curl(a, vars)
}
#[must_use]
pub fn poynting_vector(
e_field: &Vector,
b_field: &Vector,
) -> Vector {
let mu_0 = Expr::new_variable("mu_0");
e_field
.cross(b_field)
.scalar_mul(&Expr::new_div(Expr::Constant(1.0), mu_0))
}
#[must_use]
pub fn energy_density(
e_field: &Vector,
b_field: &Vector,
) -> Expr {
let epsilon_0 = Expr::new_variable("epsilon_0");
let mu_0 = Expr::new_variable("mu_0");
let term_e = Expr::new_mul(
epsilon_0,
Expr::new_pow(e_field.magnitude(), Expr::Constant(2.0)),
);
let term_b = Expr::new_div(
Expr::new_pow(b_field.magnitude(), Expr::Constant(2.0)),
mu_0,
);
simplify(&Expr::new_mul(
Expr::Constant(0.5),
Expr::new_add(term_e, term_b),
))
}
#[must_use]
pub fn coulombs_law(
charge: &Expr,
r_vector: &Vector,
) -> Vector {
let epsilon_0 = Expr::new_variable("epsilon_0");
let pi = Expr::Pi;
let denominator = simplify(&Expr::new_mul(
Expr::new_mul(Expr::Constant(4.0), pi),
epsilon_0,
));
let mag_r = r_vector.magnitude();
let mag_r_cubed = Expr::new_pow(mag_r, Expr::Constant(3.0));
let scalar = simplify(&Expr::new_div(
charge.clone(),
Expr::new_mul(denominator, mag_r_cubed),
));
r_vector.scalar_mul(&scalar)
}