I am solving a problem which in its simplest form is the following weak problem
$$\int_\Omega \sigma\nabla u\cdot\nabla v \,dx + z^{-1}\left( \int_{E_1}(u-U)(v-V)\,ds + \int_{E_2}(u+U)(v+V)\,ds \right) = 2V$$
Here E_1 and E_2 are subdomains on the boundary, $\sigma$ is a function on $\Omega$, $u\in H^1(\Omega)$ and $U\in\mathbb{R}$, and similarly for the test functions (v,V).
When assembling the first part of the form
V = FunctionSpace(mesh, "CG", 1)
R = FunctionSpace(mesh, "R", 0)
W = MixedFunctionSpace([R,V])
(U,u) = TrialFunctions(W)
(V,v) = TestFunctions(W)
dom_int = sigma*inner(grad(u), grad(v))*dx
A = assemble(dom_int)
the assembly is incredibly slow, especially when compared to not using the real function space
V = FunctionSpace(mesh, "CG", 1)
u = TrialFunction(V)
v = TestFunction(V)
dom_int = sigma*inner(grad(u), grad(v))*dx
A = assemble(dom_int)
This seems to be a known problem:
http://fenicsproject.org/qa/1231/hybrid-fem-formulation-with-some-non-spatial-dofs-with-fenics
Since I have to reassemble the A-matrix many times (iterative method where sigma is changing), this slowdown is very bad. Is there an easy way to:
- Build the A-matrix using only CG-1
- Extend the matrix by a zero row and column (how is this done, and will it ruin performance?)
I tried a workaround with cbc.block by defining
M = block_mat([[0, 0], [0, A]])+block_mat([[B]])
where A is the CG-1 matrix from above and B is the assembled matrix for
$$z^{-1}\left( \int_{E_1}(u-U)(v-V)\,ds + \int_{E_2}(u+U)(v+V)\,ds \right)$$
It did not work, when I tried to solve the system it give the error (I am not even sure if cbc.block supports adding block matrices of different shapes like this):
RuntimeError: Can't allocate vector - no usable template for block 0.
Consider calling something like bb.allocate([V, Q]) to initialise the block_vec.
Any suggestions for a workaround that might help? Ideally the assembly with real spaces should be fixed since it is far too slow.