-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Sandwich and selection rule examples (#423)
* Add new examples for a sandwich panel, basic and advanced selection rules. * Small improvement to the Virtual Geometries API * Add tests for the create method with non-default arguments for all the objects.
- Loading branch information
1 parent
c0767e4
commit 4b4d4a1
Showing
32 changed files
with
1,167 additions
and
235 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
""" | ||
.. _basic_sandwich_panel: | ||
Basic sandwich panel | ||
==================== | ||
Define a Composite Lay-up for a sandwich panel with PyACP. This example shows just the | ||
pyACP part of the setup. For a complete Composite analysis, | ||
see the :ref:`sphx_glr_examples_gallery_examples_001_basic_flat_plate.py` example | ||
""" | ||
|
||
|
||
# %% | ||
# Import standard library and third-party dependencies | ||
import pathlib | ||
import tempfile | ||
|
||
# %% | ||
# Import pyACP dependencies | ||
from ansys.acp.core import ( | ||
ACPWorkflow, | ||
FabricWithAngle, | ||
Lamina, | ||
PlyType, | ||
get_directions_plotter, | ||
launch_acp, | ||
print_model, | ||
) | ||
from ansys.acp.core.example_helpers import ExampleKeys, get_example_file | ||
from ansys.acp.core.material_property_sets import ConstantEngineeringConstants, ConstantStrainLimits | ||
|
||
# %% | ||
# Get example file from server | ||
tempdir = tempfile.TemporaryDirectory() | ||
WORKING_DIR = pathlib.Path(tempdir.name) | ||
input_file = get_example_file(ExampleKeys.BASIC_FLAT_PLATE_CDB, WORKING_DIR) | ||
|
||
# %% | ||
# Launch the PyACP server and connect to it. | ||
acp = launch_acp() | ||
|
||
# %% | ||
# Define the input file and instantiate an ACPWorkflow | ||
# The ACPWorkflow class provides convenience methods which simplify the file handling. | ||
# It automatically creates a model based on the input file. | ||
|
||
workflow = ACPWorkflow.from_cdb_file( | ||
acp=acp, | ||
cdb_file_path=input_file, | ||
local_working_directory=WORKING_DIR, | ||
) | ||
|
||
model = workflow.model | ||
print(workflow.working_directory.path) | ||
print(model.unit_system) | ||
|
||
# %% | ||
# Visualize the loaded mesh | ||
mesh = model.mesh.to_pyvista() | ||
mesh.plot(show_edges=True) | ||
|
||
|
||
# %% | ||
# Create the UD material and its corresponding fabric | ||
engineering_constants_ud = ConstantEngineeringConstants.from_orthotropic_constants( | ||
E1=5e10, E2=1e10, E3=1e10, nu12=0.28, nu13=0.28, nu23=0.3, G12=5e9, G23=4e9, G31=4e9 | ||
) | ||
|
||
strain_limit = 0.01 | ||
strain_limits = ConstantStrainLimits.from_orthotropic_constants( | ||
eXc=-strain_limit, | ||
eYc=-strain_limit, | ||
eZc=-strain_limit, | ||
eXt=strain_limit, | ||
eYt=strain_limit, | ||
eZt=strain_limit, | ||
eSxy=strain_limit, | ||
eSyz=strain_limit, | ||
eSxz=strain_limit, | ||
) | ||
|
||
ud_material = model.create_material( | ||
name="UD", | ||
ply_type=PlyType.REGULAR, | ||
engineering_constants=engineering_constants_ud, | ||
strain_limits=strain_limits, | ||
) | ||
|
||
ud_fabric = model.create_fabric(name="UD", material=ud_material, thickness=0.002) | ||
|
||
# %% | ||
# Create a multi-axial Stackup and a Sublaminate. Sublaminates and Stackups help to quickly | ||
# build repeating laminates. | ||
|
||
biax_carbon_ud = model.create_stackup( | ||
name="Biax_Carbon_UD", | ||
fabrics=( | ||
FabricWithAngle(ud_fabric, -45), | ||
FabricWithAngle(ud_fabric, 45), | ||
), | ||
) | ||
|
||
|
||
sublaminate = model.create_sublaminate( | ||
name="Sublaminate", | ||
materials=( | ||
Lamina(biax_carbon_ud, 0), | ||
Lamina(ud_fabric, 90), | ||
Lamina(biax_carbon_ud, 0), | ||
), | ||
) | ||
|
||
|
||
# %% | ||
# Create the Core Material and its corresponding Fabric | ||
engineering_constants_core = ConstantEngineeringConstants.from_isotropic_constants(E=8.5e7, nu=0.3) | ||
|
||
core = model.create_material( | ||
name="Core", | ||
ply_type=PlyType.ISOTROPIC_HOMOGENEOUS_CORE, | ||
engineering_constants=engineering_constants_core, | ||
strain_limits=strain_limits, | ||
) | ||
|
||
core_fabric = model.create_fabric(name="core", material=ud_material, thickness=0.015) | ||
|
||
# %% | ||
# Define a rosette and an oriented selection set and plot the orientations | ||
rosette = model.create_rosette(origin=(0.0, 0.0, 0.0), dir1=(1.0, 0.0, 0.0), dir2=(0.0, 1.0, 0.0)) | ||
|
||
oss = model.create_oriented_selection_set( | ||
name="oss", | ||
orientation_point=(0.0, 0.0, 0.0), | ||
orientation_direction=(0.0, 1.0, 0), | ||
element_sets=[model.element_sets["All_Elements"]], | ||
rosettes=[rosette], | ||
) | ||
|
||
model.update() | ||
assert oss.elemental_data.orientation is not None | ||
plotter = get_directions_plotter(model=model, components=[oss.elemental_data.orientation]) | ||
plotter.show() | ||
|
||
# %% | ||
# Create the modeling plies which define the layup of the sandwich panel. | ||
modeling_group = model.create_modeling_group(name="modeling_group") | ||
|
||
bottom_ply = modeling_group.create_modeling_ply( | ||
name="bottom_ply", | ||
ply_angle=0, | ||
ply_material=sublaminate, | ||
oriented_selection_sets=[oss], | ||
) | ||
|
||
core_ply = modeling_group.create_modeling_ply( | ||
name="core_ply", | ||
ply_angle=0, | ||
ply_material=core_fabric, | ||
oriented_selection_sets=[oss], | ||
) | ||
|
||
|
||
top_ply = modeling_group.create_modeling_ply( | ||
name="top_ply", | ||
ply_angle=90, | ||
ply_material=ud_fabric, | ||
oriented_selection_sets=[oss], | ||
number_of_layers=3, | ||
) | ||
|
||
# %% | ||
# Update and print the model. | ||
model.update() | ||
print_model(workflow.model) | ||
# sphinx_gallery_start_ignore | ||
from ansys.acp.core.example_helpers import _run_analysis | ||
|
||
# Run the analysis so we are sure all the material properties have been correctly | ||
# defined. | ||
_run_analysis(workflow) | ||
# sphinx_gallery_end_ignore |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
""" | ||
.. _basic_rules_example: | ||
Basic rule example | ||
================== | ||
Shows the basic usage of selection rules. | ||
Selection Rules enable you to select elements through | ||
geometrical operations and thus to shape plies. | ||
This example shows just the | ||
pyACP part of the setup. See the :ref:`sphx_glr_examples_gallery_examples_005_advanced_rules.py` | ||
for more advanced rule examples. For a complete Composite analysis, | ||
see the :ref:`sphx_glr_examples_gallery_examples_001_basic_flat_plate.py` example | ||
""" | ||
|
||
|
||
# %% | ||
# Import standard library and third-party dependencies | ||
import pathlib | ||
import tempfile | ||
|
||
# %% | ||
# Import pyACP dependencies | ||
from ansys.acp.core import ACPWorkflow, LinkedSelectionRule, PlyType, launch_acp | ||
from ansys.acp.core.example_helpers import ExampleKeys, get_example_file | ||
from ansys.acp.core.material_property_sets import ConstantEngineeringConstants | ||
|
||
# %% | ||
# Get example file from server | ||
tempdir = tempfile.TemporaryDirectory() | ||
WORKING_DIR = pathlib.Path(tempdir.name) | ||
input_file = get_example_file(ExampleKeys.BASIC_FLAT_PLATE_CDB, WORKING_DIR) | ||
|
||
# %% | ||
# Launch the PyACP server and connect to it. | ||
acp = launch_acp() | ||
|
||
# %% | ||
# Define the input file and instantiate an ACPWorkflow | ||
# The ACPWorkflow class provides convenience methods which simplify the file handling. | ||
# It automatically creates a model based on the input file. | ||
|
||
workflow = ACPWorkflow.from_cdb_file( | ||
acp=acp, | ||
cdb_file_path=input_file, | ||
local_working_directory=WORKING_DIR, | ||
) | ||
|
||
model = workflow.model | ||
print(workflow.working_directory.path) | ||
print(model.unit_system) | ||
|
||
# %% | ||
# Visualize the loaded mesh | ||
mesh = model.mesh.to_pyvista() | ||
mesh.plot(show_edges=True) | ||
|
||
|
||
# %% | ||
# Create the UD material and its corresponding fabric | ||
engineering_constants_ud = ConstantEngineeringConstants.from_orthotropic_constants( | ||
E1=5e10, E2=1e10, E3=1e10, nu12=0.28, nu13=0.28, nu23=0.3, G12=5e9, G23=4e9, G31=4e9 | ||
) | ||
|
||
ud_material = model.create_material( | ||
name="UD", | ||
ply_type=PlyType.REGULAR, | ||
engineering_constants=engineering_constants_ud, | ||
) | ||
|
||
ud_fabric = model.create_fabric(name="UD", material=ud_material, thickness=0.002) | ||
|
||
# %% | ||
# Define a rosette and an oriented selection set | ||
rosette = model.create_rosette(origin=(0.0, 0.0, 0.0), dir1=(1.0, 0.0, 0.0), dir2=(0.0, 1.0, 0.0)) | ||
|
||
oss = model.create_oriented_selection_set( | ||
name="oss", | ||
orientation_point=(0.0, 0.0, 0.0), | ||
orientation_direction=(0.0, 1.0, 0), | ||
element_sets=[model.element_sets["All_Elements"]], | ||
rosettes=[rosette], | ||
) | ||
|
||
# %% | ||
# Create a ply with an attached parallel selection rule and plot the ply extent | ||
|
||
parallel_rule = model.create_parallel_selection_rule( | ||
name="parallel_rule", | ||
origin=(0, 0, 0), | ||
direction=(1, 0, 0), | ||
lower_limit=0.005, | ||
upper_limit=1, | ||
) | ||
|
||
modeling_group = model.create_modeling_group(name="modeling_group") | ||
|
||
partial_ply = modeling_group.create_modeling_ply( | ||
name="partial_ply", | ||
ply_angle=90, | ||
ply_material=ud_fabric, | ||
oriented_selection_sets=[oss], | ||
selection_rules=[LinkedSelectionRule(parallel_rule)], | ||
number_of_layers=10, | ||
) | ||
|
||
model.update() | ||
assert model.elemental_data.thickness is not None | ||
model.elemental_data.thickness.get_pyvista_mesh(mesh=model.mesh).plot(show_edges=True) | ||
|
||
# %% | ||
# Create a cylindrical selection rule and add it to the ply. This will intersect the two rules. | ||
cylindrical_rule = model.create_cylindrical_selection_rule( | ||
name="cylindrical_rule", | ||
origin=(0.005, 0, 0.005), | ||
direction=(0, 1, 0), | ||
radius=0.002, | ||
) | ||
|
||
partial_ply.selection_rules.append(LinkedSelectionRule(cylindrical_rule)) | ||
|
||
model.update() | ||
assert model.elemental_data.thickness is not None | ||
model.elemental_data.thickness.get_pyvista_mesh(mesh=model.mesh).plot(show_edges=True) | ||
|
||
# %% | ||
# Create a spherical selection rule and assign it to the ply. Now only the spherical rule is | ||
# active. | ||
spherical_rule = model.create_spherical_selection_rule( | ||
name="spherical_rule", | ||
origin=(0.003, 0, 0.005), | ||
radius=0.002, | ||
) | ||
|
||
partial_ply.selection_rules = [LinkedSelectionRule(spherical_rule)] | ||
|
||
model.update() | ||
assert model.elemental_data.thickness is not None | ||
model.elemental_data.thickness.get_pyvista_mesh(mesh=model.mesh).plot(show_edges=True) | ||
|
||
# %% | ||
# Create a tube selection rule and assign it to the ply. Now only the tube rule is | ||
# active. | ||
tube_rule = model.create_tube_selection_rule( | ||
name="spherical_rule", | ||
# Select the pre-exsting _FIXEDSU edge which is the edge at x=0 | ||
edge_set=model.edge_sets["_FIXEDSU"], | ||
inner_radius=0.001, | ||
outer_radius=0.003, | ||
) | ||
|
||
partial_ply.selection_rules = [LinkedSelectionRule(tube_rule)] | ||
|
||
model.update() | ||
assert model.elemental_data.thickness is not None | ||
model.elemental_data.thickness.get_pyvista_mesh(mesh=model.mesh).plot(show_edges=True) |
Oops, something went wrong.