Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions python/dolfinx/fem/assemble.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,25 @@ def _pack(form):
return _pack(form)


def _check_bcs_for_different_trial_test_spaces(a: Form, bcs: Sequence[DirichletBC]) -> None:
"""Reject DirichletBCs for unsupported Petrov-Galerkin assembly."""
if not bcs or len(a.function_spaces) != 2:
return

test_space, trial_space = a.function_spaces
if test_space is trial_space:
return
if test_space.mesh is not trial_space.mesh:
return

for bc in bcs:
if test_space.contains(bc.function_space) or trial_space.contains(bc.function_space):
raise RuntimeError(
"Dirichlet boundary conditions for bilinear forms with different test "
"and trial spaces are not supported by this matrix assembly path."
)


# -- Vector and matrix instantiation --------------------------------------


Expand Down Expand Up @@ -325,6 +344,7 @@ def _assemble_matrix_csr(
The returned matrix is not finalised, i.e. ghost values are not
accumulated.
"""
_check_bcs_for_different_trial_test_spaces(a, [] if bcs is None else bcs)
bcs = [] if bcs is None else [bc._cpp_object for bc in bcs]
constants = pack_constants(a) if constants is None else constants # type: ignore[assignment]
coeffs = pack_coefficients(a) if coeffs is None else coeffs # type: ignore[assignment]
Expand Down
9 changes: 8 additions & 1 deletion python/dolfinx/fem/petsc.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@
from dolfinx.cpp.fem.petsc import discrete_gradient as _discrete_gradient
from dolfinx.cpp.fem.petsc import interpolation_matrix as _interpolation_matrix
from dolfinx.fem import IntegralType, pack_coefficients, pack_constants
from dolfinx.fem.assemble import _assemble_vector_array
from dolfinx.fem.assemble import (
_assemble_vector_array,
_check_bcs_for_different_trial_test_spaces,
)
from dolfinx.fem.assemble import apply_lifting as _apply_lifting
from dolfinx.fem.bcs import DirichletBC
from dolfinx.fem.bcs import bcs_by_block as _bcs_by_block
Expand Down Expand Up @@ -422,6 +425,10 @@ def _(
The returned matrix is not finalised, i.e. ghost values are not
accumulated.
"""
bcs = [] if bcs is None else bcs
if not isinstance(a, Sequence):
_check_bcs_for_different_trial_test_spaces(a, bcs)

if A.getType() == PETSc.Mat.Type.NEST: # type: ignore[attr-defined]
if not isinstance(a, Sequence):
raise ValueError("Must provide a sequence of forms when assembling a nest matrix")
Expand Down
28 changes: 28 additions & 0 deletions python/test/unit/fem/test_assembler.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,26 @@ def nest_matrix_norm(A):
return math.sqrt(norm)


def _different_trial_test_space_form_and_bc():
msh = create_unit_square(MPI.COMM_WORLD, 4, 4)
U = functionspace(msh, ("Lagrange", 1))
V = functionspace(msh, ("Lagrange", 2))
u = ufl.TrialFunction(U)
v = ufl.TestFunction(V)
a = form(inner(u, v) * dx)

facets = locate_entities_boundary(msh, msh.topology.dim - 1, lambda x: np.isclose(x[0], 0.0))
dofs = locate_dofs_topological(V, msh.topology.dim - 1, facets)
bc = dirichletbc(default_scalar_type(0), dofs, V)
return a, bc


def test_assembly_rejects_bcs_for_different_trial_test_spaces():
a, bc = _different_trial_test_space_form_and_bc()
with pytest.raises(RuntimeError, match="different test and trial spaces"):
assemble_matrix(a, bcs=[bc])


@pytest.mark.petsc4py
def test_vector_single_space_as_block():
from dolfinx.fem.petsc import create_vector as petsc_create_vector
Expand All @@ -193,6 +213,14 @@ def test_vector_single_space_as_block():
class TestPETScAssemblers:
"""Test PETSc-based assemblers for matrices and vectors."""

def test_assembly_rejects_bcs_for_different_trial_test_spaces(self):
"""Test that PETSc assembly rejects same-domain Petrov-Galerkin BCs."""
from dolfinx.fem.petsc import assemble_matrix as petsc_assemble_matrix

a, bc = _different_trial_test_space_form_and_bc()
with pytest.raises(RuntimeError, match="different test and trial spaces"):
petsc_assemble_matrix(a, bcs=[bc])

@pytest.mark.parametrize("mode", [GhostMode.none, GhostMode.shared_facet])
def test_basic_assembly_petsc_matrixcsr(self, mode):
"""Test basic assembly of PETSc Mat and compare with MatrixCSR assembly."""
Expand Down
Loading