Skip to content

Commit 0e062a3

Browse files
feat: allow unknown caps in model (#1261)
Co-authored-by: pyansys-ci-bot <[email protected]>
1 parent 0a63362 commit 0e062a3

File tree

5 files changed

+77
-9
lines changed

5 files changed

+77
-9
lines changed

doc/source/changelog/1261.added.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Allow unknown caps in model

src/ansys/health/heart/models.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1444,13 +1444,21 @@ def _update_cap_types(self):
14441444
break
14451445

14461446
cap_name = split.replace("-plane", "").replace("-inlet", "")
1447-
cap.type = CapType(cap_name)
14481447

1449-
if "atrium" in part.name and (
1450-
cap.type in [CapType.TRICUSPID_VALVE, CapType.MITRAL_VALVE]
1451-
):
1452-
cap_name = cap_name + "-atrium"
1453-
cap.type = CapType(cap.type.value + "-atrium")
1448+
try:
1449+
cap.type = CapType(cap_name)
1450+
1451+
if "atrium" in part.name and (
1452+
cap.type in [CapType.TRICUSPID_VALVE, CapType.MITRAL_VALVE]
1453+
):
1454+
cap_name = cap_name + "-atrium"
1455+
cap.type = CapType(cap.type.value + "-atrium")
1456+
except ValueError:
1457+
LOGGER.warning(
1458+
f"Could not map cap name {cap_name} to CapType enum - default "
1459+
"to unknown cap type."
1460+
)
1461+
cap.type = CapType.UNKNOWN
14541462

14551463
cap.name = cap_name
14561464

src/ansys/health/heart/parts.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,15 @@ def _set_from_dict(
270270

271271
for cap_name, cap_id in part_data.get("caps", {}).items():
272272
#! note that we assume cap name equals cap type here.
273-
cap = Cap(cap_name, cap_type=CapType(cap_name))
273+
try:
274+
cap_type = CapType(cap_name)
275+
except ValueError as e:
276+
LOGGER.warning(
277+
f"Invalid cap type: {cap_name}. {e}. Defaulting to UNKNOWN cap type."
278+
)
279+
cap_type = CapType.UNKNOWN
280+
281+
cap = Cap(cap_name, cap_type=cap_type)
274282
cap._mesh = mesh.get_surface(cap_id)
275283
part.caps.append(cap)
276284

src/ansys/health/heart/writer/laplace_writer.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,10 @@ def _update_ra_tricuspid_nodeset(self, atrium: pv.UnstructuredGrid) -> None:
237237

238238
def _update_atrial_caps_nodeset(self, atrium: pv.UnstructuredGrid) -> None:
239239
"""Define nodesets for the caps."""
240-
for cap in self.model.parts[0].caps:
240+
# Only loop over caps that are mapped to nodeset IDs
241+
caps = [cap for cap in self.model.parts[0].caps if cap.type in self._CAP_NODESET_MAP.keys()]
242+
243+
for cap in caps:
241244
# get node IDs for atrium mesh
242245
cap._mesh = self.model.mesh.get_surface(cap._mesh.id)
243246
ids_sub = np.where(np.isin(atrium["point_ids"], cap.global_node_ids_edge))[0]

tests/heart/test_parts.py

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
import pyvista as pv
2626

2727
from ansys.health.heart import __version__
28-
from ansys.health.heart.objects import Cap, Cavity, Mesh, SurfaceMesh
28+
from ansys.health.heart.objects import Cap, CapType, Cavity, Mesh, SurfaceMesh
2929
from ansys.health.heart.parts import (
3030
Artery,
3131
Atrium,
@@ -287,3 +287,51 @@ def test_get_element_ids_returns_empty_if_volume_id_missing(caplog):
287287
assert any(
288288
"Mesh does not contain '_volume-id' cell data." in m for m in caplog.text.splitlines()
289289
)
290+
291+
292+
def test_set_from_dict_caps_with_unknown_type():
293+
"""Test _set_from_dict can handle caps with unknown/invalid cap types."""
294+
# Setup: create a test dictionary with an invalid cap type
295+
part_name = "Left ventricle"
296+
test_dict = {
297+
part_name: {
298+
"part-id": 42,
299+
"part-type": "ventricle",
300+
"surfaces": {
301+
"Left ventricle endocardium": 1,
302+
"Left ventricle epicardium": 2,
303+
},
304+
"_version": "0.15.dev0",
305+
"caps": {
306+
"unknown_cap_type": 100, # This should trigger the unknown cap handling
307+
"invalid-cap": 101, # Another invalid cap type
308+
},
309+
}
310+
}
311+
312+
# Create a mock mesh with the required surfaces and cap surfaces
313+
mesh = _get_mock_mesh1()
314+
315+
# Add cap surfaces to the mesh for testing
316+
from pyvista.examples import load_tetbeam
317+
318+
beam = load_tetbeam()
319+
surface = beam.extract_surface()
320+
mesh.add_surface(surface, name="unknown_cap_type", id=100)
321+
mesh.add_surface(surface, name="invalid-cap", id=101)
322+
323+
# Act: reconstruct part from dictionary
324+
part = Part._set_from_dict(test_dict, mesh=mesh)
325+
326+
# Assert: part should be created successfully
327+
assert isinstance(part, Ventricle)
328+
assert part.name == part_name
329+
assert part.pid == 42
330+
331+
# Assert: caps should be created with UNKNOWN type
332+
assert len(part.caps) == 2
333+
334+
for cap in part.caps:
335+
assert cap.type == CapType.UNKNOWN
336+
assert cap._mesh is not None
337+
assert cap.name in ["unknown_cap_type", "invalid-cap"]

0 commit comments

Comments
 (0)