Advection-diffusion of a Gaussian in an interval

Advection-diffusion of a Gaussian in an interval#

\[\begin{split} \mathbb{S} \begin{cases} \Omega = [0, L_x] \\ u_0(x)=\exp\left(-\frac{(x - x_0)^2}{\sigma^2}\right) \\ u_{\text{N}}(x=0)=0 \\ u_{\text{D}}(x=L_x)=0 \\ \textbf{a}(\textbf{x})=x(L_x - x)\textbf{e}_x \\ \end{cases} \end{split}\]
import numpy as np
from lucifex.mesh import interval_mesh
from lucifex.fdm import (
    CN, AM1, AB1, AB2, FiniteDifference, advective_timestep, diffusive_timestep,
    FunctionSeries, ConstantSeries, finite_difference_order,
)
from lucifex.fem import Function, Constant
from lucifex.solver import ibvp, evaluation, extrema, BoundaryConditions
from lucifex.sim import run, Simulation
from lucifex.viz import plot_line, plot_twin_lines, plot_stacked_lines, save_figure
from lucifex.utils import nested_dict
from lucifex.pde.advection_diffusion import advection_diffusion


def create_simulation(
    Lx: float,
    Nx: int,
    dt: float,
    a_max: float,
    d: float,
    D_adv: FiniteDifference,
    D_diff: FiniteDifference,
) -> Simulation:
    order = finite_difference_order(D_adv, D_diff)
    mesh = interval_mesh(Lx, Nx)
    t = ConstantSeries(mesh, name='t', ics=0.0)
    dt = Constant(mesh, dt, name='dt')
    a = Function((mesh, 'P', 1, 1), name='a')
    ax = lambda x: 4 * a_max * x[0] * (Lx - x[0]) / Lx**2
    a.interpolate(lambda x: (ax(x), ))
    d = Constant(mesh, 0.1, name='d')
    u = FunctionSeries((mesh, 'P', 1), name='u', order=order, store=1)
    u_bcs = BoundaryConditions(
        ('neumann', lambda x: x[0], 0.0),
        ('dirichlet', lambda x: x[0] - Lx, 0.0),
    )
    u_ics = lambda x: np.exp(-(x[0] - 0.2 * Lx)**2 / (0.001 * Lx))
    u_solver = ibvp(advection_diffusion, u_ics, u_bcs)(u, dt, a, d, D_adv, D_diff)
    uMinMax = ConstantSeries(mesh, name='uMinMax', shape=(2,), store=1)
    uMinMax_solver = evaluation(uMinMax, extrema)(u[0])
    solvers = [u_solver, uMinMax_solver]
    return Simulation(solvers, t, dt)


Lx = 2.0
Nx = 200
dt = 0.01
a_max = 1.0
d = 0.1

h = Lx/ Nx
dt_diffusive = diffusive_timestep(d, h)
dt_advective = advective_timestep(a_max, h)
courant_diffusive = dt / dt_diffusive
courant_advective = dt / dt_advective

D_adv = AB2
D_diff_opts = (AB1, AM1, CN)
simulations = nested_dict((FiniteDifference, Simulation))

for D_diff in D_diff_opts:
    simulations[D_diff] = create_simulation(Lx, Nx, dt, a_max, d, D_adv, D_diff)
    
n_init = 5
n_stop = 150
for D_diff in D_diff_opts:
    run(simulations[D_diff], n_stop, n_init=n_init)
slc = slice(0, None, 2)
texstr = lambda D: str(D).replace('◦', '\circ ').replace('₁', '_1').replace('₂', '_2')
minmax_labels = ('$\min(u)$', '$\max(u)$')
D_adv_tex = texstr(D_adv)

for D_diff in D_diff_opts:
    u = simulations[D_diff]['u']
    s = texstr(D_diff)
    title_texts = [
        f"$\mathcal{{D}}_{{\mathbf{{a}}, u}}=\mathrm{{{D_adv_tex}}}$",
        f"$\mathcal{{D}}_{{\mathsf{{D}}, u}}=\mathrm{{{texstr(D_diff)}}}$",
        f"$C_{{{{\mathbf{{a}}}}}}={courant_advective}$",
        f"$C_{{\mathsf{{D}}}}={courant_diffusive}$",
    ]
    title = "\n".join(title_texts)
    legend_labels=(min(u.time_series[slc]), max(u.time_series[slc]))
    fig, ax = plot_line(u.series[slc], legend_labels, '$t$', cyc='jet', x_label='$x$', y_label='$u$', title=title)
    save_figure(f'u(x,t)_{D_diff.name}', thumbnail=(D_diff is CN))(fig)
    uMinMax = simulations[D_diff]['uMinMax']
    uMin, uMax = uMinMax.sub(0), uMinMax.sub(1)
    fig, ax = plot_twin_lines(
        uMinMax.time_series,
        (uMin.value_series, uMax.value_series),
        minmax_labels,
        x_label='$t$',
        title=title,
    )
    save_figure(f'uMinMax(t)_{D_diff.name}_twinned')(fig)
    plot_stacked_lines(
        [(uMin.time_series, uMin.value_series), (uMax.time_series, uMax.value_series)],
        '$t$',
        minmax_labels,
        title=title,
    )
    save_figure(f'uMinMax(t)_{D_diff.name}_stacked')(fig)
../../_images/1204ca8ba472761957f775bfe3241393efd52d30f1b130b2e2222985c2f627e5.png ../../_images/052f5ef9b395029ee99c2ec9239dfbf75afd4bfe644d53b4835caea231673f00.png ../../_images/d3a5d8f6718223d5d781bb5f6b3c7db1deb0dee8ac6d4e71c97fd870b5d3b3e6.png ../../_images/dc23113995ae92d81b15cd60e3c594a384e91ebb9d93fd840b1dc260a65513d1.png ../../_images/ac95ad0e565bb204e1b01865f82f67e9d67132969c87be4f3a6a27fa4e759fca.png ../../_images/552f4c605fea06f52d1def01a8c8852fcf3edae748cb3e83843816d5d31003a5.png ../../_images/b988e42e568d2802026a51dcb129f10202465857398e79559a17346b7f94a484.png ../../_images/a2b3a2d0d9d619b623e52964ec84ee524ee3a88477a1fc3f09b52239f1e93aa5.png ../../_images/b864f0d1988c62aef78e5e0d31e84a1bfb38121e5fd57bad61fbccc9d14fbb1e.png