34. Computation of Curvature#
work with Michael Neunteufel, Max Wardetzky and Jay Gopalakrishnan reference
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
34.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);
Weingarten tensor (a symmetric matrix):
\[
W = \nabla_t n
\]
Scalar curvature (Gauss curvature) is product of non-zero eigenvalues of \(W\).
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.0121953978547735
34.2. 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, min=-0.0001, max=0.0001);
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.000139999505865
34.3. 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.9998395320792809
34.4. 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.0002596199781306
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.9999999999999886
34.5. 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 = 0.9999999999998085