11. Computation of Curvature#

work with Michael Neunteufel, Max Wardetzky and Jay Gopalakrishnan

  • Given metric tensor \(g \in H(cc)\), compute Riemannian curvature \(R(g)\)

  • Compute curvature of a triangulated manifold

from netgen.occ import *
from netgen import meshing
from ngsolve import *
from ngsolve.webgui import Draw

MESHSURF = meshing.MeshingStep.MESHSURFACE

11.1. Curvature on smooth manifolds#

sp = Sphere(Pnt(0,0,0), r=1)
spmesh = Mesh(OCCGeometry(sp).GenerateMesh(maxh=0.2,perfstepsend=MESHSURF))
spmesh.Curve(3);

Define Gauss curvature from Weingarten tensor:

nsurf = specialcf.normal(3)
GaussCurv = Cof(Grad(nsurf))*nsurf*nsurf
Draw (GaussCurv, spmesh, min=0.9, max=1.1);

By Gauss-Bonnet theorem: \(\int_S \kappa = 4 \pi\)

print ("integrated curvature:",
       Integrate (GaussCurv, spmesh.Boundaries(".*")) / (4*pi))
integrated curvature: 1.0121953978549172

11.1.1. A cylinder has only flat faces:#

cyl = Cylinder( (0,0,0), Z, r=1, h = 2)
cylmesh = Mesh(OCCGeometry(cyl).GenerateMesh(maxh=0.2,perfstepsend=MESHSURF)).Curve(5)
Draw (GaussCurv, cylmesh);
cyl = Cylinder( (0,0,0), Z, r=1, h = 2)
cylf = cyl.MakeFillet(cyl.edges, 0.1)
cylfmesh = Mesh(OCCGeometry(cylf).GenerateMesh(maxh=0.2,perfstepsend=MESHSURF)).Curve(7)
Draw (GaussCurv, cylfmesh);
Integrate (GaussCurv, cylfmesh.Boundaries(".*"), order=10) / (4*pi)
1.0001399994991715

11.1.2. Edge term: jump of geodesic curvature#

\[ \kappa_g = \nu \cdot \nabla_t t \]

with co-normal vector \(\nu = n_F \times t_E\)

nu = Cross(specialcf.normal(3), specialcf.tangential(3)) 
edgecurve = specialcf.EdgeCurvature(3)  # nabla_t t
GeodesicCurv = nu*edgecurve
fes = SurfaceL2(cylmesh, order=5)
u,v = fes.TnT()
f = LinearForm(fes)
f += GaussCurv*v*ds(bonus_intorder=8)
f += -GeodesicCurv*v*ds(element_boundary=True, bonus_intorder=8)
f.Assemble()
gfu = GridFunction(fes)
mass = BilinearForm(u*v*ds).Assemble().mat
gfu.vec.data = mass.Inverse()*f.vec
print ("integrated curv =", Integrate(gfu, cylmesh.Boundaries(".*"))/(4*pi))
Draw(gfu);
integrated curv = 0.999839532080625

11.1.3. Vertex term: angle deficit#

cube = Box( (0,0,0), (1,1,1) )
cubef = cube.MakeFillet(cube.edges, 0.1)
cubefmesh = Mesh(OCCGeometry(cubef).GenerateMesh(maxh=0.2,perfstepsend=meshing.MeshingStep.MESHSURFACE)).Curve(7)
print ("integrated curv =", Integrate(GaussCurv, cubefmesh.Boundaries(".*")) / (4*pi))
Draw (GaussCurv, cubefmesh);
integrated curv = 1.0002596199782285
cube = Box( (0,0,0), (1,1,1) )
cubemesh = Mesh(OCCGeometry(cube).GenerateMesh(maxh=0.2,perfstepsend=meshing.MeshingStep.MESHSURFACE)).Curve(7)

fes = H1(cubemesh, order=5)
u,v = fes.TnT()

f = LinearForm(fes)
bbndtang  = specialcf.VertexTangentialVectors(3)
bbndtang1 = bbndtang[:,0] 
bbndtang2 = bbndtang[:,1] 
f += -v*acos(bbndtang1*bbndtang2)*ds(element_vb=BBND)

f.Assemble()
for i in range(f.space.mesh.nv):
    f.vec[i] += 2*pi

gfu = GridFunction(fes)
mass = BilinearForm(u*v*ds).Assemble().mat
gfu.vec.data = mass.Inverse()*f.vec
print ("integrated curv =", Integrate(gfu, cubemesh.Boundaries(".*"))/(4*pi))
Draw(gfu);
integrated curv = 0.9999999999999957

11.1.4. All contributions together#

sp = Sphere(Pnt(0,0,0), 1)
spmesh = Mesh(OCCGeometry(sp).GenerateMesh(maxh=0.3,perfstepsend=MESHSURF))
spmesh.Curve(2)
Draw (spmesh);
fes = H1(spmesh, order=2)
u,v = fes.TnT()
f = LinearForm(fes)
f += GaussCurv*v*ds(bonus_intorder=12)
f += -GeodesicCurv*v*ds(element_boundary=True, bonus_intorder=12)
f += -v*acos(bbndtang1*bbndtang2)*ds(element_vb=BBND)

f.Assemble()
for i in range(f.space.mesh.nv):
    f.vec[i] += 2*pi

gfu = GridFunction(fes)
mass = BilinearForm(u*v*ds(bonus_intorder=6)).Assemble().mat
gfu.vec.data = mass.Inverse()*f.vec
print ("integrated curv =", Integrate(gfu, spmesh.Boundaries(".*"), order=15)/(4*pi))
Draw(gfu);
integrated curv = 1.0000000000007234

11.2. Curvatur computation from metric tensor on parameter domain#

  • Evan S. Gawlik: High-order approximation of Gaussian Curvature with Regge finite elements, SINUM ‘20

  • J. Gopalakrishnan, M. Neunteufel, JS, M. Wardetzky: Analysis of curvature approximation via covariant curl and incompatibility for Regge metrics (WIP)

from ngsolve import *
from ngsolve.webgui import Draw
from netgen.geom2d import CSG2d, Circle
from math import pi

order    = 4
addorder = 2

geo = CSG2d()
circle = Circle(center=(0,0), radius=1.0)
geo.Add(circle)

mesh = Mesh(geo.GenerateMesh(maxh=0.1))
mesh.Curve(10)
Draw(mesh);
gfset = GridFunction(H1(mesh,order=order)**3)

r = sqrt(x**2+y**2)
phi = atan2(y,x)

gfset.Interpolate( (cos(phi)*sin(r*pi/2)-x,sin(phi)*sin(r*pi/2)-y,cos(r*pi/2)))

gfsetxy = GridFunction(H1(mesh,order=order)**2)
gfsetxy.Set ( gfset[0:2] )
mesh.SetDeformation(gfsetxy)
Draw (gfset[2], mesh, deformation=True)
mesh.UnsetDeformation()

Interpolating metric

\[ C = \nabla \varphi^T \nabla \varphi \]

into a Regge finite element space:

F = CF( (1,0, 0,1, 0,0),dims=(3,2)) + Grad(gfset)
C = F.trans*F

fesCC = HCurlCurl(mesh, order=3) 
gfC = GridFunction(fesCC)
gfC.Set(C, dual=True, bonus_intorder=4)   # half-sphere
# gfC.Set(Id(2), dual=True)    # disk

Draw (gfC[0,0], mesh);
fesR = H1(mesh, order=3)
fR = LinearForm(fesR)
u,v = fesR.TnT()

charVertex = GridFunction(H1(mesh,order=1))
charVertex.Set(1)
for el in charVertex.space.Elements(BND):
    for d in el.dofs:
        charVertex.vec[d] = 1     # set to 0 to skip bnd vert

charEdge = GridFunction(FacetFESpace(mesh,order=0))  
charEdge.vec[:] = 1
for el in charEdge.space.Elements(BND):
    for d in el.dofs:
        charEdge.vec[d] = 1     # set to 0 to skip bnd edge
       
# vertex - contributions = angle deficit
vertextang  = specialcf.VertexTangentialVectors(2)
vt1 = vertextang[:,0]
vt2 = vertextang[:,1]

fR += charVertex*v*acos(gfC[vt1,vt2]/sqrt(gfC[vt1,vt1]*gfC[vt2,vt2]))*dx(element_vb=BBND)
fR += -charVertex*v*acos((vt1*vt2)/sqrt((vt1*vt1)*(vt2*vt2)))*dx(element_vb=BBND)

t  = specialcf.tangential(2,True)
n = specialcf.normal(2)  
edgecurve = specialcf.EdgeCurvature(2)
Gamma_ttn = gfC.Operator("christoffel2")[t,t,:]
fR += charEdge*v*sqrt(Det(gfC))/gfC[t,t]*n*(Gamma_ttn+edgecurve)*dx(element_vb=BND, bonus_intorder=4)


Riemann = gfC.Operator("Riemann")
fR += 1/sqrt(Det(gfC))*Riemann[0,1,0,1] * v * dx(bonus_intorder=4)

fR.Assemble()

gfR = GridFunction(fesR)
mass = BilinearForm(sqrt(Det(gfC))*u*v*dx(bonus_intorder=4)).Assemble().mat
gfR.vec.data = mass.Inverse() * fR.vec
Draw (gfR, min=0.99, max=1.01);
print ("total curvature on half-sphere:", Integrate (gfR, mesh) / pi)
total curvature on half-sphere: -1.0000000000155922

11.3. Current work: numerics for Einstein equation#

  • solve for an evolving metric in 3+1

  • can do now linearized Einstein wave equation