Repository navigation
Update Multipatch API - #188
FrederikSchnack wants to merge 13 commits into
Conversation
Represent interface orientation explicitly and expose a signed tangential axis map that supports cross-axis 3D faces. Support repeated and self interfaces, stable multipatch views, induced subdomains, dimension-independent shared vertices, mapped interface metadata, collision-safe names, and robust topology serialization. Tighten public validation and cover the new contract with logical, mapped, subset, periodic, and round-trip tests.
Move domain plotting into a dedicated lazy-loaded module and provide shared 2D/3D rendering with optional interface, axis-map, and vertex annotations. Add textual topology inspection, reusable 2D/3D gallery domain builders, an executable gallery CLI, and integration tests without making Matplotlib an import-time dependency of sympde.
Use MathJax for rendered mathematics, configure the existing FEEC bibliography explicitly, and remove obsolete imgmath and LaTeX configuration. Also normalize the TerminalExpr parameter documentation so strict autodoc builds remain warning-free.
Add a user guide for constructing, inspecting, validating, plotting, subsetting, and serializing logical and mapped multipatch domains in 1D, 2D, and 3D. Document the downstream axis-map contract, intentional API and file-format migrations, Edge removal, current limitations, and validation responsibilities.
| if not all(p.dim == patches[0].dim for p in patches): | ||
| raise ValueError('all patches must have the same logical dimension') |
There was a problem hiding this comment.
Could you also check that all patches have the same physical dimension pdim? join currently accepts e.g. a planar square joined with a surface in 3D, which gives an inconsistent domain (see the updated issue #140, which this PR closes):
A = Mapping('FA', ldim=2, pdim=2)(Square('A'))
B = Mapping('FB', ldim=2, pdim=3)(Square('B'))
Domain.join([A, B], [((0, 0, 1), (1, 0, -1), 1)], 'Omega') # acceptedA patch without a mapping has the same physical and logical dimension:
| if not all(p.dim == patches[0].dim for p in patches): | |
| raise ValueError('all patches must have the same logical dimension') | |
| raise ValueError('all patches must have the same logical dimension') | |
| pdims = {p.mapping.pdim if p.mapping is not None else p.dim for p in patches} | |
| if len(pdims) > 1: | |
| raise ValueError('all patches must have the same physical dimension') |
Please also mention this requirement in the docstring, next to the one on the logical dimension.
A unit test in the PR's test suite, joining a pdim=2 and a pdim=3 patch and expecting ValueError, would also be a good idea.
Adapt the multipatch changes to the conventions introduced by #193 and #194: - Import objects from their defining modules in the tests and in multipatch_gallery.py, since the package initializers are now empty. - Empty sympde/utilities/__init__.py again, and export plot_domain in sympde.api from sympde.utilities.plotting. - Restore the version of sympde/utilities/utils.py from this branch, which only contains lambdify_sympde: the merge had brought back the old plotting functions. - Allow passing mapping and logical_domain of an Interface positionally, so that it can be reconstructed from its args. - Use orientation instead of ornt in test_structural_arguments_are_sympy_objects.
Move the Matplotlib imports from the top of sympde/utilities/plotting.py into _plot_domain_2d and _plot_domain_3d, so that importing the module (or sympde.api) does not load Matplotlib (see #180).
Import from sympde.api in the examples of Interface and Domain.join, and refer to Domain by its defining module in the plotting docstrings, since the package initializers are empty after #194.
Import from sympde.api in the examples of doc/multipatch.rst, and add collect_topology_vertices and print_topology to sympde.api, since the documentation uses them. Point the migration table to sympde.api.plot_domain.
Describe the changes of this PR, and remove duplicated and outdated entries from the Unreleased section.
Resolve the merge conflict in the docstring of Domain.join: the doctests of this branch replace the code block that #191 had added on master, since they render correctly and show the same 2D connectivity.
|
Thanks for this PR! I have merged Could you also have a look at #140? |
|
Will this PR also close #114? |
Issue #200 is explicitly fixed by the small PR #201, which can be merged very soon. I will ask for a small check to be added to |
Generalize symbolic multipatch topology
Summary
This PR removes the assumption that connected faces have the same normal axis and
properly defines orientations for 1D, 2D, and 3D interfaces in SymPDE's multipatch topology.
It also adds stable topology inspection APIs, preserves interface metadata
through mapping and serialization, supports repeated and self-interfaces,
computes shared vertices in 2D and 3D, and introduces reusable topology
plotting and multipatch gallery modules, that were exclusively in PSYDAC before.
The changes are confined to SymPDE, this introduces necessary changes in PSYDAC that are already mostly prepared.
Fixes #73, fixes #140, fixes #143, fixes #144.
Interface topology
Domain.join()accepts each interface as:Each side is
(patch, normal_axis, extremity), wherepatchis a patch objector its position in the
patchessequence andextremityis-1or+1.interfaces=is an alias forconnectivity=; passing both is an error.For example, two cube faces with different normal axes can be joined as:
Orientation is read from the ordered minus side to the ordered plus side:
None+1or-1(flag, sign1, sign2)All 3D entries are
+1or-1.flag=+1preserves the order of the twotangential axes;
flag=-1exchanges them.Interface.axis_mapexposes the decoded, dimension-independentcorrespondence as
(minus_axis, plus_axis, direction)entries. For theexample above:
The face-normal correspondence remains available from
interface.minus.axisandinterface.plus.axis; it is not repeated inaxis_map. This is the orientation format currently and later used in PSYDAC.Supported topology
The joined-domain implementation now supports:
interfaces as exterior boundaries; and
Generated names for repeated patch pairs use
A|B,A|B#2, and so on.Explicit names are validated globally before generated names are assigned.
An empty one-patch join still returns the original patch. A one-patch join
with declared connectivity follows the normal join path, allowing a genuine
self-interface. Passing an already joined multipatch domain as one atomic
patch is rejected explicitly.
Mapped domains preserve the logical interface, compact orientation,
InterfaceMapping, and patch mappings. Interface measures use the minus sideas their canonical parameterization instead of assuming one shared normal
axis.
Stable inspection API
The following properties provide cardinality-stable views:
domain.patches: tuple of top-dimensional patches;domain.interface_map: interface-name-to-Interfacemapping;domain.exterior_sides: tuple of exterior faces;domain.shared_vertices: tuple of shared-vertex classes;Boundary.patch: owning patch; andBoundary.normal_axis: face-normal logical axis.PatchVertexandSharedVertexare descriptive aliases for the existingpatch-corner and shared-corner symbolic types.
The established
domain.interior,domain.boundary, anddomain.cornersproperties remain available.
Serialization
Serialized interfaces now always contain the minus side, plus side, and
compact orientation. Interface dictionary keys are restored as interface
names instead of being regenerated.
Exterior boundaries use one list representation, including an empty list for
fully closed domains. The reader still accepts the historical single-boundary
dictionary and can derive missing boundary metadata from connectivity.
Stored exterior boundaries are checked against the derived topology.
Files whose interfaces omit orientation are rejected because orientation
cannot be inferred reliably from axes or extremities. Such files must be
regenerated or migrated with an explicitly confirmed orientation for every
interface.
Topology inspection and plotting
The new module
sympde.utilities.plottingprovides:collect_topology_vertices();format_topology();print_topology(); andplot_domain().collect_topology_vertices(),print_topology()andplot_domain()are alsoavailable in
sympde.api. The old plotting functions insympde.utilities.utilsare removed.plot_domain()handles ordinary and topology-annotated 2D and 3D plots andreturns its Matplotlib figure. Topology mode displays patch identities,
interface sides, signed tangential-axis correspondences, and vertex
incidence. Matplotlib is only imported when a domain is plotted, so importing
sympde.utilities.plottingorsympde.apidoes not load it.Multipatch gallery
This formerly was in psydac/feec/multipatch_domain_utilities.py.
sympde.topology.multipatch_galleryprovides explicit symbolic builders for various multipatch domains and includes a integrated plotting function.The gallery can be plotted from Python with
plot_multipatch_domain()or runas a module:
TransposedPolarMappingis now part of SymPDE's analytical mappings because it isa reusable coordinate transformation rather than a discretization detail.
Breaking changes
Boundary.join(other, ornt=...)Boundary.join(other, orientation)Interface(..., ornt=...)Interface(..., orientation)interface.orntinterface.orientationinterface.axisinterface.minus.axisandinterface.plus.axisEdgeBoundary(minus, plus, orientation[, name])tuplesplot_2d(),plot_3d(),plot_2d_single_patch(),plot_3d_single_patch()plot_domain()sympde.utilities.utils.plot_domainsympde.api.plot_domainNo default orientation is introduced. Callers must state the intended
topology explicitly.
Integration with the public API and the SymPy upgrade
This branch was merged with
masterafter #193 (SymPy upgrade) and #194(public API), and adapted to their conventions:
Interfacestoresmappingandlogical_domainin itsargsand acceptsthem positionally, so that it can be reconstructed with
interface.func(*interface.args).modules or from
sympde.api, and the package initializers stay empty.Domain.join()keeps the doctests of this branch, whichreplace the code block added in Change documentation to Github Pages #191.
entries in its "Unreleased" section are removed.
Current limitations
coincide or satisfy the declared parameterization.
Some plots