From afa2d09db7ed0977923254493b670b38bb0c5b90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yaman=20G=C3=BC=C3=A7l=C3=BC?= Date: Sun, 11 Oct 2026 19:08:20 +0200 Subject: [PATCH 1/3] Check that the components of a VectorFemSpace share the same DomainDecomposition, see #615 --- psydac/fem/tests/test_vector_spaces.py | 22 ++++++++++++++++++++++ psydac/fem/vector.py | 5 +++++ 2 files changed, 27 insertions(+) diff --git a/psydac/fem/tests/test_vector_spaces.py b/psydac/fem/tests/test_vector_spaces.py index db813da75..1ce56169c 100644 --- a/psydac/fem/tests/test_vector_spaces.py +++ b/psydac/fem/tests/test_vector_spaces.py @@ -143,6 +143,28 @@ def test_vector_space_3d(): assert F.patch_fields == (F,) assert F.component_fields == F.fields +#============================================================================== +def make_tensor_space_2d(domain_decomposition: DomainDecomposition) -> TensorFemSpace: + """Create a 2D tensor-product spline space of degree 2 on 3 x 5 cells.""" + spaces = [SplineSpace(2, grid=linspace(0., 1., n + 1)) for n in [3, 5]] + return TensorFemSpace(domain_decomposition, *spaces) + +def test_vector_space_shared_domain_decomposition(): + + ddm = DomainDecomposition([3, 5], [False, False]) + V = VectorFemSpace(make_tensor_space_2d(ddm), make_tensor_space_2d(ddm)) + + assert all(W.domain_decomposition is ddm for W in V.spaces) + +def test_vector_space_different_domain_decompositions(): + + # Two decompositions are rejected even if equivalent (see #615) + Vx = make_tensor_space_2d(DomainDecomposition([3, 5], [False, False])) + Vy = make_tensor_space_2d(DomainDecomposition([3, 5], [False, False])) + + with pytest.raises(AssertionError, match='same DomainDecomposition'): + VectorFemSpace(Vx, Vy) + ############################################### if __name__ == '__main__': diff --git a/psydac/fem/vector.py b/psydac/fem/vector.py index 68ae3bb51..84595a779 100644 --- a/psydac/fem/vector.py +++ b/psydac/fem/vector.py @@ -70,6 +70,11 @@ def __init__(self, *spaces): for nc in zip(*ncells): assert len(set(nc)) == 1 + # All spaces are defined on the same patch, hence they must share its decomposition + ddm = new_spaces[0].domain_decomposition + assert all(V.domain_decomposition is ddm for V in new_spaces), \ + 'All spaces must share the same DomainDecomposition object' + # Compute the SymPDE symbolic space from the symbolic spaces of the input spaces symbolic_spaces = [V.symbolic_space for V in spaces] symbolic_space = reduce(lambda x, y: x * y, symbolic_spaces) if all(symbolic_spaces) else None From ab451238c8fc3632ac42e226da31642de1dc339c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yaman=20G=C3=BC=C3=A7l=C3=BC?= Date: Sun, 11 Oct 2026 19:16:17 +0200 Subject: [PATCH 2/3] Mention PR #625 in CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d8fc460e8..2a02b7267 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ All notable changes to this project will be documented in this file. ### Changed +- #625 : Require all components of a `VectorFemSpace` to share the same `DomainDecomposition` object, see #615 - #576 : Use latest version of Igakit (commit dalcinl/igakit@92ee097 of 2026/07/24) which supports NumPy >= 2.4 - #595 : Use PETSc 3.25.5 whose Python bindings `petsc4py` are built correctly with `cython>=3` - #580 : Use PETSc 3.25.0 whose Python bindings `petsc4py` install correctly with `setuptools>=81.0` From 377f73bcc7981f8bfe3b5eaf898eacc67059d699 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yaman=20G=C3=BC=C3=A7l=C3=BC?= Date: Tue, 20 Oct 2026 15:57:03 +0200 Subject: [PATCH 3/3] Add MPI test with different local subdomains, and take cells and periods from the decomposition in the test helper --- psydac/fem/tests/test_vector_spaces.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/psydac/fem/tests/test_vector_spaces.py b/psydac/fem/tests/test_vector_spaces.py index 1ce56169c..26fe47f75 100644 --- a/psydac/fem/tests/test_vector_spaces.py +++ b/psydac/fem/tests/test_vector_spaces.py @@ -5,6 +5,7 @@ #---------------------------------------------------------------------------# import pytest from numpy import linspace +from mpi4py import MPI from psydac.fem.basic import FemField from psydac.fem.splines import SplineSpace @@ -145,8 +146,9 @@ def test_vector_space_3d(): #============================================================================== def make_tensor_space_2d(domain_decomposition: DomainDecomposition) -> TensorFemSpace: - """Create a 2D tensor-product spline space of degree 2 on 3 x 5 cells.""" - spaces = [SplineSpace(2, grid=linspace(0., 1., n + 1)) for n in [3, 5]] + """Create a 2D tensor-product spline space of degree 2 on the cells of the decomposition.""" + spaces = [SplineSpace(2, grid=linspace(0., 1., n + 1), periodic=periodic) + for n, periodic in zip(domain_decomposition.ncells, domain_decomposition.periods)] return TensorFemSpace(domain_decomposition, *spaces) def test_vector_space_shared_domain_decomposition(): @@ -165,6 +167,19 @@ def test_vector_space_different_domain_decompositions(): with pytest.raises(AssertionError, match='same DomainDecomposition'): VectorFemSpace(Vx, Vy) +@pytest.mark.mpi(min_size=2) +def test_vector_space_different_domain_decompositions_parallel(): + + # Decompositions along different axes give different local subdomains (see #615) + comm = MPI.COMM_WORLD + ncells = [2 * comm.size, 3 * comm.size] + Vx = make_tensor_space_2d(DomainDecomposition(ncells, [True, False], comm=comm, mpi_dims_mask=[True, False])) + Vy = make_tensor_space_2d(DomainDecomposition(ncells, [True, False], comm=comm, mpi_dims_mask=[False, True])) + assert Vx.local_domain != Vy.local_domain + + with pytest.raises(AssertionError, match='same DomainDecomposition'): + VectorFemSpace(Vx, Vy) + ############################################### if __name__ == '__main__':