Skip to content

feat(transforms): add xeltofab mesh transform bridge#240

Open
xarthurx wants to merge 2 commits intoIDEALLab:mainfrom
xarthurx:feat/xeltofab-transforms
Open

feat(transforms): add xeltofab mesh transform bridge#240
xarthurx wants to merge 2 commits intoIDEALLab:mainfrom
xarthurx:feat/xeltofab-transforms

Conversation

@xarthurx
Copy link
Copy Markdown

@xarthurx xarthurx commented Mar 31, 2026

Description

Add engibench.transforms.xeltofab module that bridges EngiBench density-field problem outputs to fabrication-ready meshes via the xeltofab library.

This addresses the roadmap item: Transforms ability — Make Matrix of EngiBench/EngiOpt Input and Output types.

Demo Results

2D: Density Field → Contour Extraction

image

3D: Density Field → Mesh Extraction

image

I/O Type Matrix

Problem Dim Design Shape Design dtype Range Compatible volfrac attr
Beams2D 2D (50, 100) float64 [0,1] Yes — contours volfrac
ThermoElastic2D 2D (64, 64) float32 [0,1] Yes — contours volfrac
ThermoElastic3D 3D (NEL³) float32 [0,1] Yes — mesh volfrac
Photonics2D 2D (120, 120) float64 [0,1] Yes — contours none
HeatConduction2D 2D (res²) float64 [0,1] Yes — contours volume
HeatConduction3D 3D (res³) float64 [0,1] Yes — mesh volume
Airfoil curve dict (2,192) mixed No — coordinates
PowerElectronics N/A (20,) float32 mixed No — parametric

Single interchange format: The numpy density array — all 6 compatible problems already output this natively. Airfoil (boundary coordinates) and PowerElectronics (circuit parameters) require fundamentally different conversion paths and are excluded.

Approach

  • to_mesh(problem, design, **kwargs) — One-call conversion. Auto-selects per-problem pipeline presets (threshold, smoothing, extraction method, decimation).
  • Per-problem presets — 2D problems get contour extraction; 3D problems get full MC → smooth → repair → remesh → decimate pipeline.
  • Parametrization: Users override any parameter via **kwargs or explicit PipelineParams. Presets serve as sensible defaults.
  • Validation: Input checks (type, ndim, NaN/Inf, range clipping). Output checks: structural failures raise RuntimeError; volume drift warns.

Usage

from engibench.problems.heatconduction3d import HeatConduction3D
from engibench.transforms.xeltofab import to_mesh, save

problem = HeatConduction3D()
design, _ = problem.random_design()
state = to_mesh(problem, design)
save(state, "output.stl")

# Override defaults
state = to_mesh(problem, design, smooth_sigma=2.0, threshold=0.4)

Install: pip install engibench[transforms] (requires Python >= 3.13)

Type of change

  • New feature (non-breaking change which adds functionality)

Files

File Purpose
engibench/transforms/__init__.py Package init
engibench/transforms/xeltofab/__init__.py Public API: to_mesh, save, PROBLEM_PRESETS
engibench/transforms/xeltofab/_core.py Bridge logic
engibench/transforms/xeltofab/_presets.py Per-problem defaults
engibench/transforms/xeltofab/_validate.py Input/output validation
tests/transforms/test_xeltofab.py 18 tests
pyproject.toml Optional dep transforms + mypy override

Checklist:

  • I have run the pre-commit checks with pre-commit run --all-files
  • I have run ruff check . and ruff format
  • I have run mypy .
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

Note: xeltofab requires Python >= 3.13. The transforms optional dependency uses a version marker (python_version >= '3.13') and is intentionally excluded from the all group to avoid breaking installs on Python 3.10–3.12. Tests auto-skip via pytest.importorskip when xeltofab is not installed. A dedicated Python 3.13 CI job may be useful in the future.

Copilot AI review requested due to automatic review settings March 31, 2026 11:53
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new engibench.transforms.xeltofab transform module to convert EngiBench density-field designs (2D/3D) into fabrication-ready contours/meshes via the optional xeltofab dependency, with presets and validation plus a dedicated test suite.

Changes:

  • Introduces to_mesh()/save() API, per-problem pipeline presets, and input/output validation for density-field → contour/mesh conversion.
  • Adds transforms optional dependency (Python >= 3.13 marker) and mypy missing-import overrides for xeltofab.
  • Adds pytest suite for validation, presets, parameter overrides, and basic mesh/contour outputs (skipped when xeltofab isn’t installed).

Reviewed changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
engibench/transforms/__init__.py Adds transforms package root.
engibench/transforms/xeltofab/__init__.py Exposes public API (to_mesh, save, PROBLEM_PRESETS).
engibench/transforms/xeltofab/_core.py Implements bridge logic using xeltofab pipeline.
engibench/transforms/xeltofab/_presets.py Defines per-problem default pipeline parameter dicts.
engibench/transforms/xeltofab/_validate.py Adds density-field input sanitization and post-pipeline validation.
pyproject.toml Adds transforms extra (py>=3.13) and mypy import overrides for xeltofab.
tests/transforms/__init__.py Creates tests subpackage for transforms.
tests/transforms/test_xeltofab.py Adds tests for validation, presets, 2D/3D conversion, saving, and overrides.
Comments suppressed due to low confidence (1)

pyproject.toml:44

  • CI currently installs .[all] (see .github/workflows/test.yml), but the all extra here doesn’t include transforms, so xeltofab won’t be installed and the new tests/transforms/test_xeltofab.py suite will be skipped even on the Python 3.13 jobs. Consider adding transforms into all behind the same python_version >= '3.13' marker (or updating CI to install .[transforms] on 3.13) so this feature is exercised in CI.
[project.optional-dependencies]
airfoil = ["sqlitedict>=1.6"] # for pyopt_history.py
electronics = ["networkx >= 3.2.1"]
beams2d = ["cvxopt >= 1.3.2", "seaborn", "scipy"]
thermoelastic2d = ["cvxopt >= 1.3.2", "mmapy >= 0.3.0"]
thermoelastic3d = ["cvxopt >= 1.3.2", "mmapy >= 0.3.0", "napari", "pyamg"]
photonics2d = ["ceviche >= 0.1.3"]
transforms = ["xeltofab >= 0.3.0; python_version >= '3.13'"]
all = [
    # All dependencies above
    "engibench[airfoil,beams2d,thermoelastic2d,thermoelastic3d,photonics2d,electronics]"
]

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@xarthurx xarthurx force-pushed the feat/xeltofab-transforms branch from 772edea to dc07d42 Compare March 31, 2026 12:01
Add engibench.transforms.xeltofab module that converts density-field
problem outputs to fabrication-ready meshes via the xeltofab library.

Covers 6 of 8 builtin problems (all density-field types).
Includes per-problem pipeline presets, input/output validation,
and 18 tests. xeltofab is an optional dependency requiring Python 3.13+.
@xarthurx xarthurx force-pushed the feat/xeltofab-transforms branch from dc07d42 to a4ecfc8 Compare March 31, 2026 12:09
@xarthurx
Copy link
Copy Markdown
Author

xarthurx commented Apr 1, 2026

For questions in #142:

1. Make Matrix of EngiBench/EngiOpt Input and Output types

See above chart.

2. Prioritize which conversions are highest value / can we just convert to/from a single one?

Yes — single interchange format: the numpy density array. All 6 compatible problems already output ndarray density fields in [0, 1] via gymnasium.spaces.Box. No per-problem serialization needed. The two excluded problems (Airfoil, PowerElectronics) are fundamentally different design representations that would need entirely different conversion paths.

3. How do we parametrize any conversion parameters?

Per-problem presets in PROBLEM_PRESETS dict (_presets.py), with user overrides via **kwargs:

  • 2D problems: contour extraction only (threshold, smooth_sigma, morph_radius)
  • 3D problems: full pipeline (+ repair, remesh, decimate, decimate_ratio)
  • Special cases: Photonics2D gets lower smoothing and no morphology to preserve sharp optical features
  # Defaults from preset
  state = to_mesh(problem, design)
  # User override
  state = to_mesh(problem, design, smooth_sigma=2.0, threshold=0.4)

4. How do we tell that it was successful/validated?

Two-stage validation in _validate.py:

  • Input validation: type check, ndim (2D/3D), NaN/Inf rejection, [0,1] range clipping with warning
  • Output validation: confirms mesh (vertices+faces) or contours were produced (raises RuntimeError if not), checks volume fraction preservation within configurable tolerance (default 5% — warns if exceeded)

Copy link
Copy Markdown
Collaborator

@g-braeunlich g-braeunlich left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only very minor suggestions. Otherwise looks very good to me (including optional dependency handling).

@xarthurx
Copy link
Copy Markdown
Author

xarthurx commented Apr 2, 2026

@g-braeunlich

I removed from __future__ import annotations where it was redundant.

I kept it in _core.py and _validate.py, since those modules annotate names that are only imported under TYPE_CHECKING or only available when the optional xeltofab dependency imports successfully. Because EngiBench still supports Python >=3.10, removing postponed annotation evaluation there could cause import-time failures on 3.10-3.13.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants