Bolt Pretension#

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 bolt-pretension analysis. Scripts then evaluate the following results: deformation, equivalent stresses, contact, and bolt

Import necessary libraries#

import os

from PIL import Image
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
from matplotlib.animation import FuncAnimation

Embed mechanical and set global variables

app = App()
app.update_globals(globals())
print(app)

cwd = os.path.join(os.getcwd(), "out")


def display_image(image_name):
    plt.figure(figsize=(16, 9))
    plt.imshow(mpimg.imread(os.path.join(cwd, image_name)))
    plt.xticks([])
    plt.yticks([])
    plt.axis("off")
    plt.show()
Ansys Mechanical [Ansys Mechanical Enterprise]
Product Version:242
Software build date: 06/03/2024 09:35:09

Configure graphics for image export#

Graphics.Camera.SetSpecificViewOrientation(ViewOrientationType.Iso)
Graphics.Camera.SetFit()
image_export_format = GraphicsImageExportFormat.PNG
settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings()
settings_720p.Resolution = GraphicsResolutionType.EnhancedResolution
settings_720p.Background = GraphicsBackgroundType.White
settings_720p.Width = 1280
settings_720p.Height = 720
settings_720p.CurrentGraphicsDisplay = False
Graphics.Camera.Rotate(180, CameraAxisType.ScreenY)

Download and import geometry#

Download the geometry file

geometry_path = download_file(
    "example_06_bolt_pret_geom.agdb", "pymechanical", "00_basic"
)

Import geometry

geometry_import_group = Model.GeometryImportGroup
geometry_import = geometry_import_group.AddGeometryImport()
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.Import(
    geometry_path, geometry_import_format, geometry_import_preferences
)


app.plot()
bolt pretension

Download and import material#

Download materials

mat_Copper_file_path = download_file(
    "example_06_Mat_Copper.xml", "pymechanical", "00_basic"
)
mat_Steel_file_path = download_file(
    "example_06_Mat_Steel.xml", "pymechanical", "00_basic"
)

Import materials

MAT = Model.Materials
MAT.Import(mat_Copper_file_path)
MAT.Import(mat_Steel_file_path)

Define Analysis and unit system#

Add Structural analysis

Model.AddStaticStructuralAnalysis()
STAT_STRUC = Model.Analyses[0]
STAT_STRUC_SOLN = STAT_STRUC.Solution
STAT_STRUC_ANA_SETTING = STAT_STRUC.Children[0]

Set up the unit system.

ExtAPI.Application.ActiveUnitSystem = MechanicalUnitSystem.StandardNMM

Store all main tree nodes as variables

MODEL = Model
GEOM = Model.Geometry
CONN_GRP = Model.Connections
CS_GRP = Model.CoordinateSystems
MSH = Model.Mesh
NS_GRP = Model.NamedSelections

Store named selections

block3_block2_cont_NS = [x for x in Tree.AllObjects if x.Name == "block3_block2_cont"][
    0
]
block3_block2_targ_NS = [x for x in Tree.AllObjects if x.Name == "block3_block2_targ"][
    0
]
shank_block3_targ_NS = [x for x in Tree.AllObjects if x.Name == "shank_block3_targ"][0]
shank_block3_cont_NS = [x for x in Tree.AllObjects if x.Name == "shank_block3_cont"][0]
block1_washer_cont_NS = [x for x in Tree.AllObjects if x.Name == "block1_washer_cont"][
    0
]
block1_washer_targ_NS = [x for x in Tree.AllObjects if x.Name == "block1_washer_targ"][
    0
]
washer_bolt_cont_NS = [x for x in Tree.AllObjects if x.Name == "washer_bolt_cont"][0]
washer_bolt_targ_NS = [x for x in Tree.AllObjects if x.Name == "washer_bolt_targ"][0]
shank_bolt_targ_NS = [x for x in Tree.AllObjects if x.Name == "shank_bolt_targ"][0]
shank_bolt_cont_NS = [x for x in Tree.AllObjects if x.Name == "shank_bolt_cont"][0]
block2_block1_cont_NS = [x for x in Tree.AllObjects if x.Name == "block2_block1_cont"][
    0
]
block2_block1_targ_NS = [x for x in Tree.AllObjects if x.Name == "block2_block1_targ"][
    0
]
all_bodies = [x for x in Tree.AllObjects if x.Name == "all_bodies"][0]
bodies_5 = [x for x in Tree.AllObjects if x.Name == "bodies_5"][0]
shank = [x for x in Tree.AllObjects if x.Name == "shank"][0]
shank_face = [x for x in Tree.AllObjects if x.Name == "shank_face"][0]
shank_face2 = [x for x in Tree.AllObjects if x.Name == "shank_face2"][0]
bottom_surface = [x for x in Tree.AllObjects if x.Name == "bottom_surface"][0]
block2_surface = [x for x in Tree.AllObjects if x.Name == "block2_surface"][0]
shank_surface = [x for x in Tree.AllObjects if x.Name == "shank_surface"][0]

Assign material to bodies

SURFACE1 = GEOM.Children[0].Children[0]
SURFACE1.Material = "Steel"

SURFACE2 = GEOM.Children[1].Children[0]
SURFACE2.Material = "Copper"

SURFACE3 = GEOM.Children[2].Children[0]
SURFACE3.Material = "Copper"

SURFACE4 = GEOM.Children[3].Children[0]
SURFACE4.Material = "Steel"

SURFACE5 = GEOM.Children[4].Children[0]
SURFACE5.Material = "Steel"

SURFACE6 = GEOM.Children[5].Children[0]
SURFACE6.Material = "Steel"

Define coordinate system#

coordinate_system = CS_GRP.AddCoordinateSystem()
coordinate_system.OriginDefineBy = CoordinateSystemAlignmentType.Fixed
coordinate_system.OriginX = Quantity(-195, "mm")
coordinate_system.OriginY = Quantity(100, "mm")
coordinate_system.OriginZ = Quantity(50, "mm")
coordinate_system.PrimaryAxis = CoordinateSystemAxisType.PositiveZAxis

Define Contacts#

Change contact settings

Delete existing contacts

for connection in CONN_GRP.Children:
    if connection.DataModelObjectCategory == DataModelObjectCategory.ConnectionGroup:
        connection.Delete()

CONT_REG1 = CONN_GRP.AddContactRegion()
CONT_REG1.SourceLocation = NS_GRP.Children[0]
CONT_REG1.TargetLocation = NS_GRP.Children[1]
CONT_REG1.ContactType = ContactType.Frictional
CONT_REG1.FrictionCoefficient = 0.2
CONT_REG1.SmallSliding = ContactSmallSlidingType.Off
CONT_REG1.UpdateStiffness = UpdateContactStiffness.Never
CMD1 = CONT_REG1.AddCommandSnippet()

Add missing contact keyopt and Archard Wear Model using a command snippet

AWM = """keyopt,cid,9,5
rmodif,cid,10,0.00
rmodif,cid,23,0.001"""
CMD1.AppendText(AWM)

CONTS = CONN_GRP.Children[0]
CONT_REG2 = CONTS.AddContactRegion()
CONT_REG2.SourceLocation = NS_GRP.Children[3]
CONT_REG2.TargetLocation = NS_GRP.Children[2]
CONT_REG2.ContactType = ContactType.Bonded
CONT_REG2.ContactFormulation = ContactFormulation.MPC

CONT_REG3 = CONTS.AddContactRegion()
CONT_REG3.SourceLocation = NS_GRP.Children[4]
CONT_REG3.TargetLocation = NS_GRP.Children[5]
CONT_REG3.ContactType = ContactType.Frictional
CONT_REG3.FrictionCoefficient = 0.2
CONT_REG3.SmallSliding = ContactSmallSlidingType.Off
CONT_REG3.UpdateStiffness = UpdateContactStiffness.Never
CMD3 = CONT_REG3.AddCommandSnippet()

# Add missing contact keyopt and Archard Wear Model using a command snippet

AWM3 = """keyopt,cid,9,5
rmodif,cid,10,0.00
rmodif,cid,23,0.001"""
CMD3.AppendText(AWM3)

CONT_REG4 = CONTS.AddContactRegion()
CONT_REG4.SourceLocation = NS_GRP.Children[6]
CONT_REG4.TargetLocation = NS_GRP.Children[7]
CONT_REG4.ContactType = ContactType.Bonded
CONT_REG4.ContactFormulation = ContactFormulation.MPC

CONT_REG5 = CONTS.AddContactRegion()
CONT_REG5.SourceLocation = NS_GRP.Children[9]
CONT_REG5.TargetLocation = NS_GRP.Children[8]
CONT_REG5.ContactType = ContactType.Bonded
CONT_REG5.ContactFormulation = ContactFormulation.MPC

CONT_REG6 = CONTS.AddContactRegion()
CONT_REG6.SourceLocation = NS_GRP.Children[10]
CONT_REG6.TargetLocation = NS_GRP.Children[11]
CONT_REG6.ContactType = ContactType.Frictional
CONT_REG6.FrictionCoefficient = 0.2
CONT_REG6.SmallSliding = ContactSmallSlidingType.Off
CONT_REG6.UpdateStiffness = UpdateContactStiffness.Never
CMD6 = CONT_REG6.AddCommandSnippet()

# Add missing contact keyopt and Archard Wear Model using a command snippet

AWM6 = """keyopt,cid,9,5
rmodif,cid,10,0.00
rmodif,cid,23,0.001"""
CMD6.AppendText(AWM6)

Mesh#

Hex_Method = MSH.AddAutomaticMethod()
Hex_Method.Location = all_bodies
Hex_Method.Method = MethodType.Automatic

BODY_SIZING1 = MSH.AddSizing()
BODY_SIZING1.Location = bodies_5
BODY_SIZING1.ElementSize = Quantity(15, "mm")

BODY_SIZING2 = MSH.AddSizing()
BODY_SIZING2.Location = shank
BODY_SIZING2.ElementSize = Quantity(7, "mm")

Face_Meshing = MSH.AddFaceMeshing()
Face_Meshing.Location = shank_face
Face_Meshing.MappedMesh = False

Sweep_Method = MSH.AddAutomaticMethod()
Sweep_Method.Location = shank
Sweep_Method.Method = MethodType.Sweep
Sweep_Method.SourceTargetSelection = 2
Sweep_Method.SourceLocation = shank_face
Sweep_Method.TargetLocation = shank_face2

MSH.Activate()
MSH.GenerateMesh()

Graphics.Camera.SetFit()
Graphics.ExportImage(os.path.join(cwd, "mesh.png"), image_export_format, settings_720p)
display_image("mesh.png")
bolt pretension

Analysis settings#

STAT_STRUC_ANA_SETTING.NumberOfSteps = 4
step_index_list = [1]

with Transaction():
    for step_index in step_index_list:
        STAT_STRUC_ANA_SETTING.SetAutomaticTimeStepping(
            step_index, AutomaticTimeStepping.Off
        )

STAT_STRUC_ANA_SETTING.Activate()
step_index_list = [1]

with Transaction():
    for step_index in step_index_list:
        STAT_STRUC_ANA_SETTING.SetNumberOfSubSteps(step_index, 2)

STAT_STRUC_ANA_SETTING.Activate()
STAT_STRUC_ANA_SETTING.SolverType = SolverType.Direct
STAT_STRUC_ANA_SETTING.SolverPivotChecking = SolverPivotChecking.Off

Define loads and boundary conditions#

FIX_SUP = STAT_STRUC.AddFixedSupport()
FIX_SUP.Location = block2_surface

Tabular_Force = STAT_STRUC.AddForce()
Tabular_Force.Location = bottom_surface
Tabular_Force.DefineBy = LoadDefineBy.Components
Tabular_Force.XComponent.Inputs[0].DiscreteValues = [
    Quantity("0[s]"),
    Quantity("1[s]"),
    Quantity("2[s]"),
    Quantity("3[s]"),
    Quantity("4[s]"),
]
Tabular_Force.XComponent.Output.DiscreteValues = [
    Quantity("0[N]"),
    Quantity("0[N]"),
    Quantity("5.e+005[N]"),
    Quantity("0[N]"),
    Quantity("-5.e+005[N]"),
]

Bolt_Pretension = STAT_STRUC.AddBoltPretension()
Bolt_Pretension.Location = shank_surface
Bolt_Pretension.Preload.Inputs[0].DiscreteValues = [
    Quantity("1[s]"),
    Quantity("2[s]"),
    Quantity("3[s]"),
    Quantity("4[s]"),
]
Bolt_Pretension.Preload.Output.DiscreteValues = [
    Quantity("6.1363e+005[N]"),
    Quantity("0 [N]"),
    Quantity("0 [N]"),
    Quantity("0[N]"),
]
Bolt_Pretension.SetDefineBy(2, BoltLoadDefineBy.Lock)
Bolt_Pretension.SetDefineBy(3, BoltLoadDefineBy.Lock)
Bolt_Pretension.SetDefineBy(4, BoltLoadDefineBy.Lock)

Tree.Activate([Bolt_Pretension])
Graphics.ExportImage(
    os.path.join(cwd, "loads_and_boundaryconditions.png"),
    image_export_format,
    settings_720p,
)
display_image("loads_and_boundaryconditions.png")
bolt pretension

Insert results#

Post_Contact_Tool = STAT_STRUC_SOLN.AddContactTool()
Post_Contact_Tool.ScopingMethod = GeometryDefineByType.Worksheet
Bolt_Tool = STAT_STRUC_SOLN.AddBoltTool()
Bolt_Working_Load = Bolt_Tool.AddWorkingLoad()
Total_Deformation = STAT_STRUC_SOLN.AddTotalDeformation()
Equivalent_stress_1 = STAT_STRUC_SOLN.AddEquivalentStress()
Equivalent_stress_2 = STAT_STRUC_SOLN.AddEquivalentStress()
Equivalent_stress_2.Location = shank
Force_Reaction_1 = STAT_STRUC_SOLN.AddForceReaction()
Force_Reaction_1.BoundaryConditionSelection = FIX_SUP
Moment_Reaction_2 = STAT_STRUC_SOLN.AddMomentReaction()
Moment_Reaction_2.BoundaryConditionSelection = FIX_SUP

Solve#

STAT_STRUC_SOLN.Solve(True)
STAT_STRUC_SS = STAT_STRUC_SOLN.Status

Messages#

Messages = ExtAPI.Application.Messages
if Messages:
    for message in Messages:
        print(f"[{message.Severity}] {message.DisplayString}")
else:
    print("No [Info]/[Warning]/[Error] Messages")
[Warning] There could be possible overconstraint between the bonded contacts which use the MPC formulation, to identify those overconstraint regions use the Contact Trackers or the Status under the Contact Tool.
[Info] All contact results of contacts with MPC formulation are zero since constraint equations are used to bond the mesh together. Review results of the parts underlying the contact surfaces for more information.
[Warning] One or more MPC or Lagrange Multiplier formulation based contact regions or remote boundary conditions may have conflicts with other applied boundary conditions or other contact or symmetry regions. This may reduce solution accuracy. For MPC based remote points, setting the relaxation method may help eliminate overconstraint. Tip: You may graphically display FE Connections from the Solution Information Object for non-cyclic analysis. Refer to Troubleshooting in the Help System for more details.
[Warning] At least one body has been found to have only 1 element in at least 2 directions along with reduced integration.  This situation can lead to invalid results or solver pivot errors.  Consider changing to full integration element control or meshing with more elements.  Offending bodies can be identified by Right-clicking in the Geometry window and choose Go To -> Bodies With One Element Through the Thickness.  Refer to Troubleshooting in the Help System for more details.

Results#

Total deformation

Tree.Activate([Total_Deformation])
Graphics.Camera.SetFit()
Graphics.ExportImage(
    os.path.join(cwd, "total_deformation.png"), image_export_format, settings_720p
)
display_image("total_deformation.png")
bolt pretension

Equivalent stress on all bodies

Tree.Activate([Equivalent_stress_1])
Graphics.Camera.SetFit()
Graphics.ExportImage(
    os.path.join(cwd, "equivalent_stress_total.png"), image_export_format, settings_720p
)
display_image("equivalent_stress_total.png")
bolt pretension

Equivalent stress on shank

Tree.Activate([Equivalent_stress_2])
Graphics.Camera.SetFit()
Graphics.ExportImage(
    os.path.join(cwd, "equivalent_stress_shank.png"), image_export_format, settings_720p
)
display_image("equivalent_stress_shank.png")
bolt pretension

Export contact status animation

Post_Contact_Tool_status = Post_Contact_Tool.Children[0]
Tree.Activate([Post_Contact_Tool_status])
Graphics.Camera.SetFit()
animation_export_format = (
    Ansys.Mechanical.DataModel.Enums.GraphicsAnimationExportFormat.GIF
)
settings_720p = Ansys.Mechanical.Graphics.AnimationExportSettings()
settings_720p.Width = 1280
settings_720p.Height = 720

Post_Contact_Tool_status.ExportAnimation(
    os.path.join(cwd, "contact_status.gif"), animation_export_format, settings_720p
)
gif = Image.open(os.path.join(cwd, "contact_status.gif"))
fig, ax = plt.subplots(figsize=(16, 9))
ax.axis("off")
img = ax.imshow(gif.convert("RGBA"))


def update(frame):
    gif.seek(frame)
    img.set_array(gif.convert("RGBA"))
    return [img]


ani = FuncAnimation(
    fig, update, frames=range(gif.n_frames), interval=200, repeat=True, blit=True
)
plt.show()