81. Schwarz preconditioners for high order finite elements#
Basis functions for high order finite element methods (aka p-version fem) are associated with vertices, edges, faces and cells of the triangulation. Thus, there is a natural way to define block-Jacobi (or block-Gauss-Seidel) preconditioners by combining dofs sitting on the same geometric entities (called nodes).
from ngsolve import *
from ngsolve.la import EigenValues_Preconditioner
from ngsolve.webgui import Draw
mesh = Mesh(unit_square.GenerateMesh(maxh=0.2))
def DefineProblem(order, printing=True):
fes = H1(mesh, order=order)
u,v = fes.TnT()
a = BilinearForm(grad(u)*grad(v)*dx+10*u*v*dx).Assemble()
f = LinearForm(x*y*v*dx).Assemble()
blocks = []
freedofs = fes.FreeDofs()
for v in mesh.vertices:
blocks.append (fes.GetDofNrs(v))
for ed in mesh.edges:
blocks.append (fes.GetDofNrs(ed))
for fa in mesh.faces:
blocks.append (fes.GetDofNrs(fa))
if printing:
print (blocks)
pre = a.mat.CreateBlockSmoother(blocks, GS=False)
return a,f,pre
a,f,pre = DefineProblem(2)
[(0,), (1,), (2,), (3,), (4,), (5,), (6,), (7,), (8,), (9,), (10,), (11,), (12,), (13,), (14,), (15,), (16,), (17,), (18,), (19,), (20,), (21,), (22,), (23,), (24,), (25,), (26,), (27,), (28,), (29,), (30,), (31,), (32,), (33,), (34,), (35,), (36,), (37,), (38,), (39,), (40,), (41,), (42,), (43,), (44,), (45,), (46,), (47,), (48,), (49,), (50,), (51,), (52,), (53,), (54,), (55,), (56,), (57,), (58,), (59,), (60,), (61,), (62,), (63,), (64,), (65,), (66,), (67,), (68,), (69,), (70,), (71,), (72,), (73,), (74,), (75,), (76,), (77,), (78,), (79,), (80,), (81,), (82,), (83,), (84,), (85,), (86,), (87,), (88,), (89,), (90,), (91,), (92,), (93,), (94,), (95,), (96,), (97,), (98,), (99,), (100,), (101,), (102,), (103,), (104,), (105,), (106,), (107,), (108,), (109,), (110,), (111,), (112,), (113,), (114,), (115,), (116,), (117,), (118,), (119,), (120,), (121,), (122,), (123,), (124,), (125,), (126,), (127,), (128,), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), ()]
gfu = GridFunction(a.space)
from ngsolve.krylovspace import CGSolver
inv = CGSolver(mat=a.mat, pre=pre, printrates='\r', maxiter=400)
gfu.vec.data = inv * f.vec
Draw (gfu);
CG iteration 1, residual = 0.03600107735785368
CG iteration 2, residual = 0.038372133430393085
CG iteration 3, residual = 0.029110059484005368
CG iteration 4, residual = 0.027141112208440944
CG iteration 5, residual = 0.017569446437950133
CG iteration 6, residual = 0.011526175793908976
CG iteration 7, residual = 0.008223670026623633
CG iteration 8, residual = 0.005175756512492302
CG iteration 9, residual = 0.0033326056989442495
CG iteration 10, residual = 0.0021695790281934047
CG iteration 11, residual = 0.0017192307844422971
CG iteration 12, residual = 0.0011194899718497886
CG iteration 13, residual = 0.0005551689787361585
CG iteration 14, residual = 0.00033185029452326164
CG iteration 15, residual = 0.00020548463318327418
CG iteration 16, residual = 0.00012501023681255603
CG iteration 17, residual = 8.249278113708203e-05
CG iteration 18, residual = 4.194808314485239e-05
CG iteration 19, residual = 2.774519246951208e-05
CG iteration 20, residual = 1.629950611838762e-05
CG iteration 21, residual = 1.0683041626248798e-05
CG iteration 22, residual = 7.829498488416673e-06
CG iteration 23, residual = 4.998589544127889e-06
CG iteration 24, residual = 3.1419610329681682e-06
CG iteration 25, residual = 1.774162749131244e-06
CG iteration 26, residual = 1.0621529093398554e-06
CG iteration 27, residual = 5.923827837653877e-07
CG iteration 28, residual = 3.0868547517303654e-07
CG iteration 29, residual = 1.6372588267151164e-07
CG iteration 30, residual = 8.453675310914573e-08
CG iteration 31, residual = 4.827118044289648e-08
CG iteration 32, residual = 2.4503550791698903e-08
CG iteration 33, residual = 1.336017892188534e-08
CG iteration 34, residual = 6.922662690227991e-09
CG iteration 35, residual = 3.974036650498149e-09
CG iteration 36, residual = 2.436704957055982e-09
CG iteration 37, residual = 1.3020788349876099e-09
CG iteration 38, residual = 7.428345203403012e-10
CG iteration 39, residual = 4.4932781620273573e-10
CG iteration 40, residual = 2.1902309893115748e-10
CG iteration 41, residual = 1.432282758621592e-10
CG iteration 42, residual = 6.154601025499428e-11
CG iteration 43, residual = 3.055221663315438e-11
CG iteration 44, residual = 1.723177834905711e-11
CG iteration 45, residual = 9.365286235132443e-12
CG iteration 46, residual = 5.019742972592409e-12
CG iteration 47, residual = 2.3167393994567743e-12
CG iteration 48, residual = 1.1284855487475755e-12
CG iteration 49, residual = 5.355145750599808e-13
CG iteration 50, residual = 2.8434096010959235e-13
CG iteration 51, residual = 1.3755390110821064e-13
CG iteration 52, residual = 6.29889613302593e-14
CG iteration 53, residual = 2.867016439654294e-14
CG converged in 53 iterations to residual 2.867016439654294e-14
Exercise:
Plot the dependency of the extremal eigenvalues on the polynomial order \(p\).
Compare time to solution. To get comparable results, plot number of dofs per second.
a,f,pre = DefineProblem(3, False)
lam = list(EigenValues_Preconditioner(a.mat, pre))
print ("lammin, lammax=", lam[0], lam[-1])
lammin, lammax= 0.07035098554201802 2.7338478939072934
81.1. Overlapping blocks#
One can improve the condition number by letting blocks overlap. Examples:
One can assign all dofs associated with one element (including the boundary) to a block. The number of blocks is the number of elements.
One can combine all dofs on all elements sharing a vertex to blocks. The number of blocks is now the number of vertics.
One can combine all dofs on all edges sharing a vertex to blocks. The dofs on faces and cells are left as extra blocks.
Exercise:
Implement these definition of blocks.
Find some more possibilities.
Which one gives the best condition number ?
Which one computes the solution in least time ?
Consult NGSolve documentation:
The \(p\)-robust analysis for triangular and tetrahedral meshes can be found in: Additive Schwarz preconditioning for p-version triangular and tetrahedral finite elements