This page was generated from unit-3.5-surfacehdg/surfacehdg.ipynb.

3.5 Scalar PDE on surfaces (with HDG)

We are solving the scalar linear transport problem

\[\partial_t u - \varepsilon \Delta_\Gamma u + \operatorname{div}_\Gamma ( \mathbf{w} u ) = 0 \quad \text{ on } \Gamma,\]

where \(\Gamma\) is a closed oriented surface in \(\mathbb{R}^3\).

[1]:
from ngsolve import *
import netgen.gui
from math import pi

Mesh of (only) the surface:

We consider the unit sphere (only surface mesh!)

[2]:
from netgen.csg import *
geo = CSGeometry()
geo.Add(Sphere(Pnt(0,0,0),1).bc("sphere"))
[2]:
0
[3]:
from netgen.meshing import MeshingParameters
from netgen.meshing import MeshingStep
mp = MeshingParameters(maxh=0.5, perfstepsend = MeshingStep.MESHSURFACE)

mesh = Mesh(geo.GenerateMesh(mp=mp))
 Start Findpoints
 main-solids: 1
 Found points 0
 Analyze spec points
 Find edges
 0 edges found
 Check intersecting edges
 CalcLocalH: 2 Points 0 Elements 0 Surface Elements
 Start Findpoints
 main-solids: 1
 Found points 0
 Analyze spec points
 Find edges
 0 edges found
 Check intersecting edges
 Start Findpoints
 main-solids: 1
 Found points 0
 Analyze spec points
 Find edges
 0 edges found
 Check intersecting edges
 Surface 1 / 1
 load internal triangle rules
 Surface meshing done
 0 illegal triangles
 Optimize Surface
 Edgeswapping, topological
 Smoothing
 Combine improve
 Smoothing
 Edgeswapping, metric
 Smoothing
 Combine improve
 Smoothing
 Edgeswapping, metric
 Smoothing
 Combine improve
 Smoothing
 126 elements, 65 points
 SplitSeparateFaces
 Update mesh topology
 Update clusters
[4]:
order = 4
if order > 0:
    mesh.Curve(order)
Draw(mesh)
 Curve elements, order = 4
 Update clusters
 Curving edges
 Curving faces

Tangential velocity field:

[5]:
t = Parameter(0.)
b = CoefficientFunction((y,-x,0))
Draw (b, mesh, "b")
eps = 5e-5

some local quantities

normal, tangential, co-normal and mesh size

[6]:
n = specialcf.normal(mesh.dim)
h = specialcf.mesh_size
local_tang = specialcf.tangential(mesh.dim)
con = Cross(n,local_tang) #co-normal pointing outside of a surface element
bn = InnerProduct(b,con)

Discretization

Surface FESpaces:

[7]:
fesl2 = SurfaceL2(mesh, order=order)
fesedge = FacetSurface(mesh, order=order)

fes = FESpace([fesl2,fesedge])
u,uE = fes.TrialFunction()
v,vE = fes.TestFunction()

surface gradients, co-normal derivatives and jumps:

[8]:
gradu = u.Trace().Deriv()
gradv = v.Trace().Deriv()
jumpu = u - uE
jumpv = v - vE
dudn = InnerProduct(gradu,con)
dvdn = InnerProduct(gradv,con)

Diffusion formulation (Hybrid Interior Penalty on Surface):

\[ \sum_T \int_T \nabla u \nabla v - \sum_T \int_{\partial T} n \nabla u (v-\widehat v) - \sum_T \int_{\partial T} n \nabla u (u-\widehat u) + \frac{\alpha p^2}{h} \sum_F \int_F (u-\widehat u)(v-\widehat v)\]
[9]:
a = BilinearForm(fes)
# diffusion

dr = ds(element_boundary=True)

alpha = 10*(order+1)**2
a += eps*gradu * gradv * ds
a += - eps*dudn * jumpv * dr
a += - eps*dvdn * jumpu * dr
a += eps*alpha/h * jumpu * jumpv * dr

Convection formulation (Hybrid Upwinding):

\[ \sum_T \int_T - u \mathbf{w} \cdot \nabla v + \sum_T \int_{\partial T} (\mathbf{w} \cdot \mathbf{n}) u^{hyb-upw} v + \sum_T \int_{\partial T_{out}} (\mathbf{w} \cdot \mathbf{n}) (\hat{u} - u) \hat{v}\]

with

\[\begin{split}u^{hyb-upw} = \left\{ \begin{array}{cll} u & \text{if } \mathbf{w} \cdot \mathbf{n} & (outflow), \\ \hat{u} & \text{else} & (inflow) . \end{array} \right.\end{split}\]

outflow

inflow

elementupwind

facetupwind

[10]:
a = BilinearForm(fes)
# convection (surface version of Egger+Schöberl formulation):
a += - u * InnerProduct(b,gradv) * ds
a += IfPos(bn, bn*u, bn*uE) * v * dr + IfPos(bn, bn, 0) * (uE - u) * vE * dr
a.Assemble()
assemble BND element 124/124
[10]:
<ngsolve.comp.BilinearForm at 0x7f4524dd9c30>

Mass matrix:

[11]:
m = BilinearForm(fes)
m += u*v*ds
m.Assemble()
assemble BND element 124/124
[11]:
<ngsolve.comp.BilinearForm at 0x7f4524e03230>

\(M^\ast\)-matrix for implicit Euler

[12]:
dt = 0.02

mstar = m.mat.CreateMatrix()
mstar.AsVector().data = m.mat.AsVector() + dt * a.mat.AsVector()
mstarinv = mstar.Inverse()

from math import pi
T = 8*pi
call pardiso ... done

Time stepping

Visualization of solution (Deformation in normal direction)

[13]:
gfu = GridFunction(fes)
gfu.components[0].Set(1.5*exp(-20*(x*x+(y-1)**2+(z)**2)),definedon=mesh.Boundaries("sphere"))
Draw (gfu.components[0], mesh, "u")
Draw (gfu.components[0]*n, mesh, "un", sd=4, autoscale=False)
res = gfu.vec.CreateVector()
SetVisualization(deformation=True)
setvalues element 124/124

The time loop

[14]:
t.Set(0)
for i in range(int(T/dt)):
    res.data = m.mat * gfu.vec
    gfu.vec.data = mstarinv * res
    Redraw(blocking=True)
    t.Set(t.Get()+dt)

Remark:

  • We can apply static condensation as in the volume