Hello everyone,
I am quite new to Fenics and I’m trying to implement a discontinuous Galerkin scheme to solve some simple PDEs in 1D. I started with the advection equation by mimicking this post Lax-Fridrichs Flux for advection equation which worked well.
Now I am trying to solve Burgers equation both with the Upwind and the Lax-Friedrichs numerical fluxes and I run into some problems. First of all, in the case of the upwind flux, I tried adapting the flux in the link above to the flux in the Burgers equation (basically substituting the advection velocity by the value of the field u which is the jacobian of the flux):
un = 0.5*(u*n[0] + abs(u*n[0]))
flux = jump(un*u)
This approach works for DG elements of order 2 but fails in other cases. Apart from that, I tried writing the upwind flux with a conditional expression which works fine for all cases:
n0 = n[0]
flux = conditional(u('-')*n0('+')>0, F(u('+')), F(u('-')))
Any ideas why the first option does not yield the expected solution?
The second question is how should I proceed to implement the Lax-Friedrich flux. In this sense, I followed the indications given in Hesthaven’s book Nodal DG methods, Jan S. Hesthaven where:
f* = avg(f(u('+'),u('-'))) + 0.5*C * jump(u('+'),u('-'))
Where C is the maximum of the flux jacobian (u in this case). I had two different ideas for the choice of C as:
- The average of u between the two sides of the facet.
- The maximum of the value of u between both sides of the facet.
None of these options yield a valid solution.
I attach the full code below, thanks in advance.
from fenics import *
from math import pi
from ufl import shape, rank
import matplotlib.pyplot as plt
#Choice of the numerical flux 'upwind' o 'laxf'
flux_method = 'upwind'
#Generate the mesh
xL = -1
xR = 1
K = 50
cell_size = (xR-xL)/K
mesh = IntervalMesh(K, xL, xR)
#Parameters for time marching algorithm
T = 0.5
cell_size = (xR-xL)/K
N = 100
dt = T/N
dt_ufl = Constant(dt)
#Create the function space of order 'ord'
Ord = 4
V = FunctionSpace(mesh, 'DG', Ord)
v = TestFunction(V)
du_trial = TrialFunction(V)
# Initial conditions
u_0 = Expression('-sin(pi*x[0])', degree = 2)
u = interpolate(u_0, V)
#Boundary conditions
def boundaryL(x, on_boundary):
return on_boundary and near(x[0], xL, DOLFIN_EPS)
uL = Constant(0.0)
def boundaryR(x, on_boundary):
return on_boundary and near(x[0], xR, DOLFIN_EPS)
uR = Constant(0.0)
bcR = DirichletBC(V, uR, boundaryR)
bcL = DirichletBC(V, uL, boundaryL)
bcs = [bcL,bcR]
#Definition of the flux
n = FacetNormal(mesh)
nu = Constant(0.0)
def F(u):
return 0.5*u*u - nu*u.dx(0)
#Definition of the numerical fluxes
if flux_method == 'upwind':
#un = 0.5*(u*n[0] + abs(u*n[0]))
#flux = jump(un*u)
n0 = n[0]
flux = conditional(u('-')*n0('+')>0, F(u('+')), F(u('-')))
elif flux_method == 'laxf':
flux = avg(F(u)) + 0.5*avg(u)*jump(u)
#flux = avg(F(u)) + 0.5*conditional(u('+')>=u('-'),u('-'),u('+'))*jump(u)
#Weak Form
a = du_trial*v*dx
L1 = dt_ufl * ( F(u)*v.dx(0)*dx
- conditional(F(u)*n[0] <= 0, 0.5*uL*uL*n[0]*v, 0.5*u*u*n[0]*v)*ds
- jump(v)*flux*dS )
#Time evolution with a SSPRK
from ufl import replace
u1 = Function(V); u2 = Function(V)
L2 = replace(L1, {u: u1}); L3 = replace(L1, {u: u2})
du = Function(V)
t = 0.0
step = 0
while t < T - 0.5*dt:
solve(a == L1, du, bcL)
u1.assign(u + du)
solve(a == L2, du, bcL)
u2.assign(0.75*u + 0.25*(u1 + du))
solve(a == L3, du, bcL)
u.assign((1/3)*u + (2/3)*(u2 + du))
step += 1
t += dt
if step % 20 == 0:
plot ( u , title = ( ' burgers ' ) )
plt.grid ( True )
plt.show()