Skip to content

Commit 7881459

Browse files
authored
More fixes to DirichletBC.dof_indices (#3941)
* Fix subspace bc dofs indices case * Extend bc dofs test
1 parent f474977 commit 7881459

File tree

2 files changed

+36
-25
lines changed

2 files changed

+36
-25
lines changed

cpp/dolfinx/fem/DirichletBC.h

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -255,12 +255,13 @@ class DirichletBC
255255
{
256256
private:
257257
/// Compute number of owned dofs indices. Will contain 'gaps' for
258-
/// sub-spaces.
258+
/// sub-spaces. The dofs must be unrolled.
259259
std::size_t num_owned(const DofMap& dofmap,
260260
std::span<const std::int32_t> dofs)
261261
{
262+
int bs = dofmap.index_map_bs();
262263
std::int32_t map_size = dofmap.index_map->size_local();
263-
std::int32_t owned_size = map_size;
264+
std::int32_t owned_size = bs * map_size;
264265
auto it = std::ranges::lower_bound(dofs, owned_size);
265266
return std::distance(dofs.begin(), it);
266267
}
@@ -324,8 +325,7 @@ class DirichletBC
324325
std::vector<std::int32_t>>
325326
DirichletBC(std::shared_ptr<const Constant<T>> g, X&& dofs,
326327
std::shared_ptr<const FunctionSpace<U>> V)
327-
: _function_space(V), _g(g), _dofs0(std::forward<X>(dofs)),
328-
_owned_indices0(num_owned(*V->dofmap(), _dofs0))
328+
: _function_space(V), _g(g), _dofs0(std::forward<X>(dofs))
329329
{
330330
assert(g);
331331
assert(V);
@@ -351,10 +351,9 @@ class DirichletBC
351351

352352
// Unroll _dofs0 if dofmap block size > 1
353353
if (const int bs = V->dofmap()->bs(); bs > 1)
354-
{
355-
_owned_indices0 *= bs;
356354
_dofs0 = unroll_dofs(_dofs0, bs);
357-
}
355+
356+
_owned_indices0 = num_owned(*_function_space->dofmap(), _dofs0);
358357
}
359358

360359
/// @brief Create a representation of a Dirichlet boundary condition
@@ -374,17 +373,15 @@ class DirichletBC
374373
std::vector<std::int32_t>>
375374
DirichletBC(std::shared_ptr<const Function<T, U>> g, X&& dofs)
376375
: _function_space(g->function_space()), _g(g),
377-
_dofs0(std::forward<X>(dofs)),
378-
_owned_indices0(num_owned(*_function_space->dofmap(), _dofs0))
376+
_dofs0(std::forward<X>(dofs))
379377
{
380378
assert(_function_space);
381379

382380
// Unroll _dofs0 if dofmap block size > 1
383381
if (const int bs = _function_space->dofmap()->bs(); bs > 1)
384-
{
385-
_owned_indices0 *= bs;
386382
_dofs0 = unroll_dofs(_dofs0, bs);
387-
}
383+
384+
_owned_indices0 = num_owned(*_function_space->dofmap(), _dofs0);
388385
}
389386

390387
/// @brief Create a representation of a Dirichlet boundary condition

python/test/unit/fem/test_bcs.py

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -366,22 +366,36 @@ def test_mixed_blocked_constant():
366366

367367
@pytest.mark.parametrize("shape", [(), (2,), (3, 2)])
368368
def test_blocked_dof_ownership(shape):
369+
"""Test that dof ownership is correctly handled for blocked function spaces."""
369370
mesh = create_unit_square(MPI.COMM_WORLD, 4, 4)
370371
V = functionspace(mesh, ("Lagrange", 1, shape))
371-
372372
u_bc = Function(V)
373-
mesh.topology.create_connectivity(mesh.topology.dim - 1, mesh.topology.dim)
374-
bc_facets = exterior_facet_indices(mesh.topology)
375-
# Blocked spaces are not unrolled here
376-
bc_dofs_u = locate_dofs_topological(V, mesh.topology.dim - 1, bc_facets)
377-
378-
# Num owned dofs
379-
num_owned_blocked = V.dofmap.index_map.size_local
380373

381-
input_dofs_owned = bc_dofs_u[bc_dofs_u < num_owned_blocked]
374+
tdim = mesh.topology.dim
375+
mesh.topology.create_connectivity(tdim - 1, tdim)
376+
boundary_facets = exterior_facet_indices(mesh.topology)
377+
boundary_dofs = locate_dofs_topological(V, tdim - 1, boundary_facets)
382378

383-
bc = dirichletbc(u_bc, bc_dofs_u)
384-
unrolled_bc_dofs, num_owned = bc.dof_indices()
379+
# Test full space BC
380+
bc = dirichletbc(u_bc, boundary_dofs)
381+
unrolled_dofs, num_owned = bc.dof_indices()
385382

386-
assert len(input_dofs_owned) * V.dofmap.index_map_bs == num_owned
387-
assert len(unrolled_bc_dofs) == len(bc_dofs_u) * V.dofmap.index_map_bs
383+
num_owned_blocked = V.dofmap.index_map.size_local
384+
bs = V.dofmap.index_map_bs
385+
owned_input_dofs = boundary_dofs[boundary_dofs < num_owned_blocked]
386+
387+
assert len(owned_input_dofs) * bs == num_owned
388+
assert len(unrolled_dofs) == len(boundary_dofs) * bs
389+
390+
# Test subspace BC for tensor spaces
391+
if len(shape) > 1:
392+
V0, _ = V.sub(0).collapse()
393+
boundary_dofs = locate_dofs_topological((V.sub(0), V0), tdim - 1, boundary_facets)
394+
bc_sub = dirichletbc(u_bc, boundary_dofs, V)
395+
unrolled_dofs_sub, num_owned_sub = bc_sub.dof_indices()
396+
397+
# Check number of unrolled owned dofs in the full non-collapsed space
398+
boundary_dofs_V = boundary_dofs[0]
399+
owned_sub_dofs = boundary_dofs_V[boundary_dofs_V < num_owned_blocked * bs]
400+
assert len(owned_sub_dofs) == num_owned_sub
401+
assert len(unrolled_dofs_sub) == len(boundary_dofs_V)

0 commit comments

Comments
 (0)