3.1. Basics on dual cell spaces#
by M. Wess, 2024#
This Notebook is part of the dualcellspaces documentation for the addon package implementing the Dual Cell method in NGSolve.
We start with doing the necessary imports
from ngsolve import *
import dualcellspaces as dcs
from ngsolve.webgui import Draw
The finite element spaces calles XXPrimalCells, XXDualCells, for the spaces on the primal and dual mesh respectively, where XX stands for H1, HCurl, HDiv.
The space H1PrimalCells#
First we study the H1 space on the prmal mesh in two dimensions.

mesh = Mesh(unit_square.GenerateMesh())
Draw(mesh);
h1 = dcs.H1DualCells(mesh,order = 1)
print("number of elements in mesh: ", mesh.ne)
print("number of dofs per element: ", int(h1.ndof/mesh.ne))
number of elements in mesh: 2
number of dofs per element: 10
Let’s take a look at the basis functions:
gfu = GridFunction(h1,multidim = h1.ndof)
for i in range(h1.ndof):
gfu.vecs[i][i] = 0.2
Draw(gfu, animate = True, min = 0, max = 0.2, intpoints = dcs.GetWebGuiPoints(2),order = 2, deformation = True, euler_angles =[-45,-6,25]);
The basis functions are nodal basis functions with respect to a certain integration rule. We may extract the integration rule from the space:
import matplotlib.pyplot as pl
import numpy as np
irs_h1 = h1.GetIntegrationRules()
pl.plot([0,1,0,0],[0,0,1,0]);
pl.plot([0,1/3,0.5,1/3,0.5],[0.5,1/3,0,1/3,0.5]);
trig_points = np.array(irs_h1[TRIG].points)
px,py = trig_points[:,0],trig_points[:,1]
pl.plot(px,py,'ob');
Exercises#
Play around with orders: how many DoFs per element do you expect for the
H1PrimalCellsspace depending on the polynomial order?Change the space to
H1DualCells. How many global DoFs do you expect depending on the polynomial order?
The space HCurlDualCells#
We study the HCurl space on the prmal mesh in two dimensions.

We create the space HCurlDualCells on a mesh with more elements to have inner vertices.
mesh_curl = Mesh(unit_square.GenerateMesh(maxh=0.435))
Draw(mesh_curl);
hcurl = dcs.HCurlDualCells(mesh_curl,order = 0)
print("number of (primal) elements in mesh: ", mesh_curl.ne)
print("number of dofs per element: ", hcurl.ndof/mesh_curl.ne)
number of (primal) elements in mesh: 14
number of dofs per element: 3.5714285714285716
Again we may take a look at the corresponding integration rules:
irs_hcurl = hcurl.GetIntegrationRules()
pl.plot([0,1,0,0],[0,0,1,0]);
pl.plot([0,1/3,0.5,1/3,0.5],[0.5,1/3,0,1/3,0.5]);
trig_points = np.array(irs_hcurl[TRIG].points)
px,py = trig_points[:,0],trig_points[:,1]
pl.plot(px,py,'ob');
print(mesh_curl.nface, mesh_curl.ne)
14 14
Exercises#
Play around with orders: how many DoFs per vertex (
Mesh.nv), edge (Mesh.nedge) and faces (in 2d equivalent:Mesh.ne,Mesh.nface)
3d spaces#
In three dimensions the spaces are defined similarly. We construct the HCurl... spaces.
mesh = Mesh(unit_cube.GenerateMesh())
print("number of elements = {}".format(mesh.ne))
for order in range(5):
print("###P = {}".format(order))
print("ndof = {}".format(dcs.HCurlPrimalCells(mesh,order=order).ndof))
print("{} * 4*(3*P^3+6*P^2+4*P+1)={}".format(mesh.ne,mesh.ne*4*(3*order**3+6*order**2+4*order+1)))
number of elements = 12
###P = 0
ndof = 48
12 * 4*(3*P^3+6*P^2+4*P+1)=48
###P = 1
ndof = 672
12 * 4*(3*P^3+6*P^2+4*P+1)=672
###P = 2
ndof = 2736
12 * 4*(3*P^3+6*P^2+4*P+1)=2736
###P = 3
ndof = 7104
12 * 4*(3*P^3+6*P^2+4*P+1)=7104
###P = 4
ndof = 14640
12 * 4*(3*P^3+6*P^2+4*P+1)=14640
print("number of elements = {}".format(mesh.ne))
for order in range(5):
print("###P = {}".format(order))
print("ndof = {}".format(dcs.HCurlDualCells(mesh,order=order).ndof))
print("2*nedges*(P+1)+6*nfaces*P*(P+1)+12*nelements*P^2(P+1)={}".format(2*mesh.nedge*(order+1)+6*mesh.nface*(order+1)*order+12*mesh.ne*order**2*(order+1)))
number of elements = 12
###P = 0
ndof = 52
2*nedges*(P+1)+6*nfaces*P*(P+1)+12*nelements*P^2(P+1)=52
###P = 1
ndof = 752
2*nedges*(P+1)+6*nfaces*P*(P+1)+12*nelements*P^2(P+1)=752
###P = 2
ndof = 2964
2*nedges*(P+1)+6*nfaces*P*(P+1)+12*nelements*P^2(P+1)=2964
###P = 3
ndof = 7552
2*nedges*(P+1)+6*nfaces*P*(P+1)+12*nelements*P^2(P+1)=7552
###P = 4
ndof = 15380
2*nedges*(P+1)+6*nfaces*P*(P+1)+12*nelements*P^2(P+1)=15380