I have two issues:
Using dolfinx.fem.petsc.LinearProblem with kind=”nest” and explicitly specifying the u argument, like
problem = dolfinx.fem.petsc.LinearProblem(
a_ufl,
L_ufl,
u = [u_h, p_h],
kind="nest",
bcs=bcs,
P=a_p,
petsc_options_prefix="demo_stokes__nested_iterative_solver_high_level_",
petsc_options={
"ksp_type": "minres",
"ksp_rtol": 1e-9,
"pc_type": "fieldsplit",
"pc_fieldsplit_type": "additive",
"fieldsplit_0_ksp_type": "preonly",
"fieldsplit_0_pc_type": "gamg",
"fieldsplit_1_ksp_type": "preonly",
"fieldsplit_1_pc_type": "jacobi",
},
)
does not work (nest is not used) if the Functions are defined with a name (e.g.
u_h, p_h = dolfinx.fem.Function(V, name='u'), dolfinx.fem.Function(Q, name='p')
), while it works if the optional name argument is not used (e.g.
u_h, p_h = dolfinx.fem.Function(V), Function(Q)
). The following MRE, adapter from the Stokes equation demo,
from mpi4py import MPI
from petsc4py import PETSc
import numpy as np
import ufl
import basix
import dolfinx
import dolfinx.fem.petsc
msh = dolfinx.mesh.create_rectangle(
MPI.COMM_WORLD, [np.array([0, 0]), np.array([1, 1])], (32, 32), dolfinx.mesh.CellType.triangle
)
def noslip_boundary(x):
return np.isclose(x[0], 0.0) | np.isclose(x[0], 1.0) | np.isclose(x[1], 0.0)
def lid(x):
return np.isclose(x[1], 1.0)
def lid_velocity_expression(x):
return np.stack((np.ones(x.shape[1]), np.zeros(x.shape[1])))
P2 = basix.ufl.element(
"Lagrange", msh.basix_cell(), degree=2, shape=(msh.geometry.dim,), dtype=dolfinx.default_real_type
)
P1 = basix.ufl.element("Lagrange", msh.basix_cell(), degree=1, dtype=dolfinx.default_real_type)
V, Q = dolfinx.fem.functionspace(msh, P2), dolfinx.fem.functionspace(msh, P1)
noslip = np.zeros(msh.geometry.dim, dtype=PETSc.ScalarType) # type: ignore
facets = dolfinx.mesh.locate_entities_boundary(msh, 1, noslip_boundary)
bc0 = dolfinx.fem.dirichletbc(noslip, dolfinx.fem.locate_dofs_topological(V, 1, facets), V)
lid_velocity = dolfinx.fem.Function(V)
lid_velocity.interpolate(lid_velocity_expression)
facets = dolfinx.mesh.locate_entities_boundary(msh, 1, lid)
bc1 = dolfinx.fem.dirichletbc(lid_velocity, dolfinx.fem.locate_dofs_topological(V, 1, facets))
bcs = [bc0, bc1]
(u, p) = ufl.TrialFunction(V), ufl.TrialFunction(Q)
(v, q) = ufl.TestFunction(V), ufl.TestFunction(Q)
f = dolfinx.fem.Constant(msh, (PETSc.ScalarType(0), PETSc.ScalarType(0))) # type: ignore
a_ufl = [
[ufl.inner(ufl.grad(u), ufl.grad(v)) * ufl.dx, ufl.inner(p, ufl.div(v)) * ufl.dx],
[ufl.inner(ufl.div(u), q) * ufl.dx, None],
]
a = dolfinx.fem.form(a_ufl)
L_ufl = [ufl.inner(f, v) * ufl.dx, ufl.ZeroBaseForm((q,))]
L = dolfinx.fem.form(L_ufl)
a_p11 = dolfinx.fem.form(ufl.inner(p, q) * ufl.dx)
a_p = [[a[0][0], None], [None, a_p11]]
# prevent nesting
u_h, p_h = dolfinx.fem.Function(V, name='u'), dolfinx.fem.Function(Q, name='p')
# does not prevent nesting
# u_h, p_h = dolfinx.fem.Function(V), Function(Q)
problem = dolfinx.fem.petsc.LinearProblem(
a_ufl,
L_ufl,
u = [u_h, p_h],
kind="nest",
bcs=bcs,
P=a_p,
petsc_options_prefix="demo_stokes__nested_iterative_solver_high_level_",
petsc_options={
"ksp_type": "minres",
"ksp_rtol": 1e-9,
"pc_type": "fieldsplit",
"pc_fieldsplit_type": "additive",
"fieldsplit_0_ksp_type": "preonly",
"fieldsplit_0_pc_type": "gamg",
"fieldsplit_1_ksp_type": "preonly",
"fieldsplit_1_pc_type": "jacobi",
},
)
null_vec = dolfinx.fem.petsc.create_vector(dolfinx.fem.extract_function_spaces(L), "nest")
null_vecs = null_vec.getNestSubVecs()
null_vecs[0].set(0.0), null_vecs[1].set(1.0)
null_vec.normalize()
nsp = PETSc.NullSpace().create(vectors=[null_vec])
problem.A.setNullSpace(nsp)
A00 = problem.A.getNestSubMatrix(0, 0)
A00.setOption(PETSc.Mat.Option.SPD, True)
P00, P11 = problem.P_mat.getNestSubMatrix(0, 0), problem.P_mat.getNestSubMatrix(1, 1)
P00.setOption(PETSc.Mat.Option.SPD, True)
P11.setOption(PETSc.Mat.Option.SPD, True)
problem.solve()
leads to
WARNING! There are options you set that were not used!
WARNING! could be spelling mistake, etc!
There are 4 unused database options. They are:
Option left: name:-demo_stokes__nested_iterative_solver_high_level_fieldsplit_0_ksp_type value: preonly source: code
Option left: name:-demo_stokes__nested_iterative_solver_high_level_fieldsplit_0_pc_type value: gamg source: code
Option left: name:-demo_stokes__nested_iterative_solver_high_level_fieldsplit_1_ksp_type value: preonly source: code
Option left: name:-demo_stokes__nested_iterative_solver_high_level_fieldsplit_1_pc_type value: jacobi source: code
No warning is issued if the functions are defined without a name, as in the commented line of the MRE.
LinearProblem takes a list of bcs, also for the case of kind=”nest”. I fear that this could lead to issues (for example, if two blocks are built over the same vector space and more than one bc needs to be applied to one of them). Am I wrong and/or misunderstanding something? Same issue with bcs_by_block?
Thank you in advance,
Marco