diff --git a/CHANGELOG.md b/CHANGELOG.md index 779ab50ae..6bd8eb12f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -61,6 +61,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 - #527 : Pass a domain decomposition `ddm` and physical dimension `pdim` to `Geometry.__init__`; remove arguments `ncells`, `periodic`, `filename`, `comm` and `mpi_dims_mask` - #527 : Use the domain decomposition of the mapping's space in `Geometry.from_discrete_mapping`; remove arguments `comm` and `mpi_dims_mask` - #527 : Key `Geometry.mappings` by the names of the domain interiors diff --git a/psydac/fem/tests/test_vector_spaces.py b/psydac/fem/tests/test_vector_spaces.py index db813da75..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 @@ -143,6 +144,42 @@ 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 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(): + + 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) + +@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__': 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