Dear Fenics community,
I have a question regarding the integration over mesh boundaries, that seems to result in different solutions depending on the finite element type I choose. The context of this question is another question I asked recently here, in which I want to compute the wall shear stress. A key step in this computation is integration over the boundary domain and depending on the element type I choose I get different answers: for instance if I choose first order continuous Galerkin elements my computations are a factor 2 too high.
I can illustrate this by a working example at the bottom of this post, where I integrate a constant vector function (1., 1., 1.) over the boundary domain and divide by the FacetArea. I would imagine that irrespective of the element type this would again result in the vector (1., 1., 1.), but this only seems to work for zeroth-order discontinous Galerkin, whereas, for instance first-order continuous Galerkin results in a constant vector (2., 2., 2.). In addition, I observe some discrepancies on the edges of the mesh. Can anybody explain to me the reason why different element types result in different solutions? I do not mind having to multiply a solution by a certain factor to get the correct answer (for instance the first-order Galerkin by a factor 0.5), but I like to know why I should do so, to avoid making incorrect assumptions. Thanks in advance
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Minimal working example surface integration question
"""
# Import statements
from fenics import *
# Create a 3D cube mesh
meshsize = 10
mesh = UnitCubeMesh(meshsize, meshsize, meshsize)
# Define function spaces
V0 = VectorFunctionSpace(mesh, 'DG', 0) # Discontinous Galerkin const.
V1 = VectorFunctionSpace(mesh, 'DG', 1) # Discontinous Galerkin 1-order
V2 = VectorFunctionSpace(mesh, 'DG', 2) # Discontinous Galerkin 2-order
VC1 = VectorFunctionSpace(mesh, 'CG', 1) # Continous Galerkin 2-order
VC2 = VectorFunctionSpace(mesh, 'CG', 2) # Continous Galerkin 2-order
# Define the test functions
v0 = TestFunction(V0)
v1 = TestFunction(V1)
v2 = TestFunction(V2)
vc1 = TestFunction(VC1)
vc2 = TestFunction(VC2)
# Define functions to be integrated
u_0 = Function(V0)
u_0 = Constant((1., 1., 1.))
u_00 = Function(V0)
u_1 = Function(V1)
u_1 = Constant((1., 1., 1.))
u_11 = Function(V1)
u_2 = Function(V2)
u_2 = Constant((1., 1., 1.))
u_22 = Function(V2)
u_c1 = Function(VC1)
u_c1 = Constant((1., 1., 1.))
u_c11 = Function(VC1)
u_c2 = Function(VC2)
u_c2 = Constant((1., 1., 1.))
u_c22 = Function(VC2)
# Integrate the functions elementwise
assemble((1 / FacetArea(mesh)) * inner(v0, u_0) * ds, tensor=u_00.vector())
assemble((1 / FacetArea(mesh)) * inner(v1, u_1) * ds, tensor=u_11.vector())
assemble((1 / FacetArea(mesh)) * inner(v2, u_2) * ds, tensor=u_22.vector())
assemble((1 / FacetArea(mesh)) * inner(vc1, u_c1) * ds, tensor=u_c11.vector())
assemble((1 / FacetArea(mesh)) * inner(vc2, u_c2) * ds, tensor=u_c22.vector())
plot(u_00, title='DG 0 vec')
# plot(u_11, title='DG 1 vec')
# plot(u_22, title='DG 2 vec')
plot(u_c11, title='CG 1 vec')
# plot(u_c22, title='CG 2 vec')
# Only one component
plot(u_00[0], title='DG 0 x-component')
# plot(u_11[0], title='DG 1 x-component')
# plot(u_22[0], title='DG 2 x-component')
plot(u_c11[0], title='CG 1 x-component')
# plot(u_c22[0], title='CG 2 x-component')
interactive()