Multigrid for high order finite element spaces

Officially released with NGSolve2504, most high order spaces provide high order polynomial preserving prolongation operators. Current restrictions:

  • require simplicial meshes

  • require uniform polynomial order

[1]:
from ngsolve import *
from ngsolve.webgui import Draw
from ngsolve.la import EigenValues_Preconditioner

mesh = Mesh(unit_square.GenerateMesh(maxh=0.2))

fes = H1(mesh, order=5, hoprolongation=True, dirichlet=".*")
u,v = fes.TnT()

a = BilinearForm(grad(u)*grad(v)*dx).Assemble()
pre = preconditioners.MultiGrid(a, smoother="block", blocktype="vertexpatch")
[2]:
for l in range(4):
    mesh.Refine()
    a.Assemble()
    lam = EigenValues_Preconditioner(a.mat, pre)
    print (lam[0], lam[-1])
0.9737767048916046 0.9999650900459265
0.9731893341714941 0.9999569893694966
0.9738508899616769 0.9999593243766862
0.9740047337504241 0.9999581308391128
[3]:
f = LinearForm(x*v*dx).Assemble()
gfu = GridFunction(fes)

Solve(a * gfu == f, dirichlet=x*(1-x), lin_solver=solvers.CGSolver, pre=pre, printrates=True)
CG iteration 1, residual = 2.500665990770517
CG iteration 2, residual = 0.024383987764233152
CG iteration 3, residual = 0.00018799791819350655
CG iteration 4, residual = 1.1484794277901268e-06
CG iteration 5, residual = 9.252209912710351e-09
CG iteration 6, residual = 6.018344974750805e-11
CG iteration 7, residual = 4.580233475866812e-13
[4]:
Draw (gfu, deformation=True);

High order with static condensation

[5]:
mesh = Mesh(unit_square.GenerateMesh(maxh=0.2))
fes = H1(mesh, order=5, hoprolongation=True, dirichlet=".*")
[6]:
mesh = Mesh(unit_square.GenerateMesh(maxh=0.2))

fes = H1(mesh, order=5, hoprolongation=True, dirichlet=".*")
u,v = fes.TnT()

a = BilinearForm(grad(u)*grad(v)*dx, condense=True).Assemble()
fes.SetHarmonicProlongation(a)
pre = preconditioners.MultiGrid(a, smoother="block", blocktype="vertexpatch")

for l in range(5):
    mesh.Refine()
    a.Assemble()
    lam = EigenValues_Preconditioner(a.mat, pre)
    print (l+1, fes.ndof, lam[0], lam[-1])
1 2801 0.8873455539760278 0.9998975910633985
2 11001 0.8957401274225056 0.9998894014559885
3 43601 0.8945786078982365 0.9998863285007136
4 173601 0.894386169292487 0.9998960435342532
5 692801 0.8953852278217878 0.9998858093863445
[7]:
f = LinearForm(x*v*dx).Assemble()
gfu = GridFunction(fes)

Solve(a * gfu == f, dirichlet=x*(1-x), lin_solver=solvers.CGSolver, pre=pre, printrates=True)
CG iteration 1, residual = 3.4886087977865676
CG iteration 2, residual = 0.12345444219082062
CG iteration 3, residual = 0.0036390880918837146
CG iteration 4, residual = 9.08036702501544e-05
CG iteration 5, residual = 2.7831282126523136e-06
CG iteration 6, residual = 7.696308282558869e-08
CG iteration 7, residual = 2.172768027790556e-09
CG iteration 8, residual = 6.173415107275903e-11
CG iteration 9, residual = 1.8887182888427588e-12
[8]:
Draw (gfu, deformation=True);
[9]:
mesh = Mesh(unit_square.GenerateMesh(maxh=2))

fes = H1(mesh, order=8, hoprolongation=True)
u,v = fes.TnT()

a = BilinearForm(grad(u)*grad(v)*dx, condense=True).Assemble()
fes.SetHarmonicProlongation(a)
pre = preconditioners.MultiGrid(a, smoother="block", blocktype="vertexpatch")

[10]:
gfu = GridFunction(fes)
gfu.Set(sin(10*x))
Draw(gfu, order=5)
mesh.Refine()
Draw(gfu, order=5)

[10]:
BaseWebGuiScene
[11]:
gfu.vec.data += a.harmonic_extension * gfu.vec
[12]:
Draw (gfu, order=6)
[12]:
BaseWebGuiScene
[ ]: