{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Gauss-Bonnet theorem\n", "This notebook discusses the Gauss-Bonnet theorem for smooth manifolds without boundary, with a smooth boundary, and piecewise smooth boundary with vertices. The arising curvature quantities are the Gauss curvature of the manifold, the geodesic curvature on the smooth part of the boundary, and the angle defect (angle deficit) at the non-smooth vertices of the boundary. The Gauss-Bonnet theorem relates the curvature of a surface $\\mathcal{S}$ with a topological quantity. More precisely, the Gauss-Bonnet theorem holds for two-dimensional Riemannian manifolds, but we consider two-dimensional surfaces embedded in $\\mathbb{R}^3$ for visualisation.\n", "\n", "## Surfaces without a boundary\n", "For closed smooth surfaces $\\mathcal{S}$ without a boundary, i.e. $\\partial\\mathcal{S}=\\emptyset$, there holds with the Gauss curvature $K$ the following version of the Gauss-Bonnet theorem:\n", "\\begin{align*}\n", "\\int_{\\mathcal{S}}K\\,ds = 2\\pi\\chi_{\\mathcal{S}}.\n", "\\end{align*}\n", "Here $\\chi_{\\mathcal{S}}$ is the Euler characteristic of the surface, a topological quantity. For a triangulation of $\\mathcal{S}$ the Euler characteristic can be computed with the formula $\\chi_{\\mathcal{S}}=\\# T-\\# E + \\# V$, i.e., the number of triangles minus number of edges plus number of vertices. It is related to the genus $g$ of a connected closed surface (''number of holes''). For orientable surfaces there holds $\\chi_{\\mathcal{S}}=2-2g$.\n", "\n", "We investigate some closed surfaces." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from ngsolve import *\n", "from netgen.occ import *\n", "from ngsolve.webgui import Draw\n", "\n", "# polynomial order for curving the surface\n", "order = 4\n", "\n", "\n", "# utility function to compute the Gauss curvature on a surface\n", "def GaussCurvature():\n", " nsurf = specialcf.normal(3)\n", " return Cof(Grad(nsurf)) * nsurf * nsurf" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For a sphere of radius $R>0$ the Gauss curvature is $K=\\frac{1}{R^2}$ and its Euler characteristic $2$ (genus $g=0$, no holes). We observe that the integral does not perfectly fit with the expected value. However, it gets way more accurate if we approximate the surface by a higher polynomial degree (or generate a finer mesh). We will understand why this happens later in this notebook." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "sphere = Sphere((0, 0, 0), 3).faces[0]\n", "mesh = Mesh(OCCGeometry(sphere).GenerateMesh(maxh=0.4)).Curve(order)\n", "Draw(mesh)\n", "print(\n", " f\"int_S K = {Integrate(GaussCurvature() * ds, mesh)} = 4*pi = {4 * pi}\"\n", " f\" = 2*pi*(#T-#E+#V) = {2 * pi * (mesh.nface - mesh.nedge + mesh.nv)}\",\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "An ellipsoid is topologically equivalent to a sphere. Therefore, we expect it to have the same Euler characteristic." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ell = Ellipsoid(Axes((0, 0, 0), X, Y), 0.75, 1 / 2, 1 / 3).faces[0]\n", "mesh = Mesh(OCCGeometry(ell).GenerateMesh(maxh=0.07)).Curve(order)\n", "Draw(mesh)\n", "print(\n", " f\"int_S K = {Integrate(GaussCurvature() * ds, mesh)} = 4*pi = {4 * pi}\"\n", " f\" = 2*pi*(#T-#E+#V) = {2 * pi * (mesh.nface - mesh.nedge + mesh.nv)}\",\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A torus has Euler characteristic $\\chi_{\\mathcal{S}}=0$. Its genus is $g=1$ as it has one hole." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "circ = WorkPlane(Axes((3, 0, 0), -Y, X)).Circle(1).Face()\n", "torus = Revolve(circ, Axis((0, 0, 0), (0, 0, 1)), 360)\n", "torus.faces.name = \"torus\"\n", "mesh = Mesh(OCCGeometry(torus.faces[0]).GenerateMesh(maxh=0.8)).Curve(order)\n", "Draw(mesh)\n", "print(\n", " f\"int_S K = {Integrate(GaussCurvature() * ds, mesh)} = 0\"\n", " f\" = 2*pi*(#T-#E+#V) = {2 * pi * (mesh.nface - mesh.nedge + mesh.nv)}\",\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Gauss-Bonnet for non-closed and non-smooth surfaces\n", "\n", "Let's try combining two tori such that the Euler characteristic changes to $-2$ because now two holes are present." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": false }, "outputs": [], "source": [ "torus2 = Translation((6.5, 0, 0))(torus)\n", "torus2.faces.name = \"torus2\"\n", "two_torus = Glue((torus2 - torus).faces[\"torus2\"] + (torus - torus2).faces[\"torus\"])\n", "mesh = Mesh(OCCGeometry(two_torus).GenerateMesh(maxh=1)).Curve(order)\n", "Draw(mesh)\n", "print(\n", " f\"int_S K = {Integrate(GaussCurvature() * ds, mesh)} = 2 * pi * (2 - 4)\"\n", " f\" = {2 * pi * (2 - 4)} = 2*pi*(#T-#E+#V) = {2 * pi * (mesh.nface - mesh.nedge + mesh.nv)}\",\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The computation by counting the number of triangles, edges, and vertices matches the expected value. However, the integral of the Gauss curvature does not. Why? \n", "\n", "The generated surface is not smooth at the interface!\n", "\n", "\n", "For non-closed and non-smooth surfaces, the Gauss-Bonnet theorem takes a different form:\n", "\\begin{align*}\n", "\\int_{\\mathcal{S}}K\\,ds + \\int_{\\partial \\mathcal{S}}\\kappa_g\\,dl = 2\\pi\\chi_{\\mathcal{S}},\n", "\\end{align*}\n", "where $\\kappa_g$ denotes the geodesic curvature of the boundary curve $\\partial \\mathcal{S}$\n", "We must include the geodesic curvature at the non-smooth interface from both sides of the tori to obtain the correct results. We recall that with the tangent vector $t$ and co-normal vector $\\mu$ the geodesic curvature is given by\n", "\\begin{align*}\n", "\\kappa_g = \\nabla_tt\\cdot \\mu.\n", "\\end{align*}\n", "Note that for a smooth surface, at least $C^1$, the geodesic curvature computed along a curve inside the manifold coincides when computed from both sides up to a sign (the co-normal vector changes its orientation). Then, the sum of the geodesic curvatures cancels out.\n", "\n", "Let's try the previous example, but now including the geodesic curvature. Now, the result looks good again." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "mu = Cross(specialcf.normal(3), specialcf.tangential(3))\n", "# for geodesic curvature\n", "edge_curve = specialcf.EdgeCurvature(3) # nabla_t t\n", "\n", "print(\n", " f\"int_S K + int_{{dS}} k_g = {Integrate(GaussCurvature() * ds, mesh)}\"\n", " f\" + {Integrate(-edge_curve * mu * ds(element_boundary=True), mesh)}\"\n", " f\" = {Integrate(GaussCurvature() * ds - edge_curve * mu * ds(element_boundary=True), mesh)}\"\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Gauss-Bonnet for surfaces with piecewise smooth boundary\n", "\n", "Consider a flat rectangle. It is topologically equivalent to the half-sphere. Thus $\\chi_{\\mathcal{S}}=1$. However, it has zero Gauss and geodesic curvature. To account for the non-smooth boundary of the rectangle, we extend the Gauss-Bonnet theorem to its general form\n", "\\begin{align*}\n", "\\int_{\\mathcal{S}}K\\,ds + \\int_{\\partial \\mathcal{S}}\\kappa_g\\,dl + \\sum_{\\mathrm{vertices}\\,V}(\\pi-\\varepsilon_V)= 2\\pi\\chi_{\\mathcal{S}}.\n", "\\end{align*}\n", "Here, we sum over all vertices, where the boundary is non-smooth and compute the jump angle $\\varepsilon_V$, which measures the angle from the incoming tangent vector to the outgoing tangent vector. The interior angle used in the Gauss-Bonnet theorem is given by $\\pi-\\varepsilon_V$. For a smooth triangulation of a smooth manifold, the sum of the jump angles at a vertex $V$ will add up to $2\\pi$. However, for a non-smooth surface, like we are considering, the sum won't be $2\\pi$. Thus, we can define the so-called angle defect $\\sphericalangle_V$ as\n", "\\begin{align*}\n", "\\sphericalangle_V = 2\\pi-\\sum_{T\\supset V}\\sphericalangle_V^T,\\qquad \\sphericalangle_V^T= \\arccos(t_1,t_2),\n", "\\end{align*}\n", "where $t_1$ and $t_2$ are the two unit tangent vectors starting at $V$ and going in direction of the edges attached to $V$ on the element $T$.\n", "\n", "In summary, we need to consider the Gauss curvature, geodesic curvature, and the interior angle for the Gauss-Bonnet theorem, visualized in the following picture. Thus, all these quantities are tightly connected to each other.\n", "