From a8050390071ad96663f83541649d9ba760b4c5a0 Mon Sep 17 00:00:00 2001 From: Daniel Wolff Date: Fri, 18 Jul 2025 11:24:04 +0200 Subject: [PATCH 1/6] Modify solid-to-solid contact BC and add new test --- README.md | 4 +- src/cubitpy/cubitpy_types.py | 9 ++- ...t_contact_condition_curve_to_curve.4C.yaml | 28 ++++++++++ tests/test_cubitpy.py | 55 ++++++++++++++++++- 4 files changed, 91 insertions(+), 5 deletions(-) create mode 100644 tests/input-files-ref/test_contact_condition_curve_to_curve.4C.yaml diff --git a/README.md b/README.md index 7c064e5..62a85b8 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ pip install . If you intend to actively develop `cubitpy`, install it in *editable mode* ```bash -pip install -e . +pip install -e ".[dev]" ``` To run CubitPy it is required to set an environment variable with the path to the Cubit directory. This should be the "root" directory for the installation. @@ -70,7 +70,7 @@ export CUBIT_ROOT=path_to_cubit_root_directory To check if everything worked as expected, run the tests from within the `tests` directory ```bash cd path_to_cubitpy/tests -pytest -q testing.py +pytest -q test_cubitpy.py ``` If you intend to actively develop CubitPy, please make sure to install the `pre-commit` hook within the python environment to follow our style guides: diff --git a/src/cubitpy/cubitpy_types.py b/src/cubitpy/cubitpy_types.py index 7a38c12..ab09f8e 100644 --- a/src/cubitpy/cubitpy_types.py +++ b/src/cubitpy/cubitpy_types.py @@ -287,6 +287,8 @@ class BoundaryConditionType(Enum): beam_to_solid_surface_meshtying = auto() beam_to_solid_surface_contact = auto() solid_to_solid_surface_contact = auto() + solid_to_solid_curve_contact = auto() + solid_to_solid_contact = auto() # fluid flow_rate = auto() @@ -327,11 +329,16 @@ def get_dat_bc_section_header(self, geometry_type): or geometry_type == FiniteElementObject.node ): return "DESIGN POINT COUPLING CONDITIONS" - elif self == self.solid_to_solid_surface_contact and ( + elif self == self.solid_to_solid_contact and ( geometry_type == GeometryType.surface or geometry_type == FiniteElementObject.node ): return "DESIGN SURF MORTAR CONTACT CONDITIONS 3D" + elif self == self.solid_to_solid_contact and ( + geometry_type == GeometryType.curve + or geometry_type == FiniteElementObject.node + ): + return "DESIGN LINE MORTAR CONTACT CONDITIONS 2D" elif self == self.fsi_coupling and ( geometry_type == GeometryType.surface or geometry_type == FiniteElementObject.node diff --git a/tests/input-files-ref/test_contact_condition_curve_to_curve.4C.yaml b/tests/input-files-ref/test_contact_condition_curve_to_curve.4C.yaml new file mode 100644 index 0000000..555a8c5 --- /dev/null +++ b/tests/input-files-ref/test_contact_condition_curve_to_curve.4C.yaml @@ -0,0 +1,28 @@ +DESIGN LINE MORTAR CONTACT CONDITIONS 2D: + - InterfaceID: 0 + Side: "Master" + E: 1 + - InterfaceID: 0 + Side: "Slave" + E: 2 +DLINE-NODE TOPOLOGY: + - "NODE 3 DLINE 1" + - "NODE 4 DLINE 1" + - "NODE 5 DLINE 2" + - "NODE 6 DLINE 2" + - "NODE 9 DLINE 2" +NODE COORDS: + - "NODE 1 COORD 0.5 0.5 0.0" + - "NODE 2 COORD -0.5 0.5 0.0" + - "NODE 3 COORD -0.5 -0.5 0.0" + - "NODE 4 COORD 0.5 -0.5 0.0" + - "NODE 5 COORD 1.0 -0.5 0.0" + - "NODE 6 COORD 0.0 -0.5 0.0" + - "NODE 7 COORD 0.0 -1.5 0.0" + - "NODE 8 COORD 1.0 -1.5 0.0" + - "NODE 9 COORD -1.0 -0.5 0.0" + - "NODE 10 COORD -1.0 -1.5 0.0" +STRUCTURE ELEMENTS: + - "1 WALL QUAD4 1 2 3 4 MAT 1 KINEM nonlinear EAS None THICK 1 STRESS_STRAIN plain_strain GP 2 2" + - "2 WALL QUAD4 5 6 7 8 MAT 1 KINEM nonlinear EAS None THICK 1 STRESS_STRAIN plain_strain GP 2 2" + - "3 WALL QUAD4 6 9 10 7 MAT 1 KINEM nonlinear EAS None THICK 1 STRESS_STRAIN plain_strain GP 2 2" diff --git a/tests/test_cubitpy.py b/tests/test_cubitpy.py index 4d0b205..6444d5d 100644 --- a/tests/test_cubitpy.py +++ b/tests/test_cubitpy.py @@ -842,6 +842,57 @@ def test_contact_condition_beam_to_surface(): compare_yaml(cubit) +def test_contact_condition_curve_to_curve(): + """Test the curve-to-curve contact condition BC.""" + cubit = CubitPy() + + # Create and mesh two rectangles + cubit.cmd("create surface rectangle width 1 height 1 zplane") + solid1 = cubit.surface(cubit.get_last_id(cupy.geometry.surface)) + cubit.cmd(f"surface {solid1.id()} size 1") + cubit.cmd("create surface rectangle width 2 height 1 zplane") + solid2 = cubit.surface(cubit.get_last_id(cupy.geometry.surface)) + cubit.cmd(f"move surface {solid2.id()} x 0 y -1 z 0 include_merged") + cubit.cmd(f"surface {solid2.id()} size 1") + cubit.cmd("mesh surface all") + + # Add elements + bc_desc = { + "KINEM": "nonlinear", + "EAS": None, + "THICK": 1, + "STRESS_STRAIN": "plain_strain", + "GP": [2, 2], + } + cubit.add_element_type( + solid1.surfaces()[0], + el_type=cupy.element_type.quad4, + bc_description=bc_desc, + ) + cubit.add_element_type( + solid2.surfaces()[0], + el_type=cupy.element_type.quad4, + bc_description=bc_desc, + ) + + # Test contact conditions + cubit.add_node_set( + solid1.curves()[2], + name="block1_contact_side", + bc_type=cupy.bc_type.solid_to_solid_contact, + bc_description={"InterfaceID": 0, "Side": "Master"}, + ) + cubit.add_node_set( + solid2.curves()[0], + name="block2_contact_side", + bc_type=cupy.bc_type.solid_to_solid_contact, + bc_description={"InterfaceID": 0, "Side": "Slave"}, + ) + + # Compare the input file created for 4C. + compare_yaml(cubit) + + def test_contact_condition_surface_to_surface(): """Test the surface-to-surface contact condition BC.""" cubit = CubitPy() @@ -855,13 +906,13 @@ def test_contact_condition_surface_to_surface(): cubit.add_node_set( solid.surfaces()[0], name="block1_contact_side", - bc_type=cupy.bc_type.solid_to_solid_surface_contact, + bc_type=cupy.bc_type.solid_to_solid_contact, bc_description={"InterfaceID": 0, "Side": "Master"}, ) cubit.add_node_set( solid2.surfaces()[3], name="block2_contact_side", - bc_type=cupy.bc_type.solid_to_solid_surface_contact, + bc_type=cupy.bc_type.solid_to_solid_contact, bc_description={"InterfaceID": 0, "Side": "Slave"}, ) From d96d7b4ef000634223bdad39e3d319eb39d5041b Mon Sep 17 00:00:00 2001 From: Ivo Steinbrecher Date: Fri, 18 Jul 2025 12:38:42 +0200 Subject: [PATCH 2/6] Remove fem objects from section creation Also add some small improvements to the readme --- README.md | 4 ++-- src/cubitpy/cubitpy_types.py | 17 +++-------------- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 62a85b8..82e4bf9 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -[![build-test](https://github.com/imcs-compsim/cubitpy/actions/workflows/.github/workflows/build-test.yml/badge.svg)](https://github.com/imcs-compsim/cubitpy/actions/workflows/.github/workflows/build-test.yml) - # CubitPy Utility functions and 4C related functionality for the Cubit and Coreform python interface, Especially for the creation of input files for 4C. +[![Cubit testing](https://github.com/imcs-compsim/cubitpy/actions/workflows/testing.yml/badge.svg)](https://github.com/imcs-compsim/cubitpy/actions/workflows/testing.yml) + ## Usage A tutorial can be found in the `/tutorial` directory. diff --git a/src/cubitpy/cubitpy_types.py b/src/cubitpy/cubitpy_types.py index ab09f8e..04545ff 100644 --- a/src/cubitpy/cubitpy_types.py +++ b/src/cubitpy/cubitpy_types.py @@ -324,30 +324,19 @@ def get_dat_bc_section_header(self, geometry_type): and geometry_type == GeometryType.surface ): return "BEAM INTERACTION/BEAM TO SOLID SURFACE CONTACT SURFACE" - elif self == self.point_coupling and ( - geometry_type == GeometryType.vertex - or geometry_type == FiniteElementObject.node - ): + elif self == self.point_coupling and (geometry_type == GeometryType.vertex): return "DESIGN POINT COUPLING CONDITIONS" elif self == self.solid_to_solid_contact and ( geometry_type == GeometryType.surface - or geometry_type == FiniteElementObject.node ): return "DESIGN SURF MORTAR CONTACT CONDITIONS 3D" elif self == self.solid_to_solid_contact and ( geometry_type == GeometryType.curve - or geometry_type == FiniteElementObject.node ): return "DESIGN LINE MORTAR CONTACT CONDITIONS 2D" - elif self == self.fsi_coupling and ( - geometry_type == GeometryType.surface - or geometry_type == FiniteElementObject.node - ): + elif self == self.fsi_coupling and (geometry_type == GeometryType.surface): return "DESIGN FSI COUPLING SURF CONDITIONS" - elif self == self.ale_dirichlet and ( - geometry_type == GeometryType.surface - or geometry_type == FiniteElementObject.node - ): + elif self == self.ale_dirichlet and (geometry_type == GeometryType.surface): return "DESIGN SURF ALE DIRICH CONDITIONS" elif self == self.flow_rate and (geometry_type == GeometryType.surface): return "DESIGN FLOW RATE SURF CONDITIONS" From c38e6b62266ee4a8a3acf16b1825335b638be069 Mon Sep 17 00:00:00 2001 From: Daniel Wolff Date: Fri, 18 Jul 2025 13:06:23 +0200 Subject: [PATCH 3/6] Fix instructions how to run tests in README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 82e4bf9..fc45583 100644 --- a/README.md +++ b/README.md @@ -67,10 +67,10 @@ To run CubitPy it is required to set an environment variable with the path to th export CUBIT_ROOT=path_to_cubit_root_directory ``` -To check if everything worked as expected, run the tests from within the `tests` directory +To check if everything worked as expected, run the test suite (from the root directory) ```bash cd path_to_cubitpy/tests -pytest -q test_cubitpy.py +pytest ``` If you intend to actively develop CubitPy, please make sure to install the `pre-commit` hook within the python environment to follow our style guides: From ad9b01aab2d5b118a8faaadd2d978c59177e3da7 Mon Sep 17 00:00:00 2001 From: Daniel Wolff Date: Fri, 18 Jul 2025 13:14:21 +0200 Subject: [PATCH 4/6] Remove unused enum and re-enable solid-to-solid-surface-contact as legacy --- src/cubitpy/cubitpy_types.py | 8 ++++---- tests/test_cubitpy.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/cubitpy/cubitpy_types.py b/src/cubitpy/cubitpy_types.py index 04545ff..6e3a746 100644 --- a/src/cubitpy/cubitpy_types.py +++ b/src/cubitpy/cubitpy_types.py @@ -287,7 +287,6 @@ class BoundaryConditionType(Enum): beam_to_solid_surface_meshtying = auto() beam_to_solid_surface_contact = auto() solid_to_solid_surface_contact = auto() - solid_to_solid_curve_contact = auto() solid_to_solid_contact = auto() # fluid @@ -326,9 +325,10 @@ def get_dat_bc_section_header(self, geometry_type): return "BEAM INTERACTION/BEAM TO SOLID SURFACE CONTACT SURFACE" elif self == self.point_coupling and (geometry_type == GeometryType.vertex): return "DESIGN POINT COUPLING CONDITIONS" - elif self == self.solid_to_solid_contact and ( - geometry_type == GeometryType.surface - ): + elif ( + self == self.solid_to_solid_contact + or self == self.solid_to_solid_surface_contact + ) and (geometry_type == GeometryType.surface): return "DESIGN SURF MORTAR CONTACT CONDITIONS 3D" elif self == self.solid_to_solid_contact and ( geometry_type == GeometryType.curve diff --git a/tests/test_cubitpy.py b/tests/test_cubitpy.py index 6444d5d..ff3ab0d 100644 --- a/tests/test_cubitpy.py +++ b/tests/test_cubitpy.py @@ -906,7 +906,7 @@ def test_contact_condition_surface_to_surface(): cubit.add_node_set( solid.surfaces()[0], name="block1_contact_side", - bc_type=cupy.bc_type.solid_to_solid_contact, + bc_type=cupy.bc_type.solid_to_solid_surface_contact, bc_description={"InterfaceID": 0, "Side": "Master"}, ) cubit.add_node_set( From 7943f5d79c71810d3abd1cb066f3d00031906a9f Mon Sep 17 00:00:00 2001 From: Daniel Wolff Date: Fri, 18 Jul 2025 14:07:07 +0200 Subject: [PATCH 5/6] Add deprecation warning for solid_to_solid_surface_contact BC enum type --- src/cubitpy/cubitpy_types.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/cubitpy/cubitpy_types.py b/src/cubitpy/cubitpy_types.py index 6e3a746..58a9e0f 100644 --- a/src/cubitpy/cubitpy_types.py +++ b/src/cubitpy/cubitpy_types.py @@ -23,6 +23,7 @@ convert them to strings for cubit or 4C commands or the wrapper.""" from enum import Enum, auto +import warnings class GeometryType(Enum): @@ -286,6 +287,9 @@ class BoundaryConditionType(Enum): beam_to_solid_volume_meshtying = auto() beam_to_solid_surface_meshtying = auto() beam_to_solid_surface_contact = auto() + # The following value "solid_to_solid_surface_contact" is deprecated and + # only kept for legacy reasons. + # Please use "solid_to_solid_contact" instead. solid_to_solid_surface_contact = auto() solid_to_solid_contact = auto() @@ -325,10 +329,16 @@ def get_dat_bc_section_header(self, geometry_type): return "BEAM INTERACTION/BEAM TO SOLID SURFACE CONTACT SURFACE" elif self == self.point_coupling and (geometry_type == GeometryType.vertex): return "DESIGN POINT COUPLING CONDITIONS" - elif ( - self == self.solid_to_solid_contact - or self == self.solid_to_solid_surface_contact - ) and (geometry_type == GeometryType.surface): + elif self == self.solid_to_solid_surface_contact and (geometry_type == GeometryType.surface): + warnings.warn( + "The 'solid_to_solid_surface_contact' boundary condition enum is deprecated " + "and will be removed in a future version. " + "Use 'solid_to_solid_contact' instead.", + category=DeprecationWarning, + stacklevel=2 + ) + return "DESIGN SURF MORTAR CONTACT CONDITIONS 3D" + elif self == self.solid_to_solid_contact and (geometry_type == GeometryType.surface): return "DESIGN SURF MORTAR CONTACT CONDITIONS 3D" elif self == self.solid_to_solid_contact and ( geometry_type == GeometryType.curve From d090edd2c097d9779a6afb3e986ff5b23f03348d Mon Sep 17 00:00:00 2001 From: Ivo Steinbrecher Date: Fri, 18 Jul 2025 14:17:24 +0200 Subject: [PATCH 6/6] Fix code style --- src/cubitpy/cubitpy_types.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/cubitpy/cubitpy_types.py b/src/cubitpy/cubitpy_types.py index 58a9e0f..c31f91b 100644 --- a/src/cubitpy/cubitpy_types.py +++ b/src/cubitpy/cubitpy_types.py @@ -22,8 +22,8 @@ """This module contains ENums for types used in cubitpy as well as functions to convert them to strings for cubit or 4C commands or the wrapper.""" -from enum import Enum, auto import warnings +from enum import Enum, auto class GeometryType(Enum): @@ -287,7 +287,7 @@ class BoundaryConditionType(Enum): beam_to_solid_volume_meshtying = auto() beam_to_solid_surface_meshtying = auto() beam_to_solid_surface_contact = auto() - # The following value "solid_to_solid_surface_contact" is deprecated and + # The following value "solid_to_solid_surface_contact" is deprecated and # only kept for legacy reasons. # Please use "solid_to_solid_contact" instead. solid_to_solid_surface_contact = auto() @@ -329,16 +329,20 @@ def get_dat_bc_section_header(self, geometry_type): return "BEAM INTERACTION/BEAM TO SOLID SURFACE CONTACT SURFACE" elif self == self.point_coupling and (geometry_type == GeometryType.vertex): return "DESIGN POINT COUPLING CONDITIONS" - elif self == self.solid_to_solid_surface_contact and (geometry_type == GeometryType.surface): + elif self == self.solid_to_solid_surface_contact and ( + geometry_type == GeometryType.surface + ): warnings.warn( "The 'solid_to_solid_surface_contact' boundary condition enum is deprecated " "and will be removed in a future version. " "Use 'solid_to_solid_contact' instead.", category=DeprecationWarning, - stacklevel=2 + stacklevel=2, ) return "DESIGN SURF MORTAR CONTACT CONDITIONS 3D" - elif self == self.solid_to_solid_contact and (geometry_type == GeometryType.surface): + elif self == self.solid_to_solid_contact and ( + geometry_type == GeometryType.surface + ): return "DESIGN SURF MORTAR CONTACT CONDITIONS 3D" elif self == self.solid_to_solid_contact and ( geometry_type == GeometryType.curve