Skip to content

Commit 6b7d89e

Browse files
committed
H(curl) constraints for BDDC
1 parent e062b43 commit 6b7d89e

File tree

1 file changed

+46
-10
lines changed

1 file changed

+46
-10
lines changed

firedrake/preconditioners/bddc.py

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ def initialize(self, pc):
104104
div_args = (divergence,)
105105
div_kwargs = dict()
106106
bddcpc.setBDDCDivergenceMat(*div_args, **div_kwargs)
107-
elif tdim >= 2 and V.finat_element.formdegree == 1:
107+
108+
elif tdim >= 3 and V.finat_element.formdegree == 1:
108109
get_gradient = appctx.get("get_discrete_gradient", get_discrete_gradient)
109110
gradient = get_gradient(V)
110111
try:
@@ -130,12 +131,19 @@ def applyTranspose(self, pc, x, y):
130131
self.pc.applyTranspose(x, y)
131132

132133

133-
def get_vertex_dofs(V):
134-
W = FunctionSpace(V.mesh(), restrict(V.ufl_element(), "vertex"))
134+
def get_dof_mapping(V, W):
135135
indices = get_restriction_indices(V, W)
136136
indices = V.dof_dset.lgmap.apply(indices)
137-
vertex_dofs = PETSc.IS().createGeneral(indices, comm=V.comm)
138-
return vertex_dofs
137+
return PETSc.IS().createGeneral(indices, comm=V.comm)
138+
139+
140+
def get_restricted_dofs(V, domain):
141+
W = FunctionSpace(V.mesh(), restrict(V.ufl_element(), domain))
142+
return get_dof_mapping(V, W)
143+
144+
145+
def get_low_order_dofs(V):
146+
return get_dof_mapping(V, V.reconstruct(degree=1))
139147

140148

141149
def get_divergence_mat(V, mat_type="aij", allow_repeated=False):
@@ -153,13 +161,41 @@ def get_divergence_mat(V, mat_type="aij", allow_repeated=False):
153161

154162

155163
def get_discrete_gradient(V):
156-
degree = max(as_tuple(V.ufl_element().degree()))
157-
variant = V.ufl_element().variant()
164+
from firedrake import VectorSpaceBasis
165+
158166
Q = FunctionSpace(V.mesh(), curl_to_grad(V.ufl_element()))
167+
degree = max(as_tuple(Q.ufl_element().degree()))
168+
variant = Q.ufl_element().variant()
159169
gradient = tabulate_exterior_derivative(Q, V)
160-
if variant == 'fdm':
161-
corners = get_vertex_dofs(Q)
162-
gradient.compose('_elements_corners', corners)
170+
171+
if variant == "fdm":
172+
vdofs = get_restricted_dofs(Q, "vertex")
173+
gradient.compose('_elements_corners', vdofs)
174+
175+
# Constant moments along edges
176+
wdofs = get_low_order_dofs(V)
177+
v0 = Function(V)
178+
with v0.dat.vec as y:
179+
y.setValues(wdofs, numpy.ones((wdofs.getSizes()[0],), dtype=PETSc.RealType))
180+
181+
# Linear moments along edges
182+
# Constant moments of gradients of H1 edge bubbles
183+
p = Function(Q).interpolate(1)
184+
q = Function(Q)
185+
186+
edofs = get_restricted_dofs(Q, "edge")
187+
edofs = edofs.difference(vdofs)
188+
with q.dat.vec as qvec, p.dat.vec as pvec:
189+
qvec.setValues(edofs, pvec.getValues(edofs))
190+
191+
v1 = Function(V)
192+
with v1.dat.vec as y, q.dat.vec as x:
193+
gradient.mult(x, y)
194+
y.chop(1E-14)
195+
196+
nsp = VectorSpaceBasis([v0, v1])
197+
gradient.compose("_constraints", nsp.nullspace())
198+
163199
grad_args = (gradient,)
164200
grad_kwargs = {'order': degree}
165201
return grad_args, grad_kwargs

0 commit comments

Comments
 (0)