Skip to content

Commit 9f721b8

Browse files
committed
Test BDDC, setCoordinates
1 parent 595ba4e commit 9f721b8

File tree

3 files changed

+67
-24
lines changed

3 files changed

+67
-24
lines changed

firedrake/assemble.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2206,7 +2206,8 @@ def masked_lgmap(lgmap, mask, block=True):
22062206

22072207

22082208
def unghosted_lgmap(lgmap, V, block=True):
2209-
mesh_dm = V.mesh().topology_dm
2209+
mesh = V._mesh
2210+
mesh_dm = mesh.topology_dm
22102211
start, end = mesh_dm.getHeightStratum(0)
22112212

22122213
own = []
@@ -2227,6 +2228,5 @@ def unghosted_lgmap(lgmap, V, block=True):
22272228
# Local indices within W
22282229
W_indices = slice(bsize * off, bsize * (off + dof))
22292230
own.extend(W_local_ises_indices[W_indices])
2230-
22312231
mask = numpy.setdiff1d(range(len(lgmap.indices)), own)
22322232
return masked_lgmap(lgmap, mask, block=block)

firedrake/preconditioners/bddc.py

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from firedrake.petsc import PETSc
55
from firedrake.dmhooks import get_function_space, get_appctx
66
from firedrake.ufl_expr import TestFunction, TrialFunction
7+
from firedrake.function import Function
78
from firedrake.functionspace import FunctionSpace, VectorFunctionSpace, TensorFunctionSpace
89
from ufl import curl, div, HCurl, HDiv, inner, dx
910
from pyop2.utils import as_tuple
@@ -29,11 +30,6 @@ class BDDCPC(PCBase):
2930
keyword arguments supplied to ``PETSc.PC.setBDDCDiscreteGradient``.
3031
- ``'divergence_mat'`` for 3D problems in H(div), this sets the Mat with the
3132
assembled bilinear form testing the divergence against an L2 space.
32-
33-
Notes
34-
-----
35-
Currently the Mat type IS is only supported by FDMPC.
36-
3733
"""
3834

3935
_prefix = "bddc_"
@@ -45,6 +41,7 @@ def initialize(self, pc):
4541
self.prefix = (pc.getOptionsPrefix() or "") + self._prefix
4642

4743
V = get_function_space(dm)
44+
variant = V.ufl_element().variant()
4845

4946
# Create new PC object as BDDC type
5047
bddcpc = PETSc.PC().create(comm=pc.comm)
@@ -54,7 +51,7 @@ def initialize(self, pc):
5451
bddcpc.setType(PETSc.PC.Type.BDDC)
5552

5653
opts = PETSc.Options(bddcpc.getOptionsPrefix())
57-
if V.ufl_element().variant() == "fdm" and "pc_bddc_use_local_mat_graph" not in opts:
54+
if variant == "fdm" and "pc_bddc_use_local_mat_graph" not in opts:
5855
# Disable computation of disconected components of subdomain interfaces
5956
opts["pc_bddc_use_local_mat_graph"] = False
6057

@@ -81,6 +78,14 @@ def initialize(self, pc):
8178
appctx = self.get_appctx(pc)
8279
sobolev_space = V.ufl_element().sobolev_space
8380

81+
# set coordinates
82+
if variant != "fdm" and is_lagrange(V):
83+
degree = V.ufl_element().embedded_superdegree
84+
W = VectorFunctionSpace(V.mesh(), "Lagrange", degree, variant=variant)
85+
coords = Function(W).interpolate(V.mesh().coordinates)
86+
view = (slice(None), *(None for _ in V.value_shape), slice(None))
87+
bddcpc.setCoordinates(numpy.tile(coords.dat.data_ro[view], (1, *V.value_shape, 1)))
88+
8489
tdim = V.mesh().topological_dimension()
8590
degree = max(as_tuple(V.ufl_element().degree()))
8691
if tdim >= 2 and V.finat_element.formdegree == tdim-1:
@@ -140,3 +145,13 @@ def get_vertex_dofs(V):
140145
V.dof_dset.lgmap.apply(indices, result=indices)
141146
vertex_dofs = PETSc.IS().createGeneral(indices, comm=V.comm)
142147
return vertex_dofs
148+
149+
150+
def is_lagrange(V):
151+
nodes = V.finat_element.fiat_equivalent.dual_basis()
152+
for node in nodes:
153+
try:
154+
pt, = node.get_point_dict()
155+
except ValueError:
156+
return False
157+
return True

tests/firedrake/regression/test_bddc.py

Lines changed: 44 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@
33
from firedrake.petsc import DEFAULT_DIRECT_SOLVER
44

55

6-
def bddc_params(static_condensation):
6+
def bddc_params():
77
chol = {
88
"pc_type": "cholesky",
99
"pc_factor_mat_solver_type": "petsc",
1010
"pc_factor_mat_ordering_type": "natural",
1111
}
1212
sp = {
13+
"mat_type": "is",
1314
"pc_type": "python",
1415
"pc_python_type": "firedrake.BDDCPC",
1516
"bddc_pc_bddc_neumann": chol,
@@ -19,12 +20,14 @@ def bddc_params(static_condensation):
1920
return sp
2021

2122

22-
def solver_parameters(static_condensation=True):
23+
def solver_parameters(static_condensation=False, variant=None):
2324
rtol = 1E-8
2425
atol = 1E-12
25-
sp_bddc = bddc_params(static_condensation)
26-
repeated = True
27-
if static_condensation:
26+
sp_bddc = bddc_params()
27+
if variant != "fdm":
28+
sp = sp_bddc
29+
30+
elif static_condensation:
2831
sp = {
2932
"pc_type": "python",
3033
"pc_python_type": "firedrake.FacetSplitPC",
@@ -33,7 +36,7 @@ def solver_parameters(static_condensation=True):
3336
"facet_fdm_static_condensation": True,
3437
"facet_fdm_pc_use_amat": False,
3538
"facet_fdm_mat_type": "is",
36-
"facet_fdm_mat_is_allow_repeated": repeated,
39+
"facet_fdm_mat_is_allow_repeated": True,
3740
"facet_fdm_pc_type": "fieldsplit",
3841
"facet_fdm_pc_fieldsplit_type": "symmetric_multiplicative",
3942
"facet_fdm_pc_fieldsplit_diag_use_amat": False,
@@ -47,22 +50,23 @@ def solver_parameters(static_condensation=True):
4750
"pc_type": "python",
4851
"pc_python_type": "firedrake.FDMPC",
4952
"fdm_pc_use_amat": False,
50-
"fdm_mat_type": "is",
51-
"fdm_mat_is_allow_repeated": repeated,
53+
"fdm_mat_is_allow_repeated": True,
5254
"fdm": sp_bddc,
5355
}
56+
5457
sp.update({
55-
"mat_type": "matfree",
5658
"ksp_type": "cg",
5759
"ksp_norm_type": "natural",
5860
"ksp_monitor": None,
5961
"ksp_rtol": rtol,
6062
"ksp_atol": atol,
6163
})
64+
if variant == "fdm":
65+
sp["mat_type"] = "matfree"
6266
return sp
6367

6468

65-
def solve_riesz_map(mesh, family, degree, bcs, condense):
69+
def solve_riesz_map(mesh, family, degree, variant, bcs, condense=False, vector=False):
6670
dirichlet_ids = []
6771
if bcs:
6872
dirichlet_ids = ["on_boundary"]
@@ -74,7 +78,10 @@ def solve_riesz_map(mesh, family, degree, bcs, condense):
7478
family = "RTCE" if tdim == 2 else "NCE"
7579
if family.endswith("F"):
7680
family = "RTCF" if tdim == 2 else "NCF"
77-
V = FunctionSpace(mesh, family, degree, variant="fdm")
81+
82+
fs = VectorFunctionSpace if vector else FunctionSpace
83+
84+
V = fs(mesh, family, degree, variant=variant)
7885
v = TestFunction(V)
7986
u = TrialFunction(V)
8087
d = {
@@ -95,13 +102,21 @@ def solve_riesz_map(mesh, family, degree, bcs, condense):
95102
bcs = [DirichletBC(V, u_exact, sub) for sub in dirichlet_ids]
96103
nsp = None
97104
if formdegree == 0:
98-
nsp = VectorSpaceBasis([Function(V).interpolate(Constant(1))])
105+
b = np.zeros(V.value_shape)
106+
expr = Constant(b)
107+
basis = []
108+
for i in np.ndindex(V.value_shape):
109+
b[...] = 0
110+
b[i] = 1
111+
expr.assign(b)
112+
basis.append(Function(V).interpolate(expr))
113+
nsp = VectorSpaceBasis(basis)
99114
nsp.orthonormalize()
100115

101116
uh = Function(V, name="solution")
102117
problem = LinearVariationalProblem(a, L, uh, bcs=bcs)
103118

104-
sp = solver_parameters(condense)
119+
sp = solver_parameters(condense, variant=variant)
105120
solver = LinearVariationalSolver(problem, near_nullspace=nsp,
106121
solver_parameters=sp,
107122
options_prefix="")
@@ -120,11 +135,24 @@ def mesh(request):
120135

121136

122137
@pytest.mark.parallel
123-
@pytest.mark.parametrize("family", "Q")
124138
@pytest.mark.parametrize("degree", (4,))
125-
@pytest.mark.parametrize("condense", (False, True))
139+
@pytest.mark.parametrize("family", "Q")
140+
@pytest.mark.parametrize("condense", (False, True), ids=("full", "condense"))
126141
def test_bddc_fdm(mesh, family, degree, condense):
142+
variant = "fdm"
127143
bcs = True
128144
tdim = mesh.topological_dimension()
129145
expected = 6 if tdim == 2 else 11
130-
assert solve_riesz_map(mesh, family, degree, bcs, condense) <= expected
146+
assert solve_riesz_map(mesh, family, degree, variant, bcs, condense=condense) <= expected
147+
148+
149+
@pytest.mark.parallel
150+
@pytest.mark.parametrize("degree", (4,))
151+
@pytest.mark.parametrize("family", "Q")
152+
@pytest.mark.parametrize("vector", (False, True), ids=("scalar", "vector"))
153+
def test_bddc_aij(mesh, family, degree, vector):
154+
variant = None
155+
bcs = True
156+
tdim = mesh.topological_dimension()
157+
expected = 7 if tdim == 2 else 11
158+
assert solve_riesz_map(mesh, family, degree, variant, bcs, vector=vector) <= expected

0 commit comments

Comments
 (0)