From aed5382d8887cc1f001e07cbaf5acfad7f38a33f Mon Sep 17 00:00:00 2001 From: 72004 Date: Fri, 16 Oct 2026 18:58:48 +0500 Subject: [PATCH 1/4] Test that Domain.export keeps the physical dimension of the mappings --- sympde/topology/tests/test_topology.py | 30 ++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/sympde/topology/tests/test_topology.py b/sympde/topology/tests/test_topology.py index 704affc0..0ec6541c 100644 --- a/sympde/topology/tests/test_topology.py +++ b/sympde/topology/tests/test_topology.py @@ -1,5 +1,10 @@ import os +import h5py +import numpy as np +import pytest +import yaml + from sympde.topology import InteriorDomain, Union from sympde.topology import Boundary from sympde.topology import Domain, ElementDomain @@ -58,6 +63,31 @@ def test_topology_1(): assert D.todict() == Omega.todict() +#============================================================================== +def test_export_surface_mapping(tmp_path): + domain = Mapping('F', ldim=2, pdim=3)(Square('Omega')) + + filename = str(tmp_path / 'surface.h5') + domain.export(filename) + D = Domain.from_file(filename) + + assert D.mapping.ldim == 2 + assert D.mapping.pdim == 3 + assert D.todict() == domain.todict() + +#============================================================================== +def test_from_file_with_old_dim_key(tmp_path): + yml = Mapping('F', dim=2)(Square('Omega')).todict() + yml['dim'] = yml.pop('ldim') + del yml['pdim'] + + filename = str(tmp_path / 'old.h5') + with h5py.File(filename, mode='w') as h5: + h5['topology.yml'] = np.array(yaml.dump(data=yml, sort_keys=None), dtype='S') + + with pytest.raises(ValueError, match="older version of SymPDE"): + Domain.from_file(filename) + #============================================================================== def test_domain_1(): Omega_1 = InteriorDomain('Omega_1', dim=2) From 1cf629836b4f1af0d3b0fa57e9033c978c66f638 Mon Sep 17 00:00:00 2001 From: 72004 Date: Fri, 16 Oct 2026 19:03:09 +0500 Subject: [PATCH 2/4] Store ldim and pdim in the exported domain metadata --- CHANGELOG.md | 1 + sympde/topology/domain.py | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 89430b40..4dee2435 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ All notable changes to this project will be documented in this file. - #140: Fix the rendering of the `Domain.join()` API documentation. - #166: Restore warning-free documentation builds, including bibliography and mathematical notation support. +- #200: Keep the physical dimension of the mappings in `Domain.export` and `Domain.from_file`. The `topology.yml` metadata now stores `ldim` and `pdim` instead of `dim`, and `Domain.from_file` raises an error for files with the old `dim` key. ### Removed diff --git a/sympde/topology/domain.py b/sympde/topology/domain.py index 4fe4ebce..34886348 100644 --- a/sympde/topology/domain.py +++ b/sympde/topology/domain.py @@ -27,7 +27,6 @@ # TODO fix circular dependency between domain and mapping if TYPE_CHECKING: from sympde.topology.mapping import Mapping -# TODO add pdim iterable_types = (tuple, list, Tuple, Union) @@ -318,7 +317,9 @@ def get_interior(self, name): def todict(self): name = str(self.name) - dim = str(self.dim) + ldim = str(self.dim) + mappings = [m for m in self.mappings.values() if m is not None] + pdim = str(mappings[0].pdim) if mappings else ldim interior = self.interior.todict() boundary = self.boundary.todict() connectivity = self.connectivity.todict() @@ -328,7 +329,8 @@ def todict(self): dtype = 'None' d = {'name': name, - 'dim': dim, + 'ldim': ldim, + 'pdim': pdim, 'dtype': dtype, 'interior': interior, 'boundary': boundary, @@ -380,8 +382,13 @@ def from_file(cls, filename): h5 = h5py.File( filename, mode='r' ) yml = yaml.load( h5['topology.yml'][()], Loader=yaml.SafeLoader ) + if 'dim' in yml: + raise ValueError(f"'{filename}' was written by an older version of SymPDE:" + " replace its 'dim' key with the keys 'ldim' and 'pdim'") + domain_name = yml['name'] - dim = int(yml['dim']) + ldim = int(yml['ldim']) + pdim = int(yml['pdim']) dtype = yml['dtype'] d_interior = yml['interior'] d_boundary = yml['boundary'] @@ -398,7 +405,7 @@ def from_file(cls, filename): constructors = [globals()[dt['type']] for dt in dtype] interiors = [cs(i['name'], **dt['parameters']) for cs,i,dt in zip(constructors, d_interior, dtype)] - mappings = [Mapping(I['mapping'], dim=dim) if I.get('mapping', "None") != "None" else None for I in d_interior] + mappings = [Mapping(I['mapping'], ldim=ldim, pdim=pdim) if I.get('mapping', "None") != "None" else None for I in d_interior] domains = [mapping(i) if mapping else i for i,mapping in zip(interiors, mappings)] patch_index = {I.name:ind for ind,I in enumerate(interiors)} From 563f1ea855bad5793f80fd0ef478e441d553328a Mon Sep 17 00:00:00 2001 From: 72004 Date: Thu, 29 Oct 2026 15:31:46 +0500 Subject: [PATCH 3/4] Raise on mappings with different pdim in Domain.todict; address review - Domain.todict() raises ValueError when the mappings disagree on pdim - Add test_export_mappings_with_different_pdim - Shorten the Fixed entry and add a Changed entry for the ldim/pdim format change - Add myself to AUTHORS --- AUTHORS | 1 + CHANGELOG.md | 3 ++- sympde/topology/domain.py | 6 ++++-- sympde/topology/tests/test_topology.py | 9 +++++++++ 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/AUTHORS b/AUTHORS index 9fbe15ef..7d17ad04 100644 --- a/AUTHORS +++ b/AUTHORS @@ -15,3 +15,4 @@ Contributors * Valentin Carlier * Paul Rigor * Frederik Schnack +* Syed Ahnaf Raza diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d55a59d..8446d44d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ All notable changes to this project will be documented in this file. - #106: Order the parameters of `Domain` like its `args` (`name`, `interiors`, `boundaries`, `mapping`, `logical_domain`, `connectivity`) and allow passing them positionally. `dim` is now keyword-only. - #106: Allow passing `ornt`, `mapping` and `logical_domain` of an `Interface` positionally, in this order. - #106: Store only `axis` and `weight` in the `args` of the 1D forms (`Mass`, `Stiffness`, `Advection`, `AdvectionT`, `Bilaplacian`). Their name is now a class attribute. +- #200: Store `ldim` and `pdim` instead of `dim` in the topology of domain files. This is a breaking change: `Domain.from_file()` rejects files with `dim`. - [DEVELOPER] Modernize the package metadata and consolidate the pytest and coverage configuration in `pyproject.toml`. - [DEVELOPER] Modernize the Sphinx configuration, API-documentation generation, and API docstring markup. - [DEVELOPER] Remove the leading underscore from the module-level names used by other SymPDE modules, and rename `_coeffs_registery` to `coefficient_types`. @@ -36,7 +37,7 @@ All notable changes to this project will be documented in this file. ### Fixed -- #200: Keep the physical dimension of the mappings in `Domain.export` and `Domain.from_file`. The `topology.yml` metadata now stores `ldim` and `pdim` instead of `dim`, and `Domain.from_file` raises an error for files with the old `dim` key. +- #200: Keep the physical dimension of the mappings in `Domain.export()` and `Domain.from_file()`. - #140: Fix the rendering of the `Domain.join()` API documentation. - #166: Restore warning-free documentation builds, including bibliography and mathematical notation support. - #106: Preserve symbol assumptions and free-symbol information with modern SymPy. diff --git a/sympde/topology/domain.py b/sympde/topology/domain.py index 77271b8a..6ff0affe 100644 --- a/sympde/topology/domain.py +++ b/sympde/topology/domain.py @@ -336,8 +336,10 @@ def get_interior(self, name): def todict(self): name = str(self.name) ldim = str(self.dim) - mappings = [m for m in self.mappings.values() if m is not None] - pdim = str(mappings[0].pdim) if mappings else ldim + pdims = {m.pdim for m in self.mappings.values() if m is not None} + if len(pdims) > 1: + raise ValueError(f'all mappings must have the same physical dimension, got {sorted(pdims)}') + pdim = str(pdims.pop()) if pdims else ldim interior = self.interior.todict() boundary = self.boundary.todict() connectivity = self.connectivity.todict() diff --git a/sympde/topology/tests/test_topology.py b/sympde/topology/tests/test_topology.py index 4c5546a5..596bda35 100644 --- a/sympde/topology/tests/test_topology.py +++ b/sympde/topology/tests/test_topology.py @@ -142,6 +142,15 @@ def test_from_file_with_old_dim_key(tmp_path): with pytest.raises(ValueError, match="older version of SymPDE"): Domain.from_file(filename) +#============================================================================== +def test_export_mappings_with_different_pdim(tmp_path): + A = Mapping('FA', ldim=2, pdim=3)(Square('A')) + B = Mapping('FB', ldim=2, pdim=2)(Square('B')) + + with pytest.raises(ValueError): + domain = Domain.join([A, B], [((0, 0, 1), (1, 0, -1), 1)], name='Omega') + domain.export(str(tmp_path / 'omega.h5')) + #============================================================================== def test_domain_1(): Omega_1 = InteriorDomain('Omega_1', dim=2) From e69ecc4c956f76fc24014ad550864397b45e31f3 Mon Sep 17 00:00:00 2001 From: 72004 Date: Thu, 29 Oct 2026 16:13:08 +0500 Subject: [PATCH 4/4] Move the #200 Changed entry to the top of the list --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8446d44d..dea55763 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ All notable changes to this project will be documented in this file. ### Changed +- #200: Store `ldim` and `pdim` instead of `dim` in the topology of domain files. This is a breaking change: `Domain.from_file()` rejects files with `dim`. - #190: Convert the README to Markdown and expand the installation, testing, and documentation-build instructions. - #194: Use explicit internal imports and load optional dependencies only when needed. - #194: Remove the leading underscore from `partial_derivatives`, `logical_partial_derivatives` (`sympde.topology.derivatives`) and `split_test_function` (`sympde.expr.evaluation`), and add them to `sympde.api`. @@ -27,7 +28,6 @@ All notable changes to this project will be documented in this file. - #106: Order the parameters of `Domain` like its `args` (`name`, `interiors`, `boundaries`, `mapping`, `logical_domain`, `connectivity`) and allow passing them positionally. `dim` is now keyword-only. - #106: Allow passing `ornt`, `mapping` and `logical_domain` of an `Interface` positionally, in this order. - #106: Store only `axis` and `weight` in the `args` of the 1D forms (`Mass`, `Stiffness`, `Advection`, `AdvectionT`, `Bilaplacian`). Their name is now a class attribute. -- #200: Store `ldim` and `pdim` instead of `dim` in the topology of domain files. This is a breaking change: `Domain.from_file()` rejects files with `dim`. - [DEVELOPER] Modernize the package metadata and consolidate the pytest and coverage configuration in `pyproject.toml`. - [DEVELOPER] Modernize the Sphinx configuration, API-documentation generation, and API docstring markup. - [DEVELOPER] Remove the leading underscore from the module-level names used by other SymPDE modules, and rename `_coeffs_registery` to `coefficient_types`.