Skip to content

Commit a929a79

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

File tree

1 file changed

+45
-10
lines changed

1 file changed

+45
-10
lines changed

firedrake/preconditioners/bddc.py

Lines changed: 45 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,40 @@ 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
158165
Q = FunctionSpace(V.mesh(), curl_to_grad(V.ufl_element()))
166+
degree = max(as_tuple(Q.ufl_element().degree()))
167+
variant = Q.ufl_element().variant()
159168
gradient = tabulate_exterior_derivative(Q, V)
160-
if variant == 'fdm':
161-
corners = get_vertex_dofs(Q)
162-
gradient.compose('_elements_corners', corners)
169+
170+
if variant == "fdm":
171+
vdofs = get_restricted_dofs(Q, "vertex")
172+
gradient.compose('_elements_corners', vdofs)
173+
174+
# Constant moments along edges
175+
wdofs = get_low_order_dofs(V)
176+
v0 = Function(V)
177+
with v0.dat.vec as y:
178+
y.setValues(wdofs, numpy.ones((wdofs.getSize(),), dtype=PETSc.RealType))
179+
180+
# Linear moments along edges
181+
# Constant moments of gradients of H1 edge bubbles
182+
p = Function(Q).interpolate(1)
183+
q = Function(Q)
184+
185+
edofs = get_restricted_dofs(Q, "edge")
186+
edofs = edofs.difference(vdofs)
187+
with q.dat.vec as qvec, p.dat.vec as pvec:
188+
qvec.setValues(edofs, pvec.getValues(edofs))
189+
190+
v1 = Function(V)
191+
with v1.dat.vec as y, q.dat.vec as x:
192+
gradient.mult(x, y)
193+
y.chop(1E-14)
194+
195+
nsp = VectorSpaceBasis([v0, v1])
196+
gradient.compose("_constraints", nsp.nullspace())
197+
163198
grad_args = (gradient,)
164199
grad_kwargs = {'order': degree}
165200
return grad_args, grad_kwargs

0 commit comments

Comments
 (0)