Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ keeping DG-SEM multipatch execution unsupported.
## Implementation Checklist

- [x] Add OpenSpec proposal/design/spec/tasks artifacts.
- [ ] Implement DG-SEM compatibility diagnostics for multipatch descriptors.
- [ ] Add strict/permissive regression tests.
- [ ] Update docs and progress tracking.
- [x] Implement DG-SEM compatibility diagnostics for multipatch descriptors.
- [x] Add strict/permissive regression tests.
- [x] Update docs and progress tracking.

## Risks / Open Questions

Expand Down
6 changes: 6 additions & 0 deletions docs/ufl-backend-support.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,12 @@ Common diagnostic codes:
- `unsupported_value_shape`
- `unsupported_multipatch_interface`

DG-SEM multipatch compatibility-only diagnostics (permissive mode):

- `dgsem_multipatch_compatibility_profile`
- `dgsem_unsupported_multipatch_orientation`
- `dgsem_unsupported_multipatch_penalty_control`

## DG-SEM Prerequisite

The `dgsem` backend requires an explicit `MeshmodeCutOverlay` payload from
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@

## 2. Capability Diagnostics

- [ ] 2.1 Keep strict unsupported behavior and add deterministic compatibility
- [x] 2.1 Keep strict unsupported behavior and add deterministic compatibility
profile diagnostics in permissive mode.
- [ ] 2.2 Emit explicit DG-SEM diagnostics for orientation variants and
- [x] 2.2 Emit explicit DG-SEM diagnostics for orientation variants and
per-interface penalty controls.

## 3. Validation + Docs

- [ ] 3.1 Add regression tests for strict/permissive diagnostics stability.
- [ ] 3.2 Update docs and execution-plan progress.
- [x] 3.1 Add regression tests for strict/permissive diagnostics stability.
- [x] 3.2 Update docs and execution-plan progress.
56 changes: 56 additions & 0 deletions src/cutkit/formdsl/capabilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,60 @@
}


def _dgsem_multipatch_compatibility_diagnostics(
form_ir: WeakFormIR,
) -> tuple[CapabilityDiagnostic, ...]:
multipatch = form_ir.multipatch
if multipatch is None:
return ()

diagnostics: list[CapabilityDiagnostic] = [
CapabilityDiagnostic(
code="dgsem_multipatch_compatibility_profile",
backend="dgsem",
detail=(
"dgsem multipatch compatibility is diagnostics-only "
f"(patches={len(multipatch.patch_ids)}, interfaces={len(multipatch.interfaces)})"
),
)
]

reversed_count = sum(
1 for interface in multipatch.interfaces if interface.orientation == "reversed"
)
if reversed_count > 0:
diagnostics.append(
CapabilityDiagnostic(
code="dgsem_unsupported_multipatch_orientation",
backend="dgsem",
detail=(
"dgsem multipatch compatibility does not support "
f"reversed orientation interfaces (count={reversed_count})"
),
alternatives=("aligned",),
)
)

controlled_penalties = sum(
1 for interface in multipatch.interfaces if interface.penalty is not None
)
if controlled_penalties > 0:
diagnostics.append(
CapabilityDiagnostic(
code="dgsem_unsupported_multipatch_penalty_control",
backend="dgsem",
detail=(
"dgsem multipatch compatibility does not support "
"per-interface penalty controls "
f"(count={controlled_penalties})"
),
alternatives=("multipatch_penalty",),
)
)

return tuple(diagnostics)


def _is_supported_value_shape(value_shape: tuple[int, ...], *, backend: str) -> bool:
if value_shape == ():
return True
Expand Down Expand Up @@ -155,6 +209,8 @@ def check_support(
alternatives=alternatives,
)
)
if backend == "dgsem":
diagnostics.extend(_dgsem_multipatch_compatibility_diagnostics(form_ir))

if strict and diagnostics:
raise CapabilityError(diagnostics[0])
Expand Down
65 changes: 64 additions & 1 deletion tests/formdsl/test_formdsl_assembly.py
Original file line number Diff line number Diff line change
Expand Up @@ -1529,7 +1529,70 @@ def test_dgsem_permissive_reports_multipatch_interface_diagnostic() -> None:
strict=False,
)

assert any(d.code == "unsupported_multipatch_interface" for d in result.diagnostics)
codes = {d.code for d in result.diagnostics}
assert "unsupported_multipatch_interface" in codes
assert "dgsem_multipatch_compatibility_profile" in codes


def test_dgsem_permissive_reports_reversed_orientation_compatibility_diagnostic() -> (
None
):
form = _base_form()
form["multipatch"] = {
"patch_ids": ["patch-a", "patch-b"],
"interfaces": [
{
"plus_patch": "patch-b",
"minus_patch": "patch-a",
"plus_boundary": "right",
"minus_boundary": "top",
"orientation": "reversed",
}
],
}

result = assemble_form(
form,
backend="dgsem",
overlay_payload=_overlay_contract(),
strict=False,
)

diagnostics_by_code = {d.code: d for d in result.diagnostics}
assert "dgsem_unsupported_multipatch_orientation" in diagnostics_by_code
assert diagnostics_by_code[
"dgsem_unsupported_multipatch_orientation"
].alternatives == ("aligned",)


def test_dgsem_permissive_reports_penalty_control_compatibility_diagnostic() -> None:
form = _base_form()
form["multipatch"] = {
"patch_ids": ["patch-a", "patch-b"],
"interfaces": [
{
"plus_patch": "patch-b",
"minus_patch": "patch-a",
"plus_boundary": "right",
"minus_boundary": "top",
"orientation": "aligned",
"penalty": 1.5,
}
],
}

result = assemble_form(
form,
backend="dgsem",
overlay_payload=_overlay_contract(),
strict=False,
)

diagnostics_by_code = {d.code: d for d in result.diagnostics}
assert "dgsem_unsupported_multipatch_penalty_control" in diagnostics_by_code
assert diagnostics_by_code[
"dgsem_unsupported_multipatch_penalty_control"
].alternatives == ("multipatch_penalty",)


def test_iga_rejects_vector_value_shape() -> None:
Expand Down
Loading