{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1.8 Exploring the mesh topology\n",
    "\n",
    "In this tutorial, we learn how to iterate over mesh entities and obtain information about how one mesh entity is connected to others. We will be able to answer questions like the following after this tutorial.\n",
    "\n",
    "- What edges are connected to a vertex?\n",
    "- What are the edges of an element?\n",
    "- What are the points of an element? \n",
    "- What elements are adjacent to a face?\n",
    "\n",
    "In some algorithms, such as custom block smoothers (that we shall see in [2.1.2](../unit-2.1.2-blockjacobi/blockjacobi.ipynb)), we will need to iterate over mesh entities using the concepts in this tutorial."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from ngsolve import *\n",
    "from ngsolve.webgui import Draw"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "mesh = Mesh(unit_cube.GenerateMesh(maxh=1))\n",
    "Draw(mesh);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Iterating over mesh objects\n",
    "\n",
    "##### Iterating over vertices:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for v in mesh.vertices:    \n",
    "    print (v, v.point)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "What is the type of `v` in `mesh.vertices`?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for v in mesh.vertices:    \n",
    "    print(type(v))   "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We'll shortly return to this `MeshNode` class."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Iterating over elements:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for el in mesh.Elements(VOL):\n",
    "    print(type(el))\n",
    "    print (\"vertices: \", el.vertices)   # get vertices of an element \n",
    "    print (\"edges: \", el.edges)         # get edges of an element "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### NodeId and MeshNodes\n",
    "\n",
    "An object of type `NodeId` in NGSolve is just a number together with a type of the mesh entity it describes.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "v = NodeId(VERTEX,0)   # a standalone NodeId object\n",
    "type(v)\n",
    "print (\"type = \", v.type, \"v.nr =\", v.nr)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`NODE_TYPE` can be one of the following:\n",
    "\n",
    "- `VERTEX`: dimension 0 \n",
    "- `EDGE`: dimension 1\n",
    "- `FACE`: dimension 2\n",
    "- `CELL`: dimension 3\n",
    "- `ELEMENT`: codimension 0\n",
    "- `FACET`: codimension 1 \n",
    "\n",
    "E.g., in $n$ space dimensions, facets are mesh objects of dimension $n-1$. When $n=2$ there are no `CELL` entities.  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Nodes can be associated to an existing mesh. Consider the above-defined node \n",
    "```\n",
    "v = NodeId(VERTEX,0)\n",
    "```\n",
    "When it is  associated to `mesh`, it becomes an object of type `MeshNode` which has coordinate information."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "meshv = mesh[v]\n",
    "print (\"type = \", type(meshv))\n",
    "print (\"point = \", meshv.point)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "type(v), type(meshv)   # note the different types"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`MeshNode` objects like `meshv` can be queried for topology information. \n",
    "\n",
    "E.g.,  what are edges connected to the mesh vertex `meshv`?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "meshv.edges"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "c = NodeId(CELL, 1)\n",
    "meshc = mesh[c]\n",
    "meshc.faces          # faces of a cell"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "f = NodeId(FACE, 2)\n",
    "meshf = mesh[f]\n",
    "meshf.edges, meshf.elements"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "## ElementId and Ngs_Element\n",
    "\n",
    "An `ElementId` is made using a number together with  an object like `BND` or `VOL` that knows the codimension."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ei = ElementId(BND,0)\n",
    "type(ei)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As with `NodeId`, we may associate `ElementId` with a mesh to get an object of type `Ngs_Element`, which can be queried for topology information."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "meshel = mesh[ei]\n",
    "type(meshel)\n",
    "print (\"type of meshel = \\n \", meshel)\n",
    "print (\"vertices =\", meshel.vertices)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that `meshel` has only three vertices because it is a **boundary element**. \n",
    "Volume elements have the same type as boundary elements:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "elt0 = mesh[ElementId(VOL, 0)]\n",
    "type(elt0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "elt0.vertices, elt0.edges, elt0.facets"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can also access the same volume element using `NodeId`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "el0 = mesh[NodeId(ELEMENT, 0)]\n",
    "type(el0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "el0.vertices, el0.edges"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Dofs\n",
    "\n",
    "Dofs are numbers enumerating the global *degrees of freedom* of a finite element space. Dofs are associated to mesh entities of the previously described  types.\n",
    "\n",
    "E.g., all dofs of the Lagrange finite element space associated to edges of the mesh can be obtained as follows.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fes = H1(mesh, order=4)\n",
    "for edge in mesh.edges:\n",
    "    print (\"type = \", type(edge)) \n",
    "    print (\"dofs = \", fes.GetDofNrs(edge))   "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "From the output, it is evident that these edge dofs are associated to `MeshNode` objects.\n",
    "\n",
    "What about dofs associated to elements?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for el in fes.Elements(VOL):\n",
    "    print(type(el))\n",
    "    print (el.dofs)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The type `ngsolve.comp.FESpaceElement` appearing in the output is derived from `Ngs_Element` as can be seen from the documentation:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from ngsolve.comp import FESpaceElement\n",
    "help(FESpaceElement)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
