DG advection with a vortex in a rectangle

DG advection with a vortex in a rectangle#

\[\begin{split} \mathbb{S} \begin{cases} \Omega = [0, 1] \times [0, 1] \\ u_0(x,y) = U_0x^2(1-x)^4y^2(1-y)^4 \\ \textbf{a} = \begin{pmatrix} \sin(\pi x)\cos(\pi y) \\ -\cos(\pi x)\sin(\pi y) \end{pmatrix} \end{cases} \end{split}\]
import numpy as np
from ufl import SpatialCoordinate, as_vector, sin, cos
from lucifex.mesh import rectangle_mesh
from lucifex.fem import Constant
from lucifex.fdm import (BE, FE, 
    FiniteDifference, FunctionSeries, ConstantSeries,
    advective_timestep)
from lucifex.solver import ibvp , BoundaryConditions
from lucifex.sim import run, Simulation
from lucifex.viz import plot_colormap, save_figure, plot_streamlines        
from lucifex.utils import nested_dict, is_continuous_lagrange, as_indices
from lucifex.pde.advection import advection, dg_advection


def create_simulation(
    element: tuple[str, int],
    Lx: float,
    Ly: float,
    Nx: int,  
    Ny: float,  
    courant: float,
    D_adv: FiniteDifference,
    mu: float,
):
    mesh = rectangle_mesh(Lx, Ly, Nx, Ny)
    t = ConstantSeries(mesh, name='t', ics=0.0)
    x = SpatialCoordinate(mesh)
    a = as_vector(
        (sin(np.pi * x[0]) * cos(np.pi * x[1]), -cos(np.pi * x[0]) * sin(np.pi * x[1]))
    )
    dt = advective_timestep(a, 'hmin', courant, mesh=mesh)
    dt = Constant(mesh, dt, name='dt')
    u = FunctionSeries((mesh, *element), name='u', store=1)
    ics = lambda x: mu * (x[0] ** 2) * (x[1] ** 2) * ((1 - x[0]) ** 4) * ((1 - x[1]) ** 4)
    bcs = BoundaryConditions(
        ('dirichlet', lambda x: x[0], 0.0),
    )
    if is_continuous_lagrange(u.function_space):
        u_solver = ibvp(advection, ics, bcs)(u, dt, a, D_adv)
    else:
        u_solver = ibvp(dg_advection, ics)(u, dt, a, D_adv, bcs=bcs)
    return Simulation(u_solver, t, dt, exprs_consts=[('a', a)])


Lx = 1.0
Ly = 1.0
Nx = 64
Ny = 64
h = Lx / Nx
mu = 1e3
courant = 0.8

elem_opts = [
    ('DP', 1),
    ('P', 1),
]
D_adv_opts = (BE, FE)

simulations = nested_dict((FiniteDifference, tuple, Simulation))

for elem in elem_opts:
    for D_adv in D_adv_opts:
        simulations[elem][D_adv] = create_simulation(elem, Lx, Ly, Nx, Ny, courant, D_adv, mu)

n_stop = 100
for elem in elem_opts:
    for D_adv in D_adv_opts:
        run(simulations[elem][D_adv], n_stop)
for elem in elem_opts:
    fam, deg = elem
    for D_adv in D_adv_opts:
        u = simulations[elem][D_adv]['u']
        a = simulations[elem][D_adv]['a']
        time_indices = as_indices(u.time_series, (0, 0.5, -1),)
        for i in time_indices:
            t = u.time_series[i]
            title = f'{fam}$_{deg}$\n $\mathcal{{D}}=\mathrm{{{D_adv}}}$\n $u(t={t:.3f})$'
            fig, ax = plot_colormap(u.series[i], title=title)
            plot_streamlines(fig, ax, a, mesh=u.function_space.mesh, density=0.75, color='cyan')
            thumbnail = (elem == ('DP', 1) and i == -1 and D_adv is BE)
            save_figure(f'{u.name}(x,y,t={t:.3f})_{fam}{deg}_{D_adv}', thumbnail=thumbnail)(fig)
../../_images/823b317d0c4632f3d83b6a32bc91ecc8a022a397bbc3b7443f1629eb27f793a8.png ../../_images/efd8bc8b4ce92206a6cab267a97e4bb2c854d4d094aa8220d947e20c1fb1cc9c.png ../../_images/d6fc88abbf701fb72ee988339aec0fd259befd40d381f7795bd0458034d575e6.png ../../_images/38425c00788196590c28f85be389da30473e7475289455a432dabd2546cbd1d4.png ../../_images/4a83d4e5559d8381d2d1ce952579b618d4f25e4809e30d7ed3f31ef2f03b00c9.png ../../_images/fa70de62126cd31792d13ba1417cdd71ab3ef051e81668ba47be5a47906ff21c.png ../../_images/131955acd7d3dfde6afb04e585ab28b853ae8fb9f3399644c1ffb46db45c95ce.png ../../_images/36679ea5c9590fe3b9f7824a578b1cbc49c98898824121aa731f5cf7c960f3cc.png ../../_images/3c95fb72ec540e2c84e6c5eb6a9eafaba72c7fd905592d3fe7642251a954a7f9.png ../../_images/621085398ee9ac4758db0d8bdda90c3512d551885b900cc102e3fd939a939d33.png ../../_images/351e6641942692b559a4b4baac8a576e07f48f0defb583cd57f405036e70801b.png ../../_images/9e98d3433caf5d5793b46078db5c76fbb1f75dcddec5a894d1347ea8d17a4c0b.png