Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add example for solid model #695

Merged
merged 23 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
b990fcc
add an example for material, stackup, fabric, and sub-laminate
roosre Nov 21, 2024
1b9b2ea
run pre-commit hooks
roosre Nov 21, 2024
ddd46c5
Merge branch 'main' into docs/materials_example
roosre Nov 21, 2024
dddbc44
fix example if run on github
roosre Nov 21, 2024
46ce532
fix materials example if run on github and pymechanical examples if r…
roosre Nov 21, 2024
ab197f7
Merge remote-tracking branch 'origin/docs/materials_example' into doc…
roosre Nov 21, 2024
2b10b1c
revert change
roosre Nov 21, 2024
396dc94
Merge branch 'main' into docs/materials_example
roosre Nov 21, 2024
28c72f3
add thumbnail for the new example
roosre Nov 21, 2024
05c9680
add solid model example
roosre Nov 21, 2024
3b11142
run pre-commit hooks
roosre Nov 21, 2024
fc8f8b3
refine example
roosre Nov 21, 2024
2339b1a
Merge remote-tracking branch 'remotes/origin/main' into docs/solid_model
roosre Nov 21, 2024
7732261
revert accidental change
roosre Nov 21, 2024
e1d4e22
run pre-commit hooks
roosre Nov 21, 2024
48ce271
add codecov.yml file
roosre Nov 22, 2024
36b0491
add additional unit tests for EdgeProperties (Lamina, TaperEdges)
roosre Nov 22, 2024
922f1fd
run pre-commit hooks
roosre Nov 22, 2024
d562fb1
revert changes and add more unit tests
roosre Nov 22, 2024
612fbb3
Merge branch 'main' into docs/solid_model
roosre Nov 25, 2024
16ac670
add plotting examples for a solid model
roosre Nov 25, 2024
67cd6e2
Merge branch 'docs/solid_model' of https://github.com/ansys-internal/…
roosre Nov 25, 2024
eb51676
fix pre-commit checks
roosre Nov 25, 2024
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
185 changes: 185 additions & 0 deletions examples/modeling_features/020-solid_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
# Copyright (C) 2022 - 2024 ANSYS, Inc. and/or its affiliates.
# SPDX-License-Identifier: MIT
#
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

"""
.. _solid_model_example:

Solid Model
===========

This example shows how to create and shape a solid model.

The solid model implements an extrusion algorithm which creates
a layered solid mesh based on the shell mesh and layup definition.
This solid mesh can be further processed by :class:`.ExtrusionGuide`,
:class:`.SnapToGeometry`, and :class:`.CutOffGeometry`.
"""
# %%
# Import the standard library and third-party dependencies.
import pathlib
import tempfile

import pyvista

# %%
# Import the PyACP dependencies.
from ansys.acp.core import (
ACPWorkflow,
CADGeometry,
CutOffGeometryOrientationType,
EdgeSetType,
ExtrusionGuideType,
SnapToGeometryOrientationType,
VirtualGeometry,
launch_acp,
)
from ansys.acp.core.extras import ExampleKeys, get_example_file

# sphinx_gallery_thumbnail_number = 4


# %%
# Load a minimal model
# ----------------------------
tempdir = tempfile.TemporaryDirectory()
WORKING_DIR = pathlib.Path(tempdir.name)
input_file = get_example_file(ExampleKeys.MINIMAL_FLAT_PLATE, WORKING_DIR)

# %%
# Launch the PyACP server and connect to it.
acp = launch_acp()

# %%
# Define the input file and instantiate an ``ACPWorkflow`` instance.
workflow = ACPWorkflow.from_acph5_file(
acp=acp,
acph5_file_path=input_file,
local_working_directory=WORKING_DIR,
)

model = workflow.model

# %%
# Create a simple layup
# ---------------------
# %%
# Add more layers to the modeling ply so that it is easier to see the
# effects of the selection rules.
modeling_ply = model.modeling_groups["modeling_group"].modeling_plies["ply"]
modeling_ply.number_of_layers = 3

# %%
# Create an initial solid model
# -----------------------------
#
# By default, the layup is extruded along the normal direction of the shell mesh.
solid_model = model.create_solid_model(
name="Solid Model",
element_sets=[model.element_sets["All_Elements"]],
)

model.update()
model.solid_mesh.to_pyvista().plot(show_edges=True)


def create_virtual_geometry_from_file(
example_key: ExampleKeys,
) -> tuple[CADGeometry, VirtualGeometry]:
"""Create a CAD geometry and virtual geometry."""
geometry_file = get_example_file(example_key, WORKING_DIR)
geometry_obj = workflow.add_cad_geometry_from_local_file(geometry_file)
workflow.model.update()
virtual_geometry = model.create_virtual_geometry(
name="thickness_virtual_geometry", cad_components=geometry_obj.root_shapes.values()
)
return geometry_obj, virtual_geometry


def plot_model_with_geometry(cad_geometry: CADGeometry, cad_geom_opacity: float = 0.1):
"""Plot solid model and geometry."""
plotter = pyvista.Plotter()
geom_mesh = cad_geometry.visualization_mesh.to_pyvista()
plotter.add_mesh(geom_mesh, color="green", opacity=cad_geom_opacity)
edges = geom_mesh.extract_feature_edges()
plotter.add_mesh(edges, color="white", line_width=4)
plotter.add_mesh(edges, color="black", line_width=2)
plotter.add_mesh(workflow.model.solid_mesh.to_pyvista(), show_edges=True)
plotter.show()


# %%
# Snap the top to a geometry
# --------------------------
#
# The :class:`.SnapToGeometry` allows to shape the bottom or top of the solid model.
# First, import the geometry and then add the snap-to feature to the solid model.
snap_to_geom, snap_to_virtual_geom = create_virtual_geometry_from_file(ExampleKeys.SNAP_TO_GEOMETRY)
solid_model.create_snap_to_geometry(
name="Snap-to Geometry",
cad_geometry=snap_to_virtual_geom,
orientation_type=SnapToGeometryOrientationType.TOP,
oriented_selection_set=model.oriented_selection_sets["oss"],
)

model.update()
plot_model_with_geometry(snap_to_geom, 0.5)

# %%
# Shape the walls
# ---------------
#
# The :class:`.ExtrusionGuide` is used to shape the side walls of the solid model.
# The feature can be defined by a direction as shown here or through a geometry.
edge_set = model.create_edge_set(
name="Edge Set",
edge_set_type=EdgeSetType.BY_REFERENCE,
element_set=model.element_sets["All_Elements"],
limit_angle=30,
origin=(0.05, 0, 0),
)
solid_model.create_extrusion_guide(
name="Extrusion Guide",
edge_set=edge_set,
extrusion_guide_type=ExtrusionGuideType.BY_DIRECTION,
direction=(-0.5, 1, 0),
radius=0.005,
depth=0.6,
)
model.update()
model.solid_mesh.to_pyvista().plot(show_edges=True)

# %%
# Cut-off an edge
# ---------------
#
# The :class:`.CutOffGeometry` is used to crop elements from the solid model.
cutoff_cad_geom, cutoff_virtual_geom = create_virtual_geometry_from_file(
ExampleKeys.CUT_OFF_GEOMETRY_SOLID_MODEL
)
solid_model.create_cut_off_geometry(
name="Cut-off Geometry",
cad_geometry=cutoff_virtual_geom,
orientation_type=CutOffGeometryOrientationType.UP,
)

model.update()
plot_model_with_geometry(cutoff_cad_geom)
roosre marked this conversation as resolved.
Show resolved Hide resolved
4 changes: 2 additions & 2 deletions src/ansys/acp/core/extras/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@
# SOFTWARE.
"""Extras of the Ansys Composites PrepPost module."""

from ansys.acp.core.extras.example_helpers import ExampleKeys, get_example_file # pragma: no cover
from ansys.acp.core.extras.example_helpers import ExampleKeys, get_example_file

__all__ = [ # pragma: no cover
__all__ = [
"ExampleKeys",
"get_example_file",
]
8 changes: 8 additions & 0 deletions src/ansys/acp/core/extras/example_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ class ExampleKeys(Enum):
OPTIMIZATION_EXAMPLE_DAT = auto()
CLASS40_AGDB = auto()
MATERIALS_XML = auto()
SNAP_TO_GEOMETRY = auto()
CUT_OFF_GEOMETRY_SOLID_MODEL = auto()


EXAMPLE_FILES: dict[ExampleKeys, _ExampleLocation] = {
Expand Down Expand Up @@ -98,6 +100,12 @@ class ExampleKeys(Enum):
),
ExampleKeys.CLASS40_AGDB: _ExampleLocation(directory="class40", filename="class40.agdb"),
ExampleKeys.MATERIALS_XML: _ExampleLocation(directory="materials", filename="materials.engd"),
ExampleKeys.SNAP_TO_GEOMETRY: _ExampleLocation(
directory="geometries", filename="snap_to_geometry.stp"
),
ExampleKeys.CUT_OFF_GEOMETRY_SOLID_MODEL: _ExampleLocation(
directory="geometries", filename="cut_off_geometry_solid_model.stp"
),
}


Expand Down
10 changes: 10 additions & 0 deletions tests/unittests/test_modeling_ply.py
Original file line number Diff line number Diff line change
Expand Up @@ -455,3 +455,13 @@ def test_linked_cutoff_selection_rule_operation_type(operation_type):
operation_type=operation_type,
)
assert "INTERSECT" in str(exc.value)


def test_taper_edge(parent_model):
edge_1 = parent_model.create_edge_set()
taper_edge = TaperEdge(edge_set=edge_1, angle=1, offset=2)
assert taper_edge != TaperEdge(edge_set=parent_model.create_edge_set(), angle=1, offset=2)
assert taper_edge != TaperEdge(edge_set=edge_1, angle=2, offset=2)
assert taper_edge != TaperEdge(edge_set=edge_1, angle=1, offset=3)
assert taper_edge == TaperEdge(edge_set=edge_1, angle=1, offset=2)
print(taper_edge)
8 changes: 8 additions & 0 deletions tests/unittests/test_stackup.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,3 +188,11 @@ def test_add_fabric(parent_object):
stackup.add_fabric(fabric2, angle=45.0)
assert stackup.fabrics[-1].fabric == fabric2
assert stackup.fabrics[-1].angle == 45.0


def test_fabric_wit_angle(parent_object):
fabric1 = parent_object.create_fabric()
fabric_with_angle = FabricWithAngle(fabric=fabric1, angle=45.0)
assert fabric_with_angle != FabricWithAngle(fabric=parent_object.create_fabric(), angle=45.0)
assert fabric_with_angle != FabricWithAngle(fabric=fabric1, angle=55.0)
assert fabric_with_angle == FabricWithAngle(fabric=fabric1, angle=45.0)
14 changes: 14 additions & 0 deletions tests/unittests/test_sublaminate.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,17 @@ def test_add_lamina(parent_object):
assert sublaminate.materials[1].angle == 0.0
assert sublaminate.materials[2].material == fabric1
assert sublaminate.materials[2].angle == -45.0


def test_lamina(parent_object):
fabric1 = parent_object.create_fabric()
fabric1.material = parent_object.create_material()
stackup = parent_object.create_stackup()
stackup.add_fabric(fabric1, angle=30.0)
stackup.add_fabric(fabric1, angle=-30.0)

lamina = Lamina(material=fabric1, angle=45.0)
assert lamina != Lamina(material=stackup, angle=45.0)
assert lamina != Lamina(material=fabric1, angle=-45.0)
assert lamina == Lamina(material=fabric1, angle=45.0)
print(lamina)
10 changes: 10 additions & 0 deletions tests/unittests/test_virtual_geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,13 @@ def test_virtual_geometry_no_or_invalid_links(parent_object, load_cad_geometry):
cad_components=cad_geometry.root_shapes.values(),
sub_shapes=[SubShape(cad_geometry=cad_geometry, path="some/path/to/shape")],
)


def test_sub_shape(parent_object, load_cad_geometry):
model = parent_object
with load_cad_geometry(model) as cad_geometry:
sub_shape = SubShape(cad_geometry=cad_geometry, path="some/path/to/shape")
with load_cad_geometry(model) as other_cad_geometry:
assert sub_shape != SubShape(cad_geometry=other_cad_geometry, path="some/path/to/shape")
assert sub_shape != SubShape(cad_geometry=cad_geometry, path="some/other/path/to/shape")
assert sub_shape == SubShape(cad_geometry=cad_geometry, path="some/path/to/shape")
Loading