Skip to content

Commit c730277

Browse files
rckirbypbrubeck
andauthored
Rckirby/patchdemo (#4317)
Co-authored-by: Pablo Brubeck <[email protected]> --------- Co-authored-by: Pablo Brubeck <[email protected]>
1 parent ca39318 commit c730277

File tree

9 files changed

+818
-1
lines changed

9 files changed

+818
-1
lines changed
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
Using patch relaxation for H(curl)
2+
==================================
3+
4+
Contributed by `Robert Kirby <https://sites.baylor.edu/robert_kirby/>`_
5+
and `Pablo Brubeck <https://www.maths.ox.ac.uk/people/pablo.brubeckmartinez/>`_.
6+
7+
Multigrid in H(div) and H(curl) also requires relaxation based on topological patches.
8+
Here, we demonstrate how to do this in the latter case.::
9+
10+
from firedrake import *
11+
12+
base = UnitCubeMesh(2, 2, 2)
13+
mh = MeshHierarchy(base, 3)
14+
mesh = mh[-1]
15+
16+
We consider the Riesz map on H(curl), discretized with lowest order
17+
Nedelec elements. We force the system with a random right-hand side and
18+
impose homogeneous Dirichlet boundary conditions::
19+
20+
21+
def run_solve(mesh, params):
22+
V = FunctionSpace(mesh, "N1curl", 1)
23+
u = TrialFunction(V)
24+
v = TestFunction(V)
25+
uh = Function(V)
26+
a = inner(curl(u), curl(v)) * dx + inner(u, v) * dx
27+
rg = RandomGenerator(PCG64(seed=123456789))
28+
L = rg.uniform(V.dual(), -1, 1)
29+
bcs = DirichletBC(V, 0, "on_boundary")
30+
31+
problem = LinearVariationalProblem(a, L, uh, bcs)
32+
solver = LinearVariationalSolver(problem, solver_parameters=params)
33+
34+
solver.solve()
35+
36+
return solver.snes.getLinearSolveIterations()
37+
38+
Having done both :class:`~.ASMStarPC` and :class:`~.PatchPC` in other demos,
39+
here we simply opt for the former. Arnold, Falk, and Winther show that vertex
40+
patches yield a robust method.::
41+
42+
43+
def mg_params(relax):
44+
return {
45+
"ksp_type": "cg",
46+
"pc_type": "mg",
47+
"mg_levels": {
48+
"ksp_type": "chebyshev",
49+
"ksp_max_it": 1,
50+
**relax
51+
},
52+
"mg_coarse": {
53+
"ksp_type": "preonly",
54+
"pc_type": "cholesky"
55+
}
56+
}
57+
58+
59+
def asm_params(construct_dim):
60+
return {
61+
"pc_type": "python",
62+
"pc_python_type": "firedrake.ASMStarPC",
63+
"pc_star_construct_dim": construct_dim,
64+
"pc_star_backend_type": "tinyasm"
65+
}
66+
67+
Hiptmair proposed a finer space decomposition for Nedelec elements using edge
68+
patches on the original Nedelec space and vertex patches on the gradient of a Lagrange space. The python type
69+
preconditioner :class:`~.HiptmairPC` automatically sets up an additive two-level method
70+
using the auxiliary Lagrange space in a multigrid hierarchy. Therefore, the overall multigrid relaxation composes the edge patches with the auxiliary space relaxation. For the latter, the residual on each level is restricted from the dual of H(curl) into the dual of H1 via the adjoint of the gradient, where a vertex patch relaxation is applied to obtain a correction that is prolonged from H1 into H(curl) via the gradient. ::
71+
72+
73+
def hiptmair_params():
74+
return {
75+
"pc_type": "python",
76+
"pc_python_type": "firedrake.HiptmairPC",
77+
"hiptmair_mg_coarse": asm_params(0),
78+
"hiptmair_mg_levels": asm_params(1),
79+
"hiptmair_mg_levels_ksp_type": "richardson",
80+
"hiptmair_mg_levels_ksp_max_it": 1,
81+
"hiptmair_mg_coarse_ksp_type": "preonly",
82+
}
83+
84+
85+
Now, for each parameter choice, we report the iteration count for the Riesz map
86+
over a range of meshes. We see that vertex patches approach give lower
87+
iteration counts than the Hiptmair approach, but they are more expensive.::
88+
89+
names = {
90+
"Vertex Star": mg_params(asm_params(0)),
91+
"Hiptmair": mg_params(hiptmair_params()),
92+
}
93+
94+
for name, parameters in names.items():
95+
print(f"{name}")
96+
print("Level | Iterations")
97+
for lvl, msh in enumerate(mh[1:], start=1):
98+
its = run_solve(msh, parameters)
99+
print(f"{lvl} | {its}")
100+
101+
For vertex patches, we expect output like,
102+
103+
======== ============
104+
Level Iterations
105+
======== ============
106+
1 10
107+
2 14
108+
3 16
109+
======== ============
110+
111+
and with Hiptmair (edge patches + vertex patches on gradients of Lagrange)
112+
113+
======== ============
114+
Level Iterations
115+
======== ============
116+
1 18
117+
2 20
118+
3 21
119+
======== ============
120+
121+
and additional mesh refinement will lead to these numbers leveling off.
122+
123+
A runnable python version of this demo can be found :demo:`here<hcurl_riesz_star.py>`.

demos/patch/hdiv_riesz_star.py.rst

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
Using patch relaxation for H(div)
2+
=================================
3+
4+
Contributed by `Robert Kirby <https://sites.baylor.edu/robert_kirby/>`_
5+
and `Pablo Brubeck <https://www.maths.ox.ac.uk/people/pablo.brubeckmartinez/>`_.
6+
7+
Multigrid in H(div) and H(curl) also requires relaxation based on topological patches.
8+
Here, we demonstrate how to do this in the former case.::
9+
10+
from firedrake import *
11+
12+
base = UnitCubeMesh(2, 2, 2)
13+
mh = MeshHierarchy(base, 3)
14+
mesh = mh[-1]
15+
16+
We consider the Riesz map on H(div), discretized with lowest order
17+
Raviart--Thomas elements. We force the system with a random right-hand side and
18+
impose homogeneous Dirichlet boundary conditions::
19+
20+
21+
def run_solve(mesh, params):
22+
V = FunctionSpace(mesh, "RT", 1)
23+
u = TrialFunction(V)
24+
v = TestFunction(V)
25+
uh = Function(V)
26+
a = inner(div(u), div(v)) * dx + inner(u, v) * dx
27+
rg = RandomGenerator(PCG64(seed=123456789))
28+
L = rg.uniform(V.dual(), -1, 1)
29+
bcs = DirichletBC(V, 0, "on_boundary")
30+
31+
problem = LinearVariationalProblem(a, L, uh, bcs)
32+
solver = LinearVariationalSolver(problem, solver_parameters=params)
33+
34+
solver.solve()
35+
36+
return solver.snes.getLinearSolveIterations()
37+
38+
Having done both :class:`~.ASMStarPC` and :class:`~.PatchPC` in other demos, here we simply opt for the former.
39+
Arnold, Falk, and Winther show that either vertex (`construct_dim=0`) or edge patches (`construct_dim=1`) will be acceptable in three dimensions.::
40+
41+
42+
def mg_params(relax):
43+
return {
44+
"ksp_type": "cg",
45+
"pc_type": "mg",
46+
"mg_levels": {
47+
"ksp_type": "chebyshev",
48+
"ksp_max_it": 1,
49+
**relax
50+
},
51+
"mg_coarse": {
52+
"ksp_type": "preonly",
53+
"pc_type": "cholesky"
54+
}
55+
}
56+
57+
58+
def asm_params(construct_dim):
59+
return {
60+
"pc_type": "python",
61+
"pc_python_type": "firedrake.ASMStarPC",
62+
"pc_star_construct_dim": construct_dim,
63+
"pc_star_backend_type": "tinyasm"
64+
}
65+
66+
Now, for each parameter choice, we report the iteration count for the Riesz map
67+
over a range of meshes. We see that vertex patches give lower iteration counts than
68+
edge patches, but they are more expensive.::
69+
70+
71+
for cdim in (0, 1):
72+
params = mg_params(asm_params(cdim))
73+
print(f"Relaxation with patches of dimension {cdim}")
74+
print("Level | Iterations")
75+
for lvl, msh in enumerate(mh[1:], start=1):
76+
its = run_solve(msh, params)
77+
print(f"{lvl} | {its}")
78+
79+
For vertex patches, we expect output like,
80+
81+
======== ============
82+
Level Iterations
83+
======== ============
84+
1 9
85+
2 10
86+
3 13
87+
======== ============
88+
89+
and with edge patches
90+
91+
======== ============
92+
Level Iterations
93+
======== ============
94+
1 25
95+
2 29
96+
3 32
97+
======== ============
98+
99+
and additional mesh refinement will lead to these numbers leveling off.
100+
101+
A runnable python version of this demo can be found :demo:`here<hdiv_riesz_star.py>`.

0 commit comments

Comments
 (0)