I have MixedElement
space V=U\times P and I would like to build a PETSc.Mat
object that could be multiplied by a vector associated to a Function
from the V space and return a PETSc.Vec
associated to a Function
living on the U space.
This is what I call an extractor, it’s essentially a potentially very large matrix filled with 0 & 1s.
My first naive attempt was to create a projection bilinear form, something like :
v=dfx.Function(V)
u=dfx.Function(V.sub(0).collapse(collapsed_dofs=True)[0])
form=ufl.inner(u,v)*ufl.dx
B=dfx.fem.assemble_matrix(form)
B.assemble()
This throws an error though : RuntimeError: Cannot create sparsity pattern. Form is not a bilinear form
though if the matrix is not square, it does look bilinear to me.
Right now I have a much less elegant iterative solution that involves creating a CSR matrix :
U=V.sub(0)
U_collapsed=U.collapse()
# Compute DoFs
dofs=dfx.fem.locate_dofs_geometrical((U, U_collapsed), lambda x: np.ones(x.shape[1]))[0]
n=dofs.size
m=V.dofmap.index_map.size_global * V.dofmap.index_map_bs
rows=np.zeros(m+1,dtype='int32')
for i in dofs: rows[i+1:]+=1 # Probably inefficient
cols=np.arange(n,dtype='int32')
vals=np.ones(n,dtype='int32')
B=pet.Mat().createAIJ([m, n],csr=[rows,cols,vals]) # AIJ represents sparse matrix
B.setUp()
B.assemble()
No surprise there, the line with a for loop is punitively slow. Anyone has an idea on doing this in a smarter manner ?