Shape Optimization of a Bracket#

This example demonstrates how to insert a Static Structural analysis into a new Mechanical session and execute a sequence of Python scripting commands that define and solve a shape optimization analysis of bracket. Scripts then evaluate the following results: deformation and optimized shape.

## %%
# Import the necessary libraries
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

from pathlib import Path
from typing import TYPE_CHECKING

from ansys.mechanical.core import App
from ansys.mechanical.core.examples import delete_downloads, download_file
from matplotlib import image as mpimg
from matplotlib import pyplot as plt

if TYPE_CHECKING:
    import Ansys

Initialize the embedded application#

app = App(globals=globals())
print(app)
Ansys Mechanical [Ansys Mechanical Enterprise]
Product Version:251
Software build date: 11/27/2024 09:34:44

Create functions to set camera and display images#

# Set the path for the output files (images, gifs, mechdat)
output_path = Path.cwd() / "out"


def display_image(
    image_path: str,
    pyplot_figsize_coordinates: tuple = (16, 9),
    plot_xticks: list = [],
    plot_yticks: list = [],
    plot_axis: str = "off",
) -> None:
    """Display the image with the specified parameters.

    Parameters
    ----------
    image_path : str
        The path to the image file to display.
    pyplot_figsize_coordinates : tuple
        The size of the figure in inches (width, height).
    plot_xticks : list
        The x-ticks to display on the plot.
    plot_yticks : list
        The y-ticks to display on the plot.
    plot_axis : str
        The axis visibility setting ('on' or 'off').
    """
    # Set the figure size based on the coordinates specified
    plt.figure(figsize=pyplot_figsize_coordinates)
    # Read the image from the file into an array
    image_path = str(output_path / image_path)
    plt.imshow(mpimg.imread(image_path))
    # Get or set the current tick locations and labels of the x-axis
    plt.xticks(plot_xticks)
    # Get or set the current tick locations and labels of the y-axis
    plt.yticks(plot_yticks)
    # Turn off the axis
    plt.axis(plot_axis)
    # Display the figure
    plt.show()

Configure graphics for image export#

# Define the graphics and camera
graphics = app.Graphics
camera = graphics.Camera

# Set the camera orientation to the isometric view and set the camera to fit the model
camera.SetSpecificViewOrientation(ViewOrientationType.Iso)
camera.SetFit()

# Set the image export format and settings
image_export_format = GraphicsImageExportFormat.PNG
settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings()
settings_720p.Resolution = (
    Ansys.Mechanical.DataModel.Enums.GraphicsResolutionType.EnhancedResolution
)
settings_720p.Background = Ansys.Mechanical.DataModel.Enums.GraphicsBackgroundType.White
settings_720p.Width = 1280
settings_720p.Height = 720
settings_720p.CurrentGraphicsDisplay = False

Download the required files#

# Download the geometry file
geometry_path = download_file("bracket_model.agdb", "pymechanical", "embedding")

Import the geometry#

# Define the model
model = app.Model

# Add the geometry import to the geometry import group
geometry_import_group = model.GeometryImportGroup
geometry_import = geometry_import_group.AddGeometryImport()

# Set the geometry import format and settings
geometry_import_format = (
    Ansys.Mechanical.DataModel.Enums.GeometryImportPreference.Format.Automatic
)
geometry_import_preferences = Ansys.ACT.Mechanical.Utilities.GeometryImportPreferences()
geometry_import_preferences.ProcessNamedSelections = True
geometry_import_preferences.NamedSelectionKey = ""
geometry_import_preferences.ProcessMaterialProperties = True
geometry_import_preferences.ProcessCoordinateSystems = True

# Import the geometry with the specified settings
geometry_import.Import(
    geometry_path, geometry_import_format, geometry_import_preferences
)

# Visualize the model in 3D
app.plot()
shape optimization bracket model

Define Named Selections#

Specify variables for named selection objects

NS_GRP = ExtAPI.DataModel.Project.Model.NamedSelections
BOUNDARY_COND_NS = [
    x for x in ExtAPI.DataModel.Tree.AllObjects if x.Name == "boundary_cond"
][0]
LOADING_NS = [x for x in ExtAPI.DataModel.Tree.AllObjects if x.Name == "loading"][0]
EXCLUSON_REGION_NS = [
    x for x in ExtAPI.DataModel.Tree.AllObjects if x.Name == "exclusion_region"
][0]
BRACKET_NS = [x for x in ExtAPI.DataModel.Tree.AllObjects if x.Name == "bracket"][0]

Define the mesh settings and generate the mesh#

mesh = app.Model.Mesh
automatic_method = mesh.AddAutomaticMethod()
automatic_method.ScopingMethod = GeometryDefineByType.Component

selection = NS_GRP.Children[3]
automatic_method.Location = selection
automatic_method.Method = MethodType.AllTriAllTet
automatic_method.ElementOrder = ElementOrder.Linear

sizing = mesh.AddSizing()
sizing.ScopingMethod = GeometryDefineByType.Component
selection = NS_GRP.Children[3]
sizing.Location = selection
sizing.ElementSize = Quantity(6e-3, "m")

mesh.GenerateMesh()

# Display mesh

app.Tree.Activate([mesh])
camera.SetFit()
graphics.ExportImage(str(output_path / "mesh.png"), image_export_format, settings_720p)
display_image("mesh.png")
shape optimization bracket model

Define Analysis#

Add Structural analysis

model = app.Model
static_structural_analysis = model.AddStaticStructuralAnalysis()

Define loads and boundary conditions#

fixed_support = static_structural_analysis.AddFixedSupport()
selection = NS_GRP.Children[0]
fixed_support.Location = selection

force = static_structural_analysis.AddForce()
selection = NS_GRP.Children[1]
force.Location = selection
force.DefineBy = LoadDefineBy.Components
force.ZComponent.Output.SetDiscreteValue(0, Quantity(25000, "N"))

Analysis settings#

solution = static_structural_analysis.Solution

Insert results#

total_deformation = solution.AddTotalDeformation()

Solve#

solution.Solve(True)
solution_status = solution.Status

Show messages#

# Print all messages from Mechanical
app.messages.show()
Severity: Warning
DisplayString: Linear Tetrahedral elements have been used in regions with linear materials. This is not recommended. Please consider changing your mesh settings to use a different element type in these regions.
Severity: Warning
DisplayString: The application requires the use of OpenGL version 4.3. The detected version 3.1 Mesa 21.2.6 does not meet this requirement. This discrepancy may produce graphical display issues for certain features. Furthermore, future versions of Mechanical may not support systems that do not meet this requirement.
Severity: Warning
DisplayString: The license manager is delayed in its response. The latest requests were answered after 29 seconds.

Results#

Total deformation

app.Tree.Activate([total_deformation])
camera.SetFit()
graphics.ExportImage(
    str(output_path / "total_deformation.png"), image_export_format, settings_720p
)
display_image("total_deformation.png")
shape optimization bracket model

Define Analysis#

Add Topology Optimization Analysis

topology_optimization = model.AddTopologyOptimizationAnalysis()
topology_optimization.ImportLoad(static_structural_analysis)

Define Optimization Settings#

Specify the shape optimization region

optimization_region = DataModel.GetObjectsByType(
    DataModelObjectCategory.OptimizationRegion
)[0]
selection = NS_GRP.Children[3]
optimization_region.DesignRegionLocation = selection
optimization_region.ExclusionScopingMethod = GeometryDefineByType.Component
selection = NS_GRP.Children[2]
optimization_region.ExclusionRegionLocation = selection

optimization_region.OptimizationType = OptimizationType.Shape
optimization_region.ShapeMoveLimitControl = TopoPropertyControlType.Manual
optimization_region.MorphingIterationMoveLimit = 0.002
optimization_region.MaxCumulatedDisplacementControl = TopoPropertyControlType.Manual
optimization_region.MorphingTotalMoveLimit = 0.02
optimization_region.MeshDeformationToleranceControl = TopoPropertyControlType.Manual

Define Objective#

Specify objective as minimizing volume

objective_type = DataModel.GetObjectsByType(DataModelObjectCategory.Objective)[0]
objective_type.Worksheet.SetObjectiveType(0, ObjectiveType.MinimizeVolume)

Define Compliance Settings#

Specify compliance as response constraint

compliance_constraint = topology_optimization.AddComplianceConstraint()
compliance_constraint.ComplianceLimit.Output.SetDiscreteValue(0, Quantity(0.27, "J"))

mass_constraint = DataModel.GetObjectsByName("Response Constraint")
DataModel.Remove(mass_constraint)

Analysis settings#

topo_solution = topology_optimization.Solution

Insert results#

# Topology_Density = SOLN.AddTopologyDensity()
topology_density = DataModel.GetObjectsByName("Topology Density")[0]

Solve: shape Optimization Simulation#

topo_solution.Solve(True)
topo_solution_status = topo_solution.Status

Show messages#

# Print all messages from Mechanical
app.messages.show()
Severity: Info
DisplayString: For geometric objective (Mass or Volume), it is recommended to use Criterion of the upstream Measure folder (inserted from Model object).
Severity: Warning
DisplayString: Linear Tetrahedral elements have been used in regions with linear materials. This is not recommended. Please consider changing your mesh settings to use a different element type in these regions.
Severity: Warning
DisplayString: The application requires the use of OpenGL version 4.3. The detected version 3.1 Mesa 21.2.6 does not meet this requirement. This discrepancy may produce graphical display issues for certain features. Furthermore, future versions of Mechanical may not support systems that do not meet this requirement.
Severity: Warning
DisplayString: The license manager is delayed in its response. The latest requests were answered after 29 seconds.

Results#

Topology Density

app.Tree.Activate([topology_density])
camera.SetFit()
graphics.ExportImage(
    str(output_path / "topology_density.png"), image_export_format, settings_720p
)
display_image("topology_density.png")
shape optimization bracket model

Cleanup#

Save project

mechdat_file = output_path / "shape-optimization.mechdat"
app.save(str(mechdat_file))

# Close the app
app.close()

# delete example file
delete_downloads()
True

Total running time of the script: (3 minutes 20.636 seconds)

Gallery generated by Sphinx-Gallery