When you apply DirichletBC to a matrix, the diagonal entries for the relevant dofs are set to 1, and all off-diagonal entries in the same rows are set to zero. For your operator you get the same effect by applying DirichletBC to the matrix A and modifying the operator to take two vectors, with homogenized BC applied to one of them.
Note that this approach breaks symmetry.
a = inner(grad(u), grad(v))* dx
b = f * v * ds(1)
p = a + u * v * dx
A = assemble(a)
B = assemble(b)
P = assemble(p)
class CompositeOperator(object):
def __init__(self, A, B, C):
self.A_mat = as_backend_type(A).mat()
self.B_vec = as_backend_type(B).vec()
self.C_vec = as_backend_type(C).vec()
def mult(self, mat, x, y):
self.A_mat.mult(x, y)
a = self.C_vec.dot(x)
y.axpy(a, self.B_vec)
def as_petscmatrix(self):
from petsc4py import PETSc
mat = PETSc.Mat().createPython(self.A_mat.getSizes(),
comm = mpi_comm_world())
mat.setPythonContext(self)
return PETScMatrix(mat)
# Apply boundary conditions
bc = DirichletBC(V, 1., "x[1]<DOLFIN_EPS")
bc.apply(A)
bc.apply(P)
C = B.copy()
bc.homogenize()
bc.apply(B)
A_B = CompositeOperator(A, B, C).as_petscmatrix()
solver = PETScKrylovSolver("cg", "hypre_amg")
solver.set_operators(A_B, P)
You have to apply the DirichletBC to the right hand side before homogenizing it.