use crate::mol::PdeSystem;
use numra_core::Scalar;
#[derive(Clone, Debug)]
pub struct HeatEquation1D<S: Scalar> {
pub alpha: S,
}
impl<S: Scalar> HeatEquation1D<S> {
pub fn new(alpha: S) -> Self {
Self { alpha }
}
}
impl<S: Scalar> PdeSystem<S> for HeatEquation1D<S> {
fn rhs(&self, _t: S, _x: S, _u: S, _du_dx: S, d2u_dx2: S) -> S {
self.alpha * d2u_dx2
}
}
#[derive(Clone)]
pub struct DiffusionReaction1D<S: Scalar, R>
where
R: Fn(S) -> S + Clone,
{
pub diffusion: S,
pub reaction: R,
}
impl<S: Scalar, R: Fn(S) -> S + Clone> DiffusionReaction1D<S, R> {
pub fn new(diffusion: S, reaction: R) -> Self {
Self {
diffusion,
reaction,
}
}
pub fn fisher(diffusion: S, growth_rate: S) -> DiffusionReaction1D<S, impl Fn(S) -> S + Clone>
where
S: Copy,
{
let r = growth_rate;
DiffusionReaction1D::new(diffusion, move |u: S| r * u * (S::ONE - u))
}
pub fn allen_cahn(diffusion: S) -> DiffusionReaction1D<S, impl Fn(S) -> S + Clone>
where
S: Copy,
{
DiffusionReaction1D::new(diffusion, |u: S| u - u * u * u)
}
}
impl<S: Scalar, R: Fn(S) -> S + Clone> PdeSystem<S> for DiffusionReaction1D<S, R> {
fn rhs(&self, _t: S, _x: S, u: S, _du_dx: S, d2u_dx2: S) -> S {
self.diffusion * d2u_dx2 + (self.reaction)(u)
}
}
#[allow(dead_code)]
#[derive(Clone, Debug)]
pub struct AdvectionDiffusion1D<S: Scalar> {
pub diffusion: S,
pub velocity: S,
}
#[allow(dead_code)]
impl<S: Scalar> AdvectionDiffusion1D<S> {
pub fn new(diffusion: S, velocity: S) -> Self {
Self {
diffusion,
velocity,
}
}
}
impl<S: Scalar> PdeSystem<S> for AdvectionDiffusion1D<S> {
fn rhs(&self, _t: S, _x: S, _u: S, du_dx: S, d2u_dx2: S) -> S {
self.diffusion * d2u_dx2 - self.velocity * du_dx
}
}
#[allow(dead_code)]
#[derive(Clone, Debug)]
pub struct Burgers1D<S: Scalar> {
pub viscosity: S,
}
#[allow(dead_code)]
impl<S: Scalar> Burgers1D<S> {
pub fn new(viscosity: S) -> Self {
Self { viscosity }
}
}
impl<S: Scalar> PdeSystem<S> for Burgers1D<S> {
fn rhs(&self, _t: S, _x: S, u: S, du_dx: S, d2u_dx2: S) -> S {
self.viscosity * d2u_dx2 - u * du_dx
}
}
#[allow(dead_code)]
#[derive(Clone, Debug)]
pub struct Wave1D<S: Scalar> {
pub wave_speed: S,
}
#[allow(dead_code)]
impl<S: Scalar> Wave1D<S> {
pub fn new(wave_speed: S) -> Self {
Self { wave_speed }
}
}
#[allow(dead_code)]
#[derive(Clone)]
pub struct HeatWithSource1D<S: Scalar, Q>
where
Q: Fn(S, S) -> S + Clone,
{
pub alpha: S,
pub source: Q,
}
#[allow(dead_code)]
impl<S: Scalar, Q: Fn(S, S) -> S + Clone> HeatWithSource1D<S, Q> {
pub fn new(alpha: S, source: Q) -> Self {
Self { alpha, source }
}
}
impl<S: Scalar, Q: Fn(S, S) -> S + Clone> PdeSystem<S> for HeatWithSource1D<S, Q> {
fn rhs(&self, t: S, x: S, _u: S, _du_dx: S, d2u_dx2: S) -> S {
self.alpha * d2u_dx2 + (self.source)(x, t)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_heat_equation() {
let heat = HeatEquation1D::new(0.1_f64);
let rhs = heat.rhs(0.0, 0.5, 0.25, 1.0, 2.0);
assert!((rhs - 0.2).abs() < 1e-10);
}
#[test]
fn test_fisher_equation() {
let fisher = DiffusionReaction1D::new(0.1_f64, |u: f64| u * (1.0 - u));
let rhs = fisher.rhs(0.0, 0.5, 0.5, 0.0, 2.0);
assert!((rhs - 0.45).abs() < 1e-10);
}
#[test]
fn test_burgers_equation() {
let burgers = Burgers1D::new(0.1_f64);
let rhs = burgers.rhs(0.0, 0.5, 1.0, 2.0, 0.0);
assert!((rhs - (-2.0)).abs() < 1e-10);
}
#[test]
fn test_heat_with_source() {
let heat = HeatWithSource1D::new(0.1_f64, |x: f64, _t: f64| x * x);
let rhs = heat.rhs(0.0, 0.5, 0.0, 0.0, 2.0);
assert!((rhs - 0.45).abs() < 1e-10);
}
}