Skip to content

Commit

Permalink
Add modeling ply thickness properties (#331)
Browse files Browse the repository at this point in the history
Add advanced thickness properties to the `ModelingPly`:
- thickness by geometry
- thickness by field (look-up table column)
- taper edges

---------

Co-authored-by: René Roos <[email protected]>
  • Loading branch information
greschd and roosre authored Jan 15, 2024
1 parent eb4bc07 commit be14103
Show file tree
Hide file tree
Showing 5 changed files with 199 additions and 5 deletions.
3 changes: 3 additions & 0 deletions src/ansys/acp/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
SphericalSelectionRule,
Stackup,
SubLaminate,
TaperEdge,
TubeSelectionRule,
UnitSystemType,
VariableOffsetSelectionRule,
Expand Down Expand Up @@ -79,12 +80,14 @@
"OrientedSelectionSet",
"ModelingGroup",
"ModelingPly",
"TaperEdge",
"ProductionPly",
"AnalysisPly",
"UnitSystemType",
"Stackup",
"Sensor",
"FabricWithAngle",
"Sensor",
"ElementalDataType",
"NodalDataType",
]
3 changes: 2 additions & 1 deletion src/ansys/acp/core/_tree_objects/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from .material import Material
from .model import Model
from .modeling_group import ModelingGroup
from .modeling_ply import ModelingPly
from .modeling_ply import ModelingPly, TaperEdge
from .oriented_selection_set import OrientedSelectionSet
from .parallel_selection_rule import ParallelSelectionRule
from .production_ply import ProductionPly
Expand Down Expand Up @@ -61,6 +61,7 @@
"OrientedSelectionSet",
"ModelingGroup",
"ModelingPly",
"TaperEdge",
"ProductionPly",
"AnalysisPly",
"Sensor",
Expand Down
12 changes: 12 additions & 0 deletions src/ansys/acp/core/_tree_objects/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
lookup_table_3d_pb2,
lookup_table_column_type_pb2,
mesh_query_pb2,
modeling_ply_pb2,
ply_material_pb2,
sensor_pb2,
unit_system_pb2,
Expand Down Expand Up @@ -191,3 +192,14 @@
) = wrap_to_string_enum(
"GeometricalRuleType", geometrical_selection_rule_pb2.GeometricalRuleType, module=__name__
)
(
ThicknessType,
thickness_type_to_pb,
thickness_type_from_pb,
) = wrap_to_string_enum("ThicknessType", modeling_ply_pb2.ThicknessType, module=__name__)

(
ThicknessFieldType,
thickness_field_type_to_pb,
thickness_field_type_from_pb,
) = wrap_to_string_enum("ThicknessFieldType", modeling_ply_pb2.ThicknessFieldType, module=__name__)
161 changes: 158 additions & 3 deletions src/ansys/acp/core/_tree_objects/modeling_ply.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@

from collections.abc import Container, Iterable
import dataclasses
from typing import Any, Callable

import numpy as np
import numpy.typing as npt
from typing_extensions import Self

from ansys.acp.core._tree_objects.base import CreatableTreeObject
from ansys.api.acp.v0 import modeling_ply_pb2, modeling_ply_pb2_grpc, production_ply_pb2_grpc

from .._utils.array_conversions import to_1D_double_array, to_tuple_from_1D_array
from ._grpc_helpers.edge_property_list import define_edge_property_list
from ._grpc_helpers.edge_property_list import GenericEdgePropertyType, define_edge_property_list
from ._grpc_helpers.linked_object_list import define_linked_object_list
from ._grpc_helpers.mapping import get_read_only_collection_property
from ._grpc_helpers.property_helper import (
Expand All @@ -20,16 +23,29 @@
)
from ._mesh_data import ElementalData, NodalData, elemental_data_property, nodal_data_property
from .base import CreatableTreeObject, IdTreeObject
from .enums import DrapingType, draping_type_from_pb, draping_type_to_pb, status_type_from_pb
from .edge_set import EdgeSet
from .enums import (
DrapingType,
ThicknessFieldType,
ThicknessType,
draping_type_from_pb,
draping_type_to_pb,
status_type_from_pb,
thickness_field_type_from_pb,
thickness_field_type_to_pb,
thickness_type_from_pb,
thickness_type_to_pb,
)
from .fabric import Fabric
from .linked_selection_rule import LinkedSelectionRule
from .lookup_table_1d_column import LookUpTable1DColumn
from .lookup_table_3d_column import LookUpTable3DColumn
from .object_registry import register
from .oriented_selection_set import OrientedSelectionSet
from .production_ply import ProductionPly
from .virtual_geometry import VirtualGeometry

__all__ = ["ModelingPly", "ModelingPlyElementalData", "ModelingPlyNodalData"]
__all__ = ["ModelingPly", "ModelingPlyElementalData", "ModelingPlyNodalData", "TaperEdge"]


@dataclasses.dataclass
Expand Down Expand Up @@ -64,6 +80,102 @@ class ModelingPlyNodalData(NodalData):
ply_offset: npt.NDArray[np.float64]


class TaperEdge(GenericEdgePropertyType):
"""Defines a taper edge.
Parameters
----------
edge_set :
Defines the edge along which the ply tapering is applied.
angle :
Defines the angle between the cutting plane and the reference surface.
offset :
Moves the cutting plane along the out-of-plane direction.
A negative value cuts the elements at the edge where the in-plane
offset is ``-offset/tan(angle)``.
"""

def __init__(self, edge_set: EdgeSet, angle: float, offset: float):
self._edge_set = edge_set
self._angle = angle
self._offset = offset
self._callback_apply_changes: Callable[[], None] | None = None

@property
def edge_set(self) -> EdgeSet:
return self._edge_set

@edge_set.setter
def edge_set(self, edge_set: EdgeSet) -> None:
self._edge_set = edge_set
if self._callback_apply_changes is not None:
self._callback_apply_changes()

@property
def angle(self) -> float:
return self._angle

@angle.setter
def angle(self, angle: float) -> None:
self._angle = angle
if self._callback_apply_changes is not None:
self._callback_apply_changes()

@property
def offset(self) -> float:
return self._offset

@offset.setter
def offset(self, offset: float) -> None:
self._offset = offset
if self._callback_apply_changes is not None:
self._callback_apply_changes()

@classmethod
def _from_pb_object(
cls,
parent_object: CreatableTreeObject,
message: modeling_ply_pb2.TaperEdge,
apply_changes: Callable[[], None],
) -> Self:
edge_set = EdgeSet._from_resource_path(
resource_path=message.edge_set, channel=parent_object._channel
)

new_obj = cls(
edge_set=edge_set,
angle=message.angle,
offset=message.offset,
)
new_obj._set_callback_apply_changes(apply_changes)
return new_obj

def _to_pb_object(self) -> modeling_ply_pb2.TaperEdge:
return modeling_ply_pb2.TaperEdge(
edge_set=self.edge_set._resource_path,
angle=self.angle,
offset=self.offset,
)

def _check(self) -> bool:
return bool(self.edge_set._resource_path.value)

def __eq__(self, other: Any) -> bool:
if isinstance(other, TaperEdge):
return (
self.edge_set == other.edge_set
and self.angle == other.angle
and self.offset == other.offset
)
return False

def __repr__(self) -> str:
return (
f"{self.__class__.__name__}(edge_set={self.edge_set!r}, "
f"angle={self.angle!r}, offset={self.offset!r})"
)


@mark_grpc_properties
@register
class ModelingPly(CreatableTreeObject, IdTreeObject):
Expand Down Expand Up @@ -107,6 +219,24 @@ class ModelingPly(CreatableTreeObject, IdTreeObject):
Correction angle between the transverse and draped transverse directions,
in degree. Optional, uses the same values as ``draping_angle_1_field``
(no shear) by default.
thickness_type :
Choose between :attr:`ThicknessType.FROM_GEOMETRY` or
:attr:`ThicknessType.FROM_TABLE` to define a ply with variable thickness.
The default value is :attr:`ThicknessType.NOMINAL`, which means the ply
thickness is constant and determined by the thickness of the ply material.
thickness_geometry :
Defines the geometry used to determine the ply thickness. Only applies if
``thickness_type`` is :attr:`ThicknessType.FROM_GEOMETRY`.
thickness_field :
Defines the look-up table column used to determine the ply thickness.
Only applies if ``thickness_type`` is :attr:`ThicknessType.FROM_TABLE`.
thickness_field_type :
If ``thickness_type`` is :attr:`ThicknessType.FROM_TABLE`, this parameter
determines how the thickness values are interpreted. They can be either
absolute values (:attr:`ThicknessFieldType.ABSOLUTE_VALUES`) or relative
values (:attr:`ThicknessFieldType.RELATIVE_SCALING_FACTOR`).
taper_edges :
Defines the taper edges of the ply.
"""

__slots__: Iterable[str] = tuple()
Expand Down Expand Up @@ -136,6 +266,11 @@ def __init__(
draping_thickness_correction: bool = True,
draping_angle_1_field: LookUpTable1DColumn | LookUpTable3DColumn | None = None,
draping_angle_2_field: LookUpTable1DColumn | LookUpTable3DColumn | None = None,
thickness_type: ThicknessType = ThicknessType.NOMINAL,
thickness_geometry: VirtualGeometry | None = None,
thickness_field: LookUpTable1DColumn | LookUpTable3DColumn | None = None,
thickness_field_type: ThicknessFieldType = ThicknessFieldType.ABSOLUTE_VALUES,
taper_edges: Iterable[TaperEdge] = (),
):
super().__init__(name=name)

Expand All @@ -155,6 +290,11 @@ def __init__(
self.draping_thickness_correction = draping_thickness_correction
self.draping_angle_1_field = draping_angle_1_field
self.draping_angle_2_field = draping_angle_2_field
self.thickness_type = thickness_type
self.thickness_geometry = thickness_geometry
self.thickness_field = thickness_field
self.thickness_field_type = thickness_field_type
self.taper_edges = taper_edges

def _create_stub(self) -> modeling_ply_pb2_grpc.ObjectServiceStub:
return modeling_ply_pb2_grpc.ObjectServiceStub(self._channel)
Expand Down Expand Up @@ -198,5 +338,20 @@ def _create_stub(self) -> modeling_ply_pb2_grpc.ObjectServiceStub:
get_read_only_collection_property(ProductionPly, production_ply_pb2_grpc.ObjectServiceStub)
)

thickness_type = grpc_data_property(
"properties.thickness_type",
from_protobuf=thickness_type_from_pb,
to_protobuf=thickness_type_to_pb,
)
thickness_geometry = grpc_link_property("properties.thickness_geometry")
thickness_field = grpc_link_property("properties.thickness_field")
thickness_field_type = grpc_data_property(
"properties.thickness_field_type",
from_protobuf=thickness_field_type_from_pb,
to_protobuf=thickness_field_type_to_pb,
)

taper_edges = define_edge_property_list("properties.taper_edges", TaperEdge)

elemental_data = elemental_data_property(ModelingPlyElementalData)
nodal_data = nodal_data_property(ModelingPlyNodalData)
25 changes: 24 additions & 1 deletion tests/unittests/test_modeling_ply.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,14 @@
NodalDataType,
Stackup,
SubLaminate,
TaperEdge,
)
from ansys.acp.core._tree_objects.enums import (
BooleanOperationType,
DrapingType,
ThicknessFieldType,
ThicknessType,
)
from ansys.acp.core._tree_objects.enums import BooleanOperationType, DrapingType

from .common.linked_object_list_tester import LinkedObjectListTestCase, LinkedObjectListTester
from .common.tree_object_tester import NoLockedMixin, ObjectPropertiesToTest, TreeObjectTester
Expand Down Expand Up @@ -52,6 +58,11 @@ class TestModelingPly(NoLockedMixin, TreeObjectTester):
"draping_thickness_correction": True,
"draping_angle_1_field": None,
"draping_angle_2_field": None,
"thickness_type": ThicknessType.NOMINAL,
"thickness_geometry": None,
"thickness_field": None,
"thickness_field_type": ThicknessFieldType.ABSOLUTE_VALUES,
"taper_edges": [],
}
CREATE_METHOD_NAME = "create_modeling_ply"

Expand Down Expand Up @@ -128,6 +139,18 @@ def object_properties(request, parent_model):
("draping_thickness_correction", False),
("draping_angle_1_field", column_1),
("draping_angle_2_field", column_2),
("thickness_type", ThicknessType.FROM_GEOMETRY),
("thickness_geometry", parent_model.create_virtual_geometry()),
("thickness_type", ThicknessType.FROM_TABLE),
("thickness_field", column_1),
("thickness_field_type", ThicknessFieldType.RELATIVE_SCALING_FACTOR),
(
"taper_edges",
[
TaperEdge(edge_set=parent_model.create_edge_set(), angle=1.2, offset=2.3),
TaperEdge(edge_set=parent_model.create_edge_set(), angle=3.4, offset=4.5),
],
),
],
read_only=[
("id", "some_id"),
Expand Down

0 comments on commit be14103

Please sign in to comment.