This page was generated from unit-1.8-meshtopology/meshtopology.ipynb.
1.8 Exploring the mesh topology¶
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.
What edges are connected to a vertex?
What are the edges of an element?
What are the points of an element?
What elements are adjacent to a face?
In some algorithms, such as custom block smoothers (that we shall see in 2.1.2), we will need to iterate over mesh entities using the concepts in this tutorial.
[1]:
from ngsolve import *
from ngsolve.webgui import Draw
from netgen.csg import unit_cube
[2]:
mesh = Mesh(unit_cube.GenerateMesh(maxh=1))
Draw(mesh)
[2]:
BaseWebGuiScene
Iterating over mesh objects¶
Iterating over vertices:¶
[3]:
for v in mesh.vertices:
print (v, v.point)
V0 (0.0, 0.0, 0.0)
V1 (0.0, 0.0, 1.0)
V2 (1.0, 0.0, 0.0)
V3 (0.0, 1.0, 0.0)
V4 (1.0, 0.0, 1.0)
V5 (0.0, 1.0, 1.0)
V6 (1.0, 1.0, 0.0)
V7 (1.0, 1.0, 1.0)
V8 (0.5000000008190509, 0.5000000010144133, 0.5000000008188038)
What is the type of v
in mesh.vertices
?
[4]:
for v in mesh.vertices:
print(type(v))
<class 'ngsolve.comp.MeshNode'>
<class 'ngsolve.comp.MeshNode'>
<class 'ngsolve.comp.MeshNode'>
<class 'ngsolve.comp.MeshNode'>
<class 'ngsolve.comp.MeshNode'>
<class 'ngsolve.comp.MeshNode'>
<class 'ngsolve.comp.MeshNode'>
<class 'ngsolve.comp.MeshNode'>
<class 'ngsolve.comp.MeshNode'>
We’ll shortly return to this MeshNode
class.
Iterating over elements:¶
[5]:
for el in mesh.Elements(VOL):
print(type(el))
print ("vertices: ", el.vertices) # get vertices of an element
print ("edges: ", el.edges) # get edges of an element
<class 'ngsolve.comp.Ngs_Element'>
vertices: (V3, V5, V7, V8)
edges: (E16, E22, E25, E13, E15, E21)
<class 'ngsolve.comp.Ngs_Element'>
vertices: (V0, V1, V8, V2)
edges: (E1, E6, E12, E0, E5, E9)
<class 'ngsolve.comp.Ngs_Element'>
vertices: (V1, V2, V4, V8)
edges: (E9, E12, E20, E6, E7, E10)
<class 'ngsolve.comp.Ngs_Element'>
vertices: (V0, V3, V8, V5)
edges: (E3, E13, E22, E2, E5, E16)
<class 'ngsolve.comp.Ngs_Element'>
vertices: (V1, V4, V5, V8)
edges: (E9, E20, E22, E7, E8, E17)
<class 'ngsolve.comp.Ngs_Element'>
vertices: (V0, V2, V8, V6)
edges: (E4, E11, E24, E1, E5, E12)
<class 'ngsolve.comp.Ngs_Element'>
vertices: (V0, V3, V6, V8)
edges: (E5, E16, E24, E2, E4, E14)
<class 'ngsolve.comp.Ngs_Element'>
vertices: (V0, V1, V5, V8)
edges: (E5, E9, E22, E0, E3, E8)
<class 'ngsolve.comp.Ngs_Element'>
vertices: (V2, V4, V8, V6)
edges: (E11, E18, E24, E10, E12, E20)
<class 'ngsolve.comp.Ngs_Element'>
vertices: (V3, V6, V8, V7)
edges: (E15, E23, E25, E14, E16, E24)
<class 'ngsolve.comp.Ngs_Element'>
vertices: (V4, V6, V7, V8)
edges: (E20, E24, E25, E18, E19, E23)
<class 'ngsolve.comp.Ngs_Element'>
vertices: (V4, V5, V8, V7)
edges: (E19, E21, E25, E17, E20, E22)
NodeId and MeshNodes¶
An object of type NodeId
in NGSolve is just a number together with a type of the mesh entity it describes.
[6]:
v = NodeId(VERTEX,0) # a standalone NodeId object
type(v)
print ("type = ", v.type, "v.nr =", v.nr)
type = NODE_TYPE.VERTEX v.nr = 0
NODE_TYPE
can be one of the following:
VERTEX
: dimension 0EDGE
: dimension 1FACE
: dimension 2CELL
: dimension 3ELEMENT
: codimension 0FACET
: codimension 1
E.g., in \(n\) space dimensions, facets are mesh objects of dimension \(n-1\). When \(n=2\) there are no CELL
entities.
Nodes can be associated to an existing mesh. Consider the above-defined node
v = NodeId(VERTEX,0)
When it is associated to mesh
, it becomes an object of type MeshNode
which has coordinate information.
[7]:
meshv = mesh[v]
print ("type = ", type(meshv))
print ("point = ", meshv.point)
type = <class 'ngsolve.comp.MeshNode'>
point = (0.0, 0.0, 0.0)
[8]:
type(v), type(meshv) # note the differnt types
[8]:
(ngsolve.comp.NodeId, ngsolve.comp.MeshNode)
MeshNode
objects like meshv
can be queried for topology information.
E.g., what are edges connected to the mesh vertex meshv
?
[9]:
meshv.edges
[9]:
(E0, E1, E2, E3, E4, E5, E6, E8, E9, E11, E12, E13, E14, E16, E22, E24)
[10]:
c = NodeId(CELL, 1)
meshc = mesh[c]
meshc.faces # faces of a cell
[10]:
(F11, F4, F0, F2)
[11]:
f = NodeId(FACE, 2)
meshf = mesh[f]
meshf.edges, meshf.elements
[11]:
((E0, E9, E5),
(<ngsolve.comp.ElementId at 0x7f86e91db730>,
<ngsolve.comp.ElementId at 0x7f86e91db7b0>))
ElementId and Ngs_Element¶
An ElementId
is made using a number together with an object like BND
or VOL
that knows the codimension.
[12]:
ei = ElementId(BND,0)
type(ei)
[12]:
ngsolve.comp.ElementId
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.
[13]:
meshel = mesh[ei]
type(meshel)
print ("type of meshel = \n ", meshel)
print ("vertices =", meshel.vertices)
type of meshel =
<ngsolve.comp.Ngs_Element object at 0x7f86e91e6270>
vertices = (V0, V1, V5)
Note that meshel
has only three vertices because it is a boundary element. Volume elements have the same type as boundary elements:
[14]:
elt0 = mesh[ElementId(VOL, 0)]
type(elt0)
[14]:
ngsolve.comp.Ngs_Element
[15]:
elt0.vertices, elt0.edges, elt0.facets
[15]:
((V3, V5, V7, V8), (E16, E22, E25, E13, E15, E21), (F28, F22, F19, F18))
You can also access the same volume element using NodeId
:
[16]:
el0 = mesh[NodeId(ELEMENT, 0)]
type(el0)
[16]:
ngsolve.comp.MeshNode
[17]:
el0.vertices, el0.edges
[17]:
((V3, V5, V7, V8), (E16, E22, E25, E13, E15, E21))
Dofs¶
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.
E.g., all dofs of the Lagrange finite element space associated to edges of the mesh can be obtained as follows.
[18]:
fes = H1(mesh, order=4)
for edge in mesh.edges:
print ("type = ", type(edge))
print ("dofs = ", fes.GetDofNrs(edge))
type = <class 'ngsolve.comp.MeshNode'>
dofs = (9, 10, 11)
type = <class 'ngsolve.comp.MeshNode'>
dofs = (12, 13, 14)
type = <class 'ngsolve.comp.MeshNode'>
dofs = (15, 16, 17)
type = <class 'ngsolve.comp.MeshNode'>
dofs = (18, 19, 20)
type = <class 'ngsolve.comp.MeshNode'>
dofs = (21, 22, 23)
type = <class 'ngsolve.comp.MeshNode'>
dofs = (24, 25, 26)
type = <class 'ngsolve.comp.MeshNode'>
dofs = (27, 28, 29)
type = <class 'ngsolve.comp.MeshNode'>
dofs = (30, 31, 32)
type = <class 'ngsolve.comp.MeshNode'>
dofs = (33, 34, 35)
type = <class 'ngsolve.comp.MeshNode'>
dofs = (36, 37, 38)
type = <class 'ngsolve.comp.MeshNode'>
dofs = (39, 40, 41)
type = <class 'ngsolve.comp.MeshNode'>
dofs = (42, 43, 44)
type = <class 'ngsolve.comp.MeshNode'>
dofs = (45, 46, 47)
type = <class 'ngsolve.comp.MeshNode'>
dofs = (48, 49, 50)
type = <class 'ngsolve.comp.MeshNode'>
dofs = (51, 52, 53)
type = <class 'ngsolve.comp.MeshNode'>
dofs = (54, 55, 56)
type = <class 'ngsolve.comp.MeshNode'>
dofs = (57, 58, 59)
type = <class 'ngsolve.comp.MeshNode'>
dofs = (60, 61, 62)
type = <class 'ngsolve.comp.MeshNode'>
dofs = (63, 64, 65)
type = <class 'ngsolve.comp.MeshNode'>
dofs = (66, 67, 68)
type = <class 'ngsolve.comp.MeshNode'>
dofs = (69, 70, 71)
type = <class 'ngsolve.comp.MeshNode'>
dofs = (72, 73, 74)
type = <class 'ngsolve.comp.MeshNode'>
dofs = (75, 76, 77)
type = <class 'ngsolve.comp.MeshNode'>
dofs = (78, 79, 80)
type = <class 'ngsolve.comp.MeshNode'>
dofs = (81, 82, 83)
type = <class 'ngsolve.comp.MeshNode'>
dofs = (84, 85, 86)
From the output, it is evident that these edge dofs are associated to MeshNode
objects.
What about dofs associated to elements?
[19]:
for el in fes.Elements(VOL):
print(type(el))
print (el.dofs)
<class 'ngsolve.comp.FESpaceElement'>
[3, 5, 7, 8, 57, 58, 59, 75, 76, 77, 84, 85, 86, 48, 49, 50, 54, 55, 56, 72, 73, 74, 171, 172, 173, 153, 154, 155, 144, 145, 146, 141, 142, 143, 177]
<class 'ngsolve.comp.FESpaceElement'>
[0, 1, 8, 2, 12, 13, 14, 27, 28, 29, 45, 46, 47, 9, 10, 11, 24, 25, 26, 36, 37, 38, 120, 121, 122, 99, 100, 101, 87, 88, 89, 93, 94, 95, 178]
<class 'ngsolve.comp.FESpaceElement'>
[1, 2, 4, 8, 36, 37, 38, 45, 46, 47, 69, 70, 71, 27, 28, 29, 30, 31, 32, 39, 40, 41, 135, 136, 137, 126, 127, 128, 120, 121, 122, 117, 118, 119, 179]
<class 'ngsolve.comp.FESpaceElement'>
[0, 3, 8, 5, 18, 19, 20, 48, 49, 50, 75, 76, 77, 15, 16, 17, 24, 25, 26, 57, 58, 59, 144, 145, 146, 111, 112, 113, 102, 103, 104, 108, 109, 110, 180]
<class 'ngsolve.comp.FESpaceElement'>
[1, 4, 5, 8, 36, 37, 38, 69, 70, 71, 75, 76, 77, 30, 31, 32, 33, 34, 35, 60, 61, 62, 159, 160, 161, 129, 130, 131, 126, 127, 128, 123, 124, 125, 181]
<class 'ngsolve.comp.FESpaceElement'>
[0, 2, 8, 6, 21, 22, 23, 42, 43, 44, 81, 82, 83, 12, 13, 14, 24, 25, 26, 45, 46, 47, 138, 139, 140, 114, 115, 116, 96, 97, 98, 99, 100, 101, 182]
<class 'ngsolve.comp.FESpaceElement'>
[0, 3, 6, 8, 24, 25, 26, 57, 58, 59, 81, 82, 83, 15, 16, 17, 21, 22, 23, 51, 52, 53, 150, 151, 152, 114, 115, 116, 108, 109, 110, 105, 106, 107, 183]
<class 'ngsolve.comp.FESpaceElement'>
[0, 1, 5, 8, 24, 25, 26, 36, 37, 38, 75, 76, 77, 9, 10, 11, 18, 19, 20, 33, 34, 35, 129, 130, 131, 111, 112, 113, 93, 94, 95, 90, 91, 92, 184]
<class 'ngsolve.comp.FESpaceElement'>
[2, 4, 8, 6, 42, 43, 44, 63, 64, 65, 81, 82, 83, 39, 40, 41, 45, 46, 47, 69, 70, 71, 165, 166, 167, 138, 139, 140, 132, 133, 134, 135, 136, 137, 185]
<class 'ngsolve.comp.FESpaceElement'>
[3, 6, 8, 7, 54, 55, 56, 78, 79, 80, 84, 85, 86, 51, 52, 53, 57, 58, 59, 81, 82, 83, 174, 175, 176, 153, 154, 155, 147, 148, 149, 150, 151, 152, 186]
<class 'ngsolve.comp.FESpaceElement'>
[4, 6, 7, 8, 69, 70, 71, 81, 82, 83, 84, 85, 86, 63, 64, 65, 66, 67, 68, 78, 79, 80, 174, 175, 176, 168, 169, 170, 165, 166, 167, 162, 163, 164, 187]
<class 'ngsolve.comp.FESpaceElement'>
[4, 5, 8, 7, 66, 67, 68, 72, 73, 74, 84, 85, 86, 60, 61, 62, 69, 70, 71, 75, 76, 77, 171, 172, 173, 168, 169, 170, 156, 157, 158, 159, 160, 161, 188]
The type ngsolve.comp.FESpaceElement
appearing in the output is derived from Ngs_Element
as can be seen from the documentation:
[20]:
from ngsolve.comp import FESpaceElement
help(FESpaceElement)
Help on class FESpaceElement in module ngsolve.comp:
class FESpaceElement(Ngs_Element)
| Method resolution order:
| FESpaceElement
| Ngs_Element
| pybind11_builtins.pybind11_object
| builtins.object
|
| Methods defined here:
|
| GetFE(...)
| GetFE(self: ngsolve.comp.FESpaceElement) -> ngsolve.fem.FiniteElement
|
| the finite element containing shape functions
|
| GetTrafo(...)
| GetTrafo(self: ngsolve.comp.FESpaceElement) -> ngsolve.fem.ElementTransformation
|
| the transformation from reference element to physical element
|
| __init__(self, /, *args, **kwargs)
| Initialize self. See help(type(self)) for accurate signature.
|
| ----------------------------------------------------------------------
| Readonly properties defined here:
|
| dofs
| degrees of freedom of element
|
| ----------------------------------------------------------------------
| Methods inherited from Ngs_Element:
|
| VB(...)
| VB(self: ngsolve.comp.Ngs_Element) -> ngsolve.comp.VorB
|
| VorB of element
|
| ----------------------------------------------------------------------
| Readonly properties inherited from Ngs_Element:
|
| edges
| tuple of global edge numbers
|
| elementnode
| inner node, i.e. cell, face or edge node for 3D/2D/1D
|
| faces
| tuple of global face numbers
|
| facets
| tuple of global face, edge or vertex numbers
|
| index
| material or boundary condition index
|
| mat
| material or boundary condition label
|
| nr
| the element number
|
| type
| geometric shape of element
|
| valid
| is element valid
|
| vertices
| tuple of global vertex numbers
|
| ----------------------------------------------------------------------
| Static methods inherited from pybind11_builtins.pybind11_object:
|
| __new__(*args, **kwargs) from pybind11_builtins.pybind11_type
| Create and return a new object. See help(type) for accurate signature.