From 1a89081921fffa4a8828a7bc6e2c9ce497310b10 Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Wed, 19 Feb 2025 11:16:07 -0500 Subject: [PATCH 01/24] replace app.update_globals with App(globals=globals()) for most examples --- examples/00_tips/tips_02.py | 3 +-- examples/00_tips/tips_03.py | 3 +-- examples/01_basic/bolt_pretension.py | 3 +-- examples/01_basic/fracture_analysis_contact_debonding.py | 3 +-- examples/01_basic/harmonic_acoustics.py | 3 +-- examples/01_basic/modal_acoustics_analysis.py | 3 +-- examples/01_basic/steady_state_thermal_analysis.py | 3 +-- examples/01_basic/topology_optimization_cantilever_beam.py | 3 +-- examples/01_basic/valve.py | 3 +-- examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py | 3 +-- examples/02_technology_showcase/conact_wear_simulation.py | 3 +-- .../non_linear_analsis_rubber_boot_seal.py | 3 +-- 12 files changed, 12 insertions(+), 24 deletions(-) diff --git a/examples/00_tips/tips_02.py b/examples/00_tips/tips_02.py index 8bc4ec54..20cdf760 100644 --- a/examples/00_tips/tips_02.py +++ b/examples/00_tips/tips_02.py @@ -18,8 +18,7 @@ # %% # Embed Mechanical and set global variables -app = App() -app.update_globals(globals()) +app = App(globals=globals()) print(app) diff --git a/examples/00_tips/tips_03.py b/examples/00_tips/tips_03.py index e6f16eb4..4b003b58 100644 --- a/examples/00_tips/tips_03.py +++ b/examples/00_tips/tips_03.py @@ -17,8 +17,7 @@ # %% # Embed Mechanical and set global variables -app = App() -app.update_globals(globals()) +app = App(globals=globals()) print(app) diff --git a/examples/01_basic/bolt_pretension.py b/examples/01_basic/bolt_pretension.py index 44450a3a..8b8e028d 100644 --- a/examples/01_basic/bolt_pretension.py +++ b/examples/01_basic/bolt_pretension.py @@ -26,8 +26,7 @@ # %% # Embed mechanical and set global variables -app = App() -app.update_globals(globals()) +app = App(globals=globals()) print(app) cwd = os.path.join(os.getcwd(), "out") diff --git a/examples/01_basic/fracture_analysis_contact_debonding.py b/examples/01_basic/fracture_analysis_contact_debonding.py index 17b4bf08..25461b4b 100644 --- a/examples/01_basic/fracture_analysis_contact_debonding.py +++ b/examples/01_basic/fracture_analysis_contact_debonding.py @@ -25,8 +25,7 @@ # %% # Embed mechanical and set global variables -app = App() -app.update_globals(globals()) +app = App(globals=globals()) print(app) cwd = os.path.join(os.getcwd(), "out") diff --git a/examples/01_basic/harmonic_acoustics.py b/examples/01_basic/harmonic_acoustics.py index cf343d3a..52839662 100644 --- a/examples/01_basic/harmonic_acoustics.py +++ b/examples/01_basic/harmonic_acoustics.py @@ -25,8 +25,7 @@ # %% # Embed mechanical and set global variables -app = App() -app.update_globals(globals()) +app = App(globals=globals()) print(app) cwd = os.path.join(os.getcwd(), "out") diff --git a/examples/01_basic/modal_acoustics_analysis.py b/examples/01_basic/modal_acoustics_analysis.py index 398a5410..59a5ed02 100644 --- a/examples/01_basic/modal_acoustics_analysis.py +++ b/examples/01_basic/modal_acoustics_analysis.py @@ -31,8 +31,7 @@ # %% # Embed mechanical and set global variables -app = App() -app.update_globals(globals()) +app = App(globals=globals()) print(app) cwd = os.path.join(os.getcwd(), "out") diff --git a/examples/01_basic/steady_state_thermal_analysis.py b/examples/01_basic/steady_state_thermal_analysis.py index 51cf3c88..56f43024 100644 --- a/examples/01_basic/steady_state_thermal_analysis.py +++ b/examples/01_basic/steady_state_thermal_analysis.py @@ -28,8 +28,7 @@ # %% # Embed mechanical and set global variables -app = App() -app.update_globals(globals()) +app = App(globals=globals()) print(app) cwd = os.path.join(os.getcwd(), "out") diff --git a/examples/01_basic/topology_optimization_cantilever_beam.py b/examples/01_basic/topology_optimization_cantilever_beam.py index 8d3cf6d4..a9c67f27 100644 --- a/examples/01_basic/topology_optimization_cantilever_beam.py +++ b/examples/01_basic/topology_optimization_cantilever_beam.py @@ -22,8 +22,7 @@ # %% # Embed Mechanical and set global variables -app = App() -app.update_globals(globals()) +app = App(globals=globals()) print(app) diff --git a/examples/01_basic/valve.py b/examples/01_basic/valve.py index 6778723f..39f25bbb 100644 --- a/examples/01_basic/valve.py +++ b/examples/01_basic/valve.py @@ -22,8 +22,7 @@ # %% # Embed mechanical and set global variables -app = App() -app.update_globals(globals()) +app = App(globals=globals()) print(app) cwd = os.path.join(os.getcwd(), "out") diff --git a/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py b/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py index 7eeb72af..d7611c46 100644 --- a/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py +++ b/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py @@ -57,8 +57,7 @@ # %% # Embed mechanical and set global variables -app = App() -app.update_globals(globals()) +app = App(globals=globals()) print(app) cwd = os.path.join(os.getcwd(), "out") diff --git a/examples/02_technology_showcase/conact_wear_simulation.py b/examples/02_technology_showcase/conact_wear_simulation.py index 9455af21..d15bbeeb 100644 --- a/examples/02_technology_showcase/conact_wear_simulation.py +++ b/examples/02_technology_showcase/conact_wear_simulation.py @@ -37,8 +37,7 @@ # %% # Embed mechanical and set global variables -app = App() -app.update_globals(globals()) +app = App(globals=globals()) print(app) cwd = os.path.join(os.getcwd(), "out") diff --git a/examples/02_technology_showcase/non_linear_analsis_rubber_boot_seal.py b/examples/02_technology_showcase/non_linear_analsis_rubber_boot_seal.py index 815cc621..b0ad0863 100644 --- a/examples/02_technology_showcase/non_linear_analsis_rubber_boot_seal.py +++ b/examples/02_technology_showcase/non_linear_analsis_rubber_boot_seal.py @@ -30,8 +30,7 @@ # %% # Embed mechanical and set global variables -app = App() -app.update_globals(globals()) +app = App(globals=globals()) print(app) cwd = os.path.join(os.getcwd(), "out") From f077a3785be6ba60bea840e714a3488caf0663d8 Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Mon, 31 Mar 2025 15:08:54 -0400 Subject: [PATCH 02/24] update examples to use globals and bump pymechanical version --- examples/00_tips/tips_01.py | 4 +- examples/00_tips/tips_02.py | 8 +- examples/00_tips/tips_03.py | 1 - examples/01_basic/bolt_pretension.py | 912 +++++++++++++++++---------- requirements/requirements_doc.txt | 4 +- 5 files changed, 588 insertions(+), 341 deletions(-) diff --git a/examples/00_tips/tips_01.py b/examples/00_tips/tips_01.py index a839fcb3..f04c42ee 100644 --- a/examples/00_tips/tips_01.py +++ b/examples/00_tips/tips_01.py @@ -17,11 +17,9 @@ # %% # Embed mechanical and set global variables -app = App() -app.update_globals(globals()) +app = App(globals=globals()) print(app) - # %% # Download and import geometry # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/examples/00_tips/tips_02.py b/examples/00_tips/tips_02.py index 20cdf760..901ca829 100644 --- a/examples/00_tips/tips_02.py +++ b/examples/00_tips/tips_02.py @@ -18,10 +18,10 @@ # %% # Embed Mechanical and set global variables -app = App(globals=globals()) +app = App() +app.update_globals(globals()) print(app) - # %% # Download and import geometry # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -32,7 +32,7 @@ # %% # Import geometry -geometry_import = Model.GeometryImportGroup.AddGeometryImport() +geometry_import = DataModel.Project.Model.GeometryImportGroup.AddGeometryImport() geometry_import.Import(geometry_path) # %% @@ -54,7 +54,7 @@ settings_720p.CurrentGraphicsDisplay = False # Rotate the geometry if needed -ExtAPI.Graphics.Camera.Rotate(180, CameraAxisType.ScreenY) +Graphics.Camera.Rotate(180, CameraAxisType.ScreenY) # %% diff --git a/examples/00_tips/tips_03.py b/examples/00_tips/tips_03.py index 4b003b58..44d9c682 100644 --- a/examples/00_tips/tips_03.py +++ b/examples/00_tips/tips_03.py @@ -20,7 +20,6 @@ app = App(globals=globals()) print(app) - # %% # Download the mechdb file # ~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/examples/01_basic/bolt_pretension.py b/examples/01_basic/bolt_pretension.py index 8b8e028d..9105cc53 100644 --- a/examples/01_basic/bolt_pretension.py +++ b/examples/01_basic/bolt_pretension.py @@ -14,188 +14,176 @@ # Import necessary libraries # ~~~~~~~~~~~~~~~~~~~~~~~~~~ -import os +from pathlib import Path from PIL import Image from ansys.mechanical.core import App from ansys.mechanical.core.examples import delete_downloads, download_file +import clr 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(globals=globals()) +# Create an instance of the Mechanical embedded application +app = App() 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() +# Import the enums and global variables instead of using app.update_globals(globals()) +# or App(globals=globals()) +from ansys.mechanical.core.embedding.enum_importer import * +from ansys.mechanical.core.embedding.imports import Transaction +clr.AddReference("System.Collections") +clr.AddReference("Ansys.ACT.WB1") +clr.AddReference("Ansys.Mechanical.DataModel") +import Ansys +from Ansys.Core.Units import Quantity # %% # 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) +# Set camera orientation +graphics = app.Graphics +camera = graphics.Camera +camera.SetSpecificViewOrientation(ViewOrientationType.Iso) +camera.SetFit() +camera.Rotate(180, CameraAxisType.ScreenY) + +# Set camera settings for 720p resolution +graphics_image_export_settings = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() +graphics_image_export_settings.Resolution = GraphicsResolutionType.EnhancedResolution +graphics_image_export_settings.Background = GraphicsBackgroundType.White +graphics_image_export_settings.CurrentGraphicsDisplay = False +graphics_image_export_settings.Width = 1280 +graphics_image_export_settings.Height = 720 # %% -# Download and import geometry -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Download the geometry file +# Set the geometry import group for the model +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -geometry_path = download_file( - "example_06_bolt_pret_geom.agdb", "pymechanical", "00_basic" -) - -# %% -# Import geometry +# Set the model +model = app.Model -geometry_import_group = Model.GeometryImportGroup +# Create a geometry import group for the model +geometry_import_group = model.GeometryImportGroup +# Add the geometry import to the group geometry_import = geometry_import_group.AddGeometryImport() +# Set the geometry import format geometry_import_format = ( Ansys.Mechanical.DataModel.Enums.GeometryImportPreference.Format.Automatic ) +# Set the geometry import preferences geometry_import_preferences = Ansys.ACT.Mechanical.Utilities.GeometryImportPreferences() geometry_import_preferences.ProcessNamedSelections = True + +# %% +# Download and import the geometry +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Download the geometry file from the ansys/example-data repository +geometry_path = download_file( + "example_06_bolt_pret_geom.agdb", "pymechanical", "00_basic" +) + +# Import/reload the geometry from the CAD (.agdb) file using the provided preferences geometry_import.Import( geometry_path, geometry_import_format, geometry_import_preferences ) # sphinx_gallery_start_ignore -assert str(geometry_import.ObjectState) == "Solved", "Geometry Import unsuccessful" +# Assert the geometry import was successful +assert geometry_import.ObjectState == ObjectState.Solved, "Geometry Import unsuccessful" # sphinx_gallery_end_ignore +# Visualize the model in 3D app.plot() - # %% # Download and import material # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Download materials -mat_Copper_file_path = download_file( +# Download the material files from the ansys/example-data repository +copper_material_file_path = download_file( "example_06_Mat_Copper.xml", "pymechanical", "00_basic" ) -mat_Steel_file_path = download_file( +steel_material_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) +# Add materials to the model and import the material files +model_materials = model.Materials +model_materials.Import(copper_material_file_path) +model_materials.Import(steel_material_file_path) # sphinx_gallery_start_ignore -assert str(MAT.ObjectState) == "FullyDefined", "Materials are not defined" +# Assert the materials are defined +assert ( + model_materials.ObjectState == ObjectState.FullyDefined +), "Materials are not defined" # sphinx_gallery_end_ignore # %% -# Define Analysis and unit system +# 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 +# Add static structural analysis to the model +model.AddStaticStructuralAnalysis() +static_structural = model.Analyses[0] +static_structural_solution = static_structural.Solution +static_structural_analysis_setting = static_structural.Children[0] -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 +named_selections_dictionary = {} +named_selections_list = [ + "block3_block2_cont", + "block3_block2_targ", + "shank_block3_cont", + "shank_block3_targ", + "block1_washer_cont", + "block1_washer_targ", + "washer_bolt_cont", + "washer_bolt_targ", + "shank_bolt_targ", + "shank_bolt_cont", + "block2_block1_cont", + "block2_block1_targ", ] -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" +# Get tree objects for each named selection +for named_selection in named_selections_list: + named_selections_dictionary[named_selection] = [ + tree_obj + for tree_obj in app.Tree.AllObjects + if tree_obj.Name == str(named_selection) + ][0] + +# Create dictionary with material assignment for each model.Geometry.Children index +children_materials = { + 0: "Steel", + 1: "Copper", + 2: "Copper", + 3: "Steel", + 4: "Steel", + 5: "Steel", +} + +# Assign surface materials to the model.Geometry bodies +geometry = model.Geometry +for children_index, material_name in children_materials.items(): + surface = geometry.Children[children_index].Children[0] + surface.Material = material_name # %% -# Define coordinate system -# ~~~~~~~~~~~~~~~~~~~~~~~~~ +# Add and define a coordinate system +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Add coordinate systems to the model +coordinate_systems = model.CoordinateSystems +coordinate_system = coordinate_systems.AddCoordinateSystem() -coordinate_system = CS_GRP.AddCoordinateSystem() +# Define the coordinate system coordinate_system.OriginDefineBy = CoordinateSystemAlignmentType.Fixed coordinate_system.OriginX = Quantity(-195, "mm") coordinate_system.OriginY = Quantity(100, "mm") @@ -203,161 +191,358 @@ def display_image(image_name): coordinate_system.PrimaryAxis = CoordinateSystemAxisType.PositiveZAxis # %% -# Define Contacts -# ~~~~~~~~~~~~~~~ -# Change contact settings - -# %% -# Delete existing contacts - -for connection in CONN_GRP.Children: +# Add and define contact regions +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +def set_contact_region_locations_and_types( + body: typing.Union[ + Ansys.ACT.Automation.Mechanical.Connections, + Ansys.ACT.Automation.Mechanical.Connections.ConnectionGroup, + ], + source_location: Ansys.ACT.Automation.Mechanical.NamedSelection, + target_location: Ansys.ACT.Automation.Mechanical.NamedSelection, + contact_type: ContactType, +) -> Ansys.ACT.Automation.Mechanical.Connections.ContactRegion: + """Add a contact region to the body with the specified source location, target location, + and contact type. + + Parameters + ---------- + body : Ansys.ACT.Automation.Mechanical.Connections or + Ansys.ACT.Automation.Mechanical.Connections.ConnectionGroup + The body to which the contact region will be added. + source_location : Ansys.ACT.Automation.Mechanical.NamedSelection + The source location for the contact region. + target_location : Ansys.ACT.Automation.Mechanical.NamedSelection + The target location for the contact region. + contact_type : ContactType + The type of contact for the contact region. + + Returns + ------- + Ansys.ACT.Automation.Mechanical.Connections.ContactRegion + The created contact region. + """ + contact_region = body.AddContactRegion() + contact_region.SourceLocation = source_location + contact_region.TargetLocation = target_location + contact_region.ContactType = contact_type + return contact_region + + +def advanced_contact_settings( + contact_region: Ansys.ACT.Automation.Mechanical.Connections.ContactRegion, + friction_coefficient: int, + small_sliding: ContactSmallSlidingType, + update_stiffness: UpdateContactStiffness, +) -> None: + """Set the friction coefficient, small sliding, and update stiffness settings for the + contact region. + + Parameters + ---------- + contact_region : Ansys.ACT.Automation.Mechanical.Connections.ContactRegion + The contact region to set the settings for. + friction_coefficient : int + The friction coefficient for the contact region. + small_sliding : ContactSmallSlidingType + The small sliding setting for the contact region. + update_stiffness : UpdateContactStiffness + The update stiffness setting for the contact region. + """ + contact_region.FrictionCoefficient = friction_coefficient + contact_region.SmallSliding = small_sliding + contact_region.UpdateStiffness = update_stiffness + + +def add_command_snippet( + contact_region: Ansys.ACT.Automation.Mechanical.Connections.ContactRegion, + archard_wear_model: str, +) -> None: + """Add a command snippet to the contact region with the specified Archard Wear Model. + + Parameters + ---------- + contact_region : Ansys.ACT.Automation.Mechanical.Connections.ContactRegion + The contact region to add the command snippet to. + archard_wear_model : str + The Archard Wear Model command snippet to add to the contact region. + """ + contact_region_cmd = contact_region.AddCommandSnippet() + contact_region_cmd.AppendText(archard_wear_model) + + +# Set up the model connections and delete the existing connections for ConnectionGroups +connections = model.Connections +for connection in connections.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 +# Set the archard wear model +archard_wear_model = """keyopt,cid,9,5 rmodif,cid,10,0.00 rmodif,cid,23,0.001""" -CMD6.AppendText(AWM6) -# %% -# Mesh -# ~~~~ +# Get named selections from the model for contact regions +named_selections = model.NamedSelections -Hex_Method = MSH.AddAutomaticMethod() -Hex_Method.Location = all_bodies -Hex_Method.Method = MethodType.Automatic +# Add a contact region for the model's named selections Children 0 and 1 with the specified +# contact type +contact_region = set_contact_region_locations_and_types( + body=connections, + source_location=named_selections.Children[0], + target_location=named_selections.Children[1], + contact_type=ContactType.Frictional, +) +# Set the friction coefficient, small sliding, and update stiffness settings for the contact region +advanced_contact_settings( + contact_region=contact_region, + friction_coefficient=0.2, + small_sliding=ContactSmallSlidingType.Off, + update_stiffness=UpdateContactStiffness.Never, +) +# Add a command snippet to the contact region with the specified Archard Wear Model +add_command_snippet(contact_region, archard_wear_model) + +# Set the connection group for the contact regions +connection_group = connections.Children[0] + +# Add a contact region for the model's named selections Children 2 and 3 with the specified +# contact type +contact_region_2 = set_contact_region_locations_and_types( + body=connection_group, + source_location=named_selections.Children[3], + target_location=named_selections.Children[2], + contact_type=ContactType.Bonded, +) +contact_region_2.ContactFormulation = ContactFormulation.MPC + +# Add a contact region for the model's named selections Children 4 and 5 with the specified +# contact type +contact_region_3 = set_contact_region_locations_and_types( + body=connection_group, + source_location=named_selections.Children[4], + target_location=named_selections.Children[5], + contact_type=ContactType.Frictional, +) +# Set the friction coefficient, small sliding, and update stiffness settings for the contact region +advanced_contact_settings( + contact_region=contact_region_3, + friction_coefficient=0.2, + small_sliding=ContactSmallSlidingType.Off, + update_stiffness=UpdateContactStiffness.Never, +) +# Add a command snippet to the contact region with the specified Archard Wear Model +add_command_snippet(contact_region_3, archard_wear_model) + +# Add a contact region for the model's named selections Children 6 and 7 with the specified +# contact type +contact_region_4 = set_contact_region_locations_and_types( + body=connection_group, + source_location=named_selections.Children[6], + target_location=named_selections.Children[7], + contact_type=ContactType.Bonded, +) +contact_region_4.ContactFormulation = ContactFormulation.MPC + +# Add a contact region for the model's named selections Children 8 and 9 with the specified +# contact type +contact_region_5 = set_contact_region_locations_and_types( + body=connection_group, + source_location=named_selections.Children[9], + target_location=named_selections.Children[8], + contact_type=ContactType.Bonded, +) +contact_region_5.ContactFormulation = ContactFormulation.MPC + +# Add a contact region for the model's named selections Children 10 and 11 with the specified +# contact type +contact_region_6 = set_contact_region_locations_and_types( + body=connection_group, + source_location=named_selections.Children[10], + target_location=named_selections.Children[11], + contact_type=ContactType.Frictional, +) +# Set the friction coefficient, small sliding, and update stiffness settings for the contact region +advanced_contact_settings( + contact_region=contact_region_6, + friction_coefficient=0.2, + small_sliding=ContactSmallSlidingType.Off, + update_stiffness=UpdateContactStiffness.Never, +) +# Add a command snippet to the contact region with the specified Archard Wear Model +add_command_snippet(contact_region_6, archard_wear_model) + +# %% +# Add mesh methods, sizing, and face meshing +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +def set_method_location(method, object_name: str, location_type: str = ""): + """Set the location of the method based on the specified name and location type.""" + # Get the tree object for the specified name + tree_obj_list = [ + tree_obj + for tree_obj in app.Tree.AllObjects + if tree_obj.Name == str(object_name) + ][0] + + # Set the method location based on the specified location type + if location_type == "source": + method.SourceLocation = tree_obj_list + elif location_type == "target": + method.TargetLocation = tree_obj_list + else: + method.Location = tree_obj_list + + +def add_mesh_sizing(mesh, object_name: str, element_size: Quantity): + """Add a mesh sizing to the mesh with the specified name, quantity value, and measurement.""" + # Add sizing to the mesh + body_sizing = mesh.AddSizing() + # Get the tree object for the specified name + body_sizing.Location = [ + tree_obj + for tree_obj in app.Tree.AllObjects + if tree_obj.Name == str(object_name) + ][0] + # Set the element size to the mesh + body_sizing.ElementSize = element_size + + +# Get the mesh for the model +mesh = model.Mesh +# Add the mesh sizing to the bodies_5 and shank objects +add_mesh_sizing(mesh=mesh, object_name="bodies_5", element_size=Quantity(15, "mm")) +add_mesh_sizing(mesh=mesh, object_name="shank", element_size=Quantity(7, "mm")) + +# Add an automatic method to the mesh and set the method type +hex_method = mesh.AddAutomaticMethod() +hex_method.Method = MethodType.Automatic +# Set the method location for the all_bodies object +set_method_location(method=hex_method, object_name="all_bodies") + +# Add face meshing to the mesh and set the MappedMesh property to False +face_meshing = mesh.AddFaceMeshing() +face_meshing.MappedMesh = False +# Set the method location for the face meshing +set_method_location(method=face_meshing, object_name="shank_face") + +# Add an automatic method to the mesh, set the method type, and set the source target selection +sweep_method = mesh.AddAutomaticMethod() +sweep_method.Method = MethodType.Sweep +sweep_method.SourceTargetSelection = 2 +# Set the method locations for the shank, shank_face, and shank_face2 objects +set_method_location(method=sweep_method, object_name="shank") +set_method_location( + method=sweep_method, object_name="shank_face", location_type="source" +) +set_method_location( + method=sweep_method, object_name="shank_face2", location_type="target" +) -BODY_SIZING1 = MSH.AddSizing() -BODY_SIZING1.Location = bodies_5 -BODY_SIZING1.ElementSize = Quantity(15, "mm") +# Activate and generate the mesh +mesh.Activate() +mesh.GenerateMesh() -BODY_SIZING2 = MSH.AddSizing() -BODY_SIZING2.Location = shank -BODY_SIZING2.ElementSize = Quantity(7, "mm") +# Fit the view to the entire model +camera.SetFit() +# Set the path for the output files (images, gifs, mechdat) +output_path = Path.cwd() / "out" +mesh_image_path = str(output_path / "mesh.png") +# Set the image export format and export the image +image_export_format = GraphicsImageExportFormat.PNG +graphics.ExportImage( + mesh_image_path, image_export_format, graphics_image_export_settings +) -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 +def display_image( + image_path: str, + pyplot_figsize_coordinates: tuple = (16, 9), + plot_xticks: list = [], + plot_yticks: list = [], + plot_axis: str = "off", +): + """Display the image with the specified parameters.""" + # Set the figure size based on the coordinates specified + plt.figure(figsize=pyplot_figsize_coordinates) + + # Read the image from the file into an array + 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() -MSH.Activate() -MSH.GenerateMesh() -Graphics.Camera.SetFit() -Graphics.ExportImage(os.path.join(cwd, "mesh.png"), image_export_format, settings_720p) -display_image("mesh.png") +# Display the mesh image +display_image(mesh_image_path) # %% # Analysis settings # ~~~~~~~~~~~~~~~~~ -STAT_STRUC_ANA_SETTING.NumberOfSteps = 4 +# Set the number of steps for the static structural analysis +static_structural_analysis_setting.NumberOfSteps = 4 + +# Set the step index list step_index_list = [1] +# Set the automatic time stepping method for the static structural analysis +# based on the step index with Transaction(): for step_index in step_index_list: - STAT_STRUC_ANA_SETTING.SetAutomaticTimeStepping( + static_structural_analysis_setting.SetAutomaticTimeStepping( step_index, AutomaticTimeStepping.Off ) -STAT_STRUC_ANA_SETTING.Activate() -step_index_list = [1] +# Activate the static structural analysis settings +static_structural_analysis_setting.Activate() +# Set the number of substeps for the static structural analysis +# based on the step index with Transaction(): for step_index in step_index_list: - STAT_STRUC_ANA_SETTING.SetNumberOfSubSteps(step_index, 2) + static_structural_analysis_setting.SetNumberOfSubSteps(step_index, 2) -STAT_STRUC_ANA_SETTING.Activate() -STAT_STRUC_ANA_SETTING.SolverType = SolverType.Direct -STAT_STRUC_ANA_SETTING.SolverPivotChecking = SolverPivotChecking.Off +# Activate the static structural analysis settings +static_structural_analysis_setting.Activate() + +# Set the solver type and solver pivoting check for the static structural analysis +static_structural_analysis_setting.SolverType = SolverType.Direct +static_structural_analysis_setting.SolverPivotChecking = SolverPivotChecking.Off # %% # Define loads and boundary conditions # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -FIX_SUP = STAT_STRUC.AddFixedSupport() -FIX_SUP.Location = block2_surface +# Add fixed support to the static structural analysis +fixed_support = static_structural.AddFixedSupport() +# Set the fixed support location for the block2_surface object +set_method_location(method=fixed_support, object_name="block2_surface") + +# Create a new force on the static structural analysis +tabular_force = static_structural.AddForce() +# Set the force location for the bottom_surface object +set_method_location(method=tabular_force, object_name="bottom_surface") -Tabular_Force = STAT_STRUC.AddForce() -Tabular_Force.Location = bottom_surface -Tabular_Force.DefineBy = LoadDefineBy.Components -Tabular_Force.XComponent.Inputs[0].DiscreteValues = [ +# Define the tabular force input and output components +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 = [ +tabular_force.XComponent.Output.DiscreteValues = [ Quantity("0[N]"), Quantity("0[N]"), Quantity("5.e+005[N]"), @@ -365,150 +550,215 @@ def display_image(image_name): Quantity("-5.e+005[N]"), ] -Bolt_Pretension = STAT_STRUC.AddBoltPretension() -Bolt_Pretension.Location = shank_surface -Bolt_Pretension.Preload.Inputs[0].DiscreteValues = [ +# Add a bolt presentation to the static structural analysis +bolt_presentation = static_structural.AddBoltPretension() +# Set the bolt presentation location for the shank_surface object +set_method_location(bolt_presentation, "shank_surface") + +# Define the bolt presentation input and output components +bolt_presentation.Preload.Inputs[0].DiscreteValues = [ Quantity("1[s]"), Quantity("2[s]"), Quantity("3[s]"), Quantity("4[s]"), ] -Bolt_Pretension.Preload.Output.DiscreteValues = [ +bolt_presentation.Preload.Output.DiscreteValues = [ Quantity("6.1363e+005[N]"), - Quantity("0 [N]"), - Quantity("0 [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) +bolt_presentation.SetDefineBy(2, BoltLoadDefineBy.Lock) +bolt_presentation.SetDefineBy(3, BoltLoadDefineBy.Lock) +bolt_presentation.SetDefineBy(4, BoltLoadDefineBy.Lock) + +# Activate the bolt presentation +app.Tree.Activate([bolt_presentation]) -Tree.Activate([Bolt_Pretension]) -Graphics.ExportImage( - os.path.join(cwd, "loads_and_boundaryconditions.png"), +# Set the image path for the loads and boundary conditions +loads_boundary_conditions_image_path = str( + output_path / "loads_boundary_conditions.png" +) +# Export the image of the loads and boundary conditions +graphics.ExportImage( + loads_boundary_conditions_image_path, image_export_format, - settings_720p, + graphics_image_export_settings, ) -display_image("loads_and_boundaryconditions.png") + +# Display the image of the loads and boundary conditions +display_image(loads_boundary_conditions_image_path) # %% # 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 +# Add a contact tool to the static structural solution and set the scoping method for it +post_contact_tool = static_structural_solution.AddContactTool() +post_contact_tool.ScopingMethod = GeometryDefineByType.Worksheet + +# Add a bolt tool to the static structural solution and add a working load to it +bolt_tool = static_structural_solution.AddBoltTool() +bolt_tool.AddWorkingLoad() + +# Add the total deformation to the static structural solution +total_deformation = static_structural_solution.AddTotalDeformation() + +# Add equivalent stress to the static structural solution +equivalent_stress_1 = static_structural_solution.AddEquivalentStress() + +# Add equivalent stress to the static structural solution and set the location for the shank object +equivalent_stress_2 = static_structural_solution.AddEquivalentStress() +set_method_location(method=equivalent_stress_2, object_name="shank") + +# Add a force reaction to the static structural solution and set the boundary condition selection +# to the fixed support +force_reaction_1 = static_structural_solution.AddForceReaction() +force_reaction_1.BoundaryConditionSelection = fixed_support + +# Add a moment reaction to the static structural solution and set the boundary condition selection +# to the fixed support +moment_reaction_2 = static_structural_solution.AddMomentReaction() +moment_reaction_2.BoundaryConditionSelection = fixed_support # %% -# Solve -# ~~~~~ +# Solve the static structural solution +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Solve the static structural solution and wait for it to finish +static_structural_solution.Solve(True) -STAT_STRUC_SOLN.Solve(True) -STAT_STRUC_SS = STAT_STRUC_SOLN.Status # sphinx_gallery_start_ignore -assert str(STAT_STRUC_SS) == "Done", "Solution status is not 'Done'" +# Assert the solution status is "Done" +assert ( + static_structural_solution.Status == SolutionStatusType.Done +), "Solution status is not 'Done'" # sphinx_gallery_end_ignore # %% -# Messages -# ~~~~~~~~ +# Print messages +# ~~~~~~~~~~~~~~ + +# Get messages from the application +messages = app.ExtAPI.Application.Messages -Messages = ExtAPI.Application.Messages -if Messages: - for message in Messages: +# Print messages with severity levels [Info], [Warning], and [Error] +if messages: + for message in messages: print(f"[{message.Severity}] {message.DisplayString}") else: - print("No [Info]/[Warning]/[Error] Messages") + print("No [Info]/[Warning]/[Error] messages") + # %% -# 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") +# Display the results +# ~~~~~~~~~~~~~~~~~~~ + +# Create a list with the total deformation, equivalent stress 1, and equivalent stress 2 objects +tree_obj_list = [total_deformation, equivalent_stress_1, equivalent_stress_2] + +# Activate each of the objects in the list and export and display the images +for tree_obj in tree_obj_list: + # Activate the object + app.Tree.Activate([tree_obj]) + # Set the camera to fit the model + camera.SetFit() + # Set the image name and path for the object + image_path = str(output_path / f"{tree_obj}.png") + # Export the image of the object + app.Graphics.ExportImage( + image_path, image_export_format, graphics_image_export_settings + ) + # Display the image of the object + display_image(image_path) # %% -# Equivalent stress on all bodies +# Export and display the contact status animation +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -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") +# Get the post contact tool status +post_contact_tool_status = post_contact_tool.Children[0] -# %% -# Equivalent stress on shank +# Activate the post contact tool status in the tree +app.Tree.Activate([post_contact_tool_status]) -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") +# Set the camera to fit the model +camera.SetFit() -# %% -# Export contact status animation +# Set the animation export format and settings +animation_export_format = GraphicsAnimationExportFormat.GIF +animation_export_settings = Ansys.Mechanical.Graphics.AnimationExportSettings() +animation_export_settings.Width = 1280 +animation_export_settings.Height = 720 -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 +# Set the path for the contact status GIF +contact_status_gif_path = str(output_path / "contact_status.gif") -Post_Contact_Tool_status.ExportAnimation( - os.path.join(cwd, "contact_status.gif"), animation_export_format, settings_720p +# Export the contact status animation to a GIF file +post_contact_tool_status.ExportAnimation( + contact_status_gif_path, animation_export_format, animation_export_settings ) -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] +def update_animation(frame: int) -> list[mpimg.AxesImage]: + """Update the animation frame for the GIF. + Parameters + ---------- + frame : int + The frame number to update the animation. -ani = FuncAnimation( - fig, update, frames=range(gif.n_frames), interval=200, repeat=True, blit=True + Returns + ------- + list[mpimg.AxesImage] + A list containing the updated image for the animation. + """ + # Seeks to the given frame in this sequence file + gif.seek(frame) + # Set the image array to the current frame of the GIF + image.set_data(gif.convert("RGBA")) + # Return the updated image + return [image] + + +# Open the GIF file and create an animation +gif = Image.open(contact_status_gif_path) +# Set the subplots for the animation and turn off the axis +figure, axes = plt.subplots(figsize=(8, 4)) +axes.axis("off") +# Change the color of the image +image = axes.imshow(gif.convert("RGBA")) + +# Create the animation using the figure, update_animation function, and the GIF frames +# Set the interval between frames to 200 milliseconds and repeat the animation +FuncAnimation( + figure, + update_animation, + frames=range(gif.n_frames), + interval=200, + repeat=True, + blit=True, ) + +# Show the animation plt.show() # %% -# Project tree -# ~~~~~~~~~~~~ +# Print the project tree +# ~~~~~~~~~~~~~~~~~~~~~~ app.print_tree() # %% -# Cleanup -# ~~~~~~~ -# Save project +# Clean up the project +# ~~~~~~~~~~~~~~~~~~~~ -app.save(os.path.join(cwd, "bolt_pretension.mechdat")) -app.new() +# Save the project +bolt_presentation_mechdat_path = str(output_path / "bolt_pretension.mechdat") +app.save(bolt_presentation_mechdat_path) -# %% -# Delete the example file +# Clear the project +app.new() +# Delete the example files delete_downloads() diff --git a/requirements/requirements_doc.txt b/requirements/requirements_doc.txt index ced4d7c5..ef9be155 100644 --- a/requirements/requirements_doc.txt +++ b/requirements/requirements_doc.txt @@ -1,3 +1,3 @@ #PyMechanical -ansys-mechanical-core[doc]==0.11.13 -ansys-mechanical-core[viz]==0.11.13 \ No newline at end of file +ansys-mechanical-core[doc]==0.11.14 +ansys-mechanical-core[viz]==0.11.14 \ No newline at end of file From c5643cf714ee147db47c862591881f462cb93d60 Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Mon, 31 Mar 2025 15:33:31 -0400 Subject: [PATCH 03/24] bump main version to 3.12 --- .github/workflows/ci_cd.yml | 2 +- .github/workflows/ci_cd_nightly.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci_cd.yml b/.github/workflows/ci_cd.yml index f313ba03..24c029ed 100644 --- a/.github/workflows/ci_cd.yml +++ b/.github/workflows/ci_cd.yml @@ -10,7 +10,7 @@ on: - main env: - MAIN_PYTHON_VERSION: '3.10' + MAIN_PYTHON_VERSION: '3.12' concurrency: group: ${{ github.workflow }}-${{ github.ref }} diff --git a/.github/workflows/ci_cd_nightly.yml b/.github/workflows/ci_cd_nightly.yml index b783c898..9b7f9acf 100644 --- a/.github/workflows/ci_cd_nightly.yml +++ b/.github/workflows/ci_cd_nightly.yml @@ -6,7 +6,7 @@ on: - cron: "0 3 * * *" env: - MAIN_PYTHON_VERSION: '3.10' + MAIN_PYTHON_VERSION: '3.12' DEV_MAJOR_REV: '25' DEV_MINOR_REV: '2' From 54d659ea9a83104fea83c54806fee77a2058617e Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Mon, 21 Apr 2025 10:14:37 -0400 Subject: [PATCH 04/24] fix Transaction import --- examples/01_basic/bolt_pretension.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/01_basic/bolt_pretension.py b/examples/01_basic/bolt_pretension.py index 9105cc53..e31c81e0 100644 --- a/examples/01_basic/bolt_pretension.py +++ b/examples/01_basic/bolt_pretension.py @@ -15,6 +15,7 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~~~ from pathlib import Path +import typing from PIL import Image from ansys.mechanical.core import App @@ -32,7 +33,7 @@ # Import the enums and global variables instead of using app.update_globals(globals()) # or App(globals=globals()) from ansys.mechanical.core.embedding.enum_importer import * -from ansys.mechanical.core.embedding.imports import Transaction +from ansys.mechanical.core.embedding.transaction import Transaction clr.AddReference("System.Collections") clr.AddReference("Ansys.ACT.WB1") From 63275c12d0636bc9fe7dc3d600d8756a6d850b18 Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Mon, 21 Apr 2025 16:54:56 -0400 Subject: [PATCH 05/24] update fracture_analysis_contact_debonding example --- examples/00_tips/tips_02.py | 4 +- .../fracture_analysis_contact_debonding.py | 735 +++++++++++------- 2 files changed, 450 insertions(+), 289 deletions(-) diff --git a/examples/00_tips/tips_02.py b/examples/00_tips/tips_02.py index 901ca829..6c1ad89c 100644 --- a/examples/00_tips/tips_02.py +++ b/examples/00_tips/tips_02.py @@ -32,7 +32,7 @@ # %% # Import geometry -geometry_import = DataModel.Project.Model.GeometryImportGroup.AddGeometryImport() +geometry_import = Model.GeometryImportGroup.AddGeometryImport() geometry_import.Import(geometry_path) # %% @@ -40,7 +40,7 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Orientation -Graphics.Camera.SetSpecificViewOrientation(ViewOrientationType.Iso) +ExtAPI.Graphics.Camera.SetSpecificViewOrientation(ViewOrientationType.Iso) # Export format image_export_format = GraphicsImageExportFormat.PNG diff --git a/examples/01_basic/fracture_analysis_contact_debonding.py b/examples/01_basic/fracture_analysis_contact_debonding.py index 25461b4b..16e90554 100644 --- a/examples/01_basic/fracture_analysis_contact_debonding.py +++ b/examples/01_basic/fracture_analysis_contact_debonding.py @@ -13,7 +13,7 @@ # Import necessary libraries # ~~~~~~~~~~~~~~~~~~~~~~~~~~ -import os +from pathlib import Path from PIL import Image from ansys.mechanical.core import App @@ -23,412 +23,573 @@ from matplotlib.animation import FuncAnimation # %% -# Embed mechanical and set global variables +# Create an instance of the Mechanical embedded application with global variables +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ app = App(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() - - # %% -# Configure graphics for image export -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Configure camera and graphics for image export +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Graphics.Camera.SetSpecificViewOrientation(ViewOrientationType.Front) +# Set camera orientation +graphics = app.Graphics +camera = graphics.Camera +camera.SetSpecificViewOrientation(ViewOrientationType.Front) + +# Set camera settings for 720p resolution 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_image_export_settings = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() +graphics_image_export_settings.Resolution = GraphicsResolutionType.EnhancedResolution +graphics_image_export_settings.Background = GraphicsBackgroundType.White +graphics_image_export_settings.CurrentGraphicsDisplay = False +graphics_image_export_settings.Width = 1280 +graphics_image_export_settings.Height = 720 # %% -# Download geometry and materials files -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -geometry_path = download_file( - "Contact_Debonding_Example.agdb", "pymechanical", "embedding" -) -mat1_path = download_file( - "Contact_Debonding_Example_Mat1.xml", "pymechanical", "embedding" -) -mat2_path = download_file( - "Contact_Debonding_Example_Mat2.xml", "pymechanical", "embedding" -) +# Set the image output path and create functions to fit the camera and display images +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Set the path for the output files (images, gifs, mechdat) +output_path = Path.cwd() / "out" + + +def set_camera_and_display_image( + camera: Ansys.ACT.Common.Graphics.MechanicalCameraWrapper, + graphics: Ansys.ACT.Common.Graphics.MechanicalGraphicsWrapper, + image_output_path: Path, + image_name: str, +) -> None: + """Set the camera to fit the model and display the image. + + Parameters + ---------- + camera : Ansys.ACT.Common.Graphics.MechanicalCameraWrapper + The camera object to set the view. + graphics : Ansys.ACT.Common.Graphics.MechanicalGraphicsWrapper + The graphics object to export the image. + image_output_path : Path + The path to save the exported image. + image_name : str + The name of the exported image file. + """ + # Set the camera to fit the mesh + camera.SetFit() + # Export the mesh image with the specified settings + image_path = image_output_path / image_name + graphics.ExportImage( + str(image_path), image_export_format, graphics_image_export_settings + ) + # Display the exported mesh image + display_image(image_path) + + +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 + 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() # %% # Import the geometry # ~~~~~~~~~~~~~~~~~~~ -geometry_import = Model.GeometryImportGroup.AddGeometryImport() +# Set the model +model = app.Model +# Create a geometry import group for the model +geometry_import_group = model.GeometryImportGroup +# Add the geometry import to the group +geometry_import = geometry_import_group.AddGeometryImport() +# Set the geometry import format geometry_import_format = ( Ansys.Mechanical.DataModel.Enums.GeometryImportPreference.Format.Automatic ) +# Set the geometry import preferences geometry_import_preferences = Ansys.ACT.Mechanical.Utilities.GeometryImportPreferences() geometry_import_preferences.ProcessNamedSelections = True geometry_import_preferences.AnalysisType = ( Ansys.Mechanical.DataModel.Enums.GeometryImportPreference.AnalysisType.Type2D ) + +# Download the geometry file from the ansys/example-data repository +geometry_path = download_file( + "Contact_Debonding_Example.agdb", "pymechanical", "embedding" +) + +# Import/reload the geometry from the CAD (.agdb) file using the provided preferences geometry_import.Import( geometry_path, geometry_import_format, geometry_import_preferences ) +# Visualize the model in 3D app.plot() # %% # Material import, named selections, and connections # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Import materials - -MODEL = Model -GEOMETRY = Model.Geometry -MAT_GRP = MODEL.Materials -MAT_GRP.Import(mat1_path) -MAT_GRP.Import(mat2_path) - -PART = [x for x in Tree.AllObjects if x.Name == "Part 2"][0] -MAT_BODY = [ - i - for i in MAT_GRP.GetChildren[Ansys.ACT.Automation.Mechanical.Material](True) - if i.Name == "Interface Body Material" -][0] -MAT_CZM = [ - i - for i in MAT_GRP.GetChildren[Ansys.ACT.Automation.Mechanical.Material](True) - if i.Name == "CZM Crack Material" -][0] -# %% -# Connections - -connections = MODEL.AddConnections() -CONNECTIONS_GRP = connections.AddConnectionGroup() -MODEL.Connections.CreateAutomaticConnections() -CONNECTIONS_GRP = Model.Connections -CONTACTS = [ - i - for i in CONNECTIONS_GRP.GetChildren[ - Ansys.ACT.Automation.Mechanical.Connections.ConnectionGroup - ](True) - if i.Name == "Contacts" -][0] -CONTACT_REGION = [ - i - for i in CONTACTS.GetChildren[ - Ansys.ACT.Automation.Mechanical.Connections.ContactRegion - ](True) - if i.Name == "Contact Region" -][0] +# Download the material files from the ansys/example-data repository +mat1_path = download_file( + "Contact_Debonding_Example_Mat1.xml", "pymechanical", "embedding" +) +mat2_path = download_file( + "Contact_Debonding_Example_Mat2.xml", "pymechanical", "embedding" +) + +# Add materials to the model and import the material files +model_materials = model.Materials +model_materials.Import(mat1_path) +model_materials.Import(mat2_path) # %% -# Named selections - -NAMED_SELECTIONS = Model.NamedSelections -NS_EDGE_HIGH = [ - i - for i in NAMED_SELECTIONS.GetChildren[ - Ansys.ACT.Automation.Mechanical.NamedSelection - ](True) - if i.Name == "High_Edge" -][0] -NS_EDGE_LOW = [ - i - for i in NAMED_SELECTIONS.GetChildren[ - Ansys.ACT.Automation.Mechanical.NamedSelection - ](True) - if i.Name == "Low_Edge" -][0] -NS_EDGES_SHORT = [ - i - for i in NAMED_SELECTIONS.GetChildren[ - Ansys.ACT.Automation.Mechanical.NamedSelection - ](True) - if i.Name == "Short_Edges" -][0] -NS_EDGES_LONG = [ - i - for i in NAMED_SELECTIONS.GetChildren[ - Ansys.ACT.Automation.Mechanical.NamedSelection - ](True) - if i.Name == "Long_Edges" -][0] -NS_EDGES_FIXED = [ - i - for i in NAMED_SELECTIONS.GetChildren[ - Ansys.ACT.Automation.Mechanical.NamedSelection - ](True) - if i.Name == "Fixed_Edges" -][0] -NS_VERTEX_DISP1 = [ - i - for i in NAMED_SELECTIONS.GetChildren[ - Ansys.ACT.Automation.Mechanical.NamedSelection - ](True) - if i.Name == "Disp1_Vertex" -][0] -NS_VERTEX_DISP2 = [ - i - for i in NAMED_SELECTIONS.GetChildren[ - Ansys.ACT.Automation.Mechanical.NamedSelection - ](True) - if i.Name == "Disp2_Vertex" -][0] -NS_FACES_BOTH = [ - i - for i in NAMED_SELECTIONS.GetChildren[ - Ansys.ACT.Automation.Mechanical.NamedSelection - ](True) - if i.Name == "Both_Faces" -][0] +# Add automatic connections to the model +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Add connections to the model +add_connections = model.AddConnections() +# Add a connection group to the connections +add_connections.AddConnectionGroup() + +# Define and create automatic connections for the model +connections = model.Connections +connections.CreateAutomaticConnections() # %% -# Define static structural analysis and settings -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Define the static structural analysis and settings +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -MODEL.AddStaticStructuralAnalysis() -STATIC_STRUCTURAL = DataModel.AnalysisByName("Static Structural") -ANALYSIS_SETTINGS = STATIC_STRUCTURAL.AnalysisSettings -SOLUTION = STATIC_STRUCTURAL.Solution -MESH = Model.Mesh +# Add a static structural analysis to the model +model.AddStaticStructuralAnalysis() +static_structural_analysis = app.DataModel.AnalysisByName("Static Structural") +static_structural_analysis_solution = static_structural_analysis.Solution -# Set unit system +# Set the unit system +app.ExtAPI.Application.ActiveUnitSystem = MechanicalUnitSystem.StandardNMM -ExtAPI.Application.ActiveUnitSystem = MechanicalUnitSystem.StandardNMM +# %% +# Define the geometry, activate it, and set the 2D behavior +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Set 2D behavior +# Define the geometry for the model +geometry = model.Geometry +# Activate the geometry +geometry.Activate() +# Set the 2D behavior for the geometry +geometry.Model2DBehavior = Model2DBehavior.PlaneStrain -GEOMETRY.Activate() -GEOMETRY.Model2DBehavior = Model2DBehavior.PlaneStrain -# Assign material +# Create a function to get the child object by name +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -PART.Activate() -PART.Material = MAT_BODY.Name -# Define contact Region +def get_child_object(body, child_type, name: str): + """Get the named selection child by name.""" + return [ + child for child in body.GetChildren[child_type](True) if child.Name == name + ][0] -CONTACT_REGION.Activate() -CONTACT_REGION.SourceLocation = NS_EDGE_HIGH -CONTACT_REGION.TargetLocation = NS_EDGE_LOW -CONTACT_REGION.ContactType = ContactType.Bonded -CONTACT_REGION.ContactFormulation = ContactFormulation.PurePenalty # %% -# Define mesh controls and generate mesh -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Get the Part 2 object from the tree, activate it, and set the material +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -MESH.Activate() -MESH.ElementOrder = ElementOrder.Quadratic -MESH.UseAdaptiveSizing = False -MESH.ElementSize = Quantity("0.75 [mm]") +# Get the Part 2 object from the tree +part2_object = [ + tree_obj for tree_obj in app.Tree.AllObjects if tree_obj.Name == "Part 2" +][0] -SIZING_MESH = MESH.AddSizing() -SIZING_MESH.Location = NS_EDGES_SHORT -SIZING_MESH.ElementSize = Quantity("0.75 [mm]") -SIZING_MESH.Behavior = SizingBehavior.Hard +# Activate the Part 2 object +part2_object.Activate() -SIZING_MESH2 = MESH.AddSizing() -SIZING_MESH2.Location = NS_EDGES_LONG -SIZING_MESH2.ElementSize = Quantity("0.5 [mm]") -SIZING_MESH2.Behavior = SizingBehavior.Hard +# Set the material for the Part 2 object +part2_object.Material = get_child_object( + model_materials, Ansys.ACT.Automation.Mechanical.Material, "Interface Body Material" +).Name + +# %% Define the contact and contact regions +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Get the contact from the connection group +contact = get_child_object( + connections, Ansys.ACT.Automation.Mechanical.Connections.ConnectionGroup, "Contacts" +) + +# Get the contact region from the contact +contact_region = get_child_object( + contact, Ansys.ACT.Automation.Mechanical.Connections.ContactRegion, "Contact Region" +) +# Activate the contact region +contact_region.Activate() + +# Define the model named selections +named_selections = model.NamedSelections +# Set the source location to the high edge named selection +contact_region.SourceLocation = get_child_object( + named_selections, Ansys.ACT.Automation.Mechanical.NamedSelection, "High_Edge" +) +# Set the target location to the low edge named selection` +contact_region.TargetLocation = get_child_object( + named_selections, Ansys.ACT.Automation.Mechanical.NamedSelection, "Low_Edge" +) +# Set the contact type to bonded +contact_region.ContactType = ContactType.Bonded +# Set the contact formulation to pure penalty +contact_region.ContactFormulation = ContactFormulation.PurePenalty -FACE_MESHING = MESH.AddFaceMeshing() -FACE_MESHING.Location = NS_FACES_BOTH -FACE_MESHING.Method = FaceMeshingMethod.Quadrilaterals +# %% +# Define the mesh controls and generate mesh +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Define the mesh for the model +mesh = model.Mesh + +# Activate the mesh +mesh.Activate() + +# Set the mesh element order to quadratic +mesh.ElementOrder = ElementOrder.Quadratic +# Turn off adaptive sizing +mesh.UseAdaptiveSizing = False +# Set the mesh element size to 0.75 mm +mesh.ElementSize = Quantity("0.75 [mm]") + + +def add_sizing( + mesh: Ansys.ACT.Automation.Mechanical.MeshControls.Mesh, + name: str, + element_size: Ansys.Core.Units.Quantity, + behavior: Ansys.Mechanical.DataModel.Enums.SizingBehavior, +) -> None: + """Add sizing to the mesh and set its location, element size, and behavior. + + Parameters + ---------- + mesh : Ansys.ACT.Automation.Mechanical.MeshControls.Mesh + The mesh object to add sizing to. + name : str + The name of the named selection to use for sizing. + element_size : Ansys.Core.Units.Quantity + The element size to set for the sizing. + behavior : Ansys.Mechanical.DataModel.Enums.SizingBehavior + The behavior of the sizing (e.g., hard or soft). + """ + sizing = mesh.AddSizing() + sizing.Location = get_child_object( + named_selections, Ansys.ACT.Automation.Mechanical.NamedSelection, name + ) + sizing.ElementSize = element_size + sizing.Behavior = behavior + + +# Add sizing to the mesh for the short and long edges +add_sizing(mesh, "Short_Edges", Quantity("0.75 [mm]"), SizingBehavior.Hard) +add_sizing(mesh, "Long_Edges", Quantity("0.5 [mm]"), SizingBehavior.Hard) + +# Add sizing to the mesh for both faces +sizing_mesh_both_faces = mesh.AddFaceMeshing() +sizing_mesh_both_faces.Location = get_child_object( + named_selections, Ansys.ACT.Automation.Mechanical.NamedSelection, "Both_Faces" +) +# Set the face meshing method to quadrilaterals +sizing_mesh_both_faces.Method = FaceMeshingMethod.Quadrilaterals -MESH.Activate() -MESH.GenerateMesh() +# Activate and generate the mesh +mesh.Activate() +mesh.GenerateMesh() -Graphics.Camera.SetFit() -Graphics.ExportImage(os.path.join(cwd, "mesh.png"), image_export_format, settings_720p) -display_image("mesh.png") +# Display the mesh image +set_camera_and_display_image(camera, graphics, output_path, "mesh.png") # %% # Add contact debonding object # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -MODEL.Activate() -FRACTURE = MODEL.AddFracture() +# Activate the model +model.Activate() + +# Add a fracture to the model +fracture = model.AddFracture() -CONTACT_DEBONDING = FRACTURE.AddContactDebonding() -CONTACT_DEBONDING.Material = MAT_CZM.Name -CONTACT_DEBONDING.ContactRegion = CONTACT_REGION +# Add contact debonding to the fracture +contact_debonding = fracture.AddContactDebonding() +# Set the material for the contact debonding +contact_debonding.Material = get_child_object( + model_materials, Ansys.ACT.Automation.Mechanical.Material, "CZM Crack Material" +).Name +# Set the contact region for the contact debonding +contact_debonding.ContactRegion = contact_region # %% -# Define analysis settings -# ~~~~~~~~~~~~~~~~~~~~~~~~ +# Define the static structural analysis settings +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -ANALYSIS_SETTINGS.Activate() -ANALYSIS_SETTINGS.AutomaticTimeStepping = AutomaticTimeStepping.On -ANALYSIS_SETTINGS.DefineBy = TimeStepDefineByType.Substeps -ANALYSIS_SETTINGS.MaximumSubsteps = 100 -ANALYSIS_SETTINGS.InitialSubsteps = 100 -ANALYSIS_SETTINGS.MinimumSubsteps = 100 -ANALYSIS_SETTINGS.LargeDeflection = True +# Define the static structural analysis settings +analysis_settings = static_structural_analysis.AnalysisSettings +# Activate the analysis settings +analysis_settings.Activate() +# Turn on automatic time stepping +analysis_settings.AutomaticTimeStepping = AutomaticTimeStepping.On +# Define the time step settings with substeps +analysis_settings.DefineBy = TimeStepDefineByType.Substeps +# Set the initial, minimum, and maximum time step sizes +analysis_settings.InitialSubsteps = 100 +analysis_settings.MinimumSubsteps = 100 +analysis_settings.MaximumSubsteps = 100 +# Turn on large deflection +analysis_settings.LargeDeflection = True # %% # Define boundary conditions # ~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Add fixed support -STATIC_STRUCTURAL.Activate() -FIXED_SUPPORT = STATIC_STRUCTURAL.AddFixedSupport() -FIXED_SUPPORT.Location = NS_EDGES_FIXED +# Activate the static structural analysis +static_structural_analysis.Activate() -# %% -# Add displacement - -STATIC_STRUCTURAL.Activate() -DISPLACEMENT = STATIC_STRUCTURAL.AddDisplacement() -DISPLACEMENT.Location = NS_VERTEX_DISP1 -DISPLACEMENT.DefineBy = LoadDefineBy.Components -DISPLACEMENT.YComponent.Output.DiscreteValues = [Quantity("10 [mm]")] +# Add fixed support to the static structural analysis +fixed_support = static_structural_analysis.AddFixedSupport() +# Set the fixed support location to the fixed edges named selection +fixed_support.Location = get_child_object( + named_selections, Ansys.ACT.Automation.Mechanical.NamedSelection, "Fixed_Edges" +) -STATIC_STRUCTURAL.Activate() -DISPLACEMENT2 = STATIC_STRUCTURAL.AddDisplacement() -DISPLACEMENT2.Location = NS_VERTEX_DISP2 -DISPLACEMENT2.DefineBy = LoadDefineBy.Components -DISPLACEMENT2.YComponent.Output.DiscreteValues = [Quantity("-10 [mm]")] +# %% +# Add displacements to the static structural analysis +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +def add_displacement( + static_structural_analysis: Ansys.ACT.Automation.Mechanical.Analysis, + named_selections: Ansys.ACT.Automation.Mechanical.NamedSelections, + name: str, + y_component_value: Ansys.Core.Units.Quantity, +) -> None: + """Add a displacement to the static structural analysis. + + Parameters + ---------- + static_structural_analysis : Ansys.ACT.Automation.Mechanical.Analysis + The static structural analysis object. + named_selections : Ansys.ACT.Automation.Mechanical.NamedSelections + The named selections object. + name : str + The name of the named selection to use for displacement. + y_component_value : str + The value of the Y component for the displacement. + """ + # Activate the static structural analysis + static_structural_analysis.Activate() + # Add a displacement to the static structural analysis + displacement = static_structural_analysis.AddDisplacement() + # Set the location for the displacement to the named selection with the given name + displacement.Location = get_child_object( + named_selections, Ansys.ACT.Automation.Mechanical.NamedSelection, name + ) + # Set the displacement type to components + displacement.DefineBy = LoadDefineBy.Components + # Set the value of the Y component for the displacement + displacement.YComponent.Output.DiscreteValues = [y_component_value] + + return displacement + + +# Add displacement to the static structural analysis +displacement1_vertex = add_displacement( + static_structural_analysis, named_selections, "Disp1_Vertex", Quantity("10 [mm]") +) +# Add another displacement to the static structural analysis +displacement2_vertex = add_displacement( + static_structural_analysis, named_selections, "Disp2_Vertex", Quantity("-10 [mm]") +) -STATIC_STRUCTURAL.Activate() +# Activate the static structural analysis +static_structural_analysis.Activate() -Graphics.Camera.SetFit() -Graphics.ExportImage( - os.path.join(cwd, "boundary_conditions.png"), image_export_format, settings_720p -) -display_image("boundary_conditions.png") +# Set the camera to fit the model and display the image of the boundary conditions +set_camera_and_display_image(camera, graphics, output_path, "boundary_conditions.png") # %% -# Add results -# ~~~~~~~~~~~ +# Add directional deformation and force reaction results to the solution +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Activate the static structural analysis solution +static_structural_analysis_solution.Activate() -SOLUTION.Activate() -DIRECTIONAL_DEFORMATION = SOLUTION.AddDirectionalDeformation() -DIRECTIONAL_DEFORMATION.NormalOrientation = NormalOrientationType.YAxis +# Add directional deformation to the static structural analysis solution +directional_deformation = ( + static_structural_analysis_solution.AddDirectionalDeformation() +) +# Set the orientation of the directional deformation to Y-axis +directional_deformation.NormalOrientation = NormalOrientationType.YAxis -FORCE_REACTION = SOLUTION.AddForceReaction() -FORCE_REACTION.BoundaryConditionSelection = DISPLACEMENT +# Add the force reaction to the static structural analysis solution +force_reaction = static_structural_analysis_solution.AddForceReaction() +# Set the boundary condition selection to the vertex named selection +force_reaction.BoundaryConditionSelection = displacement1_vertex # %% -# Solve -# ~~~~~ +# Activate the static structural analysis and solve the solution +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -STATIC_STRUCTURAL.Activate() -SOLUTION.Solve(True) +static_structural_analysis.Activate() +static_structural_analysis_solution.Solve(True) # sphinx_gallery_start_ignore -assert str(SOLUTION.Status) == "Done", "Solution status is not 'Done'" +assert ( + str(static_structural_analysis_solution.Status) == "Done" +), "Solution status is not 'Done'" # sphinx_gallery_end_ignore # %% # Messages # ~~~~~~~~ -Messages = ExtAPI.Application.Messages -if Messages: - for message in Messages: +messages = app.ExtAPI.Application.Messages +if messages: + for message in messages: print(f"[{message.Severity}] {message.DisplayString}") else: print("No [Info]/[Warning]/[Error] Messages") # %% -# Display results -# ~~~~~~~~~~~~~~~ -# Directional deformation - -DIRECTIONAL_DEFORMATION.Activate() - -Graphics.ExportImage( - os.path.join(cwd, "directional_deformation.png"), image_export_format, settings_720p +# Activate the directional deformation and force reactions and display their images +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Activate the directional deformation +directional_deformation.Activate() +# Set the camera to fit the model and display the image of the directional deformation +set_camera_and_display_image( + camera, graphics, output_path, "directional_deformation.png" ) -display_image("directional_deformation.png") -# %% -# Force reaction - -FORCE_REACTION.Activate() - -Graphics.Camera.SetFit() -Graphics.ExportImage( - os.path.join(cwd, "force_reaction.png"), image_export_format, settings_720p -) -display_image("force_reaction.png") +# Activate the force reaction +force_reaction.Activate() +# Set the camera to fit the model and display the image of the force reaction +set_camera_and_display_image(camera, graphics, output_path, "force_reaction.png") # %% # Export animation # ~~~~~~~~~~~~~~~~ -animation_export_format = ( - Ansys.Mechanical.DataModel.Enums.GraphicsAnimationExportFormat.GIF -) -settings_720p = Ansys.Mechanical.Graphics.AnimationExportSettings() -settings_720p.Width = 1280 -settings_720p.Height = 720 +# Set the animation export format and settings +animation_export_format = GraphicsAnimationExportFormat.GIF +animation_export_settings = Ansys.Mechanical.Graphics.AnimationExportSettings() +animation_export_settings.Width = 1280 +animation_export_settings.Height = 720 -FORCE_REACTION.ExportAnimation( - os.path.join(cwd, "force_reaction.gif"), animation_export_format, settings_720p +# Set the path for the contact status GIF +force_reaction_gif_path = output_path / "force_reaction.gif" + +# Export the force reaction animation to a GIF file +force_reaction.ExportAnimation( + str(force_reaction_gif_path), animation_export_format, animation_export_settings ) -gif = Image.open(os.path.join(cwd, "force_reaction.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] +def update_animation(frame: int) -> list[mpimg.AxesImage]: + """Update the animation frame for the GIF. + Parameters + ---------- + frame : int + The frame number to update the animation. -ani = FuncAnimation( - fig, update, frames=range(gif.n_frames), interval=100, repeat=True, blit=True + Returns + ------- + list[mpimg.AxesImage] + A list containing the updated image for the animation. + """ + # Seeks to the given frame in this sequence file + gif.seek(frame) + # Set the image array to the current frame of the GIF + image.set_data(gif.convert("RGBA")) + # Return the updated image + return [image] + + +# Open the GIF file and create an animation +gif = Image.open(force_reaction_gif_path) +# Set the subplots for the animation and turn off the axis +figure, axes = plt.subplots(figsize=(16, 9)) +axes.axis("off") +# Change the color of the image +image = axes.imshow(gif.convert("RGBA")) + +# Create the animation using the figure, update_animation function, and the GIF frames +# Set the interval between frames to 200 milliseconds and repeat the animation +FuncAnimation( + figure, + update_animation, + frames=range(gif.n_frames), + interval=100, + repeat=True, + blit=True, ) + +# Show the animation plt.show() # %% -# Display output file from solve -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Display output file from the solve +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Get the working directory for the static structural analysis +solve_path = Path(static_structural_analysis.WorkingDir) +# Get the solve output path +solve_out_path = solve_path / "solve.out" -def write_file_contents_to_console(path): - """Write file contents to console.""" - with open(path, "rt") as file: +# Print the content of the solve output file if it exists +if solve_out_path: + with solve_out_path.open("rt") as file: for line in file: print(line, end="") - -solve_path = STATIC_STRUCTURAL.WorkingDir -solve_out_path = os.path.join(solve_path, "solve.out") -if solve_out_path: - write_file_contents_to_console(solve_out_path) - # %% -# Project tree -# ~~~~~~~~~~~~ +# Print the project tree +# ~~~~~~~~~~~~~~~~~~~~~~ app.print_tree() # %% -# Cleanup -# ~~~~~~~ -# Save project +# Clean up the project +# ~~~~~~~~~~~~~~~~~~~~ -app.save(os.path.join(cwd, "contact_debonding.mechdat")) -app.new() +# Save the project +mechdat_path = output_path / "contact_debonding.mechdat" +app.save(str(mechdat_path)) -# %% -# Delete example files +# Clear the project +app.new() +# Delete the example files delete_downloads() From b74f7c1c94f2152eb50bbeef58fad07a0dc666e7 Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Tue, 22 Apr 2025 13:28:42 -0400 Subject: [PATCH 06/24] update harmonic acoustics example --- examples/01_basic/harmonic_acoustics.py | 789 ++++++++++++++---------- 1 file changed, 467 insertions(+), 322 deletions(-) diff --git a/examples/01_basic/harmonic_acoustics.py b/examples/01_basic/harmonic_acoustics.py index 52839662..72e402ce 100644 --- a/examples/01_basic/harmonic_acoustics.py +++ b/examples/01_basic/harmonic_acoustics.py @@ -13,7 +13,7 @@ # Import necessary libraries # ~~~~~~~~~~~~~~~~~~~~~~~~~~ -import os +from pathlib import Path from PIL import Image from ansys.mechanical.core import App @@ -28,15 +28,80 @@ app = App(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") +# %% +# Set the image output path and create functions to fit the camera and display images +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Set the path for the output files (images, gifs, mechdat) +output_path = Path.cwd() / "out" + + +def set_camera_and_display_image( + camera: Ansys.ACT.Common.Graphics.MechanicalCameraWrapper, + graphics: Ansys.ACT.Common.Graphics.MechanicalGraphicsWrapper, + graphics_image_export_settings: Ansys.Mechanical.Graphics.GraphicsImageExportSettings, + image_output_path: Path, + image_name: str, +) -> None: + """Set the camera to fit the model and display the image. + + Parameters + ---------- + camera : Ansys.ACT.Common.Graphics.MechanicalCameraWrapper + The camera object to set the view. + graphics : Ansys.ACT.Common.Graphics.MechanicalGraphicsWrapper + The graphics object to export the image. + graphics_image_export_settings : Ansys.Mechanical.Graphics.GraphicsImageExportSettings + The settings for exporting the image. + image_output_path : Path + The path to save the exported image. + image_name : str + The name of the exported image file. + """ + # Set the camera to fit the mesh + camera.SetFit() + # Export the mesh image with the specified settings + image_path = image_output_path / image_name + graphics.ExportImage( + str(image_path), image_export_format, graphics_image_export_settings + ) + # Display the exported mesh image + display_image(image_path) + + +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 + 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() @@ -44,7 +109,10 @@ def display_image(image_name): # Configure graphics for image export # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Graphics.Camera.SetSpecificViewOrientation(ViewOrientationType.Iso) +graphics = app.Graphics +camera = graphics.Camera + +camera.SetSpecificViewOrientation(ViewOrientationType.Iso) image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() settings_720p.Resolution = GraphicsResolutionType.EnhancedResolution @@ -52,337 +120,389 @@ def display_image(image_name): settings_720p.Width = 1280 settings_720p.Height = 720 settings_720p.CurrentGraphicsDisplay = False -Graphics.Camera.Rotate(180, CameraAxisType.ScreenY) - -# %% -# Download geometry and materials files -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -geometry_path = download_file("C_GEOMETRY.agdb", "pymechanical", "embedding") -mat_path = download_file("Air-material.xml", "pymechanical", "embedding") +camera.Rotate(180, CameraAxisType.ScreenY) # %% # Import the geometry # ~~~~~~~~~~~~~~~~~~~ -geometry_import = Model.GeometryImportGroup.AddGeometryImport() +model = app.Model +geometry_import = model.GeometryImportGroup.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_path = download_file("C_GEOMETRY.agdb", "pymechanical", "embedding") geometry_import.Import( geometry_path, geometry_import_format, geometry_import_preferences ) +# %% +# Set specified model geometry children to suppressed -GEOM = Model.Geometry - -solid1 = GEOM.Children[0] -solid2 = GEOM.Children[1] -solid3 = GEOM.Children[2] -solid4 = GEOM.Children[3] -solid5 = GEOM.Children[4] -solid6 = GEOM.Children[5] -solid7 = GEOM.Children[6] -solid8 = GEOM.Children[7] -solid9 = GEOM.Children[8] -solid10 = GEOM.Children[9] -solid11 = GEOM.Children[10] - -solid1.Suppressed = True -solid2.Suppressed = True -solid3.Suppressed = True -solid4.Suppressed = True -solid5.Suppressed = True -solid7.Suppressed = True -solid10.Suppressed = True -solid11.Suppressed = True - +# Define the geometry +geometry = model.Geometry +# Set which geometry children to suppress +suppressed_solids = [1, 2, 3, 4, 5, 7, 10, 11] +# Loop through the geometry children and suppress the specified ones +for child in range(geometry.Children.Count): + solid = geometry.Children[child] + if child in suppressed_solids: + solid.Suppressed = True +# Plot the geometry app.plot() # %% -# Store all Variables necessary for analysis +# Store all variables necessary for analysis # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -MESH = Model.Mesh -NS = Model.NamedSelections -CONN = Model.Connections -CS = Model.CoordinateSystems -MAT = Model.Materials +mesh = model.Mesh +named_selections = model.NamedSelections +connections = model.Connections +materials = model.Materials # %% -# Setup the Analysis -# ~~~~~~~~~~~~~~~~~~ -# Add harmonic acoustics and unit system +# Set up the analysis +# ~~~~~~~~~~~~~~~~~~~ -Model.AddHarmonicAcousticAnalysis() -ExtAPI.Application.ActiveUnitSystem = MechanicalUnitSystem.StandardMKS +# Add the harmonic acoustics analysis and unit system +model.AddHarmonicAcousticAnalysis() +app.ExtAPI.Application.ActiveUnitSystem = MechanicalUnitSystem.StandardMKS # %% # Import and assign materials -MAT.Import(mat_path) -solid6.Material = "Air" -solid8.Material = "Air" -solid9.Material = "Air" - -# %% -# Create coordinate system -LCS1 = CS.AddCoordinateSystem() -LCS1.OriginX = Quantity("0 [mm]") -LCS1.OriginY = Quantity("0 [mm]") -LCS1.OriginZ = Quantity("0 [mm]") -LCS1.PrimaryAxisDefineBy = CoordinateSystemAlignmentType.GlobalZ - -# %% -# Generate mesh - -MESH.ElementSize = Quantity("200 [mm]") -MESH.GenerateMesh() - - -# %% -# Create named selections -# ~~~~~~~~~~~~~~~~~~~~~~~~ - -SF_Velo = Model.AddNamedSelection() -SF_Velo.ScopingMethod = GeometryDefineByType.Worksheet -SF_Velo.Name = "SF_Velo" -GEN_CRT1 = SF_Velo.GenerationCriteria -CRT1 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() -CRT1.Active = True -CRT1.Action = SelectionActionType.Add -CRT1.EntityType = SelectionType.GeoFace -CRT1.Criterion = SelectionCriterionType.Size -CRT1.Operator = SelectionOperatorType.Equal -CRT1.Value = Quantity("3e6 [mm^2]") -GEN_CRT1.Add(CRT1) -CRT2 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() -CRT2.Active = True -CRT2.Action = SelectionActionType.Filter -CRT2.EntityType = SelectionType.GeoFace -CRT2.Criterion = SelectionCriterionType.LocationZ -CRT2.Operator = SelectionOperatorType.Equal -CRT2.Value = Quantity("15000 [mm]") -GEN_CRT1.Add(CRT2) -SF_Velo.Activate() -SF_Velo.Generate() - -ABS_Face = Model.AddNamedSelection() -ABS_Face.ScopingMethod = GeometryDefineByType.Worksheet -ABS_Face.Name = "ABS_Face" -GEN_CRT2 = ABS_Face.GenerationCriteria -CRT1 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() -CRT1.Active = True -CRT1.Action = SelectionActionType.Add -CRT1.EntityType = SelectionType.GeoFace -CRT1.Criterion = SelectionCriterionType.Size -CRT1.Operator = SelectionOperatorType.Equal -CRT1.Value = Quantity("1.5e6 [mm^2]") -GEN_CRT2.Add(CRT1) -CRT2 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() -CRT2.Active = True -CRT2.Action = SelectionActionType.Filter -CRT2.EntityType = SelectionType.GeoFace -CRT2.Criterion = SelectionCriterionType.LocationY -CRT2.Operator = SelectionOperatorType.Equal -CRT2.Value = Quantity("500 [mm]") -GEN_CRT2.Add(CRT2) -ABS_Face.Activate() -ABS_Face.Generate() - -PRES_Face = Model.AddNamedSelection() -PRES_Face.ScopingMethod = GeometryDefineByType.Worksheet -PRES_Face.Name = "PRES_Face" -GEN_CRT3 = PRES_Face.GenerationCriteria -CRT1 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() -CRT1.Active = True -CRT1.Action = SelectionActionType.Add -CRT1.EntityType = SelectionType.GeoFace -CRT1.Criterion = SelectionCriterionType.Size -CRT1.Operator = SelectionOperatorType.Equal -CRT1.Value = Quantity("1.5e6 [mm^2]") -GEN_CRT3.Add(CRT1) -CRT2 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() -CRT2.Active = True -CRT2.Action = SelectionActionType.Filter -CRT2.EntityType = SelectionType.GeoFace -CRT2.Criterion = SelectionCriterionType.LocationY -CRT2.Operator = SelectionOperatorType.Equal -CRT2.Value = Quantity("4500 [mm]") -GEN_CRT3.Add(CRT2) -PRES_Face.Activate() -PRES_Face.Generate() - -ACOUSTIC_Region = Model.AddNamedSelection() -ACOUSTIC_Region.ScopingMethod = GeometryDefineByType.Worksheet -ACOUSTIC_Region.Name = "ACOUSTIC_Region" -GEN_CRT4 = ACOUSTIC_Region.GenerationCriteria -CRT1 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() -CRT1.Active = True -CRT1.Action = SelectionActionType.Add -CRT1.EntityType = SelectionType.GeoBody -CRT1.Criterion = SelectionCriterionType.Type -CRT1.Operator = SelectionOperatorType.Equal -CRT1.Value = 8 -GEN_CRT4.Add(CRT1) -ACOUSTIC_Region.Activate() -ACOUSTIC_Region.Generate() - -# %% -# Analysis settings -# ~~~~~~~~~~~~~~~~~ - -ANALYSIS_SETTINGS = Model.Analyses[0].AnalysisSettings -ANALYSIS_SETTINGS.RangeMaximum = Quantity("100 [Hz]") -ANALYSIS_SETTINGS.SolutionIntervals = 50 -ANALYSIS_SETTINGS.CalculateVelocity = True -ANALYSIS_SETTINGS.CalculateEnergy = True -ANALYSIS_SETTINGS.CalculateVolumeEnergy = True +# Download and import the material +mat_path = download_file("Air-material.xml", "pymechanical", "embedding") +materials.Import(mat_path) + +# Define which geometry children to assign the material to +material_solids = [6, 8, 9] +# Loop through the geometry children and assign the material to the specified ones +for child in range(geometry.Children.Count): + solid = geometry.Children[child] + if child in material_solids: + solid.Material = "Air" + +# %% +# Add a coordinate system + +coordinate_systems = model.CoordinateSystems +coordinate_system = coordinate_systems.AddCoordinateSystem() +coordinate_system.OriginX = Quantity("0 [mm]") +coordinate_system.OriginY = Quantity("0 [mm]") +coordinate_system.OriginZ = Quantity("0 [mm]") +coordinate_system.PrimaryAxisDefineBy = CoordinateSystemAlignmentType.GlobalZ + +# %% +# Set the mesh element size and generate the mesh + +mesh.ElementSize = Quantity("200 [mm]") +mesh.GenerateMesh() + +# %% +# Create, activate, and generate named selections +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +def get_ns_generation_criteria( + model: Ansys.ACT.Automation.Mechanical.Model, face_name: str +): + """Add a named selection with the provided name and return it and the generation criteria. + + Parameters + ---------- + model : Ansys.ACT.Automation.Mechanical.Model + The Mechanical model to which the named selection will be added. + face_name : str + The name of the named selection to be created. + + Returns + ------- + tuple + A tuple containing the named selection and its generation criteria. + """ + # Add a named selection to the model + named_selection = model.AddNamedSelection() + # Set the scoping method and name of the named selection + named_selection.ScopingMethod = GeometryDefineByType.Worksheet + named_selection.Name = face_name + # Return the named selection and its generation criteria + return named_selection, named_selection.GenerationCriteria + + +def add_ns_criterion( + generation_criteria: Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion, + value: Quantity, + active: bool = True, + action: SelectionActionType = SelectionActionType.Add, + entity_type: SelectionType = SelectionType.GeoFace, + criterion: SelectionCriterionType = SelectionCriterionType.Size, + operator: SelectionOperatorType = SelectionOperatorType.Equal, +): + """Add a criterion to the named selection generation criteria. + + Parameters + ---------- + generation_criteria : Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion + The generation criteria to which the criterion will be added. + value : Quantity + The value for the criterion. + active : bool, optional + Whether the criterion is active (default is True). + action : SelectionActionType, optional + The action to be performed (default is SelectionActionType.Add). + entity_type : SelectionType, optional + The type of entity (default is SelectionType.GeoFace). + criterion : SelectionCriterionType, optional + The criterion type (default is SelectionCriterionType.Size). + operator : SelectionOperatorType, optional + The operator to be used (default is SelectionOperatorType.Equal). + """ + # Create a new named selection criterion and set its properties + ns_criterion = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() + ns_criterion.Active = active + ns_criterion.Action = action + ns_criterion.EntityType = entity_type + ns_criterion.Criterion = criterion + ns_criterion.Operator = operator + ns_criterion.Value = value + # Add the criterion to the generation criteria + generation_criteria.Add(ns_criterion) + + +# Create the SF_Velo named selection and add criteria +sf_velo, generation_criteria = get_ns_generation_criteria(model, "SF_Velo") +add_ns_criterion(generation_criteria, Quantity("3e6 [mm^2]")) +add_ns_criterion( + generation_criteria, + Quantity("15000 [mm]"), + action=SelectionActionType.Filter, + criterion=SelectionCriterionType.LocationZ, +) +# Activate and generate the named selection +sf_velo.Activate() +sf_velo.Generate() + +# Create the ABS_Face named selection and add criteria +abs_face, generation_criteria = get_ns_generation_criteria(model, "ABS_Face") +add_ns_criterion(generation_criteria, Quantity("1.5e6 [mm^2]")) +add_ns_criterion( + generation_criteria, + Quantity("5000 [mm]"), + action=SelectionActionType.Filter, + criterion=SelectionCriterionType.LocationY, +) +# Activate and generate the named selection +abs_face.Activate() +abs_face.Generate() + +# Create the PRES_Face named selection and add criteria +pres_face, generation_criteria = get_ns_generation_criteria(model, "PRES_Face") +add_ns_criterion(generation_criteria, Quantity("1.5e6 [mm^2]")) +add_ns_criterion( + generation_criteria, + Quantity("4500 [mm]"), + action=SelectionActionType.Filter, + criterion=SelectionCriterionType.LocationY, +) +# Activate and generate the named selection +pres_face.Activate() +pres_face.Generate() + +# Create the ACOUSTIC_Region named selection and add criteria +acoustic_region, generation_criteria = get_ns_generation_criteria( + model, "ACOUSTIC_Region" +) +add_ns_criterion( + generation_criteria, + 8, + entity_type=SelectionType.GeoBody, + criterion=SelectionCriterionType.Size, +) +# Activate and generate the named selection +acoustic_region.Activate() +acoustic_region.Generate() + +# %% +# Set the analysis settings +# ~~~~~~~~~~~~~~~~~~~~~~~~~ + +analysis_settings = model.Analyses[0].AnalysisSettings +analysis_settings.RangeMaximum = Quantity("100 [Hz]") +analysis_settings.SolutionIntervals = 50 +analysis_settings.CalculateVelocity = True +analysis_settings.CalculateEnergy = True +analysis_settings.CalculateVolumeEnergy = True # %% # Boundary conditions and load # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -HARM_ACOUST = Model.Analyses[0] +# Get the harmonic acoustics analysis from the model +harmonic_acoustics = model.Analyses[0] # %% -# Acoustic region +# Get the acoustic region from the harmonic acoustics analysis and set its location -Acoustic_region = [x for x in HARM_ACOUST.Children if x.Name == "Acoustics Region"][0] -Acoustic_region.Location = ACOUSTIC_Region +acoustics_region = [ + child for child in harmonic_acoustics.Children if child.Name == "Acoustics Region" +][0] +acoustics_region.Location = acoustic_region # %% -# Surface velocity +# Add acoustic surface velocity and set its location and magnitude -SURF_VEL = HARM_ACOUST.AddAcousticSurfaceVelocity() -SURF_VEL.Location = SF_Velo -SURF_VEL.Magnitude.Output.DiscreteValues = [Quantity("5000 [mm s-1]")] +surface_velocity = harmonic_acoustics.AddAcousticSurfaceVelocity() +surface_velocity.Location = sf_velo +surface_velocity.Magnitude.Output.DiscreteValues = [Quantity("5000 [mm s-1]")] # %% -# Acoustic pressure +# Add acoustic pressure and set its location and magnitude -ACOUST_PRES = HARM_ACOUST.AddAcousticPressure() -ACOUST_PRES.Location = PRES_Face -ACOUST_PRES.Magnitude = Quantity("1.5e-7 [MPa]") +acoustic_pressure = harmonic_acoustics.AddAcousticPressure() +acoustic_pressure.Location = pres_face +acoustic_pressure.Magnitude = Quantity("1.5e-7 [MPa]") # %% -# Acoustic absoption surface +# Add acoustic absorption surface and set its location and magnitude -ABSORP_SURF = HARM_ACOUST.AddAcousticAbsorptionSurface() -ABSORP_SURF.Location = ABS_Face -ABSORP_SURF.AbsorptionCoefficient.Output.DiscreteValues = [Quantity("0.02")] +absorption_surface = harmonic_acoustics.AddAcousticAbsorptionSurface() +absorption_surface.Location = abs_face +absorption_surface.AbsorptionCoefficient.Output.DiscreteValues = [Quantity("0.02")] -HARM_ACOUST.Activate() -Graphics.Camera.SetFit() -Graphics.ExportImage( - os.path.join(cwd, "bounday_conditions.png"), image_export_format, settings_720p +# Activate the harmonic acoustics analysis and display the image +harmonic_acoustics.Activate() +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "boundary_conditions.png" ) -display_image("bounday_conditions.png") # %% -# Add results -# ~~~~~~~~~~~ +# Add results to the analysis solution +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -SOLN = Model.Analyses[0].Solution +# Get the analysis solution +solution = model.Analyses[0].Solution # %% -# Acoustic pressure +# Add the acoustic pressure result and set its properties -ACOUST_PRES_RES1 = SOLN.AddAcousticPressureResult() -ACOUST_PRES_RES1.By = SetDriverStyle.ResultSet -ACOUST_PRES_RES1.SetNumber = 25 +acoustic_pressure_result = solution.AddAcousticPressureResult() +acoustic_pressure_result.By = SetDriverStyle.ResultSet +acoustic_pressure_result.SetNumber = 25 # %% -# Acoustic velocity - total and directional +# Add the acoustic total velocity result and set its frequency + +total_av_result = solution.AddAcousticTotalVelocityResult() +total_av_result.Frequency = Quantity("50 [Hz]") -ACOUST_TOT_VEL1 = SOLN.AddAcousticTotalVelocityResult() -ACOUST_TOT_VEL1.Frequency = Quantity("50 [Hz]") +# %% +# Add the acoustic directional velocity result and set its properties -ACOUST_DIR_VEL1 = SOLN.AddAcousticDirectionalVelocityResult() -ACOUST_DIR_VEL1.Frequency = Quantity("50 [Hz]") -ACOUST_DIR_VEL1.CoordinateSystem = LCS1 +directional_av_result = solution.AddAcousticDirectionalVelocityResult() +directional_av_result.Frequency = Quantity("50 [Hz]") +directional_av_result.CoordinateSystem = coordinate_system -ACOUST_DIR_VEL2 = SOLN.AddAcousticDirectionalVelocityResult() -ACOUST_DIR_VEL2.NormalOrientation = NormalOrientationType.ZAxis -ACOUST_DIR_VEL2.By = SetDriverStyle.ResultSet -ACOUST_DIR_VEL2.SetNumber = 25 +directional_av_result_2 = solution.AddAcousticDirectionalVelocityResult() +directional_av_result_2.NormalOrientation = NormalOrientationType.ZAxis +directional_av_result_2.By = SetDriverStyle.ResultSet +directional_av_result_2.SetNumber = 25 # %% -# Acoustic sound pressure and frequency bands +# Add the acoustic sound pressure level to the solution and set its frequency -ACOUST_SPL = SOLN.AddAcousticSoundPressureLevel() -ACOUST_SPL.Frequency = Quantity("50 [Hz]") +acoustic_spl = solution.AddAcousticSoundPressureLevel() +acoustic_spl.Frequency = Quantity("50 [Hz]") -ACOUST_A_SPL = SOLN.AddAcousticAWeightedSoundPressureLevel() -ACOUST_A_SPL.Frequency = Quantity("50 [Hz]") +# %% +# Add the acoustic A-weighted sound pressure level to the solution and set its frequency -ACOUST_FRQ_BAND_SPL = SOLN.AddAcousticFrequencyBandSPL() +acoustic_weighted_sound_pressure_level = ( + solution.AddAcousticAWeightedSoundPressureLevel() +) +acoustic_weighted_sound_pressure_level.Frequency = Quantity("50 [Hz]") -A_FREQ_BAND_SPL = SOLN.AddAcousticFrequencyBandAWeightedSPL() +# %% +# Add acoustic frequency bands for sound pressure level and A-weighted sound pressure levels -Z_VELO_RESP = SOLN.AddAcousticVelocityFrequencyResponse() -Z_VELO_RESP.NormalOrientation = NormalOrientationType.ZAxis -Z_VELO_RESP.Location = PRES_Face -Z_VELO_RESP.NormalOrientation = NormalOrientationType.ZAxis +solution.AddAcousticFrequencyBandSPL() +solution.AddAcousticFrequencyBandAWeightedSPL() # %% -# Acoustic kinetic and potentional energy frequency response +# Add the acoustic velocity frequency response and set its orientation and location -KE_RESP = SOLN.AddAcousticKineticEnergyFrequencyResponse() -KE_RESP.Location = ABS_Face -KE_display = KE_RESP.TimeHistoryDisplay +av_frequency_response = solution.AddAcousticVelocityFrequencyResponse() +av_frequency_response.NormalOrientation = NormalOrientationType.ZAxis +av_frequency_response.Location = pres_face -PE_RESP = SOLN.AddAcousticPotentialEnergyFrequencyResponse() -PE_RESP.Location = ABS_Face -PE_display = PE_RESP.TimeHistoryDisplay +# %% +# Add the acoustic kinetic energy and potential energy frequency response and set their locations + +ke_frequency_response = solution.AddAcousticKineticEnergyFrequencyResponse() +ke_frequency_response.Location = abs_face +ke_display = ke_frequency_response.TimeHistoryDisplay + +pe_frequency_response = solution.AddAcousticPotentialEnergyFrequencyResponse() +pe_frequency_response.Location = abs_face +pe_display = pe_frequency_response.TimeHistoryDisplay + +# %% +# Add the acoustic total velocity result and set its location, frequency, and amplitude + +total_av_result_2 = solution.AddAcousticTotalVelocityResult() +total_av_result_2.Location = pres_face +total_av_result_2.Frequency = Quantity("30 [Hz]") +total_av_result_2.Amplitude = True # %% -# Acoustic total and directional velocity +# Add the acoustic directional velocity result and set its orientation, location, frequency, +# and amplitude -ACOUST_TOT_VEL2 = SOLN.AddAcousticTotalVelocityResult() -ACOUST_TOT_VEL2.Location = PRES_Face -ACOUST_TOT_VEL2.Frequency = Quantity("30 [Hz]") -ACOUST_TOT_VEL2.Amplitude = True +directional_av_result_3 = solution.AddAcousticDirectionalVelocityResult() +directional_av_result_3.NormalOrientation = NormalOrientationType.ZAxis +directional_av_result_3.Location = pres_face +directional_av_result_3.Frequency = Quantity("10 [Hz]") +directional_av_result_3.Amplitude = True -ACOUST_DIR_VEL3 = SOLN.AddAcousticDirectionalVelocityResult() -ACOUST_DIR_VEL3.NormalOrientation = NormalOrientationType.ZAxis -ACOUST_DIR_VEL3.Location = PRES_Face -ACOUST_DIR_VEL3.Frequency = Quantity("10 [Hz]") -ACOUST_DIR_VEL3.Amplitude = True +# %% +# Add the acoustic kinetic energy and potential energy and set their locations, frequencies, +# and amplitudes -ACOUST_KE = SOLN.AddAcousticKineticEnergy() -ACOUST_KE.Location = ABS_Face -ACOUST_KE.Frequency = Quantity("68 [Hz]") -ACOUST_KE.Amplitude = True +acoustic_ke = solution.AddAcousticKineticEnergy() +acoustic_ke.Location = abs_face +acoustic_ke.Frequency = Quantity("68 [Hz]") +acoustic_ke.Amplitude = True -ACOUST_PE = SOLN.AddAcousticPotentialEnergy() -ACOUST_PE.Location = ABS_Face -ACOUST_PE.Frequency = Quantity("10 [Hz]") -ACOUST_PE.Amplitude = True +acoustic_potential_energy = solution.AddAcousticPotentialEnergy() +acoustic_potential_energy.Location = abs_face +acoustic_potential_energy.Frequency = Quantity("10 [Hz]") +acoustic_potential_energy.Amplitude = True # %% -# Solve -# ~~~~~ +# Solve the solution +# ~~~~~~~~~~~~~~~~~~ -SOLN.Solve(True) +solution.Solve(True) # sphinx_gallery_start_ignore -assert str(SOLN.Status) == "Done", "Solution status is not 'Done'" +# Assert the solution is done being solved +assert str(solution.Status) == "Done", "Solution status is not 'Done'" # sphinx_gallery_end_ignore # %% -# Messages -# ~~~~~~~~ +# Print messages +# ~~~~~~~~~~~~~~ -Messages = ExtAPI.Application.Messages -if Messages: - for message in Messages: +messages = app.ExtAPI.Application.Messages +if messages: + for message in messages: print(f"[{message.Severity}] {message.DisplayString}") else: - print("No [Info]/[Warning]/[Error] Messages") + print("No [Info]/[Warning]/[Error] messages") # %% @@ -390,116 +510,141 @@ def display_image(image_name): # ~~~~~~~~~~~~~~ # %% -# Total acoustic pressure -# ^^^^^^^^^^^^^^^^^^^^^^^ +# Activate the acoustic pressure result and display the image +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Tree.Activate([ACOUST_PRES_RES1]) -Graphics.ExportImage( - os.path.join(cwd, "acou_pressure.png"), image_export_format, settings_720p +app.Tree.Activate([acoustic_pressure_result]) +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "acoustic_pressure.png" ) -display_image("acou_pressure.png") # %% -# Total acoustic velocity -# ^^^^^^^^^^^^^^^^^^^^^^^ +# Activate the acoustic total velocity and display the image +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Tree.Activate([ACOUST_PRES_RES1]) -Graphics.ExportImage( - os.path.join(cwd, "totalvelocity.png"), image_export_format, settings_720p +app.Tree.Activate([total_av_result]) +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "total_velocity.png" ) -display_image("totalvelocity.png") # %% -# Sound pressure level -# ^^^^^^^^^^^^^^^^^^^^ +# Activate the sound pressure level and display the image +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Tree.Activate([ACOUST_SPL]) -Graphics.ExportImage( - os.path.join(cwd, "sound_pressure.png"), image_export_format, settings_720p +app.Tree.Activate([acoustic_spl]) +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "sound_pressure.png" ) -display_image("sound_pressure.png") # %% -# Total velocity on pressure surface -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# Activate the acoustic total velocity pressure and display the image +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Tree.Activate([ACOUST_TOT_VEL2]) -Graphics.ExportImage( - os.path.join(cwd, "totalvelocity_pressure.png"), image_export_format, settings_720p +app.Tree.Activate([total_av_result_2]) +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "total_velocity_pressure.png" ) -display_image("totalvelocity_pressure.png") # %% -# Kinetic energy on absorption face -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# Activate the acoustic kinetic energy on the absorption face and display the image +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Tree.Activate([ACOUST_KE]) -Graphics.ExportImage( - os.path.join(cwd, "kineticenergy.png"), image_export_format, settings_720p +app.Tree.Activate([acoustic_ke]) +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "kinetic_energy.png" ) -display_image("kineticenergy.png") # %% -# Total acoustic pressure animation -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# Export the acoustic pressure animation to a GIF file and display it +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -animation_export_format = ( - Ansys.Mechanical.DataModel.Enums.GraphicsAnimationExportFormat.GIF -) +animation_export_format = GraphicsAnimationExportFormat.GIF settings_720p = Ansys.Mechanical.Graphics.AnimationExportSettings() settings_720p.Width = 1280 settings_720p.Height = 720 -ACOUST_PRES_RES1.ExportAnimation( - os.path.join(cwd, "press.gif"), animation_export_format, settings_720p +# Set the path for the GIF +press_gif_path = output_path / "press.gif" + +# Export the force reaction animation to a GIF file +acoustic_pressure_result.ExportAnimation( + str(press_gif_path), animation_export_format, settings_720p ) -gif = Image.open(os.path.join(cwd, "press.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] +def update_animation(frame: int) -> list[mpimg.AxesImage]: + """Update the animation frame for the GIF. + Parameters + ---------- + frame : int + The frame number to update the animation. -ani = FuncAnimation( - fig, update, frames=range(gif.n_frames), interval=200, repeat=True, blit=True + Returns + ------- + list[mpimg.AxesImage] + A list containing the updated image for the animation. + """ + # Seeks to the given frame in this sequence file + gif.seek(frame) + # Set the image array to the current frame of the GIF + image.set_data(gif.convert("RGBA")) + # Return the updated image + return [image] + + +# Open the GIF file and create an animation +gif = Image.open(press_gif_path) +# Set the subplots for the animation and turn off the axis +figure, axes = plt.subplots(figsize=(16, 9)) +axes.axis("off") +# Change the color of the image +image = axes.imshow(gif.convert("RGBA")) + +# Create the animation using the figure, update_animation function, and the GIF frames +# Set the interval between frames to 200 milliseconds and repeat the animation +FuncAnimation( + figure, + update_animation, + frames=range(gif.n_frames), + interval=200, + repeat=True, + blit=True, ) + +# Show the animation plt.show() # %% -# Display output file from solve -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Display the output file from the solve +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -def write_file_contents_to_console(path): - """Write file contents to console.""" - with open(path, "rt") as file: +# Get the working directory for the solve +solve_path = harmonic_acoustics.WorkingDir +# Get the solve output file path +solve_out_path = Path(solve_path) / "solve.out" +# Check if the solve output file exists and print its contents +if solve_out_path: + with solve_out_path.open("rt") as file: for line in file: print(line, end="") - -solve_path = HARM_ACOUST.WorkingDir -solve_out_path = os.path.join(solve_path, "solve.out") -if solve_out_path: - write_file_contents_to_console(solve_out_path) - # %% -# Project tree -# ~~~~~~~~~~~~ +# Print the project tree +# ~~~~~~~~~~~~~~~~~~~~~~ app.print_tree() # %% -# Cleanup -# ~~~~~~~ -# Save project +# Clean up the project +# ~~~~~~~~~~~~~~~~~~~~ + +# Save the project +mechdat_path = output_path / "harmnonic_acoustics.mechdat" +app.save(str(mechdat_path)) -app.save(os.path.join(cwd, "harmnonic_acoustics.mechdat")) +# Clear the project app.new() -# delete example file +# Delete the example files delete_downloads() From 666816fbad545f5b85de377a80d1b3e67f459185 Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Tue, 22 Apr 2025 17:38:34 -0400 Subject: [PATCH 07/24] working example with renamed vars and using pathlib --- examples/01_basic/harmonic_acoustics.py | 691 ++++++++++-------------- 1 file changed, 286 insertions(+), 405 deletions(-) diff --git a/examples/01_basic/harmonic_acoustics.py b/examples/01_basic/harmonic_acoustics.py index 72e402ce..8cf37b6b 100644 --- a/examples/01_basic/harmonic_acoustics.py +++ b/examples/01_basic/harmonic_acoustics.py @@ -1,3 +1,25 @@ +# Copyright (C) 2023 - 2025 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. + """.. _ref_harmonic_acoustics: Harmonic acoustic analysis @@ -25,83 +47,20 @@ # %% # Embed mechanical and set global variables -app = App(globals=globals()) +app = App() +app.update_globals(globals()) print(app) -# %% -# Set the image output path and create functions to fit the camera and display images -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -# Set the path for the output files (images, gifs, mechdat) -output_path = Path.cwd() / "out" - - -def set_camera_and_display_image( - camera: Ansys.ACT.Common.Graphics.MechanicalCameraWrapper, - graphics: Ansys.ACT.Common.Graphics.MechanicalGraphicsWrapper, - graphics_image_export_settings: Ansys.Mechanical.Graphics.GraphicsImageExportSettings, - image_output_path: Path, - image_name: str, -) -> None: - """Set the camera to fit the model and display the image. - - Parameters - ---------- - camera : Ansys.ACT.Common.Graphics.MechanicalCameraWrapper - The camera object to set the view. - graphics : Ansys.ACT.Common.Graphics.MechanicalGraphicsWrapper - The graphics object to export the image. - graphics_image_export_settings : Ansys.Mechanical.Graphics.GraphicsImageExportSettings - The settings for exporting the image. - image_output_path : Path - The path to save the exported image. - image_name : str - The name of the exported image file. - """ - # Set the camera to fit the mesh - camera.SetFit() - # Export the mesh image with the specified settings - image_path = image_output_path / image_name - graphics.ExportImage( - str(image_path), image_export_format, graphics_image_export_settings - ) - # Display the exported mesh image - display_image(image_path) - - -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 +cwd = Path.cwd() / "out" + + +def display_image(image_name): + plt.figure(figsize=(16, 9)) + image_path = cwd / image_name 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.xticks([]) + plt.yticks([]) + plt.axis("off") plt.show() @@ -111,7 +70,6 @@ def display_image( graphics = app.Graphics camera = graphics.Camera - camera.SetSpecificViewOrientation(ViewOrientationType.Iso) image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() @@ -122,214 +80,186 @@ def display_image( settings_720p.CurrentGraphicsDisplay = False camera.Rotate(180, CameraAxisType.ScreenY) +# %% +# Download geometry and materials files +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +geometry_path = download_file("C_GEOMETRY.agdb", "pymechanical", "embedding") +mat_path = download_file("Air-material.xml", "pymechanical", "embedding") + # %% # Import the geometry # ~~~~~~~~~~~~~~~~~~~ model = app.Model + geometry_import = model.GeometryImportGroup.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_path = download_file("C_GEOMETRY.agdb", "pymechanical", "embedding") geometry_import.Import( geometry_path, geometry_import_format, geometry_import_preferences ) -# %% -# Set specified model geometry children to suppressed - -# Define the geometry geometry = model.Geometry -# Set which geometry children to suppress -suppressed_solids = [1, 2, 3, 4, 5, 7, 10, 11] -# Loop through the geometry children and suppress the specified ones -for child in range(geometry.Children.Count): - solid = geometry.Children[child] - if child in suppressed_solids: - solid.Suppressed = True - -# Plot the geometry + +solid1 = geometry.Children[0] +solid2 = geometry.Children[1] +solid3 = geometry.Children[2] +solid4 = geometry.Children[3] +solid5 = geometry.Children[4] +solid6 = geometry.Children[5] +solid7 = geometry.Children[6] +solid8 = geometry.Children[7] +solid9 = geometry.Children[8] +solid10 = geometry.Children[9] +solid11 = geometry.Children[10] + +solid1.Suppressed = True +solid2.Suppressed = True +solid3.Suppressed = True +solid4.Suppressed = True +solid5.Suppressed = True +solid7.Suppressed = True +solid10.Suppressed = True +solid11.Suppressed = True + app.plot() # %% -# Store all variables necessary for analysis +# Store all Variables necessary for analysis # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ mesh = model.Mesh -named_selections = model.NamedSelections -connections = model.Connections -materials = model.Materials +named_selection = model.NamedSelections +connection = model.Connections +coordinate_systems = model.CoordinateSystems +mat = model.Materials # %% -# Set up the analysis -# ~~~~~~~~~~~~~~~~~~~ +# Setup the Analysis +# ~~~~~~~~~~~~~~~~~~ +# Add harmonic acoustics and unit system -# Add the harmonic acoustics analysis and unit system model.AddHarmonicAcousticAnalysis() app.ExtAPI.Application.ActiveUnitSystem = MechanicalUnitSystem.StandardMKS # %% # Import and assign materials -# Download and import the material -mat_path = download_file("Air-material.xml", "pymechanical", "embedding") -materials.Import(mat_path) - -# Define which geometry children to assign the material to -material_solids = [6, 8, 9] -# Loop through the geometry children and assign the material to the specified ones -for child in range(geometry.Children.Count): - solid = geometry.Children[child] - if child in material_solids: - solid.Material = "Air" +mat.Import(mat_path) +solid6.Material = "Air" +solid8.Material = "Air" +solid9.Material = "Air" # %% -# Add a coordinate system - -coordinate_systems = model.CoordinateSystems -coordinate_system = coordinate_systems.AddCoordinateSystem() -coordinate_system.OriginX = Quantity("0 [mm]") -coordinate_system.OriginY = Quantity("0 [mm]") -coordinate_system.OriginZ = Quantity("0 [mm]") -coordinate_system.PrimaryAxisDefineBy = CoordinateSystemAlignmentType.GlobalZ +# Create coordinate system +lcs1 = coordinate_systems.AddCoordinateSystem() +lcs1.OriginX = Quantity("0 [mm]") +lcs1.OriginY = Quantity("0 [mm]") +lcs1.OriginZ = Quantity("0 [mm]") +lcs1.PrimaryAxisDefineBy = CoordinateSystemAlignmentType.GlobalZ # %% -# Set the mesh element size and generate the mesh +# Generate mesh mesh.ElementSize = Quantity("200 [mm]") mesh.GenerateMesh() + # %% -# Create, activate, and generate named selections -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - -def get_ns_generation_criteria( - model: Ansys.ACT.Automation.Mechanical.Model, face_name: str -): - """Add a named selection with the provided name and return it and the generation criteria. - - Parameters - ---------- - model : Ansys.ACT.Automation.Mechanical.Model - The Mechanical model to which the named selection will be added. - face_name : str - The name of the named selection to be created. - - Returns - ------- - tuple - A tuple containing the named selection and its generation criteria. - """ - # Add a named selection to the model - named_selection = model.AddNamedSelection() - # Set the scoping method and name of the named selection - named_selection.ScopingMethod = GeometryDefineByType.Worksheet - named_selection.Name = face_name - # Return the named selection and its generation criteria - return named_selection, named_selection.GenerationCriteria - - -def add_ns_criterion( - generation_criteria: Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion, - value: Quantity, - active: bool = True, - action: SelectionActionType = SelectionActionType.Add, - entity_type: SelectionType = SelectionType.GeoFace, - criterion: SelectionCriterionType = SelectionCriterionType.Size, - operator: SelectionOperatorType = SelectionOperatorType.Equal, -): - """Add a criterion to the named selection generation criteria. - - Parameters - ---------- - generation_criteria : Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion - The generation criteria to which the criterion will be added. - value : Quantity - The value for the criterion. - active : bool, optional - Whether the criterion is active (default is True). - action : SelectionActionType, optional - The action to be performed (default is SelectionActionType.Add). - entity_type : SelectionType, optional - The type of entity (default is SelectionType.GeoFace). - criterion : SelectionCriterionType, optional - The criterion type (default is SelectionCriterionType.Size). - operator : SelectionOperatorType, optional - The operator to be used (default is SelectionOperatorType.Equal). - """ - # Create a new named selection criterion and set its properties - ns_criterion = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() - ns_criterion.Active = active - ns_criterion.Action = action - ns_criterion.EntityType = entity_type - ns_criterion.Criterion = criterion - ns_criterion.Operator = operator - ns_criterion.Value = value - # Add the criterion to the generation criteria - generation_criteria.Add(ns_criterion) - - -# Create the SF_Velo named selection and add criteria -sf_velo, generation_criteria = get_ns_generation_criteria(model, "SF_Velo") -add_ns_criterion(generation_criteria, Quantity("3e6 [mm^2]")) -add_ns_criterion( - generation_criteria, - Quantity("15000 [mm]"), - action=SelectionActionType.Filter, - criterion=SelectionCriterionType.LocationZ, -) -# Activate and generate the named selection +# Create named selections +# ~~~~~~~~~~~~~~~~~~~~~~~~ + +sf_velo = model.AddNamedSelection() +sf_velo.ScopingMethod = GeometryDefineByType.Worksheet +sf_velo.Name = "sf_velo" +generation_criteria_1 = sf_velo.GenerationCriteria +criteria_1 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() +criteria_1.Active = True +criteria_1.Action = SelectionActionType.Add +criteria_1.EntityType = SelectionType.GeoFace +criteria_1.Criterion = SelectionCriterionType.Size +criteria_1.Operator = SelectionOperatorType.Equal +criteria_1.Value = Quantity("3e6 [mm^2]") +generation_criteria_1.Add(criteria_1) +criteria_2 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() +criteria_2.Active = True +criteria_2.Action = SelectionActionType.Filter +criteria_2.EntityType = SelectionType.GeoFace +criteria_2.Criterion = SelectionCriterionType.LocationZ +criteria_2.Operator = SelectionOperatorType.Equal +criteria_2.Value = Quantity("15000 [mm]") +generation_criteria_1.Add(criteria_2) sf_velo.Activate() sf_velo.Generate() -# Create the ABS_Face named selection and add criteria -abs_face, generation_criteria = get_ns_generation_criteria(model, "ABS_Face") -add_ns_criterion(generation_criteria, Quantity("1.5e6 [mm^2]")) -add_ns_criterion( - generation_criteria, - Quantity("5000 [mm]"), - action=SelectionActionType.Filter, - criterion=SelectionCriterionType.LocationY, -) -# Activate and generate the named selection +abs_face = model.AddNamedSelection() +abs_face.ScopingMethod = GeometryDefineByType.Worksheet +abs_face.Name = "abs_face" +generation_criteria_2 = abs_face.GenerationCriteria +criteria_1 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() +criteria_1.Active = True +criteria_1.Action = SelectionActionType.Add +criteria_1.EntityType = SelectionType.GeoFace +criteria_1.Criterion = SelectionCriterionType.Size +criteria_1.Operator = SelectionOperatorType.Equal +criteria_1.Value = Quantity("1.5e6 [mm^2]") +generation_criteria_2.Add(criteria_1) +criteria_2 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() +criteria_2.Active = True +criteria_2.Action = SelectionActionType.Filter +criteria_2.EntityType = SelectionType.GeoFace +criteria_2.Criterion = SelectionCriterionType.LocationY +criteria_2.Operator = SelectionOperatorType.Equal +criteria_2.Value = Quantity("500 [mm]") +generation_criteria_2.Add(criteria_2) abs_face.Activate() abs_face.Generate() -# Create the PRES_Face named selection and add criteria -pres_face, generation_criteria = get_ns_generation_criteria(model, "PRES_Face") -add_ns_criterion(generation_criteria, Quantity("1.5e6 [mm^2]")) -add_ns_criterion( - generation_criteria, - Quantity("4500 [mm]"), - action=SelectionActionType.Filter, - criterion=SelectionCriterionType.LocationY, -) -# Activate and generate the named selection +pres_face = model.AddNamedSelection() +pres_face.ScopingMethod = GeometryDefineByType.Worksheet +pres_face.Name = "pres_face" +generation_criteria_3 = pres_face.GenerationCriteria +criteria_1 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() +criteria_1.Active = True +criteria_1.Action = SelectionActionType.Add +criteria_1.EntityType = SelectionType.GeoFace +criteria_1.Criterion = SelectionCriterionType.Size +criteria_1.Operator = SelectionOperatorType.Equal +criteria_1.Value = Quantity("1.5e6 [mm^2]") +generation_criteria_3.Add(criteria_1) +criteria_2 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() +criteria_2.Active = True +criteria_2.Action = SelectionActionType.Filter +criteria_2.EntityType = SelectionType.GeoFace +criteria_2.Criterion = SelectionCriterionType.LocationY +criteria_2.Operator = SelectionOperatorType.Equal +criteria_2.Value = Quantity("4500 [mm]") +generation_criteria_3.Add(criteria_2) pres_face.Activate() pres_face.Generate() -# Create the ACOUSTIC_Region named selection and add criteria -acoustic_region, generation_criteria = get_ns_generation_criteria( - model, "ACOUSTIC_Region" -) -add_ns_criterion( - generation_criteria, - 8, - entity_type=SelectionType.GeoBody, - criterion=SelectionCriterionType.Size, -) -# Activate and generate the named selection +acoustic_region = model.AddNamedSelection() +acoustic_region.ScopingMethod = GeometryDefineByType.Worksheet +acoustic_region.Name = "acoustic_region" +generation_criteria_4 = acoustic_region.GenerationCriteria +criteria_1 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() +criteria_1.Active = True +criteria_1.Action = SelectionActionType.Add +criteria_1.EntityType = SelectionType.GeoBody +criteria_1.Criterion = SelectionCriterionType.Type +criteria_1.Operator = SelectionOperatorType.Equal +criteria_1.Value = 8 +generation_criteria_4.Add(criteria_1) acoustic_region.Activate() acoustic_region.Generate() # %% -# Set the analysis settings -# ~~~~~~~~~~~~~~~~~~~~~~~~~ +# Analysis settings +# ~~~~~~~~~~~~~~~~~ analysis_settings = model.Analyses[0].AnalysisSettings analysis_settings.RangeMaximum = Quantity("100 [Hz]") @@ -342,160 +272,137 @@ def add_ns_criterion( # Boundary conditions and load # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Get the harmonic acoustics analysis from the model harmonic_acoustics = model.Analyses[0] # %% -# Get the acoustic region from the harmonic acoustics analysis and set its location +# Acoustic region acoustics_region = [ - child for child in harmonic_acoustics.Children if child.Name == "Acoustics Region" + x for x in harmonic_acoustics.Children if x.Name == "Acoustics Region" ][0] acoustics_region.Location = acoustic_region # %% -# Add acoustic surface velocity and set its location and magnitude +# Surface velocity surface_velocity = harmonic_acoustics.AddAcousticSurfaceVelocity() surface_velocity.Location = sf_velo surface_velocity.Magnitude.Output.DiscreteValues = [Quantity("5000 [mm s-1]")] # %% -# Add acoustic pressure and set its location and magnitude +# Acoustic pressure acoustic_pressure = harmonic_acoustics.AddAcousticPressure() acoustic_pressure.Location = pres_face acoustic_pressure.Magnitude = Quantity("1.5e-7 [MPa]") # %% -# Add acoustic absorption surface and set its location and magnitude +# Acoustic absoption surface absorption_surface = harmonic_acoustics.AddAcousticAbsorptionSurface() absorption_surface.Location = abs_face absorption_surface.AbsorptionCoefficient.Output.DiscreteValues = [Quantity("0.02")] -# Activate the harmonic acoustics analysis and display the image harmonic_acoustics.Activate() -set_camera_and_display_image( - camera, graphics, settings_720p, output_path, "boundary_conditions.png" -) +camera.SetFit() +boundary_condition_image = cwd / "bounday_conditions.png" +graphics.ExportImage(str(boundary_condition_image), image_export_format, settings_720p) +display_image("bounday_conditions.png") # %% -# Add results to the analysis solution -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Add results +# ~~~~~~~~~~~ -# Get the analysis solution solution = model.Analyses[0].Solution # %% -# Add the acoustic pressure result and set its properties +# Acoustic pressure -acoustic_pressure_result = solution.AddAcousticPressureResult() -acoustic_pressure_result.By = SetDriverStyle.ResultSet -acoustic_pressure_result.SetNumber = 25 +acoustic_pressure_result_1 = solution.AddAcousticPressureResult() +acoustic_pressure_result_1.By = SetDriverStyle.ResultSet +acoustic_pressure_result_1.SetNumber = 25 # %% -# Add the acoustic total velocity result and set its frequency +# Acoustic velocity - total and directional -total_av_result = solution.AddAcousticTotalVelocityResult() -total_av_result.Frequency = Quantity("50 [Hz]") +acoustic_total_velocity_1 = solution.AddAcousticTotalVelocityResult() +acoustic_total_velocity_1.Frequency = Quantity("50 [Hz]") -# %% -# Add the acoustic directional velocity result and set its properties - -directional_av_result = solution.AddAcousticDirectionalVelocityResult() -directional_av_result.Frequency = Quantity("50 [Hz]") -directional_av_result.CoordinateSystem = coordinate_system +acoustic_directional_velocity_1 = solution.AddAcousticDirectionalVelocityResult() +acoustic_directional_velocity_1.Frequency = Quantity("50 [Hz]") +acoustic_directional_velocity_1.CoordinateSystem = lcs1 -directional_av_result_2 = solution.AddAcousticDirectionalVelocityResult() -directional_av_result_2.NormalOrientation = NormalOrientationType.ZAxis -directional_av_result_2.By = SetDriverStyle.ResultSet -directional_av_result_2.SetNumber = 25 +acoustic_directional_velocity_2 = solution.AddAcousticDirectionalVelocityResult() +acoustic_directional_velocity_2.NormalOrientation = NormalOrientationType.ZAxis +acoustic_directional_velocity_2.By = SetDriverStyle.ResultSet +acoustic_directional_velocity_2.SetNumber = 25 # %% -# Add the acoustic sound pressure level to the solution and set its frequency +# Acoustic sound pressure and frequency bands acoustic_spl = solution.AddAcousticSoundPressureLevel() acoustic_spl.Frequency = Quantity("50 [Hz]") -# %% -# Add the acoustic A-weighted sound pressure level to the solution and set its frequency - -acoustic_weighted_sound_pressure_level = ( - solution.AddAcousticAWeightedSoundPressureLevel() -) -acoustic_weighted_sound_pressure_level.Frequency = Quantity("50 [Hz]") - -# %% -# Add acoustic frequency bands for sound pressure level and A-weighted sound pressure levels +acoustic_a_spl = solution.AddAcousticAWeightedSoundPressureLevel() +acoustic_a_spl.Frequency = Quantity("50 [Hz]") -solution.AddAcousticFrequencyBandSPL() -solution.AddAcousticFrequencyBandAWeightedSPL() +acoustic_frq_band_spl = solution.AddAcousticFrequencyBandSPL() -# %% -# Add the acoustic velocity frequency response and set its orientation and location +a_freq_band_spl = solution.AddAcousticFrequencyBandAWeightedSPL() -av_frequency_response = solution.AddAcousticVelocityFrequencyResponse() -av_frequency_response.NormalOrientation = NormalOrientationType.ZAxis -av_frequency_response.Location = pres_face +z_velocity_response = solution.AddAcousticVelocityFrequencyResponse() +z_velocity_response.NormalOrientation = NormalOrientationType.ZAxis +z_velocity_response.Location = pres_face +z_velocity_response.NormalOrientation = NormalOrientationType.ZAxis # %% -# Add the acoustic kinetic energy and potential energy frequency response and set their locations +# Acoustic kinetic and potentional energy frequency response -ke_frequency_response = solution.AddAcousticKineticEnergyFrequencyResponse() -ke_frequency_response.Location = abs_face -ke_display = ke_frequency_response.TimeHistoryDisplay +ke_response = solution.AddAcousticKineticEnergyFrequencyResponse() +ke_response.Location = abs_face +KE_display = ke_response.TimeHistoryDisplay -pe_frequency_response = solution.AddAcousticPotentialEnergyFrequencyResponse() -pe_frequency_response.Location = abs_face -pe_display = pe_frequency_response.TimeHistoryDisplay +pe_response = solution.AddAcousticPotentialEnergyFrequencyResponse() +pe_response.Location = abs_face +PE_display = pe_response.TimeHistoryDisplay # %% -# Add the acoustic total velocity result and set its location, frequency, and amplitude +# Acoustic total and directional velocity -total_av_result_2 = solution.AddAcousticTotalVelocityResult() -total_av_result_2.Location = pres_face -total_av_result_2.Frequency = Quantity("30 [Hz]") -total_av_result_2.Amplitude = True +acoustic_total_velocity_2 = solution.AddAcousticTotalVelocityResult() +acoustic_total_velocity_2.Location = pres_face +acoustic_total_velocity_2.Frequency = Quantity("30 [Hz]") +acoustic_total_velocity_2.Amplitude = True -# %% -# Add the acoustic directional velocity result and set its orientation, location, frequency, -# and amplitude - -directional_av_result_3 = solution.AddAcousticDirectionalVelocityResult() -directional_av_result_3.NormalOrientation = NormalOrientationType.ZAxis -directional_av_result_3.Location = pres_face -directional_av_result_3.Frequency = Quantity("10 [Hz]") -directional_av_result_3.Amplitude = True - -# %% -# Add the acoustic kinetic energy and potential energy and set their locations, frequencies, -# and amplitudes +acoustic_directional_velocity_3 = solution.AddAcousticDirectionalVelocityResult() +acoustic_directional_velocity_3.NormalOrientation = NormalOrientationType.ZAxis +acoustic_directional_velocity_3.Location = pres_face +acoustic_directional_velocity_3.Frequency = Quantity("10 [Hz]") +acoustic_directional_velocity_3.Amplitude = True acoustic_ke = solution.AddAcousticKineticEnergy() acoustic_ke.Location = abs_face acoustic_ke.Frequency = Quantity("68 [Hz]") acoustic_ke.Amplitude = True -acoustic_potential_energy = solution.AddAcousticPotentialEnergy() -acoustic_potential_energy.Location = abs_face -acoustic_potential_energy.Frequency = Quantity("10 [Hz]") -acoustic_potential_energy.Amplitude = True +acoustic_pe = solution.AddAcousticPotentialEnergy() +acoustic_pe.Location = abs_face +acoustic_pe.Frequency = Quantity("10 [Hz]") +acoustic_pe.Amplitude = True # %% -# Solve the solution -# ~~~~~~~~~~~~~~~~~~ +# Solve +# ~~~~~ solution.Solve(True) # sphinx_gallery_start_ignore -# Assert the solution is done being solved -assert str(solution.Status) == "Done", "Solution status is not 'Done'" +assert solution.Status == SolutionStatusType.Done, "Solution status is not 'Done'" # sphinx_gallery_end_ignore # %% -# Print messages -# ~~~~~~~~~~~~~~ +# messages +# ~~~~~~~~ messages = app.ExtAPI.Application.Messages if messages: @@ -510,141 +417,115 @@ def add_ns_criterion( # ~~~~~~~~~~~~~~ # %% -# Activate the acoustic pressure result and display the image -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# Total acoustic pressure +# ^^^^^^^^^^^^^^^^^^^^^^^ -app.Tree.Activate([acoustic_pressure_result]) -set_camera_and_display_image( - camera, graphics, settings_720p, output_path, "acoustic_pressure.png" -) +app.Tree.Activate([acoustic_pressure_result_1]) +acoustic_pressure_image = cwd / "acoustic_pressure.png" +graphics.ExportImage(str(acoustic_pressure_image), image_export_format, settings_720p) +display_image("acoustic_pressure.png") # %% -# Activate the acoustic total velocity and display the image -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# Total acoustic velocity +# ^^^^^^^^^^^^^^^^^^^^^^^ -app.Tree.Activate([total_av_result]) -set_camera_and_display_image( - camera, graphics, settings_720p, output_path, "total_velocity.png" -) +app.Tree.Activate([acoustic_pressure_result_1]) +total_velocity_image = cwd / "total_velocity.png" +graphics.ExportImage(str(total_velocity_image), image_export_format, settings_720p) +display_image("total_velocity.png") # %% -# Activate the sound pressure level and display the image -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# Sound pressure level +# ^^^^^^^^^^^^^^^^^^^^ app.Tree.Activate([acoustic_spl]) -set_camera_and_display_image( - camera, graphics, settings_720p, output_path, "sound_pressure.png" -) +sound_pressure_image = cwd / "sound_pressure.png" +graphics.ExportImage(str(sound_pressure_image), image_export_format, settings_720p) +display_image("sound_pressure.png") # %% -# Activate the acoustic total velocity pressure and display the image -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# Total velocity on pressure surface +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -app.Tree.Activate([total_av_result_2]) -set_camera_and_display_image( - camera, graphics, settings_720p, output_path, "total_velocity_pressure.png" +app.Tree.Activate([acoustic_total_velocity_2]) +total_velocity_pressure_image = cwd / "total_velocity_pressure.png" +graphics.ExportImage( + str(total_velocity_pressure_image), image_export_format, settings_720p ) +display_image("total_velocity_pressure.png") # %% -# Activate the acoustic kinetic energy on the absorption face and display the image -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# Kinetic energy on absorption face +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ app.Tree.Activate([acoustic_ke]) -set_camera_and_display_image( - camera, graphics, settings_720p, output_path, "kinetic_energy.png" -) +kinetic_energy_image = cwd / "kinetic_energy.png" +graphics.ExportImage(str(kinetic_energy_image), image_export_format, settings_720p) +display_image("kinetic_energy.png") # %% -# Export the acoustic pressure animation to a GIF file and display it -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# Total acoustic pressure animation +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -animation_export_format = GraphicsAnimationExportFormat.GIF +animation_export_format = ( + Ansys.Mechanical.DataModel.Enums.GraphicsAnimationExportFormat.GIF +) settings_720p = Ansys.Mechanical.Graphics.AnimationExportSettings() settings_720p.Width = 1280 settings_720p.Height = 720 -# Set the path for the GIF -press_gif_path = output_path / "press.gif" - -# Export the force reaction animation to a GIF file -acoustic_pressure_result.ExportAnimation( - str(press_gif_path), animation_export_format, settings_720p +press_gif = cwd / "press.gif" +acoustic_pressure_result_1.ExportAnimation( + str(press_gif), animation_export_format, settings_720p ) +gif = Image.open(press_gif) +fig, ax = plt.subplots(figsize=(16, 9)) +ax.axis("off") +img = ax.imshow(gif.convert("RGBA")) -def update_animation(frame: int) -> list[mpimg.AxesImage]: - """Update the animation frame for the GIF. +def update(frame): + gif.seek(frame) + img.set_array(gif.convert("RGBA")) + return [img] - Parameters - ---------- - frame : int - The frame number to update the animation. - Returns - ------- - list[mpimg.AxesImage] - A list containing the updated image for the animation. - """ - # Seeks to the given frame in this sequence file - gif.seek(frame) - # Set the image array to the current frame of the GIF - image.set_data(gif.convert("RGBA")) - # Return the updated image - return [image] - - -# Open the GIF file and create an animation -gif = Image.open(press_gif_path) -# Set the subplots for the animation and turn off the axis -figure, axes = plt.subplots(figsize=(16, 9)) -axes.axis("off") -# Change the color of the image -image = axes.imshow(gif.convert("RGBA")) - -# Create the animation using the figure, update_animation function, and the GIF frames -# Set the interval between frames to 200 milliseconds and repeat the animation -FuncAnimation( - figure, - update_animation, - frames=range(gif.n_frames), - interval=200, - repeat=True, - blit=True, +ani = FuncAnimation( + fig, update, frames=range(gif.n_frames), interval=200, repeat=True, blit=True ) - -# Show the animation plt.show() # %% -# Display the output file from the solve -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Display output file from solve +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +def write_file_contents_to_console(path): + """Write file contents to console.""" + with open(path, "rt") as file: + for line in file: + print(line, end="") + -# Get the working directory for the solve solve_path = harmonic_acoustics.WorkingDir -# Get the solve output file path solve_out_path = Path(solve_path) / "solve.out" -# Check if the solve output file exists and print its contents if solve_out_path: - with solve_out_path.open("rt") as file: - for line in file: - print(line, end="") + write_file_contents_to_console(solve_out_path) # %% -# Print the project tree -# ~~~~~~~~~~~~~~~~~~~~~~ +# Project tree +# ~~~~~~~~~~~~ app.print_tree() # %% -# Clean up the project -# ~~~~~~~~~~~~~~~~~~~~ - -# Save the project -mechdat_path = output_path / "harmnonic_acoustics.mechdat" -app.save(str(mechdat_path)) +# Cleanup +# ~~~~~~~ +# Save project -# Clear the project +mechdat_file = cwd / "harmonic_acoustics.mechdat" +app.save(str(mechdat_file)) app.new() -# Delete the example files +# delete example file delete_downloads() From 893f90a0889e2fb09d15d0ea2ba496020640641d Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Wed, 23 Apr 2025 14:45:13 -0400 Subject: [PATCH 08/24] make vars lowercase & use pathlib instead of os --- .../fracture_analysis_contact_debonding.py | 2 +- examples/01_basic/modal_acoustics_analysis.py | 376 ++++++++-------- .../01_basic/steady_state_thermal_analysis.py | 407 +++++++++--------- .../topology_optimization_cantilever_beam.py | 144 ++++--- examples/01_basic/valve.py | 88 ++-- .../Rotor_Blade_Inverse_solve.py | 286 ++++++------ .../conact_wear_simulation.py | 298 ++++++------- .../non_linear_analsis_rubber_boot_seal.py | 386 +++++++++-------- 8 files changed, 1040 insertions(+), 947 deletions(-) diff --git a/examples/01_basic/fracture_analysis_contact_debonding.py b/examples/01_basic/fracture_analysis_contact_debonding.py index 16e90554..76916c18 100644 --- a/examples/01_basic/fracture_analysis_contact_debonding.py +++ b/examples/01_basic/fracture_analysis_contact_debonding.py @@ -466,7 +466,7 @@ def add_displacement( # sphinx_gallery_start_ignore assert ( - str(static_structural_analysis_solution.Status) == "Done" + static_structural_analysis_solution.Status == SolutionStatusType.Done ), "Solution status is not 'Done'" # sphinx_gallery_end_ignore diff --git a/examples/01_basic/modal_acoustics_analysis.py b/examples/01_basic/modal_acoustics_analysis.py index 59a5ed02..096c8fd3 100644 --- a/examples/01_basic/modal_acoustics_analysis.py +++ b/examples/01_basic/modal_acoustics_analysis.py @@ -10,7 +10,7 @@ noise reduction in various settings, audio speaker design, and geophysical exploration. Mechanical enables you to model pure acoustic problems and fluid-structure -interaction (FSI) problems.A coupled acoustic analysis accounts for FSI. +interaction (FSI) problems. A coupled acoustic analysis accounts for FSI. An uncoupled acoustic analysis simulates the fluid only and ignores any fluid-structure interaction. """ @@ -19,7 +19,7 @@ # Import necessary libraries # ~~~~~~~~~~~~~~~~~~~~~~~~~~ -import os +from pathlib import Path from PIL import Image from ansys.mechanical.core import App @@ -34,12 +34,13 @@ app = App(globals=globals()) print(app) -cwd = os.path.join(os.getcwd(), "out") +cwd = Path.cwd() / "out" def display_image(image_name): plt.figure(figsize=(16, 9)) - plt.imshow(mpimg.imread(os.path.join(cwd, image_name))) + image_path = cwd / image_name + plt.imshow(mpimg.imread(str(image_path))) plt.xticks([]) plt.yticks([]) plt.axis("off") @@ -50,7 +51,10 @@ def display_image(image_name): # Configure graphics for image export # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Graphics.Camera.SetSpecificViewOrientation(ViewOrientationType.Iso) +graphics = app.Graphics +camera = graphics.Camera + +camera.SetSpecificViewOrientation(ViewOrientationType.Iso) image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() settings_720p.Resolution = GraphicsResolutionType.EnhancedResolution @@ -71,7 +75,8 @@ def display_image(image_name): # Import the geometry # ~~~~~~~~~~~~~~~~~~~ -geometry_import_group = Model.GeometryImportGroup +model = app.Model +geometry_import_group = model.GeometryImportGroup geometry_import = geometry_import_group.AddGeometryImport() geometry_import_format = ( Ansys.Mechanical.DataModel.Enums.GeometryImportPreference.Format.Automatic @@ -82,29 +87,28 @@ def display_image(image_name): geometry_path, geometry_import_format, geometry_import_preferences ) -Graphics.Camera.SetFit() -Graphics.ExportImage( - os.path.join(cwd, "geometry.png"), image_export_format, settings_720p -) -display_image("geometry.png") +camera.SetFit() +geometry_image = cwd / "geometry.png" +graphics.ExportImage(str(geometry_image), image_export_format, settings_720p) +display_image(geometry_image.name) # %% # Store all variables necessary for analysis # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -GEOM = Model.Geometry -MESH = Model.Mesh -NS = Model.NamedSelections -CONN = Model.Connections -MAT = Model.Materials +geometry = model.Geometry +mesh = model.Mesh +named_selections = model.NamedSelections +connections = model.Connections +materials = model.Materials # %% # Import material setup analysis # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Model.AddModalAcousticAnalysis() -ExtAPI.Application.ActiveUnitSystem = MechanicalUnitSystem.StandardMKS -MAT.Import(mat_path) +model.AddModalAcousticAnalysis() +app.ExtAPI.Application.ActiveUnitSystem = MechanicalUnitSystem.StandardMKS +materials.Import(mat_path) print("Material Import Done !") # %% @@ -113,88 +117,114 @@ def display_image(image_name): acst_bodies = [ i - for i in NS.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) + for i in named_selections.GetChildren[ + Ansys.ACT.Automation.Mechanical.NamedSelection + ](True) if i.Name == "Acoustic_bodies" ][0] struct_bodies = [ i - for i in NS.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) + for i in named_selections.GetChildren[ + Ansys.ACT.Automation.Mechanical.NamedSelection + ](True) if i.Name == "Structural_bodies" ][0] top_bodies = [ i - for i in NS.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) + for i in named_selections.GetChildren[ + Ansys.ACT.Automation.Mechanical.NamedSelection + ](True) if i.Name == "top_bodies" ][0] cont_bodies = [ i - for i in NS.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) + for i in named_selections.GetChildren[ + Ansys.ACT.Automation.Mechanical.NamedSelection + ](True) if i.Name == "container_bodies" ][0] cont_V1 = [ i - for i in NS.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) + for i in named_selections.GetChildren[ + Ansys.ACT.Automation.Mechanical.NamedSelection + ](True) if i.Name == "Cont_V1" ][0] cont_V2 = [ i - for i in NS.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) + for i in named_selections.GetChildren[ + Ansys.ACT.Automation.Mechanical.NamedSelection + ](True) if i.Name == "Cont_V2" ][0] cont_V3 = [ i - for i in NS.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) + for i in named_selections.GetChildren[ + Ansys.ACT.Automation.Mechanical.NamedSelection + ](True) if i.Name == "Cont_V3" ][0] cont_face1 = [ i - for i in NS.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) + for i in named_selections.GetChildren[ + Ansys.ACT.Automation.Mechanical.NamedSelection + ](True) if i.Name == "Cont_face1" ][0] cont_face2 = [ i - for i in NS.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) + for i in named_selections.GetChildren[ + Ansys.ACT.Automation.Mechanical.NamedSelection + ](True) if i.Name == "Cont_face2" ][0] cont_face3 = [ i - for i in NS.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) + for i in named_selections.GetChildren[ + Ansys.ACT.Automation.Mechanical.NamedSelection + ](True) if i.Name == "Cont_face3" ][0] cont_face4 = [ i - for i in NS.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) + for i in named_selections.GetChildren[ + Ansys.ACT.Automation.Mechanical.NamedSelection + ](True) if i.Name == "Cont_face4" ][0] free_faces = [ i - for i in NS.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) + for i in named_selections.GetChildren[ + Ansys.ACT.Automation.Mechanical.NamedSelection + ](True) if i.Name == "Free_faces" ][0] fsi_faces = [ i - for i in NS.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) + for i in named_selections.GetChildren[ + Ansys.ACT.Automation.Mechanical.NamedSelection + ](True) if i.Name == "FSI_faces" ][0] solid1 = [ i - for i in GEOM.GetChildren[Ansys.ACT.Automation.Mechanical.Body](True) + for i in geometry.GetChildren[Ansys.ACT.Automation.Mechanical.Body](True) if i.Name == "Solid1" ][0] solid2 = [ i - for i in GEOM.GetChildren[Ansys.ACT.Automation.Mechanical.Body](True) + for i in geometry.GetChildren[Ansys.ACT.Automation.Mechanical.Body](True) if i.Name == "Solid2" ][0] solid3 = [ i - for i in GEOM.GetChildren[Ansys.ACT.Automation.Mechanical.Body](True) + for i in geometry.GetChildren[Ansys.ACT.Automation.Mechanical.Body](True) if i.Name == "Solid3" ][0] solid4 = [ i - for i in GEOM.GetChildren[Ansys.ACT.Automation.Mechanical.Body](True) + for i in geometry.GetChildren[Ansys.ACT.Automation.Mechanical.Body](True) if i.Name == "Solid4" ][0] @@ -211,81 +241,82 @@ def display_image(image_name): # Mesh # ~~~~ -MESH.ElementOrder = ElementOrder.Quadratic +mesh.ElementOrder = ElementOrder.Quadratic -method1 = MESH.AddAutomaticMethod() +method1 = mesh.AddAutomaticMethod() method1.Location = acst_bodies method1.Method = MethodType.AllTriAllTet -method2 = MESH.AddAutomaticMethod() +method2 = mesh.AddAutomaticMethod() method2.Location = top_bodies method2.Method = MethodType.Automatic # Add mesh sizing -sizing1 = MESH.AddSizing() +sizing1 = mesh.AddSizing() sizing1.Location = top_bodies sizing1.ElementSize = Quantity("0.2 [m]") sizing1.Behavior = SizingBehavior.Hard # Add mesh sizing -sizing2 = MESH.AddSizing() +sizing2 = mesh.AddSizing() sizing2.Location = acst_bodies sizing2.ElementSize = Quantity("0.2 [m]") sizing2.Behavior = SizingBehavior.Hard # Add mesh method -method3 = MESH.AddAutomaticMethod() +method3 = mesh.AddAutomaticMethod() method3.Location = cont_bodies method3.Method = MethodType.Sweep method3.SourceTargetSelection = 4 -MESH.GenerateMesh() +mesh.GenerateMesh() -Graphics.ExportImage(os.path.join(cwd, "mesh.png"), image_export_format, settings_720p) -display_image("mesh.png") +mesh_image = cwd / "mesh.png" +graphics.ExportImage(str(mesh_image), image_export_format, settings_720p) +display_image(mesh_image.name) # %% # Insert contacts # ~~~~~~~~~~~~~~~ # Contact 1 -CONN_GROUP = CONN.AddConnectionGroup() -CONT1 = CONN_GROUP.AddContactRegion() -CONT1.SourceLocation = cont_V1 -CONT1.TargetLocation = cont_face1 -CONT1.ContactFormulation = ContactFormulation.MPC -CONT1.Behavior = ContactBehavior.Asymmetric -CONT1.PinballRegion = ContactPinballType.Radius -CONT1.PinballRadius = Quantity("0.25 [m]") +connection_group = connections.AddConnectionGroup() +contact_region_1 = connection_group.AddContactRegion() +contact_region_1.SourceLocation = cont_V1 +contact_region_1.TargetLocation = cont_face1 +contact_region_1.ContactFormulation = ContactFormulation.MPC +contact_region_1.Behavior = ContactBehavior.Asymmetric +contact_region_1.PinballRegion = ContactPinballType.Radius +contact_region_1.PinballRadius = Quantity("0.25 [m]") # %% # Contact 2 -CONT2 = CONN_GROUP.AddContactRegion() -CONT2.SourceLocation = cont_V2 -CONT2.TargetLocation = cont_face2 -CONT2.ContactFormulation = ContactFormulation.MPC -CONT2.Behavior = ContactBehavior.Asymmetric -CONT2.PinballRegion = ContactPinballType.Radius -CONT2.PinballRadius = Quantity("0.25 [m]") +contact_region_2 = connection_group.AddContactRegion() +contact_region_2.SourceLocation = cont_V2 +contact_region_2.TargetLocation = cont_face2 +contact_region_2.ContactFormulation = ContactFormulation.MPC +contact_region_2.Behavior = ContactBehavior.Asymmetric +contact_region_2.PinballRegion = ContactPinballType.Radius +contact_region_2.PinballRadius = Quantity("0.25 [m]") # %% # Contact 3 -CONT3 = CONN_GROUP.AddContactRegion() -CONT3.SourceLocation = cont_V3 -CONT3.TargetLocation = cont_face3 -CONT3.ContactFormulation = ContactFormulation.MPC -CONT3.Behavior = ContactBehavior.Asymmetric -CONT3.PinballRegion = ContactPinballType.Radius -CONT3.PinballRadius = Quantity("0.25 [m]") +contact_region_3 = connection_group.AddContactRegion() +contact_region_3.SourceLocation = cont_V3 +contact_region_3.TargetLocation = cont_face3 +contact_region_3.ContactFormulation = ContactFormulation.MPC +contact_region_3.Behavior = ContactBehavior.Asymmetric +contact_region_3.PinballRegion = ContactPinballType.Radius +contact_region_3.PinballRadius = Quantity("0.25 [m]") # %% # Contact 3 -sel_manager = ExtAPI.SelectionManager +sel_manager = app.ExtAPI.SelectionManager cnv4 = DataModel.GeoData.Assemblies[0].Parts[1].Bodies[0].Vertices[3] cont_V4 = sel_manager.CreateSelectionInfo(SelectionTypeEnum.GeometryEntities) cont_V4.Entities = [cnv4] @@ -293,59 +324,59 @@ def display_image(image_name): # %% # Contact 4 -CONT4 = CONN_GROUP.AddContactRegion() -CONT4.TargetLocation = cont_face4 -CONT4.SourceLocation = cont_V4 -CONT4.ContactFormulation = ContactFormulation.MPC -CONT4.Behavior = ContactBehavior.Asymmetric -CONT4.PinballRegion = ContactPinballType.Radius -CONT4.PinballRadius = Quantity("0.25 [m]") +contact_region_4 = connection_group.AddContactRegion() +contact_region_4.TargetLocation = cont_face4 +contact_region_4.SourceLocation = cont_V4 +contact_region_4.ContactFormulation = ContactFormulation.MPC +contact_region_4.Behavior = ContactBehavior.Asymmetric +contact_region_4.PinballRegion = ContactPinballType.Radius +contact_region_4.PinballRadius = Quantity("0.25 [m]") # %% # Fully define Modal Multiphysics region with two physics regions -MODAL_ACST = DataModel.Project.Model.Analyses[0] -ACOUST_REG = MODAL_ACST.Children[2] -ACOUST_REG.Location = acst_bodies +modal_acst = DataModel.Project.Model.Analyses[0] +acoustic_region = modal_acst.Children[2] +acoustic_region.Location = acst_bodies -STRUCT_REG = MODAL_ACST.AddPhysicsRegion() -STRUCT_REG.Structural = True -STRUCT_REG.RenameBasedOnDefinition() -STRUCT_REG.Location = struct_bodies +structural_region = modal_acst.AddPhysicsRegion() +structural_region.Structural = True +structural_region.RenameBasedOnDefinition() +structural_region.Location = struct_bodies # %% # Analysis settings # ~~~~~~~~~~~~~~~~~ -ANALYSIS_SETTINGS = MODAL_ACST.Children[1] -ANALYSIS_SETTINGS.MaximumModesToFind = 12 -ANALYSIS_SETTINGS.SearchRangeMinimum = Quantity("0.1 [Hz]") -ANALYSIS_SETTINGS.SolverType = SolverType.Unsymmetric -ANALYSIS_SETTINGS.GeneralMiscellaneous = True -ANALYSIS_SETTINGS.CalculateReactions = True +analysis_settings = modal_acst.Children[1] +analysis_settings.MaximumModesToFind = 12 +analysis_settings.SearchRangeMinimum = Quantity("0.1 [Hz]") +analysis_settings.SolverType = SolverType.Unsymmetric +analysis_settings.GeneralMiscellaneous = True +analysis_settings.CalculateReactions = True # %% # Boundary conditions and load # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Free surface -FREE_SF = MODAL_ACST.AddAcousticFreeSurface() -FREE_SF.Location = free_faces +free_surface = modal_acst.AddAcousticFreeSurface() +free_surface.Location = free_faces # %% # Solid fluid interface -FSI_OBJ = MODAL_ACST.AddFluidSolidInterface() -FSI_OBJ.Location = fsi_faces +fsi_object = modal_acst.AddFluidSolidInterface() +fsi_object.Location = fsi_faces # %% # Gravity -ACCELERATION = MODAL_ACST.AddAcceleration() -ACCELERATION.DefineBy = LoadDefineBy.Components -ACCELERATION.YComponent.Output.DiscreteValues = [Quantity("9.81 [m sec^-1 sec^-1]")] +acceleration = modal_acst.AddAcceleration() +acceleration.DefineBy = LoadDefineBy.Components +acceleration.YComponent.Output.DiscreteValues = [Quantity("9.81 [m sec^-1 sec^-1]")] # %% # Fixed Support @@ -357,51 +388,50 @@ def display_image(image_name): fvert = sel_manager.CreateSelectionInfo(SelectionTypeEnum.GeometryEntities) fvert.Entities = [fv1, fv2, fv3, fv4] -FIXED_SUPPORT = MODAL_ACST.AddFixedSupport() -FIXED_SUPPORT.Location = fvert +fixed_support = modal_acst.AddFixedSupport() +fixed_support.Location = fvert -MODAL_ACST.Activate() -Graphics.ExportImage( - os.path.join(cwd, "geometry.png"), image_export_format, settings_720p -) -display_image("geometry.png") +modal_acst.Activate() + +graphics.ExportImage(str(geometry_image), image_export_format, settings_720p) +display_image(geometry_image.name) # %% # Add results # ~~~~~~~~~~~ # Add 10 modes -soln = Model.Analyses[0].Solution -TOT_DEF1 = soln.AddTotalDeformation() -TOT_DEF2 = soln.AddTotalDeformation() -TOT_DEF2.Mode = 2 -TOT_DEF3 = soln.AddTotalDeformation() -TOT_DEF3.Mode = 3 -TOT_DEF4 = soln.AddTotalDeformation() -TOT_DEF4.Mode = 4 -TOT_DEF5 = soln.AddTotalDeformation() -TOT_DEF5.Mode = 5 -TOT_DEF6 = soln.AddTotalDeformation() -TOT_DEF6.Mode = 6 -TOT_DEF7 = soln.AddTotalDeformation() -TOT_DEF7.Mode = 7 -TOT_DEF8 = soln.AddTotalDeformation() -TOT_DEF8.Mode = 8 -TOT_DEF9 = soln.AddTotalDeformation() -TOT_DEF9.Mode = 9 -TOT_DEF10 = soln.AddTotalDeformation() -TOT_DEF10.Mode = 10 +soln = model.Analyses[0].Solution +total_deformation_1 = soln.AddTotalDeformation() +total_deformation_2 = soln.AddTotalDeformation() +total_deformation_2.Mode = 2 +total_deformation_3 = soln.AddTotalDeformation() +total_deformation_3.Mode = 3 +total_deformation_4 = soln.AddTotalDeformation() +total_deformation_4.Mode = 4 +total_deformation_5 = soln.AddTotalDeformation() +total_deformation_5.Mode = 5 +total_deformation_6 = soln.AddTotalDeformation() +total_deformation_6.Mode = 6 +total_deformation_7 = soln.AddTotalDeformation() +total_deformation_7.Mode = 7 +total_deformation_8 = soln.AddTotalDeformation() +total_deformation_8.Mode = 8 +total_deformation_9 = soln.AddTotalDeformation() +total_deformation_9.Mode = 9 +total_deformation_10 = soln.AddTotalDeformation() +total_deformation_10.Mode = 10 # %% # Add acoustic pressure -ACOUST_PRES_RES = soln.AddAcousticPressureResult() +acoustic_pressure_result = soln.AddAcousticPressureResult() # %% # Add force reaction scoped to fixed Support -FORCE_REACT1 = soln.AddForceReaction() -FORCE_REACT1.BoundaryConditionSelection = FIXED_SUPPORT +force_reaction_1 = soln.AddForceReaction() +force_reaction_1.BoundaryConditionSelection = fixed_support # %% # Solve @@ -410,7 +440,7 @@ def display_image(image_name): soln.Solve(True) # sphinx_gallery_start_ignore -assert str(soln.Status) == "Done", "Solution status is not 'Done'" +assert soln.Status == SolutionStatusType.Done, "Solution status is not 'Done'" # sphinx_gallery_end_ignore @@ -418,12 +448,12 @@ def display_image(image_name): # Messages # ~~~~~~~~ -Messages = ExtAPI.Application.Messages -if Messages: - for message in Messages: +messages = app.ExtAPI.Application.Messages +if messages: + for message in messages: print(f"[{message.Severity}] {message.DisplayString}") else: - print("No [Info]/[Warning]/[Error] Messages") + print("No [Info]/[Warning]/[Error] messages") # %% @@ -431,61 +461,59 @@ def display_image(image_name): # ~~~~~~~ # Total deformation - mode 1 -Tree.Activate([TOT_DEF1]) -Graphics.Camera.SetFit() -Graphics.ExportImage( - os.path.join(cwd, "totaldeformation1.png"), image_export_format, settings_720p -) -display_image("totaldeformation1.png") +app.Tree.Activate([total_deformation_1]) +camera.SetFit() +total_deformation_image = cwd / "total_deformation_1.png" +graphics.ExportImage(str(total_deformation_image), image_export_format, settings_720p) +display_image(total_deformation_image.name) # %% # Acoustic pressure -Tree.Activate([ACOUST_PRES_RES]) -Graphics.ExportImage( - os.path.join(cwd, "acoustic_pressure.png"), image_export_format, settings_720p -) -display_image("acoustic_pressure.png") +app.Tree.Activate([acoustic_pressure_result]) +acoustic_pressure_image = cwd / "acoustic_pressure.png" +graphics.ExportImage(str(acoustic_pressure_image), image_export_format, settings_720p) +display_image(acoustic_pressure_image.name) # %% # Display all modal frequency, force reaction # and acoustic pressure values -FREQ1 = TOT_DEF1.ReportedFrequency.Value -FREQ2 = TOT_DEF2.ReportedFrequency.Value -FREQ3 = TOT_DEF3.ReportedFrequency.Value -FREQ4 = TOT_DEF4.ReportedFrequency.Value -FREQ5 = TOT_DEF5.ReportedFrequency.Value -FREQ6 = TOT_DEF6.ReportedFrequency.Value -FREQ7 = TOT_DEF7.ReportedFrequency.Value -FREQ8 = TOT_DEF8.ReportedFrequency.Value -FREQ9 = TOT_DEF9.ReportedFrequency.Value -FREQ10 = TOT_DEF10.ReportedFrequency.Value +frequency_1 = total_deformation_1.ReportedFrequency.Value +frequency_2 = total_deformation_2.ReportedFrequency.Value +frequency_3 = total_deformation_3.ReportedFrequency.Value +frequency_4 = total_deformation_4.ReportedFrequency.Value +frequency_5 = total_deformation_5.ReportedFrequency.Value +frequency_6 = total_deformation_6.ReportedFrequency.Value +frequency_7 = total_deformation_7.ReportedFrequency.Value +frequency_8 = total_deformation_8.ReportedFrequency.Value +frequency_9 = total_deformation_9.ReportedFrequency.Value +frequency_10 = total_deformation_10.ReportedFrequency.Value -PRMAX = ACOUST_PRES_RES.Maximum.Value -PRMIN = ACOUST_PRES_RES.Minimum.Value +pressure_result_max = acoustic_pressure_result.Maximum.Value +pressure_result_min = acoustic_pressure_result.Minimum.Value -FRC1_X = FORCE_REACT1.XAxis.Value -FRC1_Z = FORCE_REACT1.ZAxis.Value +force_reaction_1_x = force_reaction_1.XAxis.Value +force_reaction_1_z = force_reaction_1.ZAxis.Value print("Modal Acoustic Results") print("----------------------") -print("Frequency for mode 1 : ", FREQ1) -print("Frequency for mode 2 : ", FREQ2) -print("Frequency for mode 3 : ", FREQ3) -print("Frequency for mode 4 : ", FREQ4) -print("Frequency for mode 5 : ", FREQ5) -print("Frequency for mode 6 : ", FREQ6) -print("Frequency for mode 7 : ", FREQ7) -print("Frequency for mode 8 : ", FREQ8) -print("Frequency for mode 9 : ", FREQ9) -print("Frequency for mode 10 : ", FREQ10) -print("Acoustic pressure minimum : ", PRMIN) -print("Acoustic pressure Maximum : ", PRMAX) -print("Force reaction x-axis : ", FRC1_X) -print("Force reaction z-axis : ", FRC1_Z) +print("Frequency for mode 1 : ", frequency_1) +print("Frequency for mode 2 : ", frequency_2) +print("Frequency for mode 3 : ", frequency_3) +print("Frequency for mode 4 : ", frequency_4) +print("Frequency for mode 5 : ", frequency_5) +print("Frequency for mode 6 : ", frequency_6) +print("Frequency for mode 7 : ", frequency_7) +print("Frequency for mode 8 : ", frequency_8) +print("Frequency for mode 9 : ", frequency_9) +print("Frequency for mode 10 : ", frequency_10) +print("Acoustic pressure minimum : ", pressure_result_min) +print("Acoustic pressure Maximum : ", pressure_result_max) +print("Force reaction x-axis : ", force_reaction_1_x) +print("Force reaction z-axis : ", force_reaction_1_z) # %% # Total deformation animation for mode 10 @@ -497,10 +525,11 @@ def display_image(image_name): settings_720p.Width = 1280 settings_720p.Height = 720 -TOT_DEF10.ExportAnimation( - os.path.join(cwd, "deformation_10.gif"), animation_export_format, settings_720p +deformation_gif = cwd / "deformation_10.gif" +total_deformation_10.ExportAnimation( + str(deformation_gif), animation_export_format, settings_720p ) -gif = Image.open(os.path.join(cwd, "deformation_10.gif")) +gif = Image.open(deformation_gif) fig, ax = plt.subplots(figsize=(16, 9)) ax.axis("off") img = ax.imshow(gif.convert("RGBA")) @@ -528,7 +557,8 @@ def update(frame): # ~~~~~~~ # Save project -app.save(os.path.join(cwd, "modal_acoustics.mechdat")) +mechdat_file = cwd / "modal_acoustics.mechdat" +app.save(str(mechdat_file)) app.new() # %% diff --git a/examples/01_basic/steady_state_thermal_analysis.py b/examples/01_basic/steady_state_thermal_analysis.py index 56f43024..978d84fd 100644 --- a/examples/01_basic/steady_state_thermal_analysis.py +++ b/examples/01_basic/steady_state_thermal_analysis.py @@ -15,8 +15,7 @@ # Import necessary libraries # ~~~~~~~~~~~~~~~~~~~~~~~~~~ - -import os +from pathlib import Path from PIL import Image from ansys.mechanical.core import App @@ -31,12 +30,13 @@ app = App(globals=globals()) print(app) -cwd = os.path.join(os.getcwd(), "out") +cwd = Path.cwd() / "out" def display_image(image_name): plt.figure(figsize=(16, 9)) - plt.imshow(mpimg.imread(os.path.join(cwd, image_name))) + image_path = cwd / image_name + plt.imshow(mpimg.imread(str(image_path))) plt.xticks([]) plt.yticks([]) plt.axis("off") @@ -47,8 +47,11 @@ def display_image(image_name): # Configure graphics for image export # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Graphics.Camera.SetSpecificViewOrientation(ViewOrientationType.Iso) -Graphics.Camera.SetFit() +graphics = app.Graphics +camera = graphics.Camera + +camera.SetSpecificViewOrientation(ViewOrientationType.Iso) +camera.SetFit() image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() settings_720p.Resolution = GraphicsResolutionType.EnhancedResolution @@ -68,7 +71,9 @@ def display_image(image_name): # %% # Import the geometry -geometry_import_group = Model.GeometryImportGroup +model = app.Model + +geometry_import_group = model.GeometryImportGroup geometry_import = geometry_import_group.AddGeometryImport() geometry_import_format = ( Ansys.Mechanical.DataModel.Enums.GeometryImportPreference.Format.Automatic @@ -86,158 +91,157 @@ def display_image(image_name): # Add steady state thermal analysis # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Model.AddSteadyStateThermalAnalysis() -ExtAPI.Application.ActiveUnitSystem = MechanicalUnitSystem.StandardMKS -STAT_THERM = Model.Analyses[0] -MODEL = Model -CS = MODEL.CoordinateSystems -LCS1 = CS.AddCoordinateSystem() -LCS1.OriginX = Quantity("0 [m]") +model.AddSteadyStateThermalAnalysis() +app.ExtAPI.Application.ActiveUnitSystem = MechanicalUnitSystem.StandardMKS +stat_therm = model.Analyses[0] +coordinate_systems = model.CoordinateSystems +lcs1 = coordinate_systems.AddCoordinateSystem() +lcs1.OriginX = Quantity("0 [m]") -LCS2 = CS.AddCoordinateSystem() -LCS2.OriginX = Quantity("0 [m]") -LCS2.PrimaryAxisDefineBy = CoordinateSystemAlignmentType.GlobalY +lcs2 = coordinate_systems.AddCoordinateSystem() +lcs2.OriginX = Quantity("0 [m]") +lcs2.PrimaryAxisDefineBy = CoordinateSystemAlignmentType.GlobalY # %% # Create named selections and construction geometry # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Create named selections -FACE1 = Model.AddNamedSelection() -FACE1.ScopingMethod = GeometryDefineByType.Worksheet -FACE1.Name = "Face1" -GEN_CRT1 = FACE1.GenerationCriteria -CRT1 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() -CRT1.Active = True -CRT1.Action = SelectionActionType.Add -CRT1.EntityType = SelectionType.GeoFace -CRT1.Criterion = SelectionCriterionType.LocationZ -CRT1.Operator = SelectionOperatorType.Equal -CRT1.Value = Quantity("20 [m]") -GEN_CRT1.Add(CRT1) -FACE1.Activate() -FACE1.Generate() - -FACE2 = Model.AddNamedSelection() -FACE2.ScopingMethod = GeometryDefineByType.Worksheet -FACE2.Name = "Face2" -GEN_CRT2 = FACE2.GenerationCriteria -CRT1 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() -CRT1.Active = True -CRT1.Action = SelectionActionType.Add -CRT1.EntityType = SelectionType.GeoFace -CRT1.Criterion = SelectionCriterionType.LocationZ -CRT1.Operator = SelectionOperatorType.Equal -CRT1.Value = Quantity("0 [m]") -GEN_CRT2.Add(CRT1) -FACE2.Activate() -FACE2.Generate() - -FACE3 = Model.AddNamedSelection() -FACE3.ScopingMethod = GeometryDefineByType.Worksheet -FACE3.Name = "Face3" -GEN_CRT3 = FACE3.GenerationCriteria -CRT1 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() -CRT1.Active = True -CRT1.Action = SelectionActionType.Add -CRT1.EntityType = SelectionType.GeoFace -CRT1.Criterion = SelectionCriterionType.LocationX -CRT1.Operator = SelectionOperatorType.Equal -CRT1.Value = Quantity("1 [m]") -GEN_CRT3.Add(CRT1) -CRT2 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() -CRT2.Active = True -CRT2.Action = SelectionActionType.Filter -CRT2.EntityType = SelectionType.GeoFace -CRT2.Criterion = SelectionCriterionType.LocationY -CRT2.Operator = SelectionOperatorType.Equal -CRT2.Value = Quantity("2 [m]") -GEN_CRT3.Add(CRT2) -CRT3 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() -CRT3.Active = True -CRT3.Action = SelectionActionType.Filter -CRT3.EntityType = SelectionType.GeoFace -CRT3.Criterion = SelectionCriterionType.LocationZ -CRT3.Operator = SelectionOperatorType.Equal -CRT3.Value = Quantity("12 [m]") -GEN_CRT3.Add(CRT3) -CRT4 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() -CRT4.Active = True -CRT4.Action = SelectionActionType.Add -CRT4.EntityType = SelectionType.GeoFace -CRT4.Criterion = SelectionCriterionType.LocationZ -CRT4.Operator = SelectionOperatorType.Equal -CRT4.Value = Quantity("4.5 [m]") -GEN_CRT3.Add(CRT4) -CRT5 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() -CRT5.Active = True -CRT5.Action = SelectionActionType.Filter -CRT5.EntityType = SelectionType.GeoFace -CRT5.Criterion = SelectionCriterionType.LocationY -CRT5.Operator = SelectionOperatorType.Equal -CRT5.Value = Quantity("2 [m]") -GEN_CRT3.Add(CRT5) -FACE3.Activate() -FACE3.Generate() - -BODY1 = Model.AddNamedSelection() -BODY1.ScopingMethod = GeometryDefineByType.Worksheet -BODY1.Name = "Body1" -BODY1.GenerationCriteria.Add(None) -BODY1.GenerationCriteria[0].EntityType = SelectionType.GeoFace -BODY1.GenerationCriteria[0].Criterion = SelectionCriterionType.LocationZ -BODY1.GenerationCriteria[0].Operator = SelectionOperatorType.Equal -BODY1.GenerationCriteria[0].Value = Quantity("1 [m]") -BODY1.GenerationCriteria.Add(None) -BODY1.GenerationCriteria[1].EntityType = SelectionType.GeoFace -BODY1.GenerationCriteria[1].Criterion = SelectionCriterionType.LocationZ -BODY1.GenerationCriteria[1].Operator = SelectionOperatorType.Equal -BODY1.GenerationCriteria[1].Value = Quantity("1 [m]") -BODY1.Generate() +face1 = model.AddNamedSelection() +face1.ScopingMethod = GeometryDefineByType.Worksheet +face1.Name = "Face1" +gen_crt1 = face1.GenerationCriteria +crt1 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() +crt1.Active = True +crt1.Action = SelectionActionType.Add +crt1.EntityType = SelectionType.GeoFace +crt1.Criterion = SelectionCriterionType.LocationZ +crt1.Operator = SelectionOperatorType.Equal +crt1.Value = Quantity("20 [m]") +gen_crt1.Add(crt1) +face1.Activate() +face1.Generate() + +face2 = model.AddNamedSelection() +face2.ScopingMethod = GeometryDefineByType.Worksheet +face2.Name = "Face2" +gen_crt2 = face2.GenerationCriteria +crt1 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() +crt1.Active = True +crt1.Action = SelectionActionType.Add +crt1.EntityType = SelectionType.GeoFace +crt1.Criterion = SelectionCriterionType.LocationZ +crt1.Operator = SelectionOperatorType.Equal +crt1.Value = Quantity("0 [m]") +gen_crt2.Add(crt1) +face2.Activate() +face2.Generate() + +face3 = model.AddNamedSelection() +face3.ScopingMethod = GeometryDefineByType.Worksheet +face3.Name = "Face3" +gen_crt3 = face3.GenerationCriteria +crt1 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() +crt1.Active = True +crt1.Action = SelectionActionType.Add +crt1.EntityType = SelectionType.GeoFace +crt1.Criterion = SelectionCriterionType.LocationX +crt1.Operator = SelectionOperatorType.Equal +crt1.Value = Quantity("1 [m]") +gen_crt3.Add(crt1) +crt2 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() +crt2.Active = True +crt2.Action = SelectionActionType.Filter +crt2.EntityType = SelectionType.GeoFace +crt2.Criterion = SelectionCriterionType.LocationY +crt2.Operator = SelectionOperatorType.Equal +crt2.Value = Quantity("2 [m]") +gen_crt3.Add(crt2) +crt3 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() +crt3.Active = True +crt3.Action = SelectionActionType.Filter +crt3.EntityType = SelectionType.GeoFace +crt3.Criterion = SelectionCriterionType.LocationZ +crt3.Operator = SelectionOperatorType.Equal +crt3.Value = Quantity("12 [m]") +gen_crt3.Add(crt3) +crt4 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() +crt4.Active = True +crt4.Action = SelectionActionType.Add +crt4.EntityType = SelectionType.GeoFace +crt4.Criterion = SelectionCriterionType.LocationZ +crt4.Operator = SelectionOperatorType.Equal +crt4.Value = Quantity("4.5 [m]") +gen_crt3.Add(crt4) +crt5 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() +crt5.Active = True +crt5.Action = SelectionActionType.Filter +crt5.EntityType = SelectionType.GeoFace +crt5.Criterion = SelectionCriterionType.LocationY +crt5.Operator = SelectionOperatorType.Equal +crt5.Value = Quantity("2 [m]") +gen_crt3.Add(crt5) +face3.Activate() +face3.Generate() + +body1 = model.AddNamedSelection() +body1.ScopingMethod = GeometryDefineByType.Worksheet +body1.Name = "Body1" +body1.GenerationCriteria.Add(None) +body1.GenerationCriteria[0].EntityType = SelectionType.GeoFace +body1.GenerationCriteria[0].Criterion = SelectionCriterionType.LocationZ +body1.GenerationCriteria[0].Operator = SelectionOperatorType.Equal +body1.GenerationCriteria[0].Value = Quantity("1 [m]") +body1.GenerationCriteria.Add(None) +body1.GenerationCriteria[1].EntityType = SelectionType.GeoFace +body1.GenerationCriteria[1].Criterion = SelectionCriterionType.LocationZ +body1.GenerationCriteria[1].Operator = SelectionOperatorType.Equal +body1.GenerationCriteria[1].Value = Quantity("1 [m]") +body1.Generate() # %% # Create construction geometry -CONST_GEOM = MODEL.AddConstructionGeometry() -Path = CONST_GEOM.AddPath() +construction_geometry = model.AddConstructionGeometry() +Path = construction_geometry.AddPath() Path.StartYCoordinate = Quantity(2, "m") Path.StartZCoordinate = Quantity(20, "m") Path.StartZCoordinate = Quantity(20, "m") Path.EndXCoordinate = Quantity(2, "m") -SURF = CONST_GEOM.AddSurface() -SURF.CoordinateSystem = LCS2 -CONST_GEOM.UpdateAllSolids() +surface = construction_geometry.AddSurface() +surface.CoordinateSystem = lcs2 +construction_geometry.UpdateAllSolids() # %% # Define boundary condition and add results # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Add temperature boundary conditions -TEMP = STAT_THERM.AddTemperature() -TEMP.Location = FACE1 -TEMP.Magnitude.Output.DiscreteValues = [Quantity("22[C]"), Quantity("30[C]")] +temp = stat_therm.AddTemperature() +temp.Location = face1 +temp.Magnitude.Output.DiscreteValues = [Quantity("22[C]"), Quantity("30[C]")] -TEMP2 = STAT_THERM.AddTemperature() -TEMP2.Location = FACE2 -TEMP2.Magnitude.Output.DiscreteValues = [Quantity("22[C]"), Quantity("60[C]")] +temp2 = stat_therm.AddTemperature() +temp2.Location = face2 +temp2.Magnitude.Output.DiscreteValues = [Quantity("22[C]"), Quantity("60[C]")] -TEMP.Magnitude.Inputs[0].DiscreteValues = [ +temp.Magnitude.Inputs[0].DiscreteValues = [ Quantity("0 [sec]"), Quantity("1 [sec]"), Quantity("2 [sec]"), ] -TEMP.Magnitude.Output.DiscreteValues = [ +temp.Magnitude.Output.DiscreteValues = [ Quantity("22[C]"), Quantity("30[C]"), Quantity("40[C]"), ] -TEMP2.Magnitude.Inputs[0].DiscreteValues = [ +temp2.Magnitude.Inputs[0].DiscreteValues = [ Quantity("0 [sec]"), Quantity("1 [sec]"), Quantity("2 [sec]"), ] -TEMP2.Magnitude.Output.DiscreteValues = [ +temp2.Magnitude.Output.DiscreteValues = [ Quantity("22[C]"), Quantity("50[C]"), Quantity("80[C]"), @@ -246,162 +250,167 @@ def display_image(image_name): # %% # Add radiation -RAD = STAT_THERM.AddRadiation() -RAD.Location = FACE3 -RAD.AmbientTemperature.Inputs[0].DiscreteValues = [ +radiation = stat_therm.AddRadiation() +radiation.Location = face3 +radiation.AmbientTemperature.Inputs[0].DiscreteValues = [ Quantity("0 [sec]"), Quantity("1 [sec]"), Quantity("2 [sec]"), ] -RAD.AmbientTemperature.Output.DiscreteValues = [ +radiation.AmbientTemperature.Output.DiscreteValues = [ Quantity("22[C]"), Quantity("30[C]"), Quantity("40[C]"), ] -RAD.Correlation = RadiationType.SurfaceToSurface +radiation.Correlation = RadiationType.SurfaceToSurface # %% # Analysis settings -ANLYS_SET = STAT_THERM.AnalysisSettings -ANLYS_SET.NumberOfSteps = 2 -ANLYS_SET.CalculateVolumeEnergy = True +analysis_settings = stat_therm.AnalysisSettings +analysis_settings.NumberOfSteps = 2 +analysis_settings.CalculateVolumeEnergy = True -STAT_THERM.Activate() -Graphics.Camera.SetFit() -Graphics.ExportImage( - os.path.join(cwd, "BC_steadystate.png"), image_export_format, settings_720p -) -display_image("BC_steadystate.png") +stat_therm.Activate() +camera.SetFit() +steady_state_image = cwd / "BC_steady_state.png" +graphics.ExportImage(str(steady_state_image), image_export_format, settings_720p) +display_image(steady_state_image.name) # %% # Add results # ~~~~~~~~~~~ # Temperature -STAT_THERM_SOLN = Model.Analyses[0].Solution -TEMP_RST = STAT_THERM_SOLN.AddTemperature() -TEMP_RST.By = SetDriverStyle.MaximumOverTime +stat_therm_soln = model.Analyses[0].Solution +temp_rst = stat_therm_soln.AddTemperature() +temp_rst.By = SetDriverStyle.MaximumOverTime -TEMP_RST2 = STAT_THERM_SOLN.AddTemperature() -TEMP_RST2.Location = BODY1 +temp_rst2 = stat_therm_soln.AddTemperature() +temp_rst2.Location = body1 -TEMP_RST3 = STAT_THERM_SOLN.AddTemperature() -TEMP_RST3.Location = Path +temp_rst3 = stat_therm_soln.AddTemperature() +temp_rst3.Location = Path -TEMP_RST4 = STAT_THERM_SOLN.AddTemperature() -TEMP_RST4.Location = SURF +temp_rst4 = stat_therm_soln.AddTemperature() +temp_rst4.Location = surface # %% # Total and directional heat flux -TOT_HFLUX = STAT_THERM_SOLN.AddTotalHeatFlux() -DIR_HFLUX = STAT_THERM_SOLN.AddTotalHeatFlux() -DIR_HFLUX.ThermalResultType = TotalOrDirectional.Directional -DIR_HFLUX.NormalOrientation = NormalOrientationType.ZAxis +total_heat_flux = stat_therm_soln.AddTotalHeatFlux() +directional_heat_flux = stat_therm_soln.AddTotalHeatFlux() +directional_heat_flux.ThermalResultType = TotalOrDirectional.Directional +directional_heat_flux.NormalOrientation = NormalOrientationType.ZAxis -LCS2.PrimaryAxisDefineBy = CoordinateSystemAlignmentType.GlobalZ -DIR_HFLUX.CoordinateSystem = LCS2 -DIR_HFLUX.DisplayOption = ResultAveragingType.Averaged +lcs2.PrimaryAxisDefineBy = CoordinateSystemAlignmentType.GlobalZ +directional_heat_flux.CoordinateSystem = lcs2 +directional_heat_flux.DisplayOption = ResultAveragingType.Averaged # %% # Thermal error -THERM_ERROR = STAT_THERM_SOLN.AddThermalError() +thermal_error = stat_therm_soln.AddThermalError() # %% # Temperature probe -TEMP_PROBE = STAT_THERM_SOLN.AddTemperatureProbe() -TEMP_PROBE.GeometryLocation = FACE1 -TEMP_PROBE.LocationMethod = LocationDefinitionMethod.CoordinateSystem -TEMP_PROBE.CoordinateSystemSelection = LCS2 +temp_probe = stat_therm_soln.AddTemperatureProbe() +temp_probe.GeometryLocation = face1 +temp_probe.LocationMethod = LocationDefinitionMethod.CoordinateSystem +temp_probe.CoordinateSystemSelection = lcs2 # %% # Heat flux probe -HFLUX_PROBE = STAT_THERM_SOLN.AddHeatFluxProbe() -HFLUX_PROBE.LocationMethod = LocationDefinitionMethod.CoordinateSystem -HFLUX_PROBE.CoordinateSystemSelection = LCS2 -HFLUX_PROBE.ResultSelection = ProbeDisplayFilter.ZAxis +hflux_probe = stat_therm_soln.AddHeatFluxProbe() +hflux_probe.LocationMethod = LocationDefinitionMethod.CoordinateSystem +hflux_probe.CoordinateSystemSelection = lcs2 +hflux_probe.ResultSelection = ProbeDisplayFilter.ZAxis # %% # Reaction probe -ANLYS_SET.NodalForces = OutputControlsNodalForcesType.Yes -REAC_PROBE = STAT_THERM_SOLN.AddReactionProbe() -REAC_PROBE.LocationMethod = LocationDefinitionMethod.GeometrySelection -REAC_PROBE.GeometryLocation = FACE1 +analysis_settings.NodalForces = OutputControlsNodalForcesType.Yes +reaction_probe = stat_therm_soln.AddReactionProbe() +reaction_probe.LocationMethod = LocationDefinitionMethod.GeometrySelection +reaction_probe.GeometryLocation = face1 # %% # Radiation probe -Rad_Probe = STAT_THERM_SOLN.AddRadiationProbe() -Rad_Probe.BoundaryConditionSelection = RAD -Rad_Probe.ResultSelection = ProbeDisplayFilter.All +radiation_probe = stat_therm_soln.AddRadiationProbe() +radiation_probe.BoundaryConditionSelection = radiation +radiation_probe.ResultSelection = ProbeDisplayFilter.All # %% # Solve # ~~~~~ -STAT_THERM_SOLN.Solve(True) +stat_therm_soln.Solve(True) # sphinx_gallery_start_ignore -assert str(STAT_THERM_SOLN.Status) == "Done", "Solution status is not 'Done'" +assert ( + stat_therm_soln.Status == SolutionStatusType.Done +), "Solution status is not 'Done'" # sphinx_gallery_end_ignore # %% # Messages # ~~~~~~~~ -Messages = ExtAPI.Application.Messages -if Messages: - for message in Messages: +messages = app.ExtAPI.Application.Messages +if messages: + for message in messages: print(f"[{message.Severity}] {message.DisplayString}") else: - print("No [Info]/[Warning]/[Error] Messages") + print("No [Info]/[Warning]/[Error] messages") # Display results # ~~~~~~~~~~~~~~~ # Total body temperature -Tree.Activate([TEMP_RST]) -Graphics.Camera.SetFit() -Graphics.ExportImage(os.path.join(cwd, "temp.png"), image_export_format, settings_720p) -display_image("temp.png") +app.Tree.Activate([temp_rst]) +camera.SetFit() +temp_image = cwd / "temp.png" +graphics.ExportImage(str(temp_image), image_export_format, settings_720p) +display_image(temp_image.name) # %% # Temperature on part of the body -Tree.Activate([TEMP_RST2]) -Graphics.Camera.SetFit() -Graphics.ExportImage(os.path.join(cwd, "temp2.png"), image_export_format, settings_720p) -display_image("temp2.png") +app.Tree.Activate([temp_rst2]) +camera.SetFit() +temp2_image = cwd / "temp2.png" +graphics.ExportImage(str(temp2_image), image_export_format, settings_720p) +display_image(temp2_image.name) # %% # Temperature distribution along the specific path -Tree.Activate([TEMP_RST3]) -Graphics.Camera.SetFit() -Graphics.ExportImage(os.path.join(cwd, "temp3.png"), image_export_format, settings_720p) -display_image("temp3.png") +app.Tree.Activate([temp_rst3]) +camera.SetFit() +temp3_image = cwd / "temp3.png" +graphics.ExportImage(str(temp3_image), image_export_format, settings_720p) +display_image(temp3_image.name) # %% # Temperature of bottom surface -Tree.Activate([TEMP_RST4]) -Graphics.Camera.SetFit() -Graphics.ExportImage(os.path.join(cwd, "temp4.png"), image_export_format, settings_720p) -display_image("temp4.png") +app.Tree.Activate([temp_rst4]) +camera.SetFit() +temp4_image = cwd / "temp4.png" +graphics.ExportImage(str(temp4_image), image_export_format, settings_720p) +display_image(temp4_image.name) # %% # Export directional heat flux animation # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Directional heat flux -Tree.Activate([DIR_HFLUX]) +app.Tree.Activate([directional_heat_flux]) animation_export_format = ( Ansys.Mechanical.DataModel.Enums.GraphicsAnimationExportFormat.GIF ) @@ -409,10 +418,11 @@ def display_image(image_name): settings_720p.Width = 1280 settings_720p.Height = 720 -DIR_HFLUX.ExportAnimation( - os.path.join(cwd, "DirectionalHeatFlux.gif"), animation_export_format, settings_720p +directional_heat_flux_gif = cwd / "directional_heat_flux.gif" +directional_heat_flux.ExportAnimation( + str(directional_heat_flux_gif), animation_export_format, settings_720p ) -gif = Image.open(os.path.join(cwd, "DirectionalHeatFlux.gif")) +gif = Image.open(directional_heat_flux_gif) fig, ax = plt.subplots(figsize=(16, 9)) ax.axis("off") img = ax.imshow(gif.convert("RGBA")) @@ -441,8 +451,8 @@ def write_file_contents_to_console(path): print(line, end="") -solve_path = STAT_THERM.WorkingDir -solve_out_path = os.path.join(solve_path, "solve.out") +solve_path = stat_therm.WorkingDir +solve_out_path = solve_path + "solve.out" if solve_out_path: write_file_contents_to_console(solve_out_path) @@ -457,7 +467,8 @@ def write_file_contents_to_console(path): # ~~~~~~~ # Save project -app.save(os.path.join(cwd, "steady_state_thermal.mechdat")) +mechdat_path = cwd / "steady_state_thermal.mechdat" +app.save(str(mechdat_path)) app.new() # %% diff --git a/examples/01_basic/topology_optimization_cantilever_beam.py b/examples/01_basic/topology_optimization_cantilever_beam.py index a9c67f27..80675d84 100644 --- a/examples/01_basic/topology_optimization_cantilever_beam.py +++ b/examples/01_basic/topology_optimization_cantilever_beam.py @@ -12,7 +12,7 @@ # Import necessary libraries # ~~~~~~~~~~~~~~~~~~~~~~~~~~ -import os +from pathlib import Path from ansys.mechanical.core import App from ansys.mechanical.core.examples import delete_downloads, download_file @@ -28,19 +28,23 @@ def display_image(image_name): plt.figure(figsize=(16, 9)) - plt.imshow(mpimg.imread(os.path.join(cwd, image_name))) + image_path = cwd / image_name + plt.imshow(mpimg.imread(str(image_path))) plt.xticks([]) plt.yticks([]) plt.axis("off") plt.show() -cwd = os.path.join(os.getcwd(), "out") +cwd = Path.cwd() / "out" # %% # Configure graphics for image export -Graphics.Camera.SetSpecificViewOrientation(ViewOrientationType.Front) +graphics = app.Graphics +camera = graphics.Camera + +camera.SetSpecificViewOrientation(ViewOrientationType.Front) image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() settings_720p.Resolution = GraphicsResolutionType.EnhancedResolution @@ -58,15 +62,15 @@ def display_image(image_name): "cantilever.mechdat", "pymechanical", "embedding" ) app.open(structural_mechdat_file) -STRUCT = Model.Analyses[0] +struct = model.Analyses[0] # sphinx_gallery_start_ignore -assert str(STRUCT.ObjectState) == "Solved" +assert struct.ObjectState == ObjectState.Solved # sphinx_gallery_end_ignore -STRUCT_SLN = STRUCT.Solution -STRUCT_SLN.Solve(True) +struct_sln = struct.Solution +struct_sln.Solve(True) # sphinx_gallery_start_ignore -assert str(STRUCT_SLN.Status) == "Done", "Solution status is not 'Done'" +assert struct_sln.Status == SolutionStatusType.Done, "Solution status is not 'Done'" # sphinx_gallery_end_ignore # %% @@ -74,22 +78,20 @@ def display_image(image_name): # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Total deformation -STRUCT_SLN.Children[1].Activate() -Graphics.Camera.SetFit() -Graphics.ExportImage( - os.path.join(cwd, "total_deformation.png"), image_export_format, settings_720p -) -display_image("total_deformation.png") +struct_sln.Children[1].Activate() +camera.SetFit() +total_deformation_image = cwd / "total_deformation.png" +graphics.ExportImage(str(total_deformation_image), image_export_format, settings_720p) +display_image(total_deformation_image.name) # %% # Equivalent stress -STRUCT_SLN.Children[2].Activate() -Graphics.Camera.SetFit() -Graphics.ExportImage( - os.path.join(cwd, "equivalent_stress.png"), image_export_format, settings_720p -) -display_image("equivalent_stress.png") +struct_sln.Children[2].Activate() +camera.SetFit() +equivalent_stress_image = cwd / "equivalent_stress.png" +graphics.ExportImage(str(equivalent_stress_image), image_export_format, settings_720p) +display_image(equivalent_stress_image.name) # %% # Topology optimization @@ -97,84 +99,86 @@ def display_image(image_name): # Set MKS unit system -ExtAPI.Application.ActiveUnitSystem = MechanicalUnitSystem.StandardMKS +app.ExtAPI.Application.ActiveUnitSystem = MechanicalUnitSystem.StandardMKS # Get structural analysis and link to topology optimization -TOPO_OPT = Model.AddTopologyOptimizationAnalysis() -TOPO_OPT.TransferDataFrom(STRUCT) +topology_optimization = model.AddTopologyOptimizationAnalysis() +topology_optimization.TransferDataFrom(struct) -OPT_REG = DataModel.GetObjectsByType(DataModelObjectCategory.OptimizationRegion)[0] -OPT_REG.BoundaryCondition = BoundaryConditionType.AllLoadsAndSupports -OPT_REG.OptimizationType = OptimizationType.TopologyDensity +optimization_region = DataModel.GetObjectsByType( + DataModelObjectCategory.OptimizationRegion +)[0] +optimization_region.BoundaryCondition = BoundaryConditionType.AllLoadsAndSupports +optimization_region.OptimizationType = OptimizationType.TopologyDensity # sphinx_gallery_start_ignore -assert str(TOPO_OPT.ObjectState) == "NotSolved" +assert topology_optimization.ObjectState == ObjectState.NotSolved # sphinx_gallery_end_ignore # Insert volume response constraint object for topology optimization # Delete mass response constraint -MASS_CONSTRN = TOPO_OPT.Children[3] -MASS_CONSTRN.Delete() +mass_constraint = topology_optimization.Children[3] +mass_constraint.Delete() # Add volume response constraint -VOL_CONSTRN = TOPO_OPT.AddVolumeConstraint() +volume_constraint = topology_optimization.AddVolumeConstraint() # Insert member size manufacturing constraint -MEM_SIZE_MFG_CONSTRN = TOPO_OPT.AddMemberSizeManufacturingConstraint() -MEM_SIZE_MFG_CONSTRN.Minimum = ManuMemberSizeControlledType.Manual -MEM_SIZE_MFG_CONSTRN.MinSize = Quantity("2.4 [m]") +mem_size_manufacturing_constraint = ( + topology_optimization.AddMemberSizeManufacturingConstraint() +) +mem_size_manufacturing_constraint.Minimum = ManuMemberSizeControlledType.Manual +mem_size_manufacturing_constraint.MinSize = Quantity("2.4 [m]") -TOPO_OPT.Activate() -Graphics.Camera.SetFit() -Graphics.ExportImage( - os.path.join(cwd, "boundary_conditions.png"), image_export_format, settings_720p -) -display_image("boundary_conditions.png") +topology_optimization.Activate() +camera.SetFit() +boundary_conditions_image = cwd / "boundary_conditions.png" +graphics.ExportImage(str(boundary_conditions_image), image_export_format, settings_720p) +display_image(boundary_conditions_image.name) # %% # Solve # ~~~~~ -TOPO_OPT_SLN = TOPO_OPT.Solution -TOPO_OPT_SLN.Solve(True) +top_opt_sln = topology_optimization.Solution +top_opt_sln.Solve(True) # sphinx_gallery_start_ignore -assert str(TOPO_OPT_SLN.Status) == "Done", "Solution status is not 'Done'" +assert top_opt_sln.Status == SolutionStatusType.Done, "Solution status is not 'Done'" # sphinx_gallery_end_ignore # %% # Messages # ~~~~~~~~ -Messages = ExtAPI.Application.Messages -if Messages: - for message in Messages: +messages = app.ExtAPI.Application.Messages +if messages: + for message in messages: print(f"[{message.Severity}] {message.DisplayString}") else: - print("No [Info]/[Warning]/[Error] Messages") + print("No [Info]/[Warning]/[Error] messages") # %% # Display results # ~~~~~~~~~~~~~~~ -TOPO_OPT_SLN.Children[1].Activate() -TOPO_DENS = TOPO_OPT_SLN.Children[1] +top_opt_sln.Children[1].Activate() +topology_density = top_opt_sln.Children[1] # %% # Add smoothing to the STL -TOPO_DENS.AddSmoothing() -TOPO_OPT.Solution.EvaluateAllResults() -TOPO_DENS.Children[0].Activate() -Graphics.Camera.SetFit() -Graphics.ExportImage( - os.path.join(cwd, "topo_opitimized_smooth.png"), image_export_format, settings_720p -) -display_image("topo_opitimized_smooth.png") +topology_density.AddSmoothing() +topology_optimization.Solution.EvaluateAllResults() +topology_density.Children[0].Activate() +camera.SetFit() +smoothed_image = cwd / "topo_opitimized_smooth.png" +graphics.ExportImage(str(smoothed_image), image_export_format, settings_720p) +display_image(smoothed_image.name) # %% # Export animation @@ -186,8 +190,9 @@ def display_image(image_name): settings_720p.Width = 1280 settings_720p.Height = 720 -TOPO_DENS.ExportAnimation( - os.path.join(cwd, "Topo_opitimized.gif"), animation_export_format, settings_720p +topology_optimized_gif = cwd / "topology_opitimized.gif" +topology_density.ExportAnimation( + str(topology_optimized_gif), animation_export_format, settings_720p ) # %% @@ -198,15 +203,15 @@ def display_image(image_name): # Print topology density results print("Topology Density Results") -print("Minimum Density: ", TOPO_DENS.Minimum) -print("Maximum Density: ", TOPO_DENS.Maximum) -print("Iteration Number: ", TOPO_DENS.IterationNumber) -print("Original Volume: ", TOPO_DENS.OriginalVolume.Value) -print("Final Volume: ", TOPO_DENS.FinalVolume.Value) -print("Percent Volume of Original: ", TOPO_DENS.PercentVolumeOfOriginal) -print("Original Mass: ", TOPO_DENS.OriginalMass.Value) -print("Final Mass: ", TOPO_DENS.FinalMass.Value) -print("Percent Mass of Original: ", TOPO_DENS.PercentMassOfOriginal) +print("Minimum Density: ", topology_density.Minimum) +print("Maximum Density: ", topology_density.Maximum) +print("Iteration Number: ", topology_density.IterationNumber) +print("Original Volume: ", topology_density.OriginalVolume.Value) +print("Final Volume: ", topology_density.FinalVolume.Value) +print("Percent Volume of Original: ", topology_density.PercentVolumeOfOriginal) +print("Original Mass: ", topology_density.OriginalMass.Value) +print("Final Mass: ", topology_density.FinalMass.Value) +print("Percent Mass of Original: ", topology_density.PercentMassOfOriginal) # %% @@ -220,7 +225,8 @@ def display_image(image_name): # ~~~~~~~ # Save project -app.save(os.path.join(cwd, "cantilever_beam_topology_optimization.mechdat")) +mechdat_file = cwd / "cantilever_beam_topology_optimization.mechdat" +app.save(str(mechdat_file)) app.new() # %% diff --git a/examples/01_basic/valve.py b/examples/01_basic/valve.py index 39f25bbb..c5764ec0 100644 --- a/examples/01_basic/valve.py +++ b/examples/01_basic/valve.py @@ -10,7 +10,7 @@ # Import necessary libraries # ~~~~~~~~~~~~~~~~~~~~~~~~~~ -import os +from pathlib import Path from PIL import Image from ansys.mechanical.core import App @@ -25,12 +25,13 @@ app = App(globals=globals()) print(app) -cwd = os.path.join(os.getcwd(), "out") +cwd = Path.cwd() / "out" def display_image(image_name): plt.figure(figsize=(16, 9)) - plt.imshow(mpimg.imread(os.path.join(cwd, image_name))) + image_path = cwd / image_name + plt.imshow(mpimg.imread(str(image_path))) plt.xticks([]) plt.yticks([]) plt.axis("off") @@ -41,7 +42,10 @@ def display_image(image_name): # Configure graphics for image export # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Graphics.Camera.SetSpecificViewOrientation(ViewOrientationType.Iso) +graphics = app.Graphics +camera = graphics.Camera + +camera.SetSpecificViewOrientation(ViewOrientationType.Iso) image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() settings_720p.Resolution = GraphicsResolutionType.EnhancedResolution @@ -61,7 +65,9 @@ def display_image(image_name): # %% # Import geometry -geometry_import = Model.GeometryImportGroup.AddGeometryImport() +model = app.Model + +geometry_import = model.GeometryImportGroup.AddGeometryImport() geometry_import_format = ( Ansys.Mechanical.DataModel.Enums.GeometryImportPreference.Format.Automatic ) @@ -76,14 +82,14 @@ def display_image(image_name): # %% # Assign materials and mesh the geometry # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -material_assignment = Model.Materials.AddMaterialAssignment() +material_assignment = model.Materials.AddMaterialAssignment() material_assignment.Material = "Structural Steel" -sel = ExtAPI.SelectionManager.CreateSelectionInfo( +sel = app.ExtAPI.SelectionManager.CreateSelectionInfo( Ansys.ACT.Interfaces.Common.SelectionTypeEnum.GeometryEntities ) sel.Ids = [ body.GetGeoBody().Id - for body in Model.Geometry.GetChildren( + for body in model.Geometry.GetChildren( Ansys.Mechanical.DataModel.Enums.DataModelObjectCategory.Body, True ) ] @@ -92,39 +98,39 @@ def display_image(image_name): # %% # Define mesh settings, generate mesh -mesh = Model.Mesh +mesh = model.Mesh mesh.ElementSize = Quantity(25, "mm") mesh.GenerateMesh() -Tree.Activate([mesh]) -Graphics.ExportImage(os.path.join(cwd, "mesh.png"), image_export_format, settings_720p) -display_image("mesh.png") +app.Tree.Activate([mesh]) +mesh_image = cwd / "mesh.png" +graphics.ExportImage(str(mesh_image), image_export_format, settings_720p) +display_image(mesh_image.name) # %% # Define analysis and boundary conditions # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -analysis = Model.AddStaticStructuralAnalysis() +analysis = model.AddStaticStructuralAnalysis() fixed_support = analysis.AddFixedSupport() -fixed_support.Location = ExtAPI.DataModel.GetObjectsByName("NSFixedSupportFaces")[0] +fixed_support.Location = app.ExtAPI.DataModel.GetObjectsByName("NSFixedSupportFaces")[0] frictionless_support = analysis.AddFrictionlessSupport() -frictionless_support.Location = ExtAPI.DataModel.GetObjectsByName( +frictionless_support.Location = app.ExtAPI.DataModel.GetObjectsByName( "NSFrictionlessSupportFaces" )[0] pressure = analysis.AddPressure() -pressure.Location = ExtAPI.DataModel.GetObjectsByName("NSInsideFaces")[0] +pressure.Location = app.ExtAPI.DataModel.GetObjectsByName("NSInsideFaces")[0] pressure.Magnitude.Inputs[0].DiscreteValues = [Quantity("0 [s]"), Quantity("1 [s]")] pressure.Magnitude.Output.DiscreteValues = [Quantity("0 [Pa]"), Quantity("15 [MPa]")] analysis.Activate() -Graphics.Camera.SetFit() -Graphics.ExportImage( - os.path.join(cwd, "boundary_conditions.png"), image_export_format, settings_720p -) -display_image("boundary_conditions.png") +camera.SetFit() +boundary_conditions_image = cwd / "boundary_conditions.png" +graphics.ExportImage(str(boundary_conditions_image), image_export_format, settings_720p) +display_image(boundary_conditions_image.name) # %% @@ -140,19 +146,19 @@ def display_image(image_name): solution.Solve(True) # sphinx_gallery_start_ignore -assert str(solution.Status) == "Done", "Solution status is not 'Done'" +assert solution.Status == SolutionStatusType.Done, "Solution status is not 'Done'" # sphinx_gallery_end_ignore # %% # Messages # ~~~~~~~~ -Messages = ExtAPI.Application.Messages -if Messages: - for message in Messages: +messages = app.ExtAPI.Application.Messages +if messages: + for message in messages: print(f"[{message.Severity}] {message.DisplayString}") else: - print("No [Info]/[Warning]/[Error] Messages") + print("No [Info]/[Warning]/[Error] messages") # %% # Results @@ -161,20 +167,20 @@ def display_image(image_name): # %% # Total deformation -Tree.Activate([deformation]) -Graphics.ExportImage( - os.path.join(cwd, "totaldeformation_valve.png"), image_export_format, settings_720p +app.Tree.Activate([deformation]) +total_deformation_valve_image = cwd / "total_deformation_valve.png" +graphics.ExportImage( + str(total_deformation_valve_image), image_export_format, settings_720p ) -display_image("totaldeformation_valve.png") +display_image(total_deformation_valve_image.name) # %% # Stress -Tree.Activate([stress]) -Graphics.ExportImage( - os.path.join(cwd, "stress_valve.png"), image_export_format, settings_720p -) -display_image("stress_valve.png") +app.Tree.Activate([stress]) +stress_valve_image = cwd / "stress_valve.png" +graphics.ExportImage(str(stress_valve_image), image_export_format, settings_720p) +display_image(stress_valve_image.name) # %% # Export stress animation @@ -186,10 +192,9 @@ def display_image(image_name): settings_720p.Width = 1280 settings_720p.Height = 720 -stress.ExportAnimation( - os.path.join(cwd, "Valve.gif"), animation_export_format, settings_720p -) -gif = Image.open(os.path.join(cwd, "Valve.gif")) +valve_gif = cwd / "valve.gif" +stress.ExportAnimation(str(valve_gif), animation_export_format, settings_720p) +gif = Image.open(valve_gif) fig, ax = plt.subplots(figsize=(16, 9)) ax.axis("off") img = ax.imshow(gif.convert("RGBA")) @@ -219,7 +224,7 @@ def write_file_contents_to_console(path): solve_path = analysis.WorkingDir -solve_out_path = os.path.join(solve_path, "solve.out") +solve_out_path = solve_path + "solve.out" if solve_out_path: write_file_contents_to_console(solve_out_path) @@ -234,7 +239,8 @@ def write_file_contents_to_console(path): # ~~~~~~~ # Save project -app.save(os.path.join(cwd, "Valve.mechdat")) +mechdat_file = cwd / "valve.mechdat" +app.save(str(mechdat_file)) app.new() # %% diff --git a/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py b/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py index d7611c46..2abd6c52 100644 --- a/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py +++ b/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py @@ -47,7 +47,7 @@ """ -import os +from pathlib import Path from ansys.mechanical.core import App from ansys.mechanical.core.examples import delete_downloads, download_file @@ -60,12 +60,13 @@ app = App(globals=globals()) print(app) -cwd = os.path.join(os.getcwd(), "out") +cwd = Path.cwd() / "out" def display_image(image_name): plt.figure(figsize=(16, 9)) - plt.imshow(mpimg.imread(os.path.join(cwd, image_name))) + image_path = cwd / image_name + plt.imshow(mpimg.imread(str(image_path))) plt.xticks([]) plt.yticks([]) plt.axis("off") @@ -107,11 +108,13 @@ def display_image(image_name): # Configure graphics for image export # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -cwd = os.path.join(os.getcwd(), "out") -Graphics.Camera.SetSpecificViewOrientation( +graphics = app.Graphics +camera = graphics.Camera + +camera.SetSpecificViewOrientation( Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Iso ) -Graphics.Camera.SetFit() +camera.SetFit() image_export_format = Ansys.Mechanical.DataModel.Enums.GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() settings_720p.Resolution = ( @@ -128,7 +131,9 @@ def display_image(image_name): # ~~~~~~~~~~~~~~~ # Reads geometry file and display -geometry_import_group = Model.GeometryImportGroup +model = app.Model + +geometry_import_group = model.GeometryImportGroup geometry_import = geometry_import_group.AddGeometryImport() geometry_import_format = ( Ansys.Mechanical.DataModel.Enums.GeometryImportPreference.Format.Automatic @@ -149,62 +154,61 @@ def display_image(image_name): # ~~~~~~~~~~~~~~~~ # Import material from xml file and assign it to bodies -materials = Model.Materials +materials = model.Materials materials.Import(mat_path) -PRT1 = [x for x in Tree.AllObjects if x.Name == "Component2\Rotor11"][0] -PRT2 = [x for x in Tree.AllObjects if x.Name == "Component3"][0] -PRT2_Blade_1 = PRT2.Children[0] -PRT2_Blade_2 = PRT2.Children[1] -PRT2_Blade_3 = PRT2.Children[2] -PRT1.Material = "MAT1 (Setup, File1)" -PRT2_Blade_1.Material = "MAT1 (Setup, File1)" -PRT2_Blade_2.Material = "MAT1 (Setup, File1)" -PRT2_Blade_3.Material = "MAT1 (Setup, File1)" +part1 = [x for x in app.Tree.AllObjects if x.Name == "Component2\Rotor11"][0] +part2 = [x for x in app.Tree.AllObjects if x.Name == "Component3"][0] +part2_blade1 = part2.Children[0] +part2_blade2 = part2.Children[1] +part2_blade3 = part2.Children[2] +part1.Material = "MAT1 (Setup, File1)" +part2_blade1.Material = "MAT1 (Setup, File1)" +part2_blade2.Material = "MAT1 (Setup, File1)" +part2_blade3.Material = "MAT1 (Setup, File1)" # %% # Define units system and store variables # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Select MKS units -ExtAPI.Application.ActiveUnitSystem = MechanicalUnitSystem.StandardMKS +app.ExtAPI.Application.ActiveUnitSystem = MechanicalUnitSystem.StandardMKS # Store all main tree nodes as variables -MODEL = Model -GEOM = Model.Geometry -MESH = Model.Mesh -MAT_GRP = Model.Materials -CS = Model.CoordinateSystems -NS_GRP = Model.NamedSelections +geometry = model.Geometry +mesh = model.Mesh +materials = model.Materials +coordinate_systems = model.CoordinateSystems +named_selections = model.NamedSelections # %% # Define named selection # ~~~~~~~~~~~~~~~~~~~~~~ # Create NS for named selection -BLADE_NS = [x for x in Tree.AllObjects if x.Name == "Blade"][0] -BLADE_SURF_NS = [x for x in Tree.AllObjects if x.Name == "Blade_Surf"][0] -FIX_SUPPORT_NS = [x for x in Tree.AllObjects if x.Name == "Fix_Support"][0] -BLADE_HUB_NS = [x for x in Tree.AllObjects if x.Name == "Blade_Hub"][0] -HUB_CONTACT_NS = [x for x in Tree.AllObjects if x.Name == "Hub_Contact"][0] -BLADE_TARGET_NS = [x for x in Tree.AllObjects if x.Name == "Blade_Target"][0] -Hub_Low_NS = [x for x in Tree.AllObjects if x.Name == "Hub_Low"][0] -Hub_High_NS = [x for x in Tree.AllObjects if x.Name == "Hub_High"][0] -BLADE1_NS = [x for x in Tree.AllObjects if x.Name == "Blade1"][0] -BLADE1_Source_NS = [x for x in Tree.AllObjects if x.Name == "Blade1_Source"][0] -BLADE1_TARGET_NS = [x for x in Tree.AllObjects if x.Name == "Blade1_Target"][0] -BLADE2_NS = [x for x in Tree.AllObjects if x.Name == "Blade2"][0] -BLADE2_Source_NS = [x for x in Tree.AllObjects if x.Name == "Blade2_Source"][0] -BLADE2_TARGET_NS = [x for x in Tree.AllObjects if x.Name == "Blade2_Target"][0] -BLADE3_NS = [x for x in Tree.AllObjects if x.Name == "Blade3"][0] -BLADE3_Source_NS = [x for x in Tree.AllObjects if x.Name == "Blade3_Source"][0] -BLADE3_TARGET_NS = [x for x in Tree.AllObjects if x.Name == "Blade3_Target"][0] +blade_ns = [x for x in app.Tree.AllObjects if x.Name == "Blade"][0] +blade_surface_ns = [x for x in app.Tree.AllObjects if x.Name == "Blade_Surf"][0] +fix_support_ns = [x for x in app.Tree.AllObjects if x.Name == "Fix_Support"][0] +blade_hub_ns = [x for x in app.Tree.AllObjects if x.Name == "Blade_Hub"][0] +hub_contact_ns = [x for x in app.Tree.AllObjects if x.Name == "Hub_Contact"][0] +blade_target_ns = [x for x in app.Tree.AllObjects if x.Name == "Blade_Target"][0] +hub_low_ns = [x for x in app.Tree.AllObjects if x.Name == "Hub_Low"][0] +hub_high_ns = [x for x in app.Tree.AllObjects if x.Name == "Hub_High"][0] +blade1_ns = [x for x in app.Tree.AllObjects if x.Name == "Blade1"][0] +blade1_source_ns = [x for x in app.Tree.AllObjects if x.Name == "Blade1_Source"][0] +blade1_target_ns = [x for x in app.Tree.AllObjects if x.Name == "Blade1_Target"][0] +blade2_ns = [x for x in app.Tree.AllObjects if x.Name == "Blade2"][0] +blade2_source_ns = [x for x in app.Tree.AllObjects if x.Name == "Blade2_Source"][0] +blade2_target_ns = [x for x in app.Tree.AllObjects if x.Name == "Blade2_Target"][0] +blade3_ns = [x for x in app.Tree.AllObjects if x.Name == "Blade3"][0] +blade3_source_ns = [x for x in app.Tree.AllObjects if x.Name == "Blade3_Source"][0] +blade3_target_ns = [x for x in app.Tree.AllObjects if x.Name == "Blade3_Target"][0] # %% # Define coordinate system # ~~~~~~~~~~~~~~~~~~~~~~~~ # Create cylindrical coordinate system -coordinate_systems = Model.CoordinateSystems +coordinate_systems = model.CoordinateSystems coord_system = coordinate_systems.AddCoordinateSystem() coord_system.CoordinateSystemType = ( Ansys.ACT.Interfaces.Analysis.CoordinateSystemTypeEnum.Cylindrical @@ -218,35 +222,35 @@ def display_image(image_name): # Define connections -CONN_GRP = Model.Connections -CONT_REG1 = CONN_GRP.AddContactRegion() -CONT_REG1.SourceLocation = NS_GRP.Children[6] -CONT_REG1.TargetLocation = NS_GRP.Children[5] -CONT_REG1.Behavior = ContactBehavior.AutoAsymmetric -CONT_REG1.ContactFormulation = ContactFormulation.MPC +connections = model.Connections +contact_region1 = connections.AddContactRegion() +contact_region1.SourceLocation = named_selections.Children[6] +contact_region1.TargetLocation = named_selections.Children[5] +contact_region1.Behavior = ContactBehavior.AutoAsymmetric +contact_region1.ContactFormulation = ContactFormulation.MPC # %% # Define mesh settings and generate mesh # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -MSH = Model.Mesh -MSH.ElementSize = Quantity(0.004, "m") -MSH.UseAdaptiveSizing = False -MSH.MaximumSize = Quantity(0.004, "m") -MSH.ShapeChecking = 0 -automatic_method_Hub = MSH.AddAutomaticMethod() -automatic_method_Hub.Location = NS_GRP.Children[0] +mesh = model.Mesh +mesh.ElementSize = Quantity(0.004, "m") +mesh.UseAdaptiveSizing = False +mesh.MaximumSize = Quantity(0.004, "m") +mesh.ShapeChecking = 0 +automatic_method_Hub = mesh.AddAutomaticMethod() +automatic_method_Hub.Location = named_selections.Children[0] automatic_method_Hub.Method = MethodType.Sweep automatic_method_Hub.SweepNumberDivisions = 6 -match_control_Hub = MSH.AddMatchControl() -match_control_Hub.LowNamedSelection = NS_GRP.Children[7] -match_control_Hub.HighNamedSelection = NS_GRP.Children[8] +match_control_Hub = mesh.AddMatchControl() +match_control_Hub.LowNamedSelection = named_selections.Children[7] +match_control_Hub.HighNamedSelection = named_selections.Children[8] cyc_coordinate_system = coordinate_systems.Children[1] match_control_Hub.RotationAxis = cyc_coordinate_system -sizing_Blade = MSH.AddSizing() -selection = NS_GRP.Children[5] +sizing_Blade = mesh.AddSizing() +selection = named_selections.Children[5] sizing_Blade.Location = selection # sizing_Blade.ElementSize = Quantity(1e-3, "m") sizing_Blade.ElementSize = Quantity(1e-2, "m") @@ -255,81 +259,80 @@ def display_image(image_name): # sizing_Blade.LocalMinimumSize = Quantity(0.00025, "m") sizing_Blade.LocalMinimumSize = Quantity(0.0005, "m") -automatic_method_Blade1 = MSH.AddAutomaticMethod() -selection = NS_GRP.Children[9] +automatic_method_Blade1 = mesh.AddAutomaticMethod() +selection = named_selections.Children[9] automatic_method_Blade1.Location = selection automatic_method_Blade1.Method = MethodType.Sweep automatic_method_Blade1.SourceTargetSelection = 2 -selection = NS_GRP.Children[10] +selection = named_selections.Children[10] automatic_method_Blade1.SourceLocation = selection -selection = NS_GRP.Children[11] +selection = named_selections.Children[11] automatic_method_Blade1.TargetLocation = selection automatic_method_Blade1.SweepNumberDivisions = 5 -automatic_method_Blade2 = MSH.AddAutomaticMethod() -selection = NS_GRP.Children[12] +automatic_method_Blade2 = mesh.AddAutomaticMethod() +selection = named_selections.Children[12] automatic_method_Blade2.Location = selection automatic_method_Blade2.Method = MethodType.Sweep automatic_method_Blade2.SourceTargetSelection = 2 -selection = NS_GRP.Children[13] +selection = named_selections.Children[13] automatic_method_Blade2.SourceLocation = selection -selection = NS_GRP.Children[14] +selection = named_selections.Children[14] automatic_method_Blade2.TargetLocation = selection automatic_method_Blade2.SweepNumberDivisions = 5 -automatic_method_Blade3 = MSH.AddAutomaticMethod() -selection = NS_GRP.Children[15] +automatic_method_Blade3 = mesh.AddAutomaticMethod() +selection = named_selections.Children[15] automatic_method_Blade3.Location = selection automatic_method_Blade3.Method = MethodType.Sweep automatic_method_Blade3.SourceTargetSelection = 2 -selection = NS_GRP.Children[16] +selection = named_selections.Children[16] automatic_method_Blade3.SourceLocation = selection -selection = NS_GRP.Children[17] +selection = named_selections.Children[17] automatic_method_Blade3.TargetLocation = selection automatic_method_Blade3.SweepNumberDivisions = 5 -MSH.GenerateMesh() +mesh.GenerateMesh() -Graphics.Camera.SetFit() -Graphics.ExportImage( - os.path.join(cwd, "blade_mesh.png"), image_export_format, settings_720p -) -display_image("blade_mesh.png") +camera.SetFit() +blade_mesh_image = cwd / "blade_mesh.png" +graphics.ExportImage(str(blade_mesh_image), image_export_format, settings_720p) +display_image(blade_mesh_image.name) # %% # Define analysis settings # ~~~~~~~~~~~~~~~~~~~~~~~~ # Setup static structural settings with inverse solve -Model.AddStaticStructuralAnalysis() -STAT_STRUC = Model.Analyses[0] -ANA_SETTINGS = ExtAPI.DataModel.Project.Model.Analyses[0].AnalysisSettings -ANA_SETTINGS.AutomaticTimeStepping = AutomaticTimeStepping.On -ANA_SETTINGS.NumberOfSubSteps = 10 +model.AddStaticStructuralAnalysis() +static_structural_analysis = model.Analyses[0] +analysis_settings = app.ExtAPI.DataModel.Project.Model.Analyses[0].AnalysisSettings +analysis_settings.AutomaticTimeStepping = AutomaticTimeStepping.On +analysis_settings.NumberOfSubSteps = 10 -ANA_SETTINGS.Activate() +analysis_settings.Activate() -CMD1 = STAT_STRUC.AddCommandSnippet() +cmd1 = static_structural_analysis.AddCommandSnippet() # Add convergence criterion using command snippet. -AWM = """CNVTOL,U,1.0,5e-5,1,,""" -CMD1.AppendText(AWM) +archard_wear_model = """CNVTOL,U,1.0,5e-5,1,,""" +cmd1.AppendText(archard_wear_model) -ANA_SETTINGS.InverseOption = True -ANA_SETTINGS.LargeDeflection = True +analysis_settings.InverseOption = True +analysis_settings.LargeDeflection = True # %% # Define boundary conditions # ~~~~~~~~~~~~~~~~~~~~~~~~~~ # Apply rotational velocity -ROT_VEL = STAT_STRUC.AddRotationalVelocity() -ROT_VEL.DefineBy = LoadDefineBy.Components -ROT_VEL.ZComponent.Inputs[0].DiscreteValues = [ +rotational_velocity = static_structural_analysis.AddRotationalVelocity() +rotational_velocity.DefineBy = LoadDefineBy.Components +rotational_velocity.ZComponent.Inputs[0].DiscreteValues = [ Quantity("0 [s]"), Quantity("1 [s]"), Quantity("2 [s]"), ] -ROT_VEL.ZComponent.Output.DiscreteValues = [ +rotational_velocity.ZComponent.Output.DiscreteValues = [ Quantity("0 [rad/s]"), Quantity("1680 [rad/s]"), Quantity("1680 [rad/s]"), @@ -337,9 +340,9 @@ def display_image(image_name): # Apply Fixed Support Condition -Fixed_Support = STAT_STRUC.AddFixedSupport() -selection = NS_GRP.Children[3] -Fixed_Support.Location = selection +fixed_support = static_structural_analysis.AddFixedSupport() +selection = named_selections.Children[3] +fixed_support.Location = selection # %% @@ -347,7 +350,7 @@ def display_image(image_name): # ~~~~~~~~~~~~~~~~~~~ # Import CFX pressure data and apply it to structural blade surface -Imported_Load_Group = STAT_STRUC.AddImportedLoadExternalData() +imported_load_group = static_structural_analysis.AddImportedLoadExternalData() external_data_files = Ansys.Mechanical.ExternalData.ExternalDataFileCollection() external_data_files.SaveFilesWithProject = False @@ -392,19 +395,18 @@ def display_image(image_name): "Pressure@D", ) -Imported_Load_Group.ImportExternalDataFiles(external_data_files) -Imported_Pressure = Imported_Load_Group.AddImportedPressure() -selection = NS_GRP.Children[2] -Imported_Pressure.Location = selection -Imported_Pressure.AppliedBy = LoadAppliedBy.Direct -Imported_Pressure.ImportLoad() - -Tree.Activate([Imported_Pressure]) -Graphics.Camera.SetFit() -Graphics.ExportImage( - os.path.join(cwd, "imported_pressure.png"), image_export_format, settings_720p -) -display_image("imported_pressure.png") +imported_load_group.ImportExternalDataFiles(external_data_files) +imported_pressure = imported_load_group.AddImportedPressure() +selection = named_selections.Children[2] +imported_pressure.Location = selection +imported_pressure.AppliedBy = LoadAppliedBy.Direct +imported_pressure.ImportLoad() + +app.Tree.Activate([imported_pressure]) +camera.SetFit() +imported_pressure_image = cwd / "imported_pressure.png" +graphics.ExportImage(str(imported_pressure_image), image_export_format, settings_720p) +display_image(imported_pressure_image.name) ################################################################################### @@ -412,7 +414,7 @@ def display_image(image_name): # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Import temperature data and apply it to structural blade -Imported_Load_Group = STAT_STRUC.AddImportedLoadExternalData() +imported_load_group = static_structural_analysis.AddImportedLoadExternalData() external_data_files = Ansys.Mechanical.ExternalData.ExternalDataFileCollection() external_data_files.SaveFilesWithProject = False @@ -458,38 +460,37 @@ def display_image(image_name): "Temperature@D", ) -Imported_Load_Group.ImportExternalDataFiles(external_data_files) -imported_body_temperature = Imported_Load_Group.AddImportedBodyTemperature() +imported_load_group.ImportExternalDataFiles(external_data_files) +imported_body_temperature = imported_load_group.AddImportedBodyTemperature() -selection = NS_GRP.Children[1] +selection = named_selections.Children[1] imported_body_temperature.Location = selection imported_body_temperature.ImportLoad() -Tree.Activate([imported_body_temperature]) -Graphics.Camera.SetFit() -Graphics.ExportImage( - os.path.join(cwd, "imported_temperature.png"), image_export_format, settings_720p -) -display_image("imported_temperature.png") +app.Tree.Activate([imported_body_temperature]) +camera.SetFit() +imported_temp_image = cwd / "imported_temperature.png" +graphics.ExportImage(str(imported_temp_image), image_export_format, settings_720p) +display_image(imported_temp_image.name) # %% # Postprocessing # ~~~~~~~~~~~~~~ # Insert results -SOLN = STAT_STRUC.Solution +solution = static_structural_analysis.Solution -TOT_DEF1 = SOLN.AddTotalDeformation() -TOT_DEF1.DisplayTime = Quantity("1 [s]") +total_deformation1 = solution.AddTotalDeformation() +total_deformation1.DisplayTime = Quantity("1 [s]") -EQV_STRS1 = SOLN.AddEquivalentStress() -EQV_STRS1.DisplayTime = Quantity("1 [s]") +equivalent_stress1 = solution.AddEquivalentStress() +equivalent_stress1.DisplayTime = Quantity("1 [s]") -EQV_TOT_STRN1 = SOLN.AddEquivalentTotalStrain() -EQV_TOT_STRN1.DisplayTime = Quantity("1 [s]") +equivalent_total_strain1 = solution.AddEquivalentTotalStrain() +equivalent_total_strain1.DisplayTime = Quantity("1 [s]") -THERM_STRN1 = SOLN.AddThermalStrain() -THERM_STRN1.DisplayTime = Quantity("1 [s]") +thermal_strain1 = solution.AddThermalStrain() +thermal_strain1.DisplayTime = Quantity("1 [s]") # %% @@ -497,8 +498,8 @@ def display_image(image_name): # ~~~~~~~~~~~~ # Solve inverse analysis on blade model -SOLN.Solve(True) -STAT_STRUC_SS = SOLN.Status +solution.Solve(True) +soln_status = solution.Status # %% # Postprocessing @@ -508,30 +509,29 @@ def display_image(image_name): # %% # Total deformation -Tree.Activate([TOT_DEF1]) -Graphics.ViewOptions.ResultPreference.ExtraModelDisplay = ( +app.Tree.Activate([total_deformation1]) +graphics.ViewOptions.ResultPreference.ExtraModelDisplay = ( Ansys.Mechanical.DataModel.MechanicalEnums.Graphics.ExtraModelDisplay.NoWireframe ) -Graphics.ExportImage( - os.path.join(cwd, "deformation.png"), image_export_format, settings_720p -) -display_image("deformation.png") +deformation_image = cwd / "deformation.png" +graphics.ExportImage(str(deformation_image), image_export_format, settings_720p) +display_image(deformation_image.name) # %% # Equivalent stress -Tree.Activate([THERM_STRN1]) -Graphics.ExportImage( - os.path.join(cwd, "thermal_strain.png"), image_export_format, settings_720p -) -display_image("thermal_strain.png") +app.Tree.Activate([thermal_strain1]) +thermal_strain_image = cwd / "termal_strain.png" +graphics.ExportImage(str(thermal_strain_image), image_export_format, settings_720p) +display_image(thermal_strain_image.name) # %% # Cleanup # ~~~~~~~ # Save project -app.save(os.path.join(cwd, "blade_inverse.mechdat")) +mechdat_file = cwd / "blade_inverse.mechdat" +app.save(str(mechdat_file)) app.new() # %% diff --git a/examples/02_technology_showcase/conact_wear_simulation.py b/examples/02_technology_showcase/conact_wear_simulation.py index d15bbeeb..7da53754 100644 --- a/examples/02_technology_showcase/conact_wear_simulation.py +++ b/examples/02_technology_showcase/conact_wear_simulation.py @@ -25,7 +25,7 @@ # Import necessary libraries # ~~~~~~~~~~~~~~~~~~~~~~~~~~ -import os +from pathlib import Path from PIL import Image from ansys.mechanical.core import App @@ -40,12 +40,13 @@ app = App(globals=globals()) print(app) -cwd = os.path.join(os.getcwd(), "out") +cwd = Path.cwd() / "out" def display_image(image_name): plt.figure(figsize=(16, 9)) - plt.imshow(mpimg.imread(os.path.join(cwd, image_name))) + image_path = cwd / image_name + plt.imshow(mpimg.imread(str(image_path))) plt.xticks([]) plt.yticks([]) plt.axis("off") @@ -56,7 +57,10 @@ def display_image(image_name): # Configure graphics for image export # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Graphics.Camera.SetSpecificViewOrientation(ViewOrientationType.Front) +graphics = app.Graphics +camera = graphics.Camera + +camera.SetSpecificViewOrientation(ViewOrientationType.Front) image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() settings_720p.Resolution = GraphicsResolutionType.EnhancedResolution @@ -64,7 +68,7 @@ def display_image(image_name): settings_720p.Width = 1280 settings_720p.Height = 720 settings_720p.CurrentGraphicsDisplay = False -Graphics.Camera.Rotate(180, CameraAxisType.ScreenY) +camera.Rotate(180, CameraAxisType.ScreenY) # %% # Download geometry and materials files @@ -78,7 +82,9 @@ def display_image(image_name): # Import geometry # ~~~~~~~~~~~~~~~ -geometry_import = Model.GeometryImportGroup.AddGeometryImport() +model = app.Model + +geometry_import = model.GeometryImportGroup.AddGeometryImport() geometry_import_format = ( Ansys.Mechanical.DataModel.Enums.GeometryImportPreference.Format.Automatic ) @@ -95,9 +101,9 @@ def display_image(image_name): # Import materials # ~~~~~~~~~~~~~~~~ -MAT = Model.Materials -MAT.Import(mat1_path) -MAT.Import(mat2_path) +materials = model.Materials +materials.Import(mat1_path) +materials.Import(mat2_path) print("Material import done !") @@ -106,66 +112,67 @@ def display_image(image_name): # ~~~~~~~~~~~~~~~~~~ # Set up the unit system -ExtAPI.Application.ActiveUnitSystem = MechanicalUnitSystem.StandardNMM +app.ExtAPI.Application.ActiveUnitSystem = MechanicalUnitSystem.StandardNMM # %% # Store all main tree nodes as variables -MODEL = Model -GEOM = Model.Geometry -CS_GRP = Model.CoordinateSystems -CONN_GRP = Model.Connections -MSH = Model.Mesh -NS_GRP = Model.NamedSelections +geometry = model.Geometry +coordinate_systems = model.CoordinateSystems +connections = model.Connections +mesh = model.Mesh +named_selections = model.NamedSelections # %% # Add static structural analysis -Model.AddStaticStructuralAnalysis() -STAT_STRUC = Model.Analyses[0] -STAT_STRUC_SOLN = STAT_STRUC.Solution -STAT_STRUC_ANA_SETTING = STAT_STRUC.Children[0] +model.AddStaticStructuralAnalysis() +static_structural_analysis = model.Analyses[0] +stat_struct_soln = static_structural_analysis.Solution +stat_struct_analysis_settings = static_structural_analysis.Children[0] # %% # Store name selection -CURVE_NS = [x for x in Tree.AllObjects if x.Name == "curve"][0] -DIA_NS = [x for x in Tree.AllObjects if x.Name == "dia"][0] -VER_EDGE1 = [x for x in Tree.AllObjects if x.Name == "v1"][0] -VER_EDGE2 = [x for x in Tree.AllObjects if x.Name == "v2"][0] -HOR_EDGE1 = [x for x in Tree.AllObjects if x.Name == "h1"][0] -HOR_EDGE2 = [x for x in Tree.AllObjects if x.Name == "h2"][0] -ALL_BODIES_NS = [x for x in Tree.AllObjects if x.Name == "all_bodies"][0] +curve_named_selection = [x for x in app.Tree.AllObjects if x.Name == "curve"][0] +dia_named_selection = [x for x in app.Tree.AllObjects if x.Name == "dia"][0] +ver_edge1 = [x for x in app.Tree.AllObjects if x.Name == "v1"][0] +ver_edge2 = [x for x in app.Tree.AllObjects if x.Name == "v2"][0] +hor_edge1 = [x for x in app.Tree.AllObjects if x.Name == "h1"][0] +hor_edge2 = [x for x in app.Tree.AllObjects if x.Name == "h2"][0] +all_bodies_named_selection = [x for x in app.Tree.AllObjects if x.Name == "all_bodies"][ + 0 +] # %% # Assign material to bodies and change behavior to axisymmetric -GEOM.Model2DBehavior = Model2DBehavior.AxiSymmetric +geometry.Model2DBehavior = Model2DBehavior.AxiSymmetric -SURFACE1 = GEOM.Children[0].Children[0] -SURFACE1.Material = "Steel" -SURFACE1.Dimension = ShellBodyDimension.Two_D +surface1 = geometry.Children[0].Children[0] +surface1.Material = "Steel" +surface1.Dimension = ShellBodyDimension.Two_D -SURFACE2 = GEOM.Children[1].Children[0] -SURFACE2.Material = "Copper" -SURFACE2.Dimension = ShellBodyDimension.Two_D +surface2 = geometry.Children[1].Children[0] +surface2.Material = "Copper" +surface2.Dimension = ShellBodyDimension.Two_D # %% # Change contact settings -CONT_REG = CONN_GRP.AddContactRegion() -CONT_REG.SourceLocation = NS_GRP.Children[6] -CONT_REG.TargetLocation = NS_GRP.Children[3] -# CONT_REG.FlipContactTarget() -CONT_REG.ContactType = ContactType.Frictionless -CONT_REG.Behavior = ContactBehavior.Asymmetric -CONT_REG.ContactFormulation = ContactFormulation.AugmentedLagrange -CONT_REG.DetectionMethod = ContactDetectionPoint.NodalNormalToTarget +contact_region = connections.AddContactRegion() +contact_region.SourceLocation = named_selections.Children[6] +contact_region.TargetLocation = named_selections.Children[3] +# contact_region.FlipContactTarget() +contact_region.ContactType = ContactType.Frictionless +contact_region.Behavior = ContactBehavior.Asymmetric +contact_region.ContactFormulation = ContactFormulation.AugmentedLagrange +contact_region.DetectionMethod = ContactDetectionPoint.NodalNormalToTarget # %% # Add a command snippet to use Archard Wear Model -AWM = """keyo,cid,5,1 +archard_wear_model = """keyo,cid,5,1 keyo,cid,10,2 pi=acos(-1) slide_velocity=1e5 @@ -180,148 +187,150 @@ def display_image(image_name): TBDATA,1,kcopper,1,1,0,0 TBFIELD,TIME,4 TBDATA,1,kcopper,1,1,0,0""" -CMD1 = CONT_REG.AddCommandSnippet() -CMD1.AppendText(AWM) +cmd1 = contact_region.AddCommandSnippet() +cmd1.AppendText(archard_wear_model) # %% # Insert remote point -REM_PT = MODEL.AddRemotePoint() -REM_PT.Location = DIA_NS -REM_PT.Behavior = LoadBehavior.Rigid +remote_point = model.AddRemotePoint() +remote_point.Location = dia_named_selection +remote_point.Behavior = LoadBehavior.Rigid # %% # Mesh # ~~~~ -MSH.ElementOrder = ElementOrder.Linear -MSH.ElementSize = Quantity("1 [mm]") +mesh.ElementOrder = ElementOrder.Linear +mesh.ElementSize = Quantity("1 [mm]") -EDGE_SIZING1 = MSH.AddSizing() -EDGE_SIZING1.Location = HOR_EDGE1 -EDGE_SIZING1.Type = SizingType.NumberOfDivisions -EDGE_SIZING1.NumberOfDivisions = 70 +edge_sizing1 = mesh.AddSizing() +edge_sizing1.Location = hor_edge1 +edge_sizing1.Type = SizingType.NumberOfDivisions +edge_sizing1.NumberOfDivisions = 70 -EDGE_SIZING2 = MSH.AddSizing() -EDGE_SIZING2.Location = HOR_EDGE2 -EDGE_SIZING2.Type = SizingType.NumberOfDivisions -EDGE_SIZING2.NumberOfDivisions = 70 +edge_sizing2 = mesh.AddSizing() +edge_sizing2.Location = hor_edge2 +edge_sizing2.Type = SizingType.NumberOfDivisions +edge_sizing2.NumberOfDivisions = 70 -EDGE_SIZING3 = MSH.AddSizing() -EDGE_SIZING3.Location = VER_EDGE1 -EDGE_SIZING3.Type = SizingType.NumberOfDivisions -EDGE_SIZING3.NumberOfDivisions = 35 +edge_sizing3 = mesh.AddSizing() +edge_sizing3.Location = ver_edge1 +edge_sizing3.Type = SizingType.NumberOfDivisions +edge_sizing3.NumberOfDivisions = 35 -EDGE_SIZING4 = MSH.AddSizing() -EDGE_SIZING4.Location = VER_EDGE2 -EDGE_SIZING4.Type = SizingType.NumberOfDivisions -EDGE_SIZING4.NumberOfDivisions = 35 +edge_sizing4 = mesh.AddSizing() +edge_sizing4.Location = ver_edge2 +edge_sizing4.Type = SizingType.NumberOfDivisions +edge_sizing4.NumberOfDivisions = 35 -EDGE_SIZING5 = MSH.AddSizing() -EDGE_SIZING5.Location = DIA_NS -EDGE_SIZING5.Type = SizingType.NumberOfDivisions -EDGE_SIZING5.NumberOfDivisions = 40 +edge_sizing5 = mesh.AddSizing() +edge_sizing5.Location = dia_named_selection +edge_sizing5.Type = SizingType.NumberOfDivisions +edge_sizing5.NumberOfDivisions = 40 -EDGE_SIZING6 = MSH.AddSizing() -EDGE_SIZING6.Location = CURVE_NS -EDGE_SIZING6.Type = SizingType.NumberOfDivisions -EDGE_SIZING6.NumberOfDivisions = 60 +edge_sizing6 = mesh.AddSizing() +edge_sizing6.Location = curve_named_selection +edge_sizing6.Type = SizingType.NumberOfDivisions +edge_sizing6.NumberOfDivisions = 60 -MSH.GenerateMesh() +mesh.GenerateMesh() -Graphics.Camera.SetFit() -Graphics.ExportImage(os.path.join(cwd, "mesh.png"), image_export_format, settings_720p) -display_image("mesh.png") +camera.SetFit() +mesh_image = cwd / "mesh.png" +graphics.ExportImage(str(mesh_image), image_export_format, settings_720p) +display_image(mesh_image.name) # %% # Analysis settings # ~~~~~~~~~~~~~~~~~ -STAT_STRUC_ANA_SETTING.NumberOfSteps = 2 -STAT_STRUC_ANA_SETTING.CurrentStepNumber = 1 -STAT_STRUC_ANA_SETTING.AutomaticTimeStepping = AutomaticTimeStepping.On -STAT_STRUC_ANA_SETTING.DefineBy = TimeStepDefineByType.Time -STAT_STRUC_ANA_SETTING.InitialTimeStep = Quantity("0.1 [s]") -STAT_STRUC_ANA_SETTING.MinimumTimeStep = Quantity("0.0001 [s]") -STAT_STRUC_ANA_SETTING.MaximumTimeStep = Quantity("1 [s]") -STAT_STRUC_ANA_SETTING.CurrentStepNumber = 2 -STAT_STRUC_ANA_SETTING.Activate() -STAT_STRUC_ANA_SETTING.StepEndTime = Quantity("4 [s]") -STAT_STRUC_ANA_SETTING.AutomaticTimeStepping = AutomaticTimeStepping.On -STAT_STRUC_ANA_SETTING.DefineBy = TimeStepDefineByType.Time -STAT_STRUC_ANA_SETTING.InitialTimeStep = Quantity("0.01 [s]") -STAT_STRUC_ANA_SETTING.MinimumTimeStep = Quantity("0.000001 [s]") -STAT_STRUC_ANA_SETTING.MaximumTimeStep = Quantity("0.02 [s]") - -STAT_STRUC_ANA_SETTING.LargeDeflection = True +stat_struct_analysis_settings.NumberOfSteps = 2 +stat_struct_analysis_settings.CurrentStepNumber = 1 +stat_struct_analysis_settings.AutomaticTimeStepping = AutomaticTimeStepping.On +stat_struct_analysis_settings.DefineBy = TimeStepDefineByType.Time +stat_struct_analysis_settings.InitialTimeStep = Quantity("0.1 [s]") +stat_struct_analysis_settings.MinimumTimeStep = Quantity("0.0001 [s]") +stat_struct_analysis_settings.MaximumTimeStep = Quantity("1 [s]") +stat_struct_analysis_settings.CurrentStepNumber = 2 +stat_struct_analysis_settings.Activate() +stat_struct_analysis_settings.StepEndTime = Quantity("4 [s]") +stat_struct_analysis_settings.AutomaticTimeStepping = AutomaticTimeStepping.On +stat_struct_analysis_settings.DefineBy = TimeStepDefineByType.Time +stat_struct_analysis_settings.InitialTimeStep = Quantity("0.01 [s]") +stat_struct_analysis_settings.MinimumTimeStep = Quantity("0.000001 [s]") +stat_struct_analysis_settings.MaximumTimeStep = Quantity("0.02 [s]") + +stat_struct_analysis_settings.LargeDeflection = True # %% # Insert loading and boundary conditions # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -FIX_SUP = STAT_STRUC.AddFixedSupport() -FIX_SUP.Location = HOR_EDGE1 +fixed_support = static_structural_analysis.AddFixedSupport() +fixed_support.Location = hor_edge1 -REM_DISP = STAT_STRUC.AddRemoteDisplacement() -REM_DISP.Location = REM_PT -REM_DISP.XComponent.Output.DiscreteValues = [Quantity("0[mm]")] -REM_DISP.RotationZ.Output.DiscreteValues = [Quantity("0[deg]")] +remote_displacement = static_structural_analysis.AddRemoteDisplacement() +remote_displacement.Location = remote_point +remote_displacement.XComponent.Output.DiscreteValues = [Quantity("0[mm]")] +remote_displacement.RotationZ.Output.DiscreteValues = [Quantity("0[deg]")] -REM_FRC = STAT_STRUC.AddRemoteForce() -REM_FRC.Location = REM_PT -REM_FRC.DefineBy = LoadDefineBy.Components -REM_FRC.YComponent.Output.DiscreteValues = [Quantity("-150796320 [N]")] +remote_force = static_structural_analysis.AddRemoteForce() +remote_force.Location = remote_point +remote_force.DefineBy = LoadDefineBy.Components +remote_force.YComponent.Output.DiscreteValues = [Quantity("-150796320 [N]")] # Nonlinear Adaptivity does not support contact criterion yet hence command snippet used -NLAD = """NLADAPTIVE,all,add,contact,wear,0.50 +nonlinear_adaptivity = """NLADAPTIVE,all,add,contact,wear,0.50 NLADAPTIVE,all,on,all,all,1,,4 NLADAPTIVE,all,list,all,all""" -CMD2 = STAT_STRUC.AddCommandSnippet() -CMD2.AppendText(NLAD) -CMD2.StepSelectionMode = SequenceSelectionType.All +cmd2 = static_structural_analysis.AddCommandSnippet() +cmd2.AppendText(nonlinear_adaptivity) +cmd2.StepSelectionMode = SequenceSelectionType.All -STAT_STRUC.Activate() -Graphics.Camera.SetFit() -Graphics.ExportImage(os.path.join(cwd, "mesh.png"), image_export_format, settings_720p) -display_image("mesh.png") +static_structural_analysis.Activate() +camera.SetFit() +graphics.ExportImage(str(mesh_image), image_export_format, settings_720p) +display_image(mesh_image.name) # %% # Insert results # ~~~~~~~~~~~~~~ -TOT_DEF = STAT_STRUC_SOLN.AddTotalDeformation() +total_deformation = stat_struct_soln.AddTotalDeformation() -NORM_STRS1 = STAT_STRUC_SOLN.AddNormalStress() -NORM_STRS1.NormalOrientation = NormalOrientationType.YAxis -NORM_STRS1.DisplayTime = Quantity("1 [s]") -NORM_STRS1.DisplayOption = ResultAveragingType.Unaveraged +normal_stress1 = stat_struct_soln.AddNormalStress() +normal_stress1.NormalOrientation = NormalOrientationType.YAxis +normal_stress1.DisplayTime = Quantity("1 [s]") +normal_stress1.DisplayOption = ResultAveragingType.Unaveraged -NORM_STRS2 = STAT_STRUC_SOLN.AddNormalStress() -NORM_STRS2.NormalOrientation = NormalOrientationType.YAxis -NORM_STRS2.DisplayTime = Quantity("4 [s]") -NORM_STRS2.DisplayOption = ResultAveragingType.Unaveraged +normal_stress2 = stat_struct_soln.AddNormalStress() +normal_stress2.NormalOrientation = NormalOrientationType.YAxis +normal_stress2.DisplayTime = Quantity("4 [s]") +normal_stress2.DisplayOption = ResultAveragingType.Unaveraged -CONT_TOOL = STAT_STRUC_SOLN.AddContactTool() -CONT_TOOL.ScopingMethod = GeometryDefineByType.Geometry -SEL1 = ExtAPI.SelectionManager.AddSelection(ALL_BODIES_NS) -SEL2 = ExtAPI.SelectionManager.CurrentSelection -CONT_TOOL.Location = SEL2 -ExtAPI.SelectionManager.ClearSelection() -CONT_PRES1 = CONT_TOOL.AddPressure() -CONT_PRES1.DisplayTime = Quantity("1 [s]") +contact_tool = stat_struct_soln.AddContactTool() +contact_tool.ScopingMethod = GeometryDefineByType.Geometry +selection1 = app.ExtAPI.SelectionManager.AddSelection(all_bodies_named_selection) +selection2 = app.ExtAPI.SelectionManager.CurrentSelection +contact_tool.Location = selection2 +app.ExtAPI.SelectionManager.ClearSelection() +contact_pressure1 = contact_tool.AddPressure() +contact_pressure1.DisplayTime = Quantity("1 [s]") -CONT_PRES2 = CONT_TOOL.AddPressure() -CONT_PRES2.DisplayTime = Quantity("4 [s]") +contact_pressure2 = contact_tool.AddPressure() +contact_pressure2.DisplayTime = Quantity("4 [s]") # %% # Solve # ~~~~~ -STAT_STRUC_SOLN.Solve(True) -STAT_STRUC_SS = STAT_STRUC_SOLN.Status +stat_struct_soln.Solve(True) # sphinx_gallery_start_ignore -assert str(STAT_STRUC_SS) == "Done", "Solution status is not 'Done'" +assert ( + stat_struct_soln.Status == SolutionStatusType.Done +), "Solution status is not 'Done'" # sphinx_gallery_end_ignore # %% @@ -329,11 +338,10 @@ def display_image(image_name): # ~~~~~~~~~~~~~~ # Normal stress -Tree.Activate([NORM_STRS1]) -Graphics.ExportImage( - os.path.join(cwd, "normal_stresss.png"), image_export_format, settings_720p -) -display_image("normal_stresss.png") +app.Tree.Activate([normal_stress1]) +normal_stress_image = cwd / "normal_stress" +graphics.ExportImage(str(normal_stress_image), image_export_format, settings_720p) +display_image(normal_stress_image.name) # %% # Total deformation animation @@ -345,10 +353,11 @@ def display_image(image_name): settings_720p.Width = 1280 settings_720p.Height = 720 -TOT_DEF.ExportAnimation( - os.path.join(cwd, "totaldeformation.gif"), animation_export_format, settings_720p +total_deformation_gif = cwd / "total_deformation.gif" +total_deformation.ExportAnimation( + str(total_deformation_gif), animation_export_format, settings_720p ) -gif = Image.open(os.path.join(cwd, "totaldeformation.gif")) +gif = Image.open(total_deformation_gif) fig, ax = plt.subplots(figsize=(16, 9)) ax.axis("off") img = ax.imshow(gif.convert("RGBA")) @@ -377,7 +386,8 @@ def update(frame): # ~~~~~~~ # Save project -app.save(os.path.join(cwd, "contact_wear.mechdat")) +mechdat_file = cwd / "contact_wear.mechdat" +app.save(str(mechdat_file)) app.new() # delete example file diff --git a/examples/02_technology_showcase/non_linear_analsis_rubber_boot_seal.py b/examples/02_technology_showcase/non_linear_analsis_rubber_boot_seal.py index b0ad0863..97fa2ced 100644 --- a/examples/02_technology_showcase/non_linear_analsis_rubber_boot_seal.py +++ b/examples/02_technology_showcase/non_linear_analsis_rubber_boot_seal.py @@ -18,7 +18,7 @@ # Import necessary libraries # ~~~~~~~~~~~~~~~~~~~~~~~~~~ -import os +from pathlib import Path from PIL import Image from ansys.mechanical.core import App @@ -33,12 +33,13 @@ app = App(globals=globals()) print(app) -cwd = os.path.join(os.getcwd(), "out") +cwd = Path.cwd() / "out" def display_image(image_name): plt.figure(figsize=(16, 9)) - plt.imshow(mpimg.imread(os.path.join(cwd, image_name))) + image_path = cwd / image_name + plt.imshow(mpimg.imread(str(image_path))) plt.xticks([]) plt.yticks([]) plt.axis("off") @@ -49,8 +50,11 @@ def display_image(image_name): # Configure graphics for image export # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Graphics.Camera.SetSpecificViewOrientation(ViewOrientationType.Iso) -Graphics.Camera.SetFit() +graphics = app.Graphics +camera = graphics.Camera + +camera.SetSpecificViewOrientation(ViewOrientationType.Iso) +camera.SetFit() image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() settings_720p.Resolution = GraphicsResolutionType.EnhancedResolution @@ -73,13 +77,16 @@ def display_image(image_name): # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Import material -materials = Model.Materials +model = app.Model + +materials = model.Materials materials.Import(mat_path) print("Material import done !") + # %% # Import geometry -geometry_import = Model.GeometryImportGroup.AddGeometryImport() +geometry_import = model.GeometryImportGroup.AddGeometryImport() geometry_import_format = ( Ansys.Mechanical.DataModel.Enums.GeometryImportPreference.Format.Automatic ) @@ -97,315 +104,338 @@ def display_image(image_name): # ~~~~~~~~~~~~~~~~~~ # Set up the unit system -ExtAPI.Application.ActiveUnitSystem = MechanicalUnitSystem.StandardNMM -ExtAPI.Application.ActiveAngleUnit = AngleUnitType.Radian +app.ExtAPI.Application.ActiveUnitSystem = MechanicalUnitSystem.StandardNMM +app.ExtAPI.Application.ActiveAngleUnit = AngleUnitType.Radian # %% # Store all main tree nodes as variables -GEOM = Model.Geometry -PRT1 = [x for x in Tree.AllObjects if x.Name == "Part"][0] -PRT2 = [x for x in Tree.AllObjects if x.Name == "Solid"][1] -CS_GRP = Model.CoordinateSystems -GCS = CS_GRP.Children[0] +geometry = model.Geometry +part1 = [x for x in app.Tree.AllObjects if x.Name == "Part"][0] +part2 = [x for x in app.Tree.AllObjects if x.Name == "Solid"][1] +coordinate_systems = model.CoordinateSystems +gcs = coordinate_systems.Children[0] # %% # Add static structural analysis -Model.AddStaticStructuralAnalysis() -STAT_STRUC = Model.Analyses[0] -ANA_SETTING = STAT_STRUC.Children[0] -STAT_STRUC_SOLN = STAT_STRUC.Solution -SOLN_INFO = STAT_STRUC_SOLN.SolutionInformation +model.AddStaticStructuralAnalysis() +static_structural_analysis = model.Analyses[0] +analysis_settings = static_structural_analysis.Children[0] +stat_struct_soln = static_structural_analysis.Solution +soln_info = stat_struct_soln.SolutionInformation # %% # Define named selection and coordinate system -NS_GRP = ExtAPI.DataModel.Project.Model.NamedSelections -TOP_FACE = [ +named_selections = app.ExtAPI.DataModel.Project.Model.NamedSelections +top_face = [ i - for i in NS_GRP.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) + for i in named_selections.GetChildren[ + Ansys.ACT.Automation.Mechanical.NamedSelection + ](True) if i.Name == "Top_Face" ][0] -BOTTOM_FACE = [ +bottom_face = [ i - for i in NS_GRP.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) + for i in named_selections.GetChildren[ + Ansys.ACT.Automation.Mechanical.NamedSelection + ](True) if i.Name == "Bottom_Face" ][0] -SYMM_FACES30 = [ +symm_faces30 = [ i - for i in NS_GRP.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) + for i in named_selections.GetChildren[ + Ansys.ACT.Automation.Mechanical.NamedSelection + ](True) if i.Name == "Symm_Faces30" ][0] -FACES2 = [ +faces2 = [ i - for i in NS_GRP.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) + for i in named_selections.GetChildren[ + Ansys.ACT.Automation.Mechanical.NamedSelection + ](True) if i.Name == "Faces2" ][0] -CYL_FACES2 = [ +cyl_faces2 = [ i - for i in NS_GRP.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) + for i in named_selections.GetChildren[ + Ansys.ACT.Automation.Mechanical.NamedSelection + ](True) if i.Name == "Cyl_Faces2" ][0] -RUBBER_BODIES30 = [ +rubber_bodies30 = [ i - for i in NS_GRP.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) + for i in named_selections.GetChildren[ + Ansys.ACT.Automation.Mechanical.NamedSelection + ](True) if i.Name == "Rubber_Bodies30" ][0] -INNER_FACES30 = [ +inner_faces30 = [ i - for i in NS_GRP.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) + for i in named_selections.GetChildren[ + Ansys.ACT.Automation.Mechanical.NamedSelection + ](True) if i.Name == "Inner_Faces30" ][0] -OUTER_FACES30 = [ +outer_faces30 = [ i - for i in NS_GRP.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) + for i in named_selections.GetChildren[ + Ansys.ACT.Automation.Mechanical.NamedSelection + ](True) if i.Name == "Outer_Faces30" ][0] -SHAFT_FACE = [ +shaft_face = [ i - for i in NS_GRP.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) + for i in named_selections.GetChildren[ + Ansys.ACT.Automation.Mechanical.NamedSelection + ](True) if i.Name == "Shaft_Face" ][0] -SYMM_FACES15 = [ +symm_faces15 = [ i - for i in NS_GRP.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) + for i in named_selections.GetChildren[ + Ansys.ACT.Automation.Mechanical.NamedSelection + ](True) if i.Name == "Symm_Faces15" ][0] -LCS1 = CS_GRP.AddCoordinateSystem() -LCS1.OriginY = Quantity("97[mm]") +lcs1 = coordinate_systems.AddCoordinateSystem() +lcs1.OriginY = Quantity("97[mm]") # %% # Assign material -PRT1.Material = "Boot" -PRT2.StiffnessBehavior = StiffnessBehavior.Rigid +part1.Material = "Boot" +part2.StiffnessBehavior = StiffnessBehavior.Rigid # %% # Define connections -CONN_GRP = Model.Connections -CONT_REG1 = CONN_GRP.AddContactRegion() -CONT_REG1.TargetLocation = SHAFT_FACE -CONT_REG1.SourceLocation = INNER_FACES30 -CONT_REG1.ContactType = ContactType.Frictional -CONT_REG1.FrictionCoefficient = 0.2 -CONT_REG1.Behavior = ContactBehavior.Asymmetric -CONT_REG1.SmallSliding = ContactSmallSlidingType.Off -CONT_REG1.DetectionMethod = ContactDetectionPoint.OnGaussPoint -CONT_REG1.UpdateStiffness = UpdateContactStiffness.EachIteration -CONT_REG1.InterfaceTreatment = ContactInitialEffect.AddOffsetRampedEffects -CONT_REG1.TargetGeometryCorrection = TargetCorrection.Smoothing -CONT_REG1.TargetOrientation = TargetOrientation.Cylinder -CONT_REG1.TargetStartingPoint = GCS -CONT_REG1.TargetEndingPoint = LCS1 - -CONTS = CONN_GRP.Children[0] -CONT_REG2 = CONTS.AddContactRegion() -CONT_REG2.SourceLocation = INNER_FACES30 -CONT_REG2.TargetLocation = INNER_FACES30 -CONT_REG2.ContactType = ContactType.Frictional -CONT_REG2.FrictionCoefficient = 0.2 -CONT_REG2.Behavior = ContactBehavior.Asymmetric -CONT_REG2.SmallSliding = ContactSmallSlidingType.Off -CONT_REG2.DetectionMethod = ContactDetectionPoint.NodalProjectedNormalFromContact -CONT_REG2.UpdateStiffness = UpdateContactStiffness.EachIteration -CONT_REG2.NormalStiffnessValueType = ElementControlsNormalStiffnessType.Factor -CONT_REG2.NormalStiffnessFactor = 1 - -CONT_REG3 = CONTS.AddContactRegion() -CONT_REG3.SourceLocation = OUTER_FACES30 -CONT_REG3.TargetLocation = OUTER_FACES30 -CONT_REG3.ContactType = ContactType.Frictional -CONT_REG3.FrictionCoefficient = 0.2 -CONT_REG3.Behavior = ContactBehavior.Asymmetric -CONT_REG3.SmallSliding = ContactSmallSlidingType.Off -CONT_REG3.DetectionMethod = ContactDetectionPoint.NodalProjectedNormalFromContact -CONT_REG3.UpdateStiffness = UpdateContactStiffness.EachIteration -CONT_REG3.NormalStiffnessValueType = ElementControlsNormalStiffnessType.Factor -CONT_REG3.NormalStiffnessFactor = 1 +connections = model.Connections +contact_region1 = connections.AddContactRegion() +contact_region1.TargetLocation = shaft_face +contact_region1.SourceLocation = inner_faces30 +contact_region1.ContactType = ContactType.Frictional +contact_region1.FrictionCoefficient = 0.2 +contact_region1.Behavior = ContactBehavior.Asymmetric +contact_region1.SmallSliding = ContactSmallSlidingType.Off +contact_region1.DetectionMethod = ContactDetectionPoint.OnGaussPoint +contact_region1.UpdateStiffness = UpdateContactStiffness.EachIteration +contact_region1.InterfaceTreatment = ContactInitialEffect.AddOffsetRampedEffects +contact_region1.TargetGeometryCorrection = TargetCorrection.Smoothing +contact_region1.TargetOrientation = TargetOrientation.Cylinder +contact_region1.TargetStartingPoint = gcs +contact_region1.TargetEndingPoint = lcs1 + +conts = connections.Children[0] +contact_region2 = conts.AddContactRegion() +contact_region2.SourceLocation = inner_faces30 +contact_region2.TargetLocation = inner_faces30 +contact_region2.ContactType = ContactType.Frictional +contact_region2.FrictionCoefficient = 0.2 +contact_region2.Behavior = ContactBehavior.Asymmetric +contact_region2.SmallSliding = ContactSmallSlidingType.Off +contact_region2.DetectionMethod = ContactDetectionPoint.NodalProjectedNormalFromContact +contact_region2.UpdateStiffness = UpdateContactStiffness.EachIteration +contact_region2.NormalStiffnessValueType = ElementControlsNormalStiffnessType.Factor +contact_region2.NormalStiffnessFactor = 1 + +contact_region3 = conts.AddContactRegion() +contact_region3.SourceLocation = outer_faces30 +contact_region3.TargetLocation = outer_faces30 +contact_region3.ContactType = ContactType.Frictional +contact_region3.FrictionCoefficient = 0.2 +contact_region3.Behavior = ContactBehavior.Asymmetric +contact_region3.SmallSliding = ContactSmallSlidingType.Off +contact_region3.DetectionMethod = ContactDetectionPoint.NodalProjectedNormalFromContact +contact_region3.UpdateStiffness = UpdateContactStiffness.EachIteration +contact_region3.NormalStiffnessValueType = ElementControlsNormalStiffnessType.Factor +contact_region3.NormalStiffnessFactor = 1 # %% # Mesh # ~~~~ -MSH = Model.Mesh -FACE_MSH = MSH.AddFaceMeshing() -FACE_MSH.Location = SHAFT_FACE -FACE_MSH.InternalNumberOfDivisions = 1 +mesh = model.Mesh +face_mesh = mesh.AddFaceMeshing() +face_mesh.Location = shaft_face +face_mesh.InternalNumberOfDivisions = 1 -MSH_SIZE = MSH.AddSizing() -MSH_SIZE.Location = SYMM_FACES15 -MSH_SIZE.ElementSize = Quantity("2 [mm]") +mesh_size = mesh.AddSizing() +mesh_size.Location = symm_faces15 +mesh_size.ElementSize = Quantity("2 [mm]") -MSH.ElementOrder = ElementOrder.Linear -MSH.Resolution = 2 +mesh.ElementOrder = ElementOrder.Linear +mesh.Resolution = 2 -MSH.GenerateMesh() +mesh.GenerateMesh() -Graphics.ExportImage(os.path.join(cwd, "mesh.png"), image_export_format, settings_720p) -display_image("mesh.png") +mesh_image = cwd / "mesh.png" +graphics.ExportImage(str(mesh_image), image_export_format, settings_720p) +display_image(mesh_image.name) # %% # Define remote points # ~~~~~~~~~~~~~~~~~~~~ # scope them to the top and bottom faces of rigid shaft -RMPT01 = Model.AddRemotePoint() -RMPT01.Location = BOTTOM_FACE -RMPT01.Behavior = LoadBehavior.Rigid +remote_point01 = model.AddRemotePoint() +remote_point01.Location = bottom_face +remote_point01.Behavior = LoadBehavior.Rigid -RMPT02 = Model.AddRemotePoint() -RMPT02.Location = TOP_FACE -RMPT02.Behavior = LoadBehavior.Rigid +remote_point02 = model.AddRemotePoint() +remote_point02.Location = top_face +remote_point02.Behavior = LoadBehavior.Rigid # %% # Analysis settings # ~~~~~~~~~~~~~~~~~ -ANA_SETTING.Activate() -ANA_SETTING.LargeDeflection = True -ANA_SETTING.Stabilization = StabilizationType.Off - -ANA_SETTING.NumberOfSteps = 2 -ANA_SETTING.CurrentStepNumber = 1 -ANA_SETTING.AutomaticTimeStepping = AutomaticTimeStepping.On -ANA_SETTING.DefineBy = TimeStepDefineByType.Substeps -ANA_SETTING.InitialSubsteps = 5 -ANA_SETTING.MinimumSubsteps = 5 -ANA_SETTING.MaximumSubsteps = 1000 -ANA_SETTING.StoreResultsAt = TimePointsOptions.EquallySpacedPoints -ANA_SETTING.StoreResulsAtValue = 5 - -ANA_SETTING.CurrentStepNumber = 2 -ANA_SETTING.AutomaticTimeStepping = AutomaticTimeStepping.On -ANA_SETTING.DefineBy = TimeStepDefineByType.Substeps -ANA_SETTING.InitialSubsteps = 10 -ANA_SETTING.MinimumSubsteps = 10 -ANA_SETTING.MaximumSubsteps = 1000 -ANA_SETTING.StoreResultsAt = TimePointsOptions.EquallySpacedPoints -ANA_SETTING.StoreResulsAtValue = 10 - -ANA_SETTING.CurrentStepNumber = 3 -ANA_SETTING.AutomaticTimeStepping = AutomaticTimeStepping.On -ANA_SETTING.DefineBy = TimeStepDefineByType.Substeps -ANA_SETTING.InitialSubsteps = 30 -ANA_SETTING.MinimumSubsteps = 30 -ANA_SETTING.MaximumSubsteps = 1000 -ANA_SETTING.StoreResultsAt = TimePointsOptions.EquallySpacedPoints -ANA_SETTING.StoreResulsAtValue = 20 - -SOLN_INFO.NewtonRaphsonResiduals = 4 +analysis_settings.Activate() +analysis_settings.LargeDeflection = True +analysis_settings.Stabilization = StabilizationType.Off + +analysis_settings.NumberOfSteps = 2 +analysis_settings.CurrentStepNumber = 1 +analysis_settings.AutomaticTimeStepping = AutomaticTimeStepping.On +analysis_settings.DefineBy = TimeStepDefineByType.Substeps +analysis_settings.InitialSubsteps = 5 +analysis_settings.MinimumSubsteps = 5 +analysis_settings.MaximumSubsteps = 1000 +analysis_settings.StoreResultsAt = TimePointsOptions.EquallySpacedPoints +analysis_settings.StoreResulsAtValue = 5 + +analysis_settings.CurrentStepNumber = 2 +analysis_settings.AutomaticTimeStepping = AutomaticTimeStepping.On +analysis_settings.DefineBy = TimeStepDefineByType.Substeps +analysis_settings.InitialSubsteps = 10 +analysis_settings.MinimumSubsteps = 10 +analysis_settings.MaximumSubsteps = 1000 +analysis_settings.StoreResultsAt = TimePointsOptions.EquallySpacedPoints +analysis_settings.StoreResulsAtValue = 10 + +analysis_settings.CurrentStepNumber = 3 +analysis_settings.AutomaticTimeStepping = AutomaticTimeStepping.On +analysis_settings.DefineBy = TimeStepDefineByType.Substeps +analysis_settings.InitialSubsteps = 30 +analysis_settings.MinimumSubsteps = 30 +analysis_settings.MaximumSubsteps = 1000 +analysis_settings.StoreResultsAt = TimePointsOptions.EquallySpacedPoints +analysis_settings.StoreResulsAtValue = 20 + +soln_info.NewtonRaphsonResiduals = 4 # %% # Loads and boundary conditions # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -REM_DISP = STAT_STRUC.AddRemoteDisplacement() -REM_DISP.Location = RMPT01 -REM_DISP.XComponent.Inputs[0].DiscreteValues = [ +remote_displacement = static_structural_analysis.AddRemoteDisplacement() +remote_displacement.Location = remote_point01 +remote_displacement.XComponent.Inputs[0].DiscreteValues = [ Quantity("0 [s]"), Quantity("1 [s]"), Quantity("2 [s]"), Quantity("3 [s]"), ] -REM_DISP.XComponent.Output.DiscreteValues = [ +remote_displacement.XComponent.Output.DiscreteValues = [ Quantity("0 [mm]"), Quantity("0 [mm]"), Quantity("0 [mm]"), Quantity("0 [mm]"), ] -REM_DISP.YComponent.Inputs[0].DiscreteValues = [ +remote_displacement.YComponent.Inputs[0].DiscreteValues = [ Quantity("0 [s]"), Quantity("1 [s]"), Quantity("2 [s]"), Quantity("3 [s]"), ] -REM_DISP.YComponent.Output.DiscreteValues = [ +remote_displacement.YComponent.Output.DiscreteValues = [ Quantity("0 [mm]"), Quantity("0 [mm]"), Quantity("-10 [mm]"), Quantity("-10 [mm]"), ] -REM_DISP.ZComponent.Inputs[0].DiscreteValues = [ +remote_displacement.ZComponent.Inputs[0].DiscreteValues = [ Quantity("0 [s]"), Quantity("1 [s]"), Quantity("2 [s]"), Quantity("3 [s]"), ] -REM_DISP.ZComponent.Output.DiscreteValues = [ +remote_displacement.ZComponent.Output.DiscreteValues = [ Quantity("0 [mm]"), Quantity("0 [mm]"), Quantity("0 [mm]"), Quantity("0 [mm]"), ] -REM_DISP.RotationX.Inputs[0].DiscreteValues = [ +remote_displacement.RotationX.Inputs[0].DiscreteValues = [ Quantity("0 [s]"), Quantity("1 [s]"), Quantity("2 [s]"), Quantity("3 [s]"), ] -REM_DISP.RotationX.Output.DiscreteValues = [ +remote_displacement.RotationX.Output.DiscreteValues = [ Quantity("0 [rad]"), Quantity("0 [rad]"), Quantity("0 [rad]"), Quantity("0 [rad]"), ] -REM_DISP.RotationY.Inputs[0].DiscreteValues = [ +remote_displacement.RotationY.Inputs[0].DiscreteValues = [ Quantity("0 [s]"), Quantity("1 [s]"), Quantity("2 [s]"), Quantity("3 [s]"), ] -REM_DISP.RotationY.Output.DiscreteValues = [ +remote_displacement.RotationY.Output.DiscreteValues = [ Quantity("0 [rad]"), Quantity("0 [rad]"), Quantity("0 [rad]"), Quantity("0 [rad]"), ] -REM_DISP.RotationZ.Inputs[0].DiscreteValues = [ +remote_displacement.RotationZ.Inputs[0].DiscreteValues = [ Quantity("0 [s]"), Quantity("1 [s]"), Quantity("2 [s]"), Quantity("3 [s]"), ] -REM_DISP.RotationZ.Output.DiscreteValues = [ +remote_displacement.RotationZ.Output.DiscreteValues = [ Quantity("0 [rad]"), Quantity("0 [rad]"), Quantity("0 [rad]"), Quantity("0.55 [rad]"), ] -FRIC_SUP01 = STAT_STRUC.AddFrictionlessSupport() -FRIC_SUP01.Location = SYMM_FACES30 -FRIC_SUP01.Name = "Symmetry_BC" -FRIC_SUP02 = STAT_STRUC.AddFrictionlessSupport() -FRIC_SUP02.Location = FACES2 -FRIC_SUP02.Name = "Boot_Bottom_BC" -FRIC_SUP03 = STAT_STRUC.AddFrictionlessSupport() -FRIC_SUP03.Location = CYL_FACES2 -FRIC_SUP03.Name = "Boot_Radial_BC" +frictionless_support1 = static_structural_analysis.AddFrictionlessSupport() +frictionless_support1.Location = symm_faces30 +frictionless_support1.Name = "Symmetry_BC" +frictionless_support2 = static_structural_analysis.AddFrictionlessSupport() +frictionless_support2.Location = faces2 +frictionless_support2.Name = "Boot_Bottom_BC" +frictionless_support3 = static_structural_analysis.AddFrictionlessSupport() +frictionless_support3.Location = cyl_faces2 +frictionless_support3.Name = "Boot_Radial_BC" # %% # Add results # ~~~~~~~~~~~ -TOT_DEF = STAT_STRUC.Solution.AddTotalDeformation() -TOT_DEF.Location = RUBBER_BODIES30 +total_deformation = static_structural_analysis.Solution.AddTotalDeformation() +total_deformation.Location = rubber_bodies30 -EQV_STRS = STAT_STRUC.Solution.AddEquivalentStress() -EQV_STRS.Location = RUBBER_BODIES30 +equivalent_stress = static_structural_analysis.Solution.AddEquivalentStress() +equivalent_stress.Location = rubber_bodies30 # %% # Solve # ~~~~~ -STAT_STRUC.Solution.Solve(True) +static_structural_analysis.Solution.Solve(True) # sphinx_gallery_start_ignore -assert str(STAT_STRUC_SOLN.Status) == "Done", "Solution status is not 'Done'" +assert ( + stat_struct_soln.Status == SolutionStatusType.Done +), "Solution status is not 'Done'" # sphinx_gallery_end_ignore # %% @@ -414,20 +444,18 @@ def display_image(image_name): # Total deformation -Tree.Activate([TOT_DEF]) -Graphics.ExportImage( - os.path.join(cwd, "totaldeformation.png"), image_export_format, settings_720p -) -display_image("totaldeformation.png") +app.Tree.Activate([total_deformation]) +total_deformation_image = cwd / "total_deformation.png" +graphics.ExportImage(str(total_deformation_image), image_export_format, settings_720p) +display_image(total_deformation_image.name) # %% # Equivalent stress -Tree.Activate([EQV_STRS]) -Graphics.ExportImage( - os.path.join(cwd, "equivalent_stress.png"), image_export_format, settings_720p -) -display_image("equivalent_stress.png") +app.Tree.Activate([equivalent_stress]) +equivalent_stress_image = cwd / "equivalent_stress.png" +graphics.ExportImage(str(total_deformation_image), image_export_format, settings_720p) +display_image(total_deformation_image.name) # %% # Total deformation animation @@ -439,10 +467,11 @@ def display_image(image_name): settings_720p.Width = 1280 settings_720p.Height = 720 -TOT_DEF.ExportAnimation( - os.path.join(cwd, "totaldeformation.gif"), animation_export_format, settings_720p +total_deformation_gif = cwd / "total_deformation.gif" +total_deformation.ExportAnimation( + str(total_deformation_gif), animation_export_format, settings_720p ) -gif = Image.open(os.path.join(cwd, "totaldeformation.gif")) +gif = Image.open(total_deformation_gif) fig, ax = plt.subplots(figsize=(16, 9)) ax.axis("off") img = ax.imshow(gif.convert("RGBA")) @@ -465,7 +494,8 @@ def update(frame): # ~~~~~~~ # Save project -app.save(os.path.join(cwd, "non-linear-rubber-boot-seal.mechdat")) +mechdat_file = cwd / "non_linear_rubber_boot_seal.mechdat" +app.save(str(mechdat_file)) app.new() # delete example file From 8ae008e15085c56d980250c9d02f6840c40798bb Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Wed, 23 Apr 2025 16:18:11 -0400 Subject: [PATCH 09/24] add set_camera_display_image and update_animation functions --- examples/00_tips/tips_01.py | 26 +-- examples/00_tips/tips_02.py | 68 ++++--- examples/00_tips/tips_03.py | 12 +- examples/01_basic/bolt_pretension.py | 1 + examples/01_basic/harmonic_acoustics.py | 169 ++++++++++++----- examples/01_basic/modal_acoustics_analysis.py | 165 +++++++++++++---- .../01_basic/steady_state_thermal_analysis.py | 170 +++++++++++++----- .../topology_optimization_cantilever_beam.py | 162 ++++++++++++++--- examples/01_basic/valve.py | 158 ++++++++++++---- .../Rotor_Blade_Inverse_solve.py | 121 +++++++++---- .../conact_wear_simulation.py | 151 ++++++++++++---- .../non_linear_analsis_rubber_boot_seal.py | 152 ++++++++++++---- 12 files changed, 1033 insertions(+), 322 deletions(-) diff --git a/examples/00_tips/tips_01.py b/examples/00_tips/tips_01.py index f04c42ee..ad9596c1 100644 --- a/examples/00_tips/tips_01.py +++ b/examples/00_tips/tips_01.py @@ -15,27 +15,28 @@ from ansys.mechanical.core.examples import delete_downloads, download_file # %% -# Embed mechanical and set global variables +# Create an instance of the Mechanical embedded application app = App(globals=globals()) print(app) # %% -# Download and import geometry -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Download geometry +# Download and import geometry file +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Download the geometry file geometry_path = download_file("Valve.pmdb", "pymechanical", "embedding") -# %% -# Import geometry +# Define the model +model = app.Model -geometry_import = Model.GeometryImportGroup.AddGeometryImport() +# Import the geometry file +geometry_import = model.GeometryImportGroup.AddGeometryImport() geometry_import.Import(geometry_path) # %% -# Visualize in 3D -# ~~~~~~~~~~~~~~~ +# Visualize the model in 3D +# ~~~~~~~~~~~~~~~~~~~~~~~~~ app.plot() @@ -44,8 +45,11 @@ # This visualization is currently available only for geometry and on version 24R2 or later # %% -# Cleanup -# ~~~~~~~ +# Clean up the files and app +# ~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Delete the downloaded files delete_downloads() + +# Refresh the app app.new() diff --git a/examples/00_tips/tips_02.py b/examples/00_tips/tips_02.py index 6c1ad89c..98604e92 100644 --- a/examples/00_tips/tips_02.py +++ b/examples/00_tips/tips_02.py @@ -10,27 +10,32 @@ # Import necessary libraries # ~~~~~~~~~~~~~~~~~~~~~~~~~~ -import os +from pathlib import Path from ansys.mechanical.core import App from ansys.mechanical.core.examples import delete_downloads, download_file # %% -# Embed Mechanical and set global variables +# Create an instance of the Mechanical embedded application +# Create an instance of the App class app = App() + +# Update the global variables app.update_globals(globals()) + +# Print the app to ensure it is working print(app) # %% -# Download and import geometry -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Download geometry +# Download and import the geometry file +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Download the geometry file geometry_path = download_file("Valve.pmdb", "pymechanical", "embedding") # %% -# Import geometry +# Import the geometry file geometry_import = Model.GeometryImportGroup.AddGeometryImport() geometry_import.Import(geometry_path) @@ -39,13 +44,13 @@ # Configure graphics for image export # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Orientation +# Set the orientation of the camera ExtAPI.Graphics.Camera.SetSpecificViewOrientation(ViewOrientationType.Iso) -# Export format +# Set the image export format image_export_format = GraphicsImageExportFormat.PNG -# Resolution and background +# Configure the export settings for the image settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() settings_720p.Resolution = GraphicsResolutionType.EnhancedResolution settings_720p.Background = GraphicsBackgroundType.White @@ -53,24 +58,34 @@ settings_720p.Height = 720 settings_720p.CurrentGraphicsDisplay = False -# Rotate the geometry if needed +# Rotate the geometry on the Y-axis Graphics.Camera.Rotate(180, CameraAxisType.ScreenY) - # %% -# Custom function for displaying the image -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Create a function to display the image +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ from matplotlib import image as mpimg from matplotlib import pyplot as plt -# Temporary directory to save the image -cwd = os.path.join(os.getcwd(), "out") +# Directory to save the image +output_path = Path.output_path() / "out" -def display_image(image_name): +def display_image(image_name) -> None: + """Display the image using matplotlib. + + Parameters + ---------- + image_name : str + The name of the image file to display. + """ + # Create the full path to the image + image_path = output_path / image_name + + # Plot the figure and display the image plt.figure(figsize=(16, 9)) - plt.imshow(mpimg.imread(os.path.join(cwd, image_name))) + plt.imshow(mpimg.imread(str(image_path))) plt.xticks([]) plt.yticks([]) plt.axis("off") @@ -81,19 +96,22 @@ def display_image(image_name): # Export and display the image # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Fits the geometry in the viewing area +# Fit the geometry in the viewing area Graphics.Camera.SetFit() -Graphics.ExportImage( - os.path.join(cwd, "geometry.png"), image_export_format, settings_720p -) +# Export the image +geometry_image = output_path / "geometry.png" +Graphics.ExportImage(str(geometry_image), image_export_format, settings_720p) -# Display the image using matplotlib -display_image("geometry.png") +# Display the image +display_image(geometry_image.name) # %% -# Cleanup -# ~~~~~~~ +# Clean up the downloaded files and app +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Delete the downloaded files delete_downloads() + +# Refresh the app app.new() diff --git a/examples/00_tips/tips_03.py b/examples/00_tips/tips_03.py index 44d9c682..32633852 100644 --- a/examples/00_tips/tips_03.py +++ b/examples/00_tips/tips_03.py @@ -15,7 +15,7 @@ from ansys.mechanical.core.examples import delete_downloads, download_file # %% -# Embed Mechanical and set global variables +# Create an instance of the Mechanical embedded application app = App(globals=globals()) print(app) @@ -41,12 +41,16 @@ # Display the tree only under the first analysis # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -app.print_tree(Model.Analyses[0]) +first_analysis = app.Model.Analyses[0] +app.print_tree(first_analysis) # %% -# Cleanup -# ~~~~~~~ +# Clean up the downloaded files and app +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Delete the downloaded files delete_downloads() + +# Refresh the app app.new() diff --git a/examples/01_basic/bolt_pretension.py b/examples/01_basic/bolt_pretension.py index e31c81e0..cae5ac98 100644 --- a/examples/01_basic/bolt_pretension.py +++ b/examples/01_basic/bolt_pretension.py @@ -27,6 +27,7 @@ # %% # Create an instance of the Mechanical embedded application + app = App() print(app) diff --git a/examples/01_basic/harmonic_acoustics.py b/examples/01_basic/harmonic_acoustics.py index 8cf37b6b..b4c33cda 100644 --- a/examples/01_basic/harmonic_acoustics.py +++ b/examples/01_basic/harmonic_acoustics.py @@ -51,16 +51,80 @@ app.update_globals(globals()) print(app) -cwd = Path.cwd() / "out" - - -def display_image(image_name): - plt.figure(figsize=(16, 9)) - image_path = cwd / image_name +# %% +# Set the image output path and create functions to fit the camera and display images +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Set the path for the output files (images, gifs, mechdat) +output_path = Path.cwd() / "out" + + +def set_camera_and_display_image( + camera: Ansys.ACT.Common.Graphics.MechanicalCameraWrapper, + graphics: Ansys.ACT.Common.Graphics.MechanicalGraphicsWrapper, + graphics_image_export_settings: Ansys.Mechanical.Graphics.GraphicsImageExportSettings, + image_output_path: Path, + image_name: str, +) -> None: + """Set the camera to fit the model and display the image. + + Parameters + ---------- + camera : Ansys.ACT.Common.Graphics.MechanicalCameraWrapper + The camera object to set the view. + graphics : Ansys.ACT.Common.Graphics.MechanicalGraphicsWrapper + The graphics object to export the image. + graphics_image_export_settings : Ansys.Mechanical.Graphics.GraphicsImageExportSettings + The settings for exporting the image. + image_output_path : Path + The path to save the exported image. + image_name : str + The name of the exported image file. + """ + # Set the camera to fit the mesh + camera.SetFit() + # Export the mesh image with the specified settings + image_path = image_output_path / image_name + graphics.ExportImage( + str(image_path), image_export_format, graphics_image_export_settings + ) + # Display the exported mesh image + display_image(image_path) + + +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 plt.imshow(mpimg.imread(image_path)) - plt.xticks([]) - plt.yticks([]) - plt.axis("off") + # 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() @@ -304,10 +368,9 @@ def display_image(image_name): absorption_surface.AbsorptionCoefficient.Output.DiscreteValues = [Quantity("0.02")] harmonic_acoustics.Activate() -camera.SetFit() -boundary_condition_image = cwd / "bounday_conditions.png" -graphics.ExportImage(str(boundary_condition_image), image_export_format, settings_720p) -display_image("bounday_conditions.png") +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "bounday_conditions.png" +) # %% # Add results @@ -421,47 +484,45 @@ def display_image(image_name): # ^^^^^^^^^^^^^^^^^^^^^^^ app.Tree.Activate([acoustic_pressure_result_1]) -acoustic_pressure_image = cwd / "acoustic_pressure.png" -graphics.ExportImage(str(acoustic_pressure_image), image_export_format, settings_720p) -display_image("acoustic_pressure.png") +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "acoustic_pressure.png" +) # %% # Total acoustic velocity # ^^^^^^^^^^^^^^^^^^^^^^^ app.Tree.Activate([acoustic_pressure_result_1]) -total_velocity_image = cwd / "total_velocity.png" -graphics.ExportImage(str(total_velocity_image), image_export_format, settings_720p) -display_image("total_velocity.png") +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "total_velocity.png" +) # %% # Sound pressure level # ^^^^^^^^^^^^^^^^^^^^ app.Tree.Activate([acoustic_spl]) -sound_pressure_image = cwd / "sound_pressure.png" -graphics.ExportImage(str(sound_pressure_image), image_export_format, settings_720p) -display_image("sound_pressure.png") +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "sound_pressure.png" +) # %% # Total velocity on pressure surface # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ app.Tree.Activate([acoustic_total_velocity_2]) -total_velocity_pressure_image = cwd / "total_velocity_pressure.png" -graphics.ExportImage( - str(total_velocity_pressure_image), image_export_format, settings_720p +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "total_velocity_pressure.png" ) -display_image("total_velocity_pressure.png") # %% # Kinetic energy on absorption face # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ app.Tree.Activate([acoustic_ke]) -kinetic_energy_image = cwd / "kinetic_energy.png" -graphics.ExportImage(str(kinetic_energy_image), image_export_format, settings_720p) -display_image("kinetic_energy.png") +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "kinetic_energy.png" +) # %% # Total acoustic pressure animation @@ -474,25 +535,53 @@ def display_image(image_name): settings_720p.Width = 1280 settings_720p.Height = 720 -press_gif = cwd / "press.gif" +press_gif = output_path / "press.gif" acoustic_pressure_result_1.ExportAnimation( str(press_gif), animation_export_format, settings_720p ) -gif = Image.open(press_gif) -fig, ax = plt.subplots(figsize=(16, 9)) -ax.axis("off") -img = ax.imshow(gif.convert("RGBA")) -def update(frame): +def update_animation(frame: int) -> list[mpimg.AxesImage]: + """Update the animation frame for the GIF. + + Parameters + ---------- + frame : int + The frame number to update the animation. + + Returns + ------- + list[mpimg.AxesImage] + A list containing the updated image for the animation. + """ + # Seeks to the given frame in this sequence file gif.seek(frame) - img.set_array(gif.convert("RGBA")) - return [img] + # Set the image array to the current frame of the GIF + image.set_data(gif.convert("RGBA")) + # Return the updated image + return [image] -ani = FuncAnimation( - fig, update, frames=range(gif.n_frames), interval=200, repeat=True, blit=True +# Open the GIF file and create an animation +gif = Image.open(press_gif) +# Set the subplots for the animation and turn off the axis +figure, axes = plt.subplots(figsize=(16, 9)) +axes.axis("off") +# Change the color of the image +image = axes.imshow(gif.convert("RGBA")) + +# Create the animation using the figure, update_animation function, and the GIF frames +# Set the interval between frames to 200 milliseconds and repeat the animation +FuncAnimation( + figure, + update_animation, + frames=range(gif.n_frames), + interval=100, + repeat=True, + blit=True, ) + +# Show the animation plt.show() # %% @@ -523,7 +612,7 @@ def write_file_contents_to_console(path): # ~~~~~~~ # Save project -mechdat_file = cwd / "harmonic_acoustics.mechdat" +mechdat_file = output_path / "harmonic_acoustics.mechdat" app.save(str(mechdat_file)) app.new() diff --git a/examples/01_basic/modal_acoustics_analysis.py b/examples/01_basic/modal_acoustics_analysis.py index 096c8fd3..57d0b46f 100644 --- a/examples/01_basic/modal_acoustics_analysis.py +++ b/examples/01_basic/modal_acoustics_analysis.py @@ -34,16 +34,80 @@ app = App(globals=globals()) print(app) -cwd = Path.cwd() / "out" - - -def display_image(image_name): - plt.figure(figsize=(16, 9)) - image_path = cwd / image_name - plt.imshow(mpimg.imread(str(image_path))) - plt.xticks([]) - plt.yticks([]) - plt.axis("off") +# %% +# Set the image output path and create functions to fit the camera and display images +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Set the path for the output files (images, gifs, mechdat) +output_path = Path.cwd() / "out" + + +def set_camera_and_display_image( + camera: Ansys.ACT.Common.Graphics.MechanicalCameraWrapper, + graphics: Ansys.ACT.Common.Graphics.MechanicalGraphicsWrapper, + graphics_image_export_settings: Ansys.Mechanical.Graphics.GraphicsImageExportSettings, + image_output_path: Path, + image_name: str, +) -> None: + """Set the camera to fit the model and display the image. + + Parameters + ---------- + camera : Ansys.ACT.Common.Graphics.MechanicalCameraWrapper + The camera object to set the view. + graphics : Ansys.ACT.Common.Graphics.MechanicalGraphicsWrapper + The graphics object to export the image. + graphics_image_export_settings : Ansys.Mechanical.Graphics.GraphicsImageExportSettings + The settings for exporting the image. + image_output_path : Path + The path to save the exported image. + image_name : str + The name of the exported image file. + """ + # Set the camera to fit the mesh + camera.SetFit() + # Export the mesh image with the specified settings + image_path = image_output_path / image_name + graphics.ExportImage( + str(image_path), image_export_format, graphics_image_export_settings + ) + # Display the exported mesh image + display_image(image_path) + + +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 + 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() @@ -87,10 +151,9 @@ def display_image(image_name): geometry_path, geometry_import_format, geometry_import_preferences ) -camera.SetFit() -geometry_image = cwd / "geometry.png" -graphics.ExportImage(str(geometry_image), image_export_format, settings_720p) -display_image(geometry_image.name) +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "geometry.png" +) # %% # Store all variables necessary for analysis @@ -274,9 +337,7 @@ def display_image(image_name): mesh.GenerateMesh() -mesh_image = cwd / "mesh.png" -graphics.ExportImage(str(mesh_image), image_export_format, settings_720p) -display_image(mesh_image.name) +set_camera_and_display_image(camera, graphics, settings_720p, output_path, "mesh.png") # %% # Insert contacts @@ -393,8 +454,9 @@ def display_image(image_name): modal_acst.Activate() -graphics.ExportImage(str(geometry_image), image_export_format, settings_720p) -display_image(geometry_image.name) +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "geometry.png" +) # %% # Add results @@ -462,20 +524,17 @@ def display_image(image_name): # Total deformation - mode 1 app.Tree.Activate([total_deformation_1]) -camera.SetFit() -total_deformation_image = cwd / "total_deformation_1.png" -graphics.ExportImage(str(total_deformation_image), image_export_format, settings_720p) -display_image(total_deformation_image.name) - +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "total_deformation.png" +) # %% # Acoustic pressure app.Tree.Activate([acoustic_pressure_result]) -acoustic_pressure_image = cwd / "acoustic_pressure.png" -graphics.ExportImage(str(acoustic_pressure_image), image_export_format, settings_720p) -display_image(acoustic_pressure_image.name) - +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "acoustic_pressure.png" +) # %% # Display all modal frequency, force reaction @@ -525,25 +584,53 @@ def display_image(image_name): settings_720p.Width = 1280 settings_720p.Height = 720 -deformation_gif = cwd / "deformation_10.gif" +deformation_gif = output_path / "total_deformation_10.gif" total_deformation_10.ExportAnimation( str(deformation_gif), animation_export_format, settings_720p ) -gif = Image.open(deformation_gif) -fig, ax = plt.subplots(figsize=(16, 9)) -ax.axis("off") -img = ax.imshow(gif.convert("RGBA")) -def update(frame): +def update_animation(frame: int) -> list[mpimg.AxesImage]: + """Update the animation frame for the GIF. + + Parameters + ---------- + frame : int + The frame number to update the animation. + + Returns + ------- + list[mpimg.AxesImage] + A list containing the updated image for the animation. + """ + # Seeks to the given frame in this sequence file gif.seek(frame) - img.set_array(gif.convert("RGBA")) - return [img] + # Set the image array to the current frame of the GIF + image.set_data(gif.convert("RGBA")) + # Return the updated image + return [image] -ani = FuncAnimation( - fig, update, frames=range(gif.n_frames), interval=100, repeat=True, blit=True +# Open the GIF file and create an animation +gif = Image.open(deformation_gif) +# Set the subplots for the animation and turn off the axis +figure, axes = plt.subplots(figsize=(16, 9)) +axes.axis("off") +# Change the color of the image +image = axes.imshow(gif.convert("RGBA")) + +# Create the animation using the figure, update_animation function, and the GIF frames +# Set the interval between frames to 200 milliseconds and repeat the animation +FuncAnimation( + figure, + update_animation, + frames=range(gif.n_frames), + interval=100, + repeat=True, + blit=True, ) + +# Show the animation plt.show() # %% @@ -557,7 +644,7 @@ def update(frame): # ~~~~~~~ # Save project -mechdat_file = cwd / "modal_acoustics.mechdat" +mechdat_file = output_path / "modal_acoustics.mechdat" app.save(str(mechdat_file)) app.new() diff --git a/examples/01_basic/steady_state_thermal_analysis.py b/examples/01_basic/steady_state_thermal_analysis.py index 978d84fd..cd8b7efb 100644 --- a/examples/01_basic/steady_state_thermal_analysis.py +++ b/examples/01_basic/steady_state_thermal_analysis.py @@ -30,16 +30,80 @@ app = App(globals=globals()) print(app) -cwd = Path.cwd() / "out" - - -def display_image(image_name): - plt.figure(figsize=(16, 9)) - image_path = cwd / image_name - plt.imshow(mpimg.imread(str(image_path))) - plt.xticks([]) - plt.yticks([]) - plt.axis("off") +# %% +# Set the image output path and create functions to fit the camera and display images +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Set the path for the output files (images, gifs, mechdat) +output_path = Path.cwd() / "out" + + +def set_camera_and_display_image( + camera: Ansys.ACT.Common.Graphics.MechanicalCameraWrapper, + graphics: Ansys.ACT.Common.Graphics.MechanicalGraphicsWrapper, + graphics_image_export_settings: Ansys.Mechanical.Graphics.GraphicsImageExportSettings, + image_output_path: Path, + image_name: str, +) -> None: + """Set the camera to fit the model and display the image. + + Parameters + ---------- + camera : Ansys.ACT.Common.Graphics.MechanicalCameraWrapper + The camera object to set the view. + graphics : Ansys.ACT.Common.Graphics.MechanicalGraphicsWrapper + The graphics object to export the image. + graphics_image_export_settings : Ansys.Mechanical.Graphics.GraphicsImageExportSettings + The settings for exporting the image. + image_output_path : Path + The path to save the exported image. + image_name : str + The name of the exported image file. + """ + # Set the camera to fit the mesh + camera.SetFit() + # Export the mesh image with the specified settings + image_path = image_output_path / image_name + graphics.ExportImage( + str(image_path), image_export_format, graphics_image_export_settings + ) + # Display the exported mesh image + display_image(image_path) + + +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 + 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() @@ -272,10 +336,9 @@ def display_image(image_name): analysis_settings.CalculateVolumeEnergy = True stat_therm.Activate() -camera.SetFit() -steady_state_image = cwd / "BC_steady_state.png" -graphics.ExportImage(str(steady_state_image), image_export_format, settings_720p) -display_image(steady_state_image.name) +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "bc_steady_state.png" +) # %% # Add results @@ -286,7 +349,6 @@ def display_image(image_name): temp_rst = stat_therm_soln.AddTemperature() temp_rst.By = SetDriverStyle.MaximumOverTime - temp_rst2 = stat_therm_soln.AddTemperature() temp_rst2.Location = body1 @@ -373,37 +435,33 @@ def display_image(image_name): # Total body temperature app.Tree.Activate([temp_rst]) -camera.SetFit() -temp_image = cwd / "temp.png" -graphics.ExportImage(str(temp_image), image_export_format, settings_720p) -display_image(temp_image.name) +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "total_body_temp.png" +) # %% # Temperature on part of the body app.Tree.Activate([temp_rst2]) -camera.SetFit() -temp2_image = cwd / "temp2.png" -graphics.ExportImage(str(temp2_image), image_export_format, settings_720p) -display_image(temp2_image.name) +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "part_temp_body.png" +) # %% # Temperature distribution along the specific path app.Tree.Activate([temp_rst3]) -camera.SetFit() -temp3_image = cwd / "temp3.png" -graphics.ExportImage(str(temp3_image), image_export_format, settings_720p) -display_image(temp3_image.name) +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "path_temp_distribution.png" +) # %% # Temperature of bottom surface app.Tree.Activate([temp_rst4]) -camera.SetFit() -temp4_image = cwd / "temp4.png" -graphics.ExportImage(str(temp4_image), image_export_format, settings_720p) -display_image(temp4_image.name) +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "bottom_surface_temp.png" +) # %% # Export directional heat flux animation @@ -418,25 +476,53 @@ def display_image(image_name): settings_720p.Width = 1280 settings_720p.Height = 720 -directional_heat_flux_gif = cwd / "directional_heat_flux.gif" +directional_heat_flux_gif = output_path / "directional_heat_flux.gif" directional_heat_flux.ExportAnimation( str(directional_heat_flux_gif), animation_export_format, settings_720p ) -gif = Image.open(directional_heat_flux_gif) -fig, ax = plt.subplots(figsize=(16, 9)) -ax.axis("off") -img = ax.imshow(gif.convert("RGBA")) -def update(frame): +def update_animation(frame: int) -> list[mpimg.AxesImage]: + """Update the animation frame for the GIF. + + Parameters + ---------- + frame : int + The frame number to update the animation. + + Returns + ------- + list[mpimg.AxesImage] + A list containing the updated image for the animation. + """ + # Seeks to the given frame in this sequence file gif.seek(frame) - img.set_array(gif.convert("RGBA")) - return [img] + # Set the image array to the current frame of the GIF + image.set_data(gif.convert("RGBA")) + # Return the updated image + return [image] -ani = FuncAnimation( - fig, update, frames=range(gif.n_frames), interval=100, repeat=True, blit=True +# Open the GIF file and create an animation +gif = Image.open(directional_heat_flux_gif) +# Set the subplots for the animation and turn off the axis +figure, axes = plt.subplots(figsize=(16, 9)) +axes.axis("off") +# Change the color of the image +image = axes.imshow(gif.convert("RGBA")) + +# Create the animation using the figure, update_animation function, and the GIF frames +# Set the interval between frames to 200 milliseconds and repeat the animation +FuncAnimation( + figure, + update_animation, + frames=range(gif.n_frames), + interval=100, + repeat=True, + blit=True, ) + +# Show the animation plt.show() # %% @@ -467,7 +553,7 @@ def write_file_contents_to_console(path): # ~~~~~~~ # Save project -mechdat_path = cwd / "steady_state_thermal.mechdat" +mechdat_path = output_path / "steady_state_thermal.mechdat" app.save(str(mechdat_path)) app.new() diff --git a/examples/01_basic/topology_optimization_cantilever_beam.py b/examples/01_basic/topology_optimization_cantilever_beam.py index 80675d84..f054d20d 100644 --- a/examples/01_basic/topology_optimization_cantilever_beam.py +++ b/examples/01_basic/topology_optimization_cantilever_beam.py @@ -14,10 +14,12 @@ from pathlib import Path +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 @@ -26,18 +28,83 @@ print(app) -def display_image(image_name): - plt.figure(figsize=(16, 9)) - image_path = cwd / image_name - plt.imshow(mpimg.imread(str(image_path))) - plt.xticks([]) - plt.yticks([]) - plt.axis("off") +# %% +# Set the image output path and create functions to fit the camera and display images +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Set the path for the output files (images, gifs, mechdat) +output_path = Path.cwd() / "out" + + +def set_camera_and_display_image( + camera: Ansys.ACT.Common.Graphics.MechanicalCameraWrapper, + graphics: Ansys.ACT.Common.Graphics.MechanicalGraphicsWrapper, + graphics_image_export_settings: Ansys.Mechanical.Graphics.GraphicsImageExportSettings, + image_output_path: Path, + image_name: str, +) -> None: + """Set the camera to fit the model and display the image. + + Parameters + ---------- + camera : Ansys.ACT.Common.Graphics.MechanicalCameraWrapper + The camera object to set the view. + graphics : Ansys.ACT.Common.Graphics.MechanicalGraphicsWrapper + The graphics object to export the image. + graphics_image_export_settings : Ansys.Mechanical.Graphics.GraphicsImageExportSettings + The settings for exporting the image. + image_output_path : Path + The path to save the exported image. + image_name : str + The name of the exported image file. + """ + # Set the camera to fit the mesh + camera.SetFit() + # Export the mesh image with the specified settings + image_path = image_output_path / image_name + graphics.ExportImage( + str(image_path), image_export_format, graphics_image_export_settings + ) + # Display the exported mesh image + display_image(image_path) + + +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 + 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() -cwd = Path.cwd() / "out" - # %% # Configure graphics for image export @@ -79,19 +146,17 @@ def display_image(image_name): # Total deformation struct_sln.Children[1].Activate() -camera.SetFit() -total_deformation_image = cwd / "total_deformation.png" -graphics.ExportImage(str(total_deformation_image), image_export_format, settings_720p) -display_image(total_deformation_image.name) +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "total_deformation.png" +) # %% # Equivalent stress struct_sln.Children[2].Activate() -camera.SetFit() -equivalent_stress_image = cwd / "equivalent_stress.png" -graphics.ExportImage(str(equivalent_stress_image), image_export_format, settings_720p) -display_image(equivalent_stress_image.name) +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "equivalent_stress.png" +) # %% # Topology optimization @@ -136,10 +201,9 @@ def display_image(image_name): topology_optimization.Activate() -camera.SetFit() -boundary_conditions_image = cwd / "boundary_conditions.png" -graphics.ExportImage(str(boundary_conditions_image), image_export_format, settings_720p) -display_image(boundary_conditions_image.name) +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "boundary_conditions.png" +) # %% # Solve @@ -175,10 +239,9 @@ def display_image(image_name): topology_density.AddSmoothing() topology_optimization.Solution.EvaluateAllResults() topology_density.Children[0].Activate() -camera.SetFit() -smoothed_image = cwd / "topo_opitimized_smooth.png" -graphics.ExportImage(str(smoothed_image), image_export_format, settings_720p) -display_image(smoothed_image.name) +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "topo_opitimized_smooth.png" +) # %% # Export animation @@ -190,13 +253,54 @@ def display_image(image_name): settings_720p.Width = 1280 settings_720p.Height = 720 -topology_optimized_gif = cwd / "topology_opitimized.gif" +topology_optimized_gif = output_path / "topology_opitimized.gif" topology_density.ExportAnimation( str(topology_optimized_gif), animation_export_format, settings_720p ) -# %% -# .. image:: /_static/basic/Topo_opitimized.gif + +def update_animation(frame: int) -> list[mpimg.AxesImage]: + """Update the animation frame for the GIF. + + Parameters + ---------- + frame : int + The frame number to update the animation. + + Returns + ------- + list[mpimg.AxesImage] + A list containing the updated image for the animation. + """ + # Seeks to the given frame in this sequence file + gif.seek(frame) + # Set the image array to the current frame of the GIF + image.set_data(gif.convert("RGBA")) + # Return the updated image + return [image] + + +# Open the GIF file and create an animation +gif = Image.open(topology_optimized_gif) +# Set the subplots for the animation and turn off the axis +figure, axes = plt.subplots(figsize=(16, 9)) +axes.axis("off") +# Change the color of the image +image = axes.imshow(gif.convert("RGBA")) + +# Create the animation using the figure, update_animation function, and the GIF frames +# Set the interval between frames to 200 milliseconds and repeat the animation +FuncAnimation( + figure, + update_animation, + frames=range(gif.n_frames), + interval=100, + repeat=True, + blit=True, +) + +# Show the animation +plt.show() # %% # Review the results @@ -225,7 +329,7 @@ def display_image(image_name): # ~~~~~~~ # Save project -mechdat_file = cwd / "cantilever_beam_topology_optimization.mechdat" +mechdat_file = output_path / "cantilever_beam_topology_optimization.mechdat" app.save(str(mechdat_file)) app.new() diff --git a/examples/01_basic/valve.py b/examples/01_basic/valve.py index c5764ec0..5231712a 100644 --- a/examples/01_basic/valve.py +++ b/examples/01_basic/valve.py @@ -25,16 +25,80 @@ app = App(globals=globals()) print(app) -cwd = Path.cwd() / "out" - - -def display_image(image_name): - plt.figure(figsize=(16, 9)) - image_path = cwd / image_name - plt.imshow(mpimg.imread(str(image_path))) - plt.xticks([]) - plt.yticks([]) - plt.axis("off") +# %% +# Set the image output path and create functions to fit the camera and display images +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Set the path for the output files (images, gifs, mechdat) +output_path = Path.cwd() / "out" + + +def set_camera_and_display_image( + camera: Ansys.ACT.Common.Graphics.MechanicalCameraWrapper, + graphics: Ansys.ACT.Common.Graphics.MechanicalGraphicsWrapper, + graphics_image_export_settings: Ansys.Mechanical.Graphics.GraphicsImageExportSettings, + image_output_path: Path, + image_name: str, +) -> None: + """Set the camera to fit the model and display the image. + + Parameters + ---------- + camera : Ansys.ACT.Common.Graphics.MechanicalCameraWrapper + The camera object to set the view. + graphics : Ansys.ACT.Common.Graphics.MechanicalGraphicsWrapper + The graphics object to export the image. + graphics_image_export_settings : Ansys.Mechanical.Graphics.GraphicsImageExportSettings + The settings for exporting the image. + image_output_path : Path + The path to save the exported image. + image_name : str + The name of the exported image file. + """ + # Set the camera to fit the mesh + camera.SetFit() + # Export the mesh image with the specified settings + image_path = image_output_path / image_name + graphics.ExportImage( + str(image_path), image_export_format, graphics_image_export_settings + ) + # Display the exported mesh image + display_image(image_path) + + +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 + 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() @@ -102,9 +166,7 @@ def display_image(image_name): mesh.ElementSize = Quantity(25, "mm") mesh.GenerateMesh() app.Tree.Activate([mesh]) -mesh_image = cwd / "mesh.png" -graphics.ExportImage(str(mesh_image), image_export_format, settings_720p) -display_image(mesh_image.name) +set_camera_and_display_image(camera, graphics, settings_720p, output_path, "mesh.png") # %% # Define analysis and boundary conditions @@ -127,11 +189,9 @@ def display_image(image_name): pressure.Magnitude.Output.DiscreteValues = [Quantity("0 [Pa]"), Quantity("15 [MPa]")] analysis.Activate() -camera.SetFit() -boundary_conditions_image = cwd / "boundary_conditions.png" -graphics.ExportImage(str(boundary_conditions_image), image_export_format, settings_720p) -display_image(boundary_conditions_image.name) - +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "boundary_conditions.png" +) # %% # Add results @@ -168,19 +228,17 @@ def display_image(image_name): # Total deformation app.Tree.Activate([deformation]) -total_deformation_valve_image = cwd / "total_deformation_valve.png" -graphics.ExportImage( - str(total_deformation_valve_image), image_export_format, settings_720p +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "total_deformation_valve.png" ) -display_image(total_deformation_valve_image.name) # %% # Stress app.Tree.Activate([stress]) -stress_valve_image = cwd / "stress_valve.png" -graphics.ExportImage(str(stress_valve_image), image_export_format, settings_720p) -display_image(stress_valve_image.name) +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "stress_valve.png" +) # %% # Export stress animation @@ -192,23 +250,51 @@ def display_image(image_name): settings_720p.Width = 1280 settings_720p.Height = 720 -valve_gif = cwd / "valve.gif" +valve_gif = output_path / "valve.gif" stress.ExportAnimation(str(valve_gif), animation_export_format, settings_720p) -gif = Image.open(valve_gif) -fig, ax = plt.subplots(figsize=(16, 9)) -ax.axis("off") -img = ax.imshow(gif.convert("RGBA")) -def update(frame): +def update_animation(frame: int) -> list[mpimg.AxesImage]: + """Update the animation frame for the GIF. + + Parameters + ---------- + frame : int + The frame number to update the animation. + + Returns + ------- + list[mpimg.AxesImage] + A list containing the updated image for the animation. + """ + # Seeks to the given frame in this sequence file gif.seek(frame) - img.set_array(gif.convert("RGBA")) - return [img] + # Set the image array to the current frame of the GIF + image.set_data(gif.convert("RGBA")) + # Return the updated image + return [image] -ani = FuncAnimation( - fig, update, frames=range(gif.n_frames), interval=100, repeat=True, blit=True +# Open the GIF file and create an animation +gif = Image.open(valve_gif) +# Set the subplots for the animation and turn off the axis +figure, axes = plt.subplots(figsize=(16, 9)) +axes.axis("off") +# Change the color of the image +image = axes.imshow(gif.convert("RGBA")) + +# Create the animation using the figure, update_animation function, and the GIF frames +# Set the interval between frames to 200 milliseconds and repeat the animation +FuncAnimation( + figure, + update_animation, + frames=range(gif.n_frames), + interval=100, + repeat=True, + blit=True, ) + +# Show the animation plt.show() # %% @@ -239,7 +325,7 @@ def write_file_contents_to_console(path): # ~~~~~~~ # Save project -mechdat_file = cwd / "valve.mechdat" +mechdat_file = output_path / "valve.mechdat" app.save(str(mechdat_file)) app.new() diff --git a/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py b/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py index 2abd6c52..b3ef388d 100644 --- a/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py +++ b/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py @@ -60,16 +60,80 @@ app = App(globals=globals()) print(app) -cwd = Path.cwd() / "out" - - -def display_image(image_name): - plt.figure(figsize=(16, 9)) - image_path = cwd / image_name - plt.imshow(mpimg.imread(str(image_path))) - plt.xticks([]) - plt.yticks([]) - plt.axis("off") +# %% +# Set the image output path and create functions to fit the camera and display images +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Set the path for the output files (images, gifs, mechdat) +output_path = Path.cwd() / "out" + + +def set_camera_and_display_image( + camera: Ansys.ACT.Common.Graphics.MechanicalCameraWrapper, + graphics: Ansys.ACT.Common.Graphics.MechanicalGraphicsWrapper, + graphics_image_export_settings: Ansys.Mechanical.Graphics.GraphicsImageExportSettings, + image_output_path: Path, + image_name: str, +) -> None: + """Set the camera to fit the model and display the image. + + Parameters + ---------- + camera : Ansys.ACT.Common.Graphics.MechanicalCameraWrapper + The camera object to set the view. + graphics : Ansys.ACT.Common.Graphics.MechanicalGraphicsWrapper + The graphics object to export the image. + graphics_image_export_settings : Ansys.Mechanical.Graphics.GraphicsImageExportSettings + The settings for exporting the image. + image_output_path : Path + The path to save the exported image. + image_name : str + The name of the exported image file. + """ + # Set the camera to fit the mesh + camera.SetFit() + # Export the mesh image with the specified settings + image_path = image_output_path / image_name + graphics.ExportImage( + str(image_path), image_export_format, graphics_image_export_settings + ) + # Display the exported mesh image + display_image(image_path) + + +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 + 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() @@ -293,11 +357,9 @@ def display_image(image_name): automatic_method_Blade3.SweepNumberDivisions = 5 mesh.GenerateMesh() - -camera.SetFit() -blade_mesh_image = cwd / "blade_mesh.png" -graphics.ExportImage(str(blade_mesh_image), image_export_format, settings_720p) -display_image(blade_mesh_image.name) +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "blade_mesh.png" +) # %% # Define analysis settings @@ -403,11 +465,9 @@ def display_image(image_name): imported_pressure.ImportLoad() app.Tree.Activate([imported_pressure]) -camera.SetFit() -imported_pressure_image = cwd / "imported_pressure.png" -graphics.ExportImage(str(imported_pressure_image), image_export_format, settings_720p) -display_image(imported_pressure_image.name) - +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "imported_pressure.png" +) ################################################################################### # Import Temperature @@ -468,10 +528,9 @@ def display_image(image_name): imported_body_temperature.ImportLoad() app.Tree.Activate([imported_body_temperature]) -camera.SetFit() -imported_temp_image = cwd / "imported_temperature.png" -graphics.ExportImage(str(imported_temp_image), image_export_format, settings_720p) -display_image(imported_temp_image.name) +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "imported_temperature.png" +) # %% # Postprocessing @@ -513,24 +572,24 @@ def display_image(image_name): graphics.ViewOptions.ResultPreference.ExtraModelDisplay = ( Ansys.Mechanical.DataModel.MechanicalEnums.Graphics.ExtraModelDisplay.NoWireframe ) -deformation_image = cwd / "deformation.png" -graphics.ExportImage(str(deformation_image), image_export_format, settings_720p) -display_image(deformation_image.name) +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "total_deformation.png" +) # %% # Equivalent stress app.Tree.Activate([thermal_strain1]) -thermal_strain_image = cwd / "termal_strain.png" -graphics.ExportImage(str(thermal_strain_image), image_export_format, settings_720p) -display_image(thermal_strain_image.name) +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "thermal_strain.png" +) # %% # Cleanup # ~~~~~~~ # Save project -mechdat_file = cwd / "blade_inverse.mechdat" +mechdat_file = output_path / "blade_inverse.mechdat" app.save(str(mechdat_file)) app.new() diff --git a/examples/02_technology_showcase/conact_wear_simulation.py b/examples/02_technology_showcase/conact_wear_simulation.py index 7da53754..ddf59547 100644 --- a/examples/02_technology_showcase/conact_wear_simulation.py +++ b/examples/02_technology_showcase/conact_wear_simulation.py @@ -40,16 +40,80 @@ app = App(globals=globals()) print(app) -cwd = Path.cwd() / "out" - - -def display_image(image_name): - plt.figure(figsize=(16, 9)) - image_path = cwd / image_name - plt.imshow(mpimg.imread(str(image_path))) - plt.xticks([]) - plt.yticks([]) - plt.axis("off") +# %% +# Set the image output path and create functions to fit the camera and display images +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Set the path for the output files (images, gifs, mechdat) +output_path = Path.cwd() / "out" + + +def set_camera_and_display_image( + camera: Ansys.ACT.Common.Graphics.MechanicalCameraWrapper, + graphics: Ansys.ACT.Common.Graphics.MechanicalGraphicsWrapper, + graphics_image_export_settings: Ansys.Mechanical.Graphics.GraphicsImageExportSettings, + image_output_path: Path, + image_name: str, +) -> None: + """Set the camera to fit the model and display the image. + + Parameters + ---------- + camera : Ansys.ACT.Common.Graphics.MechanicalCameraWrapper + The camera object to set the view. + graphics : Ansys.ACT.Common.Graphics.MechanicalGraphicsWrapper + The graphics object to export the image. + graphics_image_export_settings : Ansys.Mechanical.Graphics.GraphicsImageExportSettings + The settings for exporting the image. + image_output_path : Path + The path to save the exported image. + image_name : str + The name of the exported image file. + """ + # Set the camera to fit the mesh + camera.SetFit() + # Export the mesh image with the specified settings + image_path = image_output_path / image_name + graphics.ExportImage( + str(image_path), image_export_format, graphics_image_export_settings + ) + # Display the exported mesh image + display_image(image_path) + + +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 + 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() @@ -235,11 +299,7 @@ def display_image(image_name): edge_sizing6.NumberOfDivisions = 60 mesh.GenerateMesh() - -camera.SetFit() -mesh_image = cwd / "mesh.png" -graphics.ExportImage(str(mesh_image), image_export_format, settings_720p) -display_image(mesh_image.name) +set_camera_and_display_image(camera, graphics, settings_720p, output_path, "mesh.png") # %% # Analysis settings @@ -290,9 +350,7 @@ def display_image(image_name): cmd2.StepSelectionMode = SequenceSelectionType.All static_structural_analysis.Activate() -camera.SetFit() -graphics.ExportImage(str(mesh_image), image_export_format, settings_720p) -display_image(mesh_image.name) +set_camera_and_display_image(camera, graphics, settings_720p, output_path, "mesh.png") # %% # Insert results @@ -339,9 +397,9 @@ def display_image(image_name): # Normal stress app.Tree.Activate([normal_stress1]) -normal_stress_image = cwd / "normal_stress" -graphics.ExportImage(str(normal_stress_image), image_export_format, settings_720p) -display_image(normal_stress_image.name) +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "normal_stress.png" +) # %% # Total deformation animation @@ -353,27 +411,54 @@ def display_image(image_name): settings_720p.Width = 1280 settings_720p.Height = 720 -total_deformation_gif = cwd / "total_deformation.gif" +total_deformation_gif = output_path / "total_deformation.gif" total_deformation.ExportAnimation( str(total_deformation_gif), animation_export_format, settings_720p ) -gif = Image.open(total_deformation_gif) -fig, ax = plt.subplots(figsize=(16, 9)) -ax.axis("off") -img = ax.imshow(gif.convert("RGBA")) -def update(frame): +def update_animation(frame: int) -> list[mpimg.AxesImage]: + """Update the animation frame for the GIF. + + Parameters + ---------- + frame : int + The frame number to update the animation. + + Returns + ------- + list[mpimg.AxesImage] + A list containing the updated image for the animation. + """ + # Seeks to the given frame in this sequence file gif.seek(frame) - img.set_array(gif.convert("RGBA")) - return [img] + # Set the image array to the current frame of the GIF + image.set_data(gif.convert("RGBA")) + # Return the updated image + return [image] -ani = FuncAnimation( - fig, update, frames=range(gif.n_frames), interval=200, repeat=True, blit=True +# Open the GIF file and create an animation +gif = Image.open(total_deformation_gif) +# Set the subplots for the animation and turn off the axis +figure, axes = plt.subplots(figsize=(16, 9)) +axes.axis("off") +# Change the color of the image +image = axes.imshow(gif.convert("RGBA")) + +# Create the animation using the figure, update_animation function, and the GIF frames +# Set the interval between frames to 200 milliseconds and repeat the animation +FuncAnimation( + figure, + update_animation, + frames=range(gif.n_frames), + interval=200, + repeat=True, + blit=True, ) -plt.show() +# Show the animation +plt.show() # %% # Project tree @@ -386,7 +471,7 @@ def update(frame): # ~~~~~~~ # Save project -mechdat_file = cwd / "contact_wear.mechdat" +mechdat_file = output_path / "contact_wear.mechdat" app.save(str(mechdat_file)) app.new() diff --git a/examples/02_technology_showcase/non_linear_analsis_rubber_boot_seal.py b/examples/02_technology_showcase/non_linear_analsis_rubber_boot_seal.py index 97fa2ced..f4b8a79c 100644 --- a/examples/02_technology_showcase/non_linear_analsis_rubber_boot_seal.py +++ b/examples/02_technology_showcase/non_linear_analsis_rubber_boot_seal.py @@ -33,16 +33,80 @@ app = App(globals=globals()) print(app) -cwd = Path.cwd() / "out" - - -def display_image(image_name): - plt.figure(figsize=(16, 9)) - image_path = cwd / image_name - plt.imshow(mpimg.imread(str(image_path))) - plt.xticks([]) - plt.yticks([]) - plt.axis("off") +# %% +# Set the image output path and create functions to fit the camera and display images +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Set the path for the output files (images, gifs, mechdat) +output_path = Path.cwd() / "out" + + +def set_camera_and_display_image( + camera: Ansys.ACT.Common.Graphics.MechanicalCameraWrapper, + graphics: Ansys.ACT.Common.Graphics.MechanicalGraphicsWrapper, + graphics_image_export_settings: Ansys.Mechanical.Graphics.GraphicsImageExportSettings, + image_output_path: Path, + image_name: str, +) -> None: + """Set the camera to fit the model and display the image. + + Parameters + ---------- + camera : Ansys.ACT.Common.Graphics.MechanicalCameraWrapper + The camera object to set the view. + graphics : Ansys.ACT.Common.Graphics.MechanicalGraphicsWrapper + The graphics object to export the image. + graphics_image_export_settings : Ansys.Mechanical.Graphics.GraphicsImageExportSettings + The settings for exporting the image. + image_output_path : Path + The path to save the exported image. + image_name : str + The name of the exported image file. + """ + # Set the camera to fit the mesh + camera.SetFit() + # Export the mesh image with the specified settings + image_path = image_output_path / image_name + graphics.ExportImage( + str(image_path), image_export_format, graphics_image_export_settings + ) + # Display the exported mesh image + display_image(image_path) + + +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 + 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() @@ -270,10 +334,7 @@ def display_image(image_name): mesh.Resolution = 2 mesh.GenerateMesh() - -mesh_image = cwd / "mesh.png" -graphics.ExportImage(str(mesh_image), image_export_format, settings_720p) -display_image(mesh_image.name) +set_camera_and_display_image(camera, graphics, settings_720p, output_path, "mesh.png") # %% # Define remote points @@ -445,17 +506,17 @@ def display_image(image_name): app.Tree.Activate([total_deformation]) -total_deformation_image = cwd / "total_deformation.png" -graphics.ExportImage(str(total_deformation_image), image_export_format, settings_720p) -display_image(total_deformation_image.name) +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "total_deformation.png" +) # %% # Equivalent stress app.Tree.Activate([equivalent_stress]) -equivalent_stress_image = cwd / "equivalent_stress.png" -graphics.ExportImage(str(total_deformation_image), image_export_format, settings_720p) -display_image(total_deformation_image.name) +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, "equivalent_stress.png" +) # %% # Total deformation animation @@ -467,34 +528,61 @@ def display_image(image_name): settings_720p.Width = 1280 settings_720p.Height = 720 -total_deformation_gif = cwd / "total_deformation.gif" +total_deformation_gif = output_path / "total_deformation.gif" total_deformation.ExportAnimation( str(total_deformation_gif), animation_export_format, settings_720p ) -gif = Image.open(total_deformation_gif) -fig, ax = plt.subplots(figsize=(16, 9)) -ax.axis("off") -img = ax.imshow(gif.convert("RGBA")) -def update(frame): +def update_animation(frame: int) -> list[mpimg.AxesImage]: + """Update the animation frame for the GIF. + + Parameters + ---------- + frame : int + The frame number to update the animation. + + Returns + ------- + list[mpimg.AxesImage] + A list containing the updated image for the animation. + """ + # Seeks to the given frame in this sequence file gif.seek(frame) - img.set_array(gif.convert("RGBA")) - return [img] + # Set the image array to the current frame of the GIF + image.set_data(gif.convert("RGBA")) + # Return the updated image + return [image] -ani = FuncAnimation( - fig, update, frames=range(gif.n_frames), interval=200, repeat=True, blit=True +# Open the GIF file and create an animation +gif = Image.open(total_deformation_gif) +# Set the subplots for the animation and turn off the axis +figure, axes = plt.subplots(figsize=(16, 9)) +axes.axis("off") +# Change the color of the image +image = axes.imshow(gif.convert("RGBA")) + +# Create the animation using the figure, update_animation function, and the GIF frames +# Set the interval between frames to 200 milliseconds and repeat the animation +FuncAnimation( + figure, + update_animation, + frames=range(gif.n_frames), + interval=200, + repeat=True, + blit=True, ) -plt.show() +# Show the animation +plt.show() # %% # Cleanup # ~~~~~~~ # Save project -mechdat_file = cwd / "non_linear_rubber_boot_seal.mechdat" +mechdat_file = output_path / "non_linear_rubber_boot_seal.mechdat" app.save(str(mechdat_file)) app.new() From c4226b2c153dd87d830a254d6deab8a096f78d2d Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Thu, 24 Apr 2025 15:17:06 -0400 Subject: [PATCH 10/24] add type_checking and remove typehints --- examples/00_tips/tips_02.py | 4 +- examples/01_basic/bolt_pretension.py | 2 +- .../fracture_analysis_contact_debonding.py | 16 ++-- examples/01_basic/harmonic_acoustics.py | 80 +++++++++++-------- examples/01_basic/modal_acoustics_analysis.py | 13 ++- .../01_basic/steady_state_thermal_analysis.py | 13 ++- .../topology_optimization_cantilever_beam.py | 13 ++- examples/01_basic/valve.py | 13 ++- .../Rotor_Blade_Inverse_solve.py | 11 ++- .../conact_wear_simulation.py | 13 ++- .../non_linear_analsis_rubber_boot_seal.py | 13 ++- 11 files changed, 123 insertions(+), 68 deletions(-) diff --git a/examples/00_tips/tips_02.py b/examples/00_tips/tips_02.py index 98604e92..8c8c8e5d 100644 --- a/examples/00_tips/tips_02.py +++ b/examples/00_tips/tips_02.py @@ -45,7 +45,7 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Set the orientation of the camera -ExtAPI.Graphics.Camera.SetSpecificViewOrientation(ViewOrientationType.Iso) +ExtAPI.Graphics.Camera.SetSpecificViewOrientation(Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Iso) # Set the image export format image_export_format = GraphicsImageExportFormat.PNG @@ -69,7 +69,7 @@ from matplotlib import pyplot as plt # Directory to save the image -output_path = Path.output_path() / "out" +output_path = Path.cwd() / "out" def display_image(image_name) -> None: diff --git a/examples/01_basic/bolt_pretension.py b/examples/01_basic/bolt_pretension.py index cae5ac98..99665bc8 100644 --- a/examples/01_basic/bolt_pretension.py +++ b/examples/01_basic/bolt_pretension.py @@ -49,7 +49,7 @@ # Set camera orientation graphics = app.Graphics camera = graphics.Camera -camera.SetSpecificViewOrientation(ViewOrientationType.Iso) +camera.SetSpecificViewOrientation(Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Iso) camera.SetFit() camera.Rotate(180, CameraAxisType.ScreenY) diff --git a/examples/01_basic/fracture_analysis_contact_debonding.py b/examples/01_basic/fracture_analysis_contact_debonding.py index 76916c18..1ee80d59 100644 --- a/examples/01_basic/fracture_analysis_contact_debonding.py +++ b/examples/01_basic/fracture_analysis_contact_debonding.py @@ -22,6 +22,11 @@ from matplotlib import pyplot as plt from matplotlib.animation import FuncAnimation +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + import Ansys + # %% # Create an instance of the Mechanical embedded application with global variables # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -36,7 +41,7 @@ # Set camera orientation graphics = app.Graphics camera = graphics.Camera -camera.SetSpecificViewOrientation(ViewOrientationType.Front) +camera.SetSpecificViewOrientation(Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Front) # Set camera settings for 720p resolution image_export_format = GraphicsImageExportFormat.PNG @@ -58,6 +63,7 @@ def set_camera_and_display_image( camera: Ansys.ACT.Common.Graphics.MechanicalCameraWrapper, graphics: Ansys.ACT.Common.Graphics.MechanicalGraphicsWrapper, + graphics_image_export_settings: Ansys.Mechanical.Graphics.GraphicsImageExportSettings, image_output_path: Path, image_name: str, ) -> None: @@ -329,7 +335,7 @@ def add_sizing( mesh.GenerateMesh() # Display the mesh image -set_camera_and_display_image(camera, graphics, output_path, "mesh.png") +set_camera_and_display_image(camera, graphics, graphics_image_export_settings, output_path, "mesh.png") # %% # Add contact debonding object @@ -436,7 +442,7 @@ def add_displacement( static_structural_analysis.Activate() # Set the camera to fit the model and display the image of the boundary conditions -set_camera_and_display_image(camera, graphics, output_path, "boundary_conditions.png") +set_camera_and_display_image(camera, graphics, graphics_image_export_settings, output_path, "boundary_conditions.png") # %% # Add directional deformation and force reaction results to the solution @@ -489,13 +495,13 @@ def add_displacement( directional_deformation.Activate() # Set the camera to fit the model and display the image of the directional deformation set_camera_and_display_image( - camera, graphics, output_path, "directional_deformation.png" + camera, graphics, graphics_image_export_settings, output_path, "directional_deformation.png" ) # Activate the force reaction force_reaction.Activate() # Set the camera to fit the model and display the image of the force reaction -set_camera_and_display_image(camera, graphics, output_path, "force_reaction.png") +set_camera_and_display_image(camera, graphics, graphics_image_export_settings, output_path, "force_reaction.png") # %% # Export animation diff --git a/examples/01_basic/harmonic_acoustics.py b/examples/01_basic/harmonic_acoustics.py index b4c33cda..5d962980 100644 --- a/examples/01_basic/harmonic_acoustics.py +++ b/examples/01_basic/harmonic_acoustics.py @@ -44,6 +44,11 @@ from matplotlib import pyplot as plt from matplotlib.animation import FuncAnimation +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + import Ansys + # %% # Embed mechanical and set global variables @@ -60,9 +65,9 @@ def set_camera_and_display_image( - camera: Ansys.ACT.Common.Graphics.MechanicalCameraWrapper, - graphics: Ansys.ACT.Common.Graphics.MechanicalGraphicsWrapper, - graphics_image_export_settings: Ansys.Mechanical.Graphics.GraphicsImageExportSettings, + camera, + graphics, + graphics_image_export_settings, image_output_path: Path, image_name: str, ) -> None: @@ -134,7 +139,7 @@ def display_image( graphics = app.Graphics camera = graphics.Camera -camera.SetSpecificViewOrientation(ViewOrientationType.Iso) +camera.SetSpecificViewOrientation(Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Iso) image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() settings_720p.Resolution = GraphicsResolutionType.EnhancedResolution @@ -148,15 +153,19 @@ def display_image( # Download geometry and materials files # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Download the geometry file from the ansys/example-data repository geometry_path = download_file("C_GEOMETRY.agdb", "pymechanical", "embedding") +# Download the material file from the ansys/example-data repository mat_path = download_file("Air-material.xml", "pymechanical", "embedding") # %% # Import the geometry # ~~~~~~~~~~~~~~~~~~~ +# Define the model model = app.Model +# Add the geometry import group and set its preferences geometry_import = model.GeometryImportGroup.AddGeometryImport() geometry_import_format = ( Ansys.Mechanical.DataModel.Enums.GeometryImportPreference.Format.Automatic @@ -167,33 +176,20 @@ def display_image( geometry_path, geometry_import_format, geometry_import_preferences ) +# Define the geometry in the model geometry = model.Geometry -solid1 = geometry.Children[0] -solid2 = geometry.Children[1] -solid3 = geometry.Children[2] -solid4 = geometry.Children[3] -solid5 = geometry.Children[4] -solid6 = geometry.Children[5] -solid7 = geometry.Children[6] -solid8 = geometry.Children[7] -solid9 = geometry.Children[8] -solid10 = geometry.Children[9] -solid11 = geometry.Children[10] - -solid1.Suppressed = True -solid2.Suppressed = True -solid3.Suppressed = True -solid4.Suppressed = True -solid5.Suppressed = True -solid7.Suppressed = True -solid10.Suppressed = True -solid11.Suppressed = True +# Suppress the bodies at the specified geometry.Children indices +suppressed_indices = [0, 1, 2, 3, 4, 6, 9, 10] +for child in range(geometry.Children.Count): + if child in suppressed_indices: + geometry.Children[child].Suppressed = True +# Visualize the model in 3D app.plot() # %% -# Store all Variables necessary for analysis +# Store all variables necessary for analysis # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ mesh = model.Mesh @@ -203,23 +199,28 @@ def display_image( mat = model.Materials # %% -# Setup the Analysis -# ~~~~~~~~~~~~~~~~~~ -# Add harmonic acoustics and unit system +# Set up the analysis +# ~~~~~~~~~~~~~~~~~~~ +# Add the harmonic acoustics analysis and unit system model.AddHarmonicAcousticAnalysis() app.ExtAPI.Application.ActiveUnitSystem = MechanicalUnitSystem.StandardMKS # %% # Import and assign materials +# Import the material file mat.Import(mat_path) -solid6.Material = "Air" -solid8.Material = "Air" -solid9.Material = "Air" + +# Assign the material to geometry.Children bodies that are not suppressed +for child in range(geometry.Children.Count): + if child not in suppressed_indices: + geometry.Children[child].Material = "Air" # %% # Create coordinate system + +# Add a coordinate system and set its properties lcs1 = coordinate_systems.AddCoordinateSystem() lcs1.OriginX = Quantity("0 [mm]") lcs1.OriginY = Quantity("0 [mm]") @@ -227,12 +228,11 @@ def display_image( lcs1.PrimaryAxisDefineBy = CoordinateSystemAlignmentType.GlobalZ # %% -# Generate mesh +# Generate the mesh mesh.ElementSize = Quantity("200 [mm]") mesh.GenerateMesh() - # %% # Create named selections # ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -240,6 +240,7 @@ def display_image( sf_velo = model.AddNamedSelection() sf_velo.ScopingMethod = GeometryDefineByType.Worksheet sf_velo.Name = "sf_velo" + generation_criteria_1 = sf_velo.GenerationCriteria criteria_1 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() criteria_1.Active = True @@ -249,6 +250,7 @@ def display_image( criteria_1.Operator = SelectionOperatorType.Equal criteria_1.Value = Quantity("3e6 [mm^2]") generation_criteria_1.Add(criteria_1) + criteria_2 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() criteria_2.Active = True criteria_2.Action = SelectionActionType.Filter @@ -257,12 +259,15 @@ def display_image( criteria_2.Operator = SelectionOperatorType.Equal criteria_2.Value = Quantity("15000 [mm]") generation_criteria_1.Add(criteria_2) + sf_velo.Activate() sf_velo.Generate() + abs_face = model.AddNamedSelection() abs_face.ScopingMethod = GeometryDefineByType.Worksheet abs_face.Name = "abs_face" + generation_criteria_2 = abs_face.GenerationCriteria criteria_1 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() criteria_1.Active = True @@ -272,6 +277,7 @@ def display_image( criteria_1.Operator = SelectionOperatorType.Equal criteria_1.Value = Quantity("1.5e6 [mm^2]") generation_criteria_2.Add(criteria_1) + criteria_2 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() criteria_2.Active = True criteria_2.Action = SelectionActionType.Filter @@ -280,12 +286,15 @@ def display_image( criteria_2.Operator = SelectionOperatorType.Equal criteria_2.Value = Quantity("500 [mm]") generation_criteria_2.Add(criteria_2) + abs_face.Activate() abs_face.Generate() + pres_face = model.AddNamedSelection() pres_face.ScopingMethod = GeometryDefineByType.Worksheet pres_face.Name = "pres_face" + generation_criteria_3 = pres_face.GenerationCriteria criteria_1 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() criteria_1.Active = True @@ -295,6 +304,7 @@ def display_image( criteria_1.Operator = SelectionOperatorType.Equal criteria_1.Value = Quantity("1.5e6 [mm^2]") generation_criteria_3.Add(criteria_1) + criteria_2 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() criteria_2.Active = True criteria_2.Action = SelectionActionType.Filter @@ -303,12 +313,15 @@ def display_image( criteria_2.Operator = SelectionOperatorType.Equal criteria_2.Value = Quantity("4500 [mm]") generation_criteria_3.Add(criteria_2) + pres_face.Activate() pres_face.Generate() + acoustic_region = model.AddNamedSelection() acoustic_region.ScopingMethod = GeometryDefineByType.Worksheet acoustic_region.Name = "acoustic_region" + generation_criteria_4 = acoustic_region.GenerationCriteria criteria_1 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() criteria_1.Active = True @@ -318,6 +331,7 @@ def display_image( criteria_1.Operator = SelectionOperatorType.Equal criteria_1.Value = 8 generation_criteria_4.Add(criteria_1) + acoustic_region.Activate() acoustic_region.Generate() diff --git a/examples/01_basic/modal_acoustics_analysis.py b/examples/01_basic/modal_acoustics_analysis.py index 57d0b46f..99ab31c1 100644 --- a/examples/01_basic/modal_acoustics_analysis.py +++ b/examples/01_basic/modal_acoustics_analysis.py @@ -28,6 +28,11 @@ from matplotlib import pyplot as plt from matplotlib.animation import FuncAnimation +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + import Ansys + # %% # Embed mechanical and set global variables @@ -43,9 +48,9 @@ def set_camera_and_display_image( - camera: Ansys.ACT.Common.Graphics.MechanicalCameraWrapper, - graphics: Ansys.ACT.Common.Graphics.MechanicalGraphicsWrapper, - graphics_image_export_settings: Ansys.Mechanical.Graphics.GraphicsImageExportSettings, + camera, + graphics, + graphics_image_export_settings, image_output_path: Path, image_name: str, ) -> None: @@ -118,7 +123,7 @@ def display_image( graphics = app.Graphics camera = graphics.Camera -camera.SetSpecificViewOrientation(ViewOrientationType.Iso) +camera.SetSpecificViewOrientation(Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Iso) image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() settings_720p.Resolution = GraphicsResolutionType.EnhancedResolution diff --git a/examples/01_basic/steady_state_thermal_analysis.py b/examples/01_basic/steady_state_thermal_analysis.py index cd8b7efb..d4f16440 100644 --- a/examples/01_basic/steady_state_thermal_analysis.py +++ b/examples/01_basic/steady_state_thermal_analysis.py @@ -24,6 +24,11 @@ from matplotlib import pyplot as plt from matplotlib.animation import FuncAnimation +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + import Ansys + # %% # Embed mechanical and set global variables @@ -39,9 +44,9 @@ def set_camera_and_display_image( - camera: Ansys.ACT.Common.Graphics.MechanicalCameraWrapper, - graphics: Ansys.ACT.Common.Graphics.MechanicalGraphicsWrapper, - graphics_image_export_settings: Ansys.Mechanical.Graphics.GraphicsImageExportSettings, + camera, + graphics, + graphics_image_export_settings, image_output_path: Path, image_name: str, ) -> None: @@ -114,7 +119,7 @@ def display_image( graphics = app.Graphics camera = graphics.Camera -camera.SetSpecificViewOrientation(ViewOrientationType.Iso) +camera.SetSpecificViewOrientation(Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Iso) camera.SetFit() image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() diff --git a/examples/01_basic/topology_optimization_cantilever_beam.py b/examples/01_basic/topology_optimization_cantilever_beam.py index f054d20d..d41cae97 100644 --- a/examples/01_basic/topology_optimization_cantilever_beam.py +++ b/examples/01_basic/topology_optimization_cantilever_beam.py @@ -21,6 +21,11 @@ from matplotlib import pyplot as plt from matplotlib.animation import FuncAnimation +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + import Ansys + # %% # Embed Mechanical and set global variables @@ -37,9 +42,9 @@ def set_camera_and_display_image( - camera: Ansys.ACT.Common.Graphics.MechanicalCameraWrapper, - graphics: Ansys.ACT.Common.Graphics.MechanicalGraphicsWrapper, - graphics_image_export_settings: Ansys.Mechanical.Graphics.GraphicsImageExportSettings, + camera, + graphics, + graphics_image_export_settings, image_output_path: Path, image_name: str, ) -> None: @@ -111,7 +116,7 @@ def display_image( graphics = app.Graphics camera = graphics.Camera -camera.SetSpecificViewOrientation(ViewOrientationType.Front) +camera.SetSpecificViewOrientation(Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Front) image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() settings_720p.Resolution = GraphicsResolutionType.EnhancedResolution diff --git a/examples/01_basic/valve.py b/examples/01_basic/valve.py index 5231712a..48ada00b 100644 --- a/examples/01_basic/valve.py +++ b/examples/01_basic/valve.py @@ -19,6 +19,11 @@ from matplotlib import pyplot as plt from matplotlib.animation import FuncAnimation +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + import Ansys + # %% # Embed mechanical and set global variables @@ -34,9 +39,9 @@ def set_camera_and_display_image( - camera: Ansys.ACT.Common.Graphics.MechanicalCameraWrapper, - graphics: Ansys.ACT.Common.Graphics.MechanicalGraphicsWrapper, - graphics_image_export_settings: Ansys.Mechanical.Graphics.GraphicsImageExportSettings, + camera, + graphics, + graphics_image_export_settings, image_output_path: Path, image_name: str, ) -> None: @@ -109,7 +114,7 @@ def display_image( graphics = app.Graphics camera = graphics.Camera -camera.SetSpecificViewOrientation(ViewOrientationType.Iso) +camera.SetSpecificViewOrientation(Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Iso) image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() settings_720p.Resolution = GraphicsResolutionType.EnhancedResolution diff --git a/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py b/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py index b3ef388d..16065330 100644 --- a/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py +++ b/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py @@ -54,6 +54,11 @@ from matplotlib import image as mpimg from matplotlib import pyplot as plt +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + import Ansys + # %% # Embed mechanical and set global variables @@ -69,9 +74,9 @@ def set_camera_and_display_image( - camera: Ansys.ACT.Common.Graphics.MechanicalCameraWrapper, - graphics: Ansys.ACT.Common.Graphics.MechanicalGraphicsWrapper, - graphics_image_export_settings: Ansys.Mechanical.Graphics.GraphicsImageExportSettings, + camera, + graphics, + graphics_image_export_settings, image_output_path: Path, image_name: str, ) -> None: diff --git a/examples/02_technology_showcase/conact_wear_simulation.py b/examples/02_technology_showcase/conact_wear_simulation.py index ddf59547..9ad631d3 100644 --- a/examples/02_technology_showcase/conact_wear_simulation.py +++ b/examples/02_technology_showcase/conact_wear_simulation.py @@ -34,6 +34,11 @@ from matplotlib import pyplot as plt from matplotlib.animation import FuncAnimation +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + import Ansys + # %% # Embed mechanical and set global variables @@ -49,9 +54,9 @@ def set_camera_and_display_image( - camera: Ansys.ACT.Common.Graphics.MechanicalCameraWrapper, - graphics: Ansys.ACT.Common.Graphics.MechanicalGraphicsWrapper, - graphics_image_export_settings: Ansys.Mechanical.Graphics.GraphicsImageExportSettings, + camera, + graphics, + graphics_image_export_settings, image_output_path: Path, image_name: str, ) -> None: @@ -124,7 +129,7 @@ def display_image( graphics = app.Graphics camera = graphics.Camera -camera.SetSpecificViewOrientation(ViewOrientationType.Front) +camera.SetSpecificViewOrientation(Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Front) image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() settings_720p.Resolution = GraphicsResolutionType.EnhancedResolution diff --git a/examples/02_technology_showcase/non_linear_analsis_rubber_boot_seal.py b/examples/02_technology_showcase/non_linear_analsis_rubber_boot_seal.py index f4b8a79c..61f5a3f1 100644 --- a/examples/02_technology_showcase/non_linear_analsis_rubber_boot_seal.py +++ b/examples/02_technology_showcase/non_linear_analsis_rubber_boot_seal.py @@ -27,6 +27,11 @@ from matplotlib import pyplot as plt from matplotlib.animation import FuncAnimation +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + import Ansys + # %% # Embed mechanical and set global variables @@ -42,9 +47,9 @@ def set_camera_and_display_image( - camera: Ansys.ACT.Common.Graphics.MechanicalCameraWrapper, - graphics: Ansys.ACT.Common.Graphics.MechanicalGraphicsWrapper, - graphics_image_export_settings: Ansys.Mechanical.Graphics.GraphicsImageExportSettings, + camera, + graphics, + graphics_image_export_settings, image_output_path: Path, image_name: str, ) -> None: @@ -117,7 +122,7 @@ def display_image( graphics = app.Graphics camera = graphics.Camera -camera.SetSpecificViewOrientation(ViewOrientationType.Iso) +camera.SetSpecificViewOrientation(Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Iso) camera.SetFit() image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() From 8de224a878dce2ab3353e454528e2ed338696e18 Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Thu, 24 Apr 2025 15:20:13 -0400 Subject: [PATCH 11/24] code style fix --- examples/00_tips/tips_02.py | 4 ++- examples/01_basic/bolt_pretension.py | 4 ++- .../fracture_analysis_contact_debonding.py | 29 ++++++++++++++----- examples/01_basic/harmonic_acoustics.py | 7 +++-- examples/01_basic/modal_acoustics_analysis.py | 7 +++-- .../01_basic/steady_state_thermal_analysis.py | 7 +++-- .../topology_optimization_cantilever_beam.py | 7 +++-- examples/01_basic/valve.py | 7 +++-- .../Rotor_Blade_Inverse_solve.py | 3 +- .../conact_wear_simulation.py | 7 +++-- ...> non_linear_analysis_rubber_boot_seal.py} | 7 +++-- 11 files changed, 57 insertions(+), 32 deletions(-) rename examples/02_technology_showcase/{non_linear_analsis_rubber_boot_seal.py => non_linear_analysis_rubber_boot_seal.py} (99%) diff --git a/examples/00_tips/tips_02.py b/examples/00_tips/tips_02.py index 8c8c8e5d..bcc21102 100644 --- a/examples/00_tips/tips_02.py +++ b/examples/00_tips/tips_02.py @@ -45,7 +45,9 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Set the orientation of the camera -ExtAPI.Graphics.Camera.SetSpecificViewOrientation(Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Iso) +ExtAPI.Graphics.Camera.SetSpecificViewOrientation( + Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Iso +) # Set the image export format image_export_format = GraphicsImageExportFormat.PNG diff --git a/examples/01_basic/bolt_pretension.py b/examples/01_basic/bolt_pretension.py index 99665bc8..c63825f9 100644 --- a/examples/01_basic/bolt_pretension.py +++ b/examples/01_basic/bolt_pretension.py @@ -49,7 +49,9 @@ # Set camera orientation graphics = app.Graphics camera = graphics.Camera -camera.SetSpecificViewOrientation(Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Iso) +camera.SetSpecificViewOrientation( + Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Iso +) camera.SetFit() camera.Rotate(180, CameraAxisType.ScreenY) diff --git a/examples/01_basic/fracture_analysis_contact_debonding.py b/examples/01_basic/fracture_analysis_contact_debonding.py index 1ee80d59..8e55bc9c 100644 --- a/examples/01_basic/fracture_analysis_contact_debonding.py +++ b/examples/01_basic/fracture_analysis_contact_debonding.py @@ -14,6 +14,7 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~~~ from pathlib import Path +from typing import TYPE_CHECKING from PIL import Image from ansys.mechanical.core import App @@ -22,8 +23,6 @@ from matplotlib import pyplot as plt from matplotlib.animation import FuncAnimation -from typing import TYPE_CHECKING - if TYPE_CHECKING: import Ansys @@ -41,7 +40,9 @@ # Set camera orientation graphics = app.Graphics camera = graphics.Camera -camera.SetSpecificViewOrientation(Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Front) +camera.SetSpecificViewOrientation( + Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Front +) # Set camera settings for 720p resolution image_export_format = GraphicsImageExportFormat.PNG @@ -335,7 +336,9 @@ def add_sizing( mesh.GenerateMesh() # Display the mesh image -set_camera_and_display_image(camera, graphics, graphics_image_export_settings, output_path, "mesh.png") +set_camera_and_display_image( + camera, graphics, graphics_image_export_settings, output_path, "mesh.png" +) # %% # Add contact debonding object @@ -442,7 +445,13 @@ def add_displacement( static_structural_analysis.Activate() # Set the camera to fit the model and display the image of the boundary conditions -set_camera_and_display_image(camera, graphics, graphics_image_export_settings, output_path, "boundary_conditions.png") +set_camera_and_display_image( + camera, + graphics, + graphics_image_export_settings, + output_path, + "boundary_conditions.png", +) # %% # Add directional deformation and force reaction results to the solution @@ -495,13 +504,19 @@ def add_displacement( directional_deformation.Activate() # Set the camera to fit the model and display the image of the directional deformation set_camera_and_display_image( - camera, graphics, graphics_image_export_settings, output_path, "directional_deformation.png" + camera, + graphics, + graphics_image_export_settings, + output_path, + "directional_deformation.png", ) # Activate the force reaction force_reaction.Activate() # Set the camera to fit the model and display the image of the force reaction -set_camera_and_display_image(camera, graphics, graphics_image_export_settings, output_path, "force_reaction.png") +set_camera_and_display_image( + camera, graphics, graphics_image_export_settings, output_path, "force_reaction.png" +) # %% # Export animation diff --git a/examples/01_basic/harmonic_acoustics.py b/examples/01_basic/harmonic_acoustics.py index 5d962980..814ae10f 100644 --- a/examples/01_basic/harmonic_acoustics.py +++ b/examples/01_basic/harmonic_acoustics.py @@ -36,6 +36,7 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~~~ from pathlib import Path +from typing import TYPE_CHECKING from PIL import Image from ansys.mechanical.core import App @@ -44,8 +45,6 @@ from matplotlib import pyplot as plt from matplotlib.animation import FuncAnimation -from typing import TYPE_CHECKING - if TYPE_CHECKING: import Ansys @@ -139,7 +138,9 @@ def display_image( graphics = app.Graphics camera = graphics.Camera -camera.SetSpecificViewOrientation(Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Iso) +camera.SetSpecificViewOrientation( + Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Iso +) image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() settings_720p.Resolution = GraphicsResolutionType.EnhancedResolution diff --git a/examples/01_basic/modal_acoustics_analysis.py b/examples/01_basic/modal_acoustics_analysis.py index 99ab31c1..6438c9e9 100644 --- a/examples/01_basic/modal_acoustics_analysis.py +++ b/examples/01_basic/modal_acoustics_analysis.py @@ -20,6 +20,7 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~~~ from pathlib import Path +from typing import TYPE_CHECKING from PIL import Image from ansys.mechanical.core import App @@ -28,8 +29,6 @@ from matplotlib import pyplot as plt from matplotlib.animation import FuncAnimation -from typing import TYPE_CHECKING - if TYPE_CHECKING: import Ansys @@ -123,7 +122,9 @@ def display_image( graphics = app.Graphics camera = graphics.Camera -camera.SetSpecificViewOrientation(Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Iso) +camera.SetSpecificViewOrientation( + Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Iso +) image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() settings_720p.Resolution = GraphicsResolutionType.EnhancedResolution diff --git a/examples/01_basic/steady_state_thermal_analysis.py b/examples/01_basic/steady_state_thermal_analysis.py index d4f16440..4419918a 100644 --- a/examples/01_basic/steady_state_thermal_analysis.py +++ b/examples/01_basic/steady_state_thermal_analysis.py @@ -16,6 +16,7 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~~~ from pathlib import Path +from typing import TYPE_CHECKING from PIL import Image from ansys.mechanical.core import App @@ -24,8 +25,6 @@ from matplotlib import pyplot as plt from matplotlib.animation import FuncAnimation -from typing import TYPE_CHECKING - if TYPE_CHECKING: import Ansys @@ -119,7 +118,9 @@ def display_image( graphics = app.Graphics camera = graphics.Camera -camera.SetSpecificViewOrientation(Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Iso) +camera.SetSpecificViewOrientation( + Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Iso +) camera.SetFit() image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() diff --git a/examples/01_basic/topology_optimization_cantilever_beam.py b/examples/01_basic/topology_optimization_cantilever_beam.py index d41cae97..546a1c7a 100644 --- a/examples/01_basic/topology_optimization_cantilever_beam.py +++ b/examples/01_basic/topology_optimization_cantilever_beam.py @@ -13,6 +13,7 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~~~ from pathlib import Path +from typing import TYPE_CHECKING from PIL import Image from ansys.mechanical.core import App @@ -21,8 +22,6 @@ from matplotlib import pyplot as plt from matplotlib.animation import FuncAnimation -from typing import TYPE_CHECKING - if TYPE_CHECKING: import Ansys @@ -116,7 +115,9 @@ def display_image( graphics = app.Graphics camera = graphics.Camera -camera.SetSpecificViewOrientation(Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Front) +camera.SetSpecificViewOrientation( + Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Front +) image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() settings_720p.Resolution = GraphicsResolutionType.EnhancedResolution diff --git a/examples/01_basic/valve.py b/examples/01_basic/valve.py index 48ada00b..ebeb0c1b 100644 --- a/examples/01_basic/valve.py +++ b/examples/01_basic/valve.py @@ -11,6 +11,7 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~~~ from pathlib import Path +from typing import TYPE_CHECKING from PIL import Image from ansys.mechanical.core import App @@ -19,8 +20,6 @@ from matplotlib import pyplot as plt from matplotlib.animation import FuncAnimation -from typing import TYPE_CHECKING - if TYPE_CHECKING: import Ansys @@ -114,7 +113,9 @@ def display_image( graphics = app.Graphics camera = graphics.Camera -camera.SetSpecificViewOrientation(Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Iso) +camera.SetSpecificViewOrientation( + Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Iso +) image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() settings_720p.Resolution = GraphicsResolutionType.EnhancedResolution diff --git a/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py b/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py index 16065330..bf8aa8cd 100644 --- a/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py +++ b/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py @@ -48,14 +48,13 @@ """ 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 -from typing import TYPE_CHECKING - if TYPE_CHECKING: import Ansys diff --git a/examples/02_technology_showcase/conact_wear_simulation.py b/examples/02_technology_showcase/conact_wear_simulation.py index 9ad631d3..65530036 100644 --- a/examples/02_technology_showcase/conact_wear_simulation.py +++ b/examples/02_technology_showcase/conact_wear_simulation.py @@ -26,6 +26,7 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~~~ from pathlib import Path +from typing import TYPE_CHECKING from PIL import Image from ansys.mechanical.core import App @@ -34,8 +35,6 @@ from matplotlib import pyplot as plt from matplotlib.animation import FuncAnimation -from typing import TYPE_CHECKING - if TYPE_CHECKING: import Ansys @@ -129,7 +128,9 @@ def display_image( graphics = app.Graphics camera = graphics.Camera -camera.SetSpecificViewOrientation(Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Front) +camera.SetSpecificViewOrientation( + Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Front +) image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() settings_720p.Resolution = GraphicsResolutionType.EnhancedResolution diff --git a/examples/02_technology_showcase/non_linear_analsis_rubber_boot_seal.py b/examples/02_technology_showcase/non_linear_analysis_rubber_boot_seal.py similarity index 99% rename from examples/02_technology_showcase/non_linear_analsis_rubber_boot_seal.py rename to examples/02_technology_showcase/non_linear_analysis_rubber_boot_seal.py index 61f5a3f1..380896d6 100644 --- a/examples/02_technology_showcase/non_linear_analsis_rubber_boot_seal.py +++ b/examples/02_technology_showcase/non_linear_analysis_rubber_boot_seal.py @@ -19,6 +19,7 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~~~ from pathlib import Path +from typing import TYPE_CHECKING from PIL import Image from ansys.mechanical.core import App @@ -27,8 +28,6 @@ from matplotlib import pyplot as plt from matplotlib.animation import FuncAnimation -from typing import TYPE_CHECKING - if TYPE_CHECKING: import Ansys @@ -122,7 +121,9 @@ def display_image( graphics = app.Graphics camera = graphics.Camera -camera.SetSpecificViewOrientation(Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Iso) +camera.SetSpecificViewOrientation( + Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Iso +) camera.SetFit() image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() From d9f630853ee2806cb838651848d56857d74f332b Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Thu, 24 Apr 2025 15:31:42 -0400 Subject: [PATCH 12/24] fix vieworientationtype --- examples/00_tips/tips_02.py | 4 +--- examples/01_basic/bolt_pretension.py | 4 +--- examples/01_basic/fracture_analysis_contact_debonding.py | 4 +--- examples/01_basic/harmonic_acoustics.py | 4 +--- examples/01_basic/modal_acoustics_analysis.py | 4 +--- examples/01_basic/steady_state_thermal_analysis.py | 4 +--- examples/01_basic/topology_optimization_cantilever_beam.py | 4 +--- examples/01_basic/valve.py | 4 +--- examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py | 4 +--- examples/02_technology_showcase/conact_wear_simulation.py | 4 +--- 10 files changed, 10 insertions(+), 30 deletions(-) diff --git a/examples/00_tips/tips_02.py b/examples/00_tips/tips_02.py index bcc21102..184dd0b8 100644 --- a/examples/00_tips/tips_02.py +++ b/examples/00_tips/tips_02.py @@ -45,9 +45,7 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Set the orientation of the camera -ExtAPI.Graphics.Camera.SetSpecificViewOrientation( - Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Iso -) +ExtAPI.Graphics.Camera.SetSpecificViewOrientation(ViewOrientationType.Iso) # Set the image export format image_export_format = GraphicsImageExportFormat.PNG diff --git a/examples/01_basic/bolt_pretension.py b/examples/01_basic/bolt_pretension.py index c63825f9..cae5ac98 100644 --- a/examples/01_basic/bolt_pretension.py +++ b/examples/01_basic/bolt_pretension.py @@ -49,9 +49,7 @@ # Set camera orientation graphics = app.Graphics camera = graphics.Camera -camera.SetSpecificViewOrientation( - Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Iso -) +camera.SetSpecificViewOrientation(ViewOrientationType.Iso) camera.SetFit() camera.Rotate(180, CameraAxisType.ScreenY) diff --git a/examples/01_basic/fracture_analysis_contact_debonding.py b/examples/01_basic/fracture_analysis_contact_debonding.py index 8e55bc9c..f46e6424 100644 --- a/examples/01_basic/fracture_analysis_contact_debonding.py +++ b/examples/01_basic/fracture_analysis_contact_debonding.py @@ -40,9 +40,7 @@ # Set camera orientation graphics = app.Graphics camera = graphics.Camera -camera.SetSpecificViewOrientation( - Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Front -) +camera.SetSpecificViewOrientation(ViewOrientationType.Front) # Set camera settings for 720p resolution image_export_format = GraphicsImageExportFormat.PNG diff --git a/examples/01_basic/harmonic_acoustics.py b/examples/01_basic/harmonic_acoustics.py index 814ae10f..e67bce61 100644 --- a/examples/01_basic/harmonic_acoustics.py +++ b/examples/01_basic/harmonic_acoustics.py @@ -138,9 +138,7 @@ def display_image( graphics = app.Graphics camera = graphics.Camera -camera.SetSpecificViewOrientation( - Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Iso -) +camera.SetSpecificViewOrientation(ViewOrientationType.Iso) image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() settings_720p.Resolution = GraphicsResolutionType.EnhancedResolution diff --git a/examples/01_basic/modal_acoustics_analysis.py b/examples/01_basic/modal_acoustics_analysis.py index 6438c9e9..114271df 100644 --- a/examples/01_basic/modal_acoustics_analysis.py +++ b/examples/01_basic/modal_acoustics_analysis.py @@ -122,9 +122,7 @@ def display_image( graphics = app.Graphics camera = graphics.Camera -camera.SetSpecificViewOrientation( - Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Iso -) +camera.SetSpecificViewOrientation(ViewOrientationType.Iso) image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() settings_720p.Resolution = GraphicsResolutionType.EnhancedResolution diff --git a/examples/01_basic/steady_state_thermal_analysis.py b/examples/01_basic/steady_state_thermal_analysis.py index 4419918a..5e6db0b0 100644 --- a/examples/01_basic/steady_state_thermal_analysis.py +++ b/examples/01_basic/steady_state_thermal_analysis.py @@ -118,9 +118,7 @@ def display_image( graphics = app.Graphics camera = graphics.Camera -camera.SetSpecificViewOrientation( - Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Iso -) +camera.SetSpecificViewOrientation(ViewOrientationType.Iso) camera.SetFit() image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() diff --git a/examples/01_basic/topology_optimization_cantilever_beam.py b/examples/01_basic/topology_optimization_cantilever_beam.py index 546a1c7a..17873673 100644 --- a/examples/01_basic/topology_optimization_cantilever_beam.py +++ b/examples/01_basic/topology_optimization_cantilever_beam.py @@ -115,9 +115,7 @@ def display_image( graphics = app.Graphics camera = graphics.Camera -camera.SetSpecificViewOrientation( - Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Front -) +camera.SetSpecificViewOrientation(ViewOrientationType.Front) image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() settings_720p.Resolution = GraphicsResolutionType.EnhancedResolution diff --git a/examples/01_basic/valve.py b/examples/01_basic/valve.py index ebeb0c1b..9482f50e 100644 --- a/examples/01_basic/valve.py +++ b/examples/01_basic/valve.py @@ -113,9 +113,7 @@ def display_image( graphics = app.Graphics camera = graphics.Camera -camera.SetSpecificViewOrientation( - Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Iso -) +camera.SetSpecificViewOrientation(ViewOrientationType.Iso) image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() settings_720p.Resolution = GraphicsResolutionType.EnhancedResolution diff --git a/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py b/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py index bf8aa8cd..45d90302 100644 --- a/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py +++ b/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py @@ -179,9 +179,7 @@ def display_image( graphics = app.Graphics camera = graphics.Camera -camera.SetSpecificViewOrientation( - Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Iso -) +camera.SetSpecificViewOrientation(ViewOrientationType.Iso) camera.SetFit() image_export_format = Ansys.Mechanical.DataModel.Enums.GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() diff --git a/examples/02_technology_showcase/conact_wear_simulation.py b/examples/02_technology_showcase/conact_wear_simulation.py index 65530036..cfda2a56 100644 --- a/examples/02_technology_showcase/conact_wear_simulation.py +++ b/examples/02_technology_showcase/conact_wear_simulation.py @@ -128,9 +128,7 @@ def display_image( graphics = app.Graphics camera = graphics.Camera -camera.SetSpecificViewOrientation( - Ansys.Mechanical.DataModel.Enums.ViewOrientationType.Front -) +camera.SetSpecificViewOrientation(ViewOrientationType.Front) image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() settings_720p.Resolution = GraphicsResolutionType.EnhancedResolution From 6b02dfc2424c472d1e0e4cc2f7308763cee88e05 Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Fri, 25 Apr 2025 17:10:07 -0400 Subject: [PATCH 13/24] add functions to some examples --- .../fracture_analysis_contact_debonding.py | 12 +- examples/01_basic/harmonic_acoustics.py | 390 +++++++----- examples/01_basic/modal_acoustics_analysis.py | 601 +++++++++--------- .../01_basic/steady_state_thermal_analysis.py | 2 +- .../topology_optimization_cantilever_beam.py | 2 +- examples/01_basic/valve.py | 2 +- .../Rotor_Blade_Inverse_solve.py | 4 +- .../conact_wear_simulation.py | 2 +- .../non_linear_analysis_rubber_boot_seal.py | 2 +- 9 files changed, 557 insertions(+), 460 deletions(-) diff --git a/examples/01_basic/fracture_analysis_contact_debonding.py b/examples/01_basic/fracture_analysis_contact_debonding.py index f46e6424..a462d526 100644 --- a/examples/01_basic/fracture_analysis_contact_debonding.py +++ b/examples/01_basic/fracture_analysis_contact_debonding.py @@ -27,10 +27,10 @@ import Ansys # %% -# Create an instance of the Mechanical embedded application with global variables -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Create an instance of the Mechanical embedded application -app = App(globals=globals()) +app = App() # globals=globals() +app.update_globals(globals()) print(app) # %% @@ -60,9 +60,9 @@ def set_camera_and_display_image( - camera: Ansys.ACT.Common.Graphics.MechanicalCameraWrapper, - graphics: Ansys.ACT.Common.Graphics.MechanicalGraphicsWrapper, - graphics_image_export_settings: Ansys.Mechanical.Graphics.GraphicsImageExportSettings, + camera, + graphics, + graphics_image_export_settings, image_output_path: Path, image_name: str, ) -> None: diff --git a/examples/01_basic/harmonic_acoustics.py b/examples/01_basic/harmonic_acoustics.py index e67bce61..689924b5 100644 --- a/examples/01_basic/harmonic_acoustics.py +++ b/examples/01_basic/harmonic_acoustics.py @@ -49,7 +49,7 @@ import Ansys # %% -# Embed mechanical and set global variables +# Create an instance of the Mechanical embedded application app = App() app.update_globals(globals()) @@ -69,6 +69,7 @@ def set_camera_and_display_image( graphics_image_export_settings, image_output_path: Path, image_name: str, + set_fit: bool = False, ) -> None: """Set the camera to fit the model and display the image. @@ -85,8 +86,9 @@ def set_camera_and_display_image( image_name : str The name of the exported image file. """ - # Set the camera to fit the mesh - camera.SetFit() + if set_fit: + # Set the camera to fit the mesh + camera.SetFit() # Export the mesh image with the specified settings image_path = image_output_path / image_name graphics.ExportImage( @@ -138,7 +140,11 @@ def display_image( graphics = app.Graphics camera = graphics.Camera + +# Set the camera orientation to isometric view camera.SetSpecificViewOrientation(ViewOrientationType.Iso) + +# Set the image export format to PNG and configure the export settings image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() settings_720p.Resolution = GraphicsResolutionType.EnhancedResolution @@ -171,6 +177,8 @@ def display_image( ) geometry_import_preferences = Ansys.ACT.Mechanical.Utilities.GeometryImportPreferences() geometry_import_preferences.ProcessNamedSelections = True + +# Import the geometry file with the specified format and preferences geometry_import.Import( geometry_path, geometry_import_format, geometry_import_preferences ) @@ -234,109 +242,125 @@ def display_image( # %% # Create named selections -# ~~~~~~~~~~~~~~~~~~~~~~~~ - -sf_velo = model.AddNamedSelection() -sf_velo.ScopingMethod = GeometryDefineByType.Worksheet -sf_velo.Name = "sf_velo" - -generation_criteria_1 = sf_velo.GenerationCriteria -criteria_1 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() -criteria_1.Active = True -criteria_1.Action = SelectionActionType.Add -criteria_1.EntityType = SelectionType.GeoFace -criteria_1.Criterion = SelectionCriterionType.Size -criteria_1.Operator = SelectionOperatorType.Equal -criteria_1.Value = Quantity("3e6 [mm^2]") -generation_criteria_1.Add(criteria_1) - -criteria_2 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() -criteria_2.Active = True -criteria_2.Action = SelectionActionType.Filter -criteria_2.EntityType = SelectionType.GeoFace -criteria_2.Criterion = SelectionCriterionType.LocationZ -criteria_2.Operator = SelectionOperatorType.Equal -criteria_2.Value = Quantity("15000 [mm]") -generation_criteria_1.Add(criteria_2) +# ~~~~~~~~~~~~~~~~~~~~~~~ -sf_velo.Activate() -sf_velo.Generate() +def setup_named_selection(scoping_method, name): + """Create a named selection with the specified scoping method and name. -abs_face = model.AddNamedSelection() -abs_face.ScopingMethod = GeometryDefineByType.Worksheet -abs_face.Name = "abs_face" - -generation_criteria_2 = abs_face.GenerationCriteria -criteria_1 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() -criteria_1.Active = True -criteria_1.Action = SelectionActionType.Add -criteria_1.EntityType = SelectionType.GeoFace -criteria_1.Criterion = SelectionCriterionType.Size -criteria_1.Operator = SelectionOperatorType.Equal -criteria_1.Value = Quantity("1.5e6 [mm^2]") -generation_criteria_2.Add(criteria_1) - -criteria_2 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() -criteria_2.Active = True -criteria_2.Action = SelectionActionType.Filter -criteria_2.EntityType = SelectionType.GeoFace -criteria_2.Criterion = SelectionCriterionType.LocationY -criteria_2.Operator = SelectionOperatorType.Equal -criteria_2.Value = Quantity("500 [mm]") -generation_criteria_2.Add(criteria_2) + Parameters + ---------- + scoping_method : GeometryDefineByType + The scoping method for the named selection. + name : str + The name of the named selection. -abs_face.Activate() -abs_face.Generate() + Returns + ------- + Ansys.ACT.Automation.Mechanical.NamedSelection + The created named selection. + """ + ns = model.AddNamedSelection() + ns.ScopingMethod = scoping_method + ns.Name = name + return ns + + +def add_generation_criteria( + named_selection, + value, + active=True, + action=SelectionActionType.Add, + entity_type=SelectionType.GeoFace, + criterion=SelectionCriterionType.Size, + operator=SelectionOperatorType.Equal, +): + """Add generation criteria to the named selection. + Parameters + ---------- + named_selection : Ansys.ACT.Automation.Mechanical.NamedSelection + The named selection to which the criteria will be added. + value : Quantity + The value for the criteria. + active : bool + Whether the criteria is active. + action : SelectionActionType + The action type for the criteria. + entity_type : SelectionType + The entity type for the criteria. + criterion : SelectionCriterionType + The criterion type for the criteria. + operator : SelectionOperatorType + The operator for the criteria. + """ + generation_criteria = named_selection.GenerationCriteria + criteria = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() + criteria.Active = active + criteria.Action = action + criteria.EntityType = entity_type + criteria.Criterion = criterion + criteria.Operator = operator + criteria.Value = value + generation_criteria.Add(criteria) + + +# Add a named selection for the surface velocity and define its generation criteria +sf_velo = setup_named_selection(GeometryDefineByType.Worksheet, "sf_velo") +add_generation_criteria(sf_velo, Quantity("3e6 [mm^2]")) +add_generation_criteria( + sf_velo, + Quantity("15000 [mm]"), + action=SelectionActionType.Filter, + criterion=SelectionCriterionType.LocationZ, +) +# Activate and generate the named selection +sf_velo.Activate() +sf_velo.Generate() -pres_face = model.AddNamedSelection() -pres_face.ScopingMethod = GeometryDefineByType.Worksheet -pres_face.Name = "pres_face" - -generation_criteria_3 = pres_face.GenerationCriteria -criteria_1 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() -criteria_1.Active = True -criteria_1.Action = SelectionActionType.Add -criteria_1.EntityType = SelectionType.GeoFace -criteria_1.Criterion = SelectionCriterionType.Size -criteria_1.Operator = SelectionOperatorType.Equal -criteria_1.Value = Quantity("1.5e6 [mm^2]") -generation_criteria_3.Add(criteria_1) - -criteria_2 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() -criteria_2.Active = True -criteria_2.Action = SelectionActionType.Filter -criteria_2.EntityType = SelectionType.GeoFace -criteria_2.Criterion = SelectionCriterionType.LocationY -criteria_2.Operator = SelectionOperatorType.Equal -criteria_2.Value = Quantity("4500 [mm]") -generation_criteria_3.Add(criteria_2) +# Add named selections for the absorption faces and define its generation criteria +abs_face = setup_named_selection(GeometryDefineByType.Worksheet, "abs_face") +add_generation_criteria(abs_face, Quantity("1.5e6 [mm^2]")) +add_generation_criteria( + abs_face, + Quantity("500 [mm]"), + action=SelectionActionType.Filter, + criterion=SelectionCriterionType.LocationY, +) +# Activate and generate the named selection +abs_face.Activate() +abs_face.Generate() +# Add named selections for the pressure faces and define its generation criteria +pres_face = setup_named_selection(GeometryDefineByType.Worksheet, "pres_face") +add_generation_criteria(pres_face, Quantity("1.5e6 [mm^2]")) +add_generation_criteria( + pres_face, + Quantity("4500 [mm]"), + action=SelectionActionType.Filter, + criterion=SelectionCriterionType.LocationY, +) +# Activate and generate the named selection pres_face.Activate() pres_face.Generate() - -acoustic_region = model.AddNamedSelection() -acoustic_region.ScopingMethod = GeometryDefineByType.Worksheet -acoustic_region.Name = "acoustic_region" - -generation_criteria_4 = acoustic_region.GenerationCriteria -criteria_1 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() -criteria_1.Active = True -criteria_1.Action = SelectionActionType.Add -criteria_1.EntityType = SelectionType.GeoBody -criteria_1.Criterion = SelectionCriterionType.Type -criteria_1.Operator = SelectionOperatorType.Equal -criteria_1.Value = 8 -generation_criteria_4.Add(criteria_1) - +# Add named selections for the acoustic region and define its generation criteria +acoustic_region = setup_named_selection( + GeometryDefineByType.Worksheet, "acoustic_region" +) +add_generation_criteria( + acoustic_region, + 8, + entity_type=SelectionType.GeoBody, + criterion=SelectionCriterionType.Type, +) +# Activate and generate the named selection acoustic_region.Activate() acoustic_region.Generate() # %% -# Analysis settings -# ~~~~~~~~~~~~~~~~~ +# Set up the analysis settings +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ analysis_settings = model.Analyses[0].AnalysisSettings analysis_settings.RangeMaximum = Quantity("100 [Hz]") @@ -349,19 +373,24 @@ def display_image( # Boundary conditions and load # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Get the harmonic acoustics analysis harmonic_acoustics = model.Analyses[0] # %% # Acoustic region +# Get the acoustics region from the harmonic acoustics analysis +# and set its location to the acoustic region named selection acoustics_region = [ - x for x in harmonic_acoustics.Children if x.Name == "Acoustics Region" + child for child in harmonic_acoustics.Children if child.Name == "Acoustics Region" ][0] acoustics_region.Location = acoustic_region # %% # Surface velocity +# Add a surface velocity boundary condition to the harmonic acoustics analysis +# and set its location to the sf_velo named selection surface_velocity = harmonic_acoustics.AddAcousticSurfaceVelocity() surface_velocity.Location = sf_velo surface_velocity.Magnitude.Output.DiscreteValues = [Quantity("5000 [mm s-1]")] @@ -369,6 +398,8 @@ def display_image( # %% # Acoustic pressure +# Add an acoustic pressure boundary condition to the harmonic acoustics analysis +# and set its location to the pres_face named selection acoustic_pressure = harmonic_acoustics.AddAcousticPressure() acoustic_pressure.Location = pres_face acoustic_pressure.Magnitude = Quantity("1.5e-7 [MPa]") @@ -376,99 +407,138 @@ def display_image( # %% # Acoustic absoption surface +# Add an acoustic absorption surface to the harmonic acoustics analysis +# and set its location to the abs_face named selection absorption_surface = harmonic_acoustics.AddAcousticAbsorptionSurface() absorption_surface.Location = abs_face absorption_surface.AbsorptionCoefficient.Output.DiscreteValues = [Quantity("0.02")] +# Activate the harmonic acoustics analysis harmonic_acoustics.Activate() +# Set the camera to fit the mesh and export the image set_camera_and_display_image( - camera, graphics, settings_720p, output_path, "bounday_conditions.png" + camera, graphics, settings_720p, output_path, "bounday_conditions.png", set_fit=True ) # %% -# Add results -# ~~~~~~~~~~~ +# Add results to the harmonic acoustics solution +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Get the harmonic acoustics solution solution = model.Analyses[0].Solution # %% -# Acoustic pressure +# Add the acoustic pressure result acoustic_pressure_result_1 = solution.AddAcousticPressureResult() acoustic_pressure_result_1.By = SetDriverStyle.ResultSet acoustic_pressure_result_1.SetNumber = 25 # %% -# Acoustic velocity - total and directional +# Add the acoustic total and directional velocity results +# Add the acoustic total velocity result and set its frequency acoustic_total_velocity_1 = solution.AddAcousticTotalVelocityResult() acoustic_total_velocity_1.Frequency = Quantity("50 [Hz]") +# Add the acoustic directional velocity result and set its frequency and coordinate system acoustic_directional_velocity_1 = solution.AddAcousticDirectionalVelocityResult() acoustic_directional_velocity_1.Frequency = Quantity("50 [Hz]") acoustic_directional_velocity_1.CoordinateSystem = lcs1 +# Add the acoustic total velocity result and set its orientation acoustic_directional_velocity_2 = solution.AddAcousticDirectionalVelocityResult() acoustic_directional_velocity_2.NormalOrientation = NormalOrientationType.ZAxis acoustic_directional_velocity_2.By = SetDriverStyle.ResultSet acoustic_directional_velocity_2.SetNumber = 25 # %% -# Acoustic sound pressure and frequency bands +# Add the acoustic sound pressure levels and frequency band responses +# Add the acoustic sound pressure level and set its frequency acoustic_spl = solution.AddAcousticSoundPressureLevel() acoustic_spl.Frequency = Quantity("50 [Hz]") +# Add the acoustic A-weighted sound pressure level and set its frequency acoustic_a_spl = solution.AddAcousticAWeightedSoundPressureLevel() acoustic_a_spl.Frequency = Quantity("50 [Hz]") +# Add the acoustic frequency band sound pressure level acoustic_frq_band_spl = solution.AddAcousticFrequencyBandSPL() +# Add the acoustic A-weighted frequency band sound pressure level a_freq_band_spl = solution.AddAcousticFrequencyBandAWeightedSPL() +# Add the acoustic velocity frequency response and set its orientation and location z_velocity_response = solution.AddAcousticVelocityFrequencyResponse() z_velocity_response.NormalOrientation = NormalOrientationType.ZAxis +# Set the location to the pressure face named selection z_velocity_response.Location = pres_face -z_velocity_response.NormalOrientation = NormalOrientationType.ZAxis # %% -# Acoustic kinetic and potentional energy frequency response +# Add the acoustic kinetic and potentional energy frequency responses +# Add the acoustic kinetic energy frequency response and set its location +# to the absorption face named selection ke_response = solution.AddAcousticKineticEnergyFrequencyResponse() ke_response.Location = abs_face -KE_display = ke_response.TimeHistoryDisplay +ke_display = ke_response.TimeHistoryDisplay +# Add the acoustic potential energy frequency response and set its location +# to the absorption face named selection pe_response = solution.AddAcousticPotentialEnergyFrequencyResponse() pe_response.Location = abs_face -PE_display = pe_response.TimeHistoryDisplay +pe_display = pe_response.TimeHistoryDisplay # %% -# Acoustic total and directional velocity +# Add the acoustic total and directional velocity results + +def set_properties( + element, + frequency, + location, + amplitude=True, + normal_orientation=None, +): + """Set the properties of the acoustic velocity result.""" + element.Frequency = frequency + element.Amplitude = amplitude + if normal_orientation: + element.NormalOrientation = normal_orientation + # Set the location to the specified named selection + element.Location = location + return element + + +# Add the acoustic total velocity result and set its frequency to 30 Hz +# and its location to the pressure face named selection acoustic_total_velocity_2 = solution.AddAcousticTotalVelocityResult() -acoustic_total_velocity_2.Location = pres_face -acoustic_total_velocity_2.Frequency = Quantity("30 [Hz]") -acoustic_total_velocity_2.Amplitude = True +set_properties(acoustic_total_velocity_2, Quantity("30 [Hz]"), pres_face) +# Add the acoustic directional velocity result and set its frequency to 10 Hz, +# its location to the pressure face named selection, and its orientation to the Z-axis acoustic_directional_velocity_3 = solution.AddAcousticDirectionalVelocityResult() -acoustic_directional_velocity_3.NormalOrientation = NormalOrientationType.ZAxis -acoustic_directional_velocity_3.Location = pres_face -acoustic_directional_velocity_3.Frequency = Quantity("10 [Hz]") -acoustic_directional_velocity_3.Amplitude = True +set_properties( + acoustic_directional_velocity_3, + Quantity("10 [Hz]"), + pres_face, + normal_orientation=NormalOrientationType.ZAxis, +) +# Add the acoustic velocity frequency response and set its frequency +# to 68 Hz and its location to the absorption face named selection acoustic_ke = solution.AddAcousticKineticEnergy() -acoustic_ke.Location = abs_face -acoustic_ke.Frequency = Quantity("68 [Hz]") -acoustic_ke.Amplitude = True +set_properties(acoustic_ke, Quantity("68 [Hz]"), abs_face) +# Add the acoustic potential energy frequency response and set its frequency +# to 10 Hz and its location to the absorption face named selection acoustic_pe = solution.AddAcousticPotentialEnergy() -acoustic_pe.Location = abs_face -acoustic_pe.Frequency = Quantity("10 [Hz]") -acoustic_pe.Amplitude = True +set_properties(acoustic_pe, Quantity("10 [Hz]"), abs_face) # %% -# Solve -# ~~~~~ +# Solve the harmonic acoustics analysis solution +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ solution.Solve(True) @@ -477,15 +547,15 @@ def display_image( # sphinx_gallery_end_ignore # %% -# messages -# ~~~~~~~~ +# Print messages +# ~~~~~~~~~~~~~~ messages = app.ExtAPI.Application.Messages if messages: for message in messages: print(f"[{message.Severity}] {message.DisplayString}") else: - print("No [Info]/[Warning]/[Error] messages") + print("No [Info]/[Warning]/[Error] Messages") # %% @@ -493,17 +563,17 @@ def display_image( # ~~~~~~~~~~~~~~ # %% -# Total acoustic pressure -# ^^^^^^^^^^^^^^^^^^^^^^^ +# Display the total acoustic pressure result +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ app.Tree.Activate([acoustic_pressure_result_1]) set_camera_and_display_image( - camera, graphics, settings_720p, output_path, "acoustic_pressure.png" + camera, graphics, settings_720p, output_path, "pressure.png" ) # %% -# Total acoustic velocity -# ^^^^^^^^^^^^^^^^^^^^^^^ +# Display the total acoustic velocity +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ app.Tree.Activate([acoustic_pressure_result_1]) set_camera_and_display_image( @@ -511,26 +581,26 @@ def display_image( ) # %% -# Sound pressure level -# ^^^^^^^^^^^^^^^^^^^^ +# Display the acoustic sound pressure level +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ app.Tree.Activate([acoustic_spl]) set_camera_and_display_image( - camera, graphics, settings_720p, output_path, "sound_pressure.png" + camera, graphics, settings_720p, output_path, "sound_pressure_level.png" ) # %% -# Total velocity on pressure surface -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# Display the acoustic directional velocity +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -app.Tree.Activate([acoustic_total_velocity_2]) +app.Tree.Activate([acoustic_directional_velocity_3]) set_camera_and_display_image( - camera, graphics, settings_720p, output_path, "total_velocity_pressure.png" + camera, graphics, settings_720p, output_path, "directional_velocity.png" ) # %% -# Kinetic energy on absorption face -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# Display the acoustic kinetic energy +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ app.Tree.Activate([acoustic_ke]) set_camera_and_display_image( @@ -538,21 +608,33 @@ def display_image( ) # %% -# Total acoustic pressure animation -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# Display the total acoustic pressure animation +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# Set the animation export format to GIF animation_export_format = ( Ansys.Mechanical.DataModel.Enums.GraphicsAnimationExportFormat.GIF ) + +# Configure the export settings for the animation settings_720p = Ansys.Mechanical.Graphics.AnimationExportSettings() settings_720p.Width = 1280 settings_720p.Height = 720 +# Export the animation of the acoustic pressure result press_gif = output_path / "press.gif" acoustic_pressure_result_1.ExportAnimation( str(press_gif), animation_export_format, settings_720p ) +# Open the GIF file and create an animation +gif = Image.open(press_gif) +# Set the subplots for the animation and turn off the axis +figure, axes = plt.subplots(figsize=(16, 9)) +axes.axis("off") +# Change the color of the image +image = axes.imshow(gif.convert("RGBA")) + def update_animation(frame: int) -> list[mpimg.AxesImage]: """Update the animation frame for the GIF. @@ -575,21 +657,13 @@ def update_animation(frame: int) -> list[mpimg.AxesImage]: return [image] -# Open the GIF file and create an animation -gif = Image.open(press_gif) -# Set the subplots for the animation and turn off the axis -figure, axes = plt.subplots(figsize=(16, 9)) -axes.axis("off") -# Change the color of the image -image = axes.imshow(gif.convert("RGBA")) - # Create the animation using the figure, update_animation function, and the GIF frames # Set the interval between frames to 200 milliseconds and repeat the animation -FuncAnimation( +ani = FuncAnimation( figure, update_animation, frames=range(gif.n_frames), - interval=100, + interval=200, repeat=True, blit=True, ) @@ -598,8 +672,8 @@ def update_animation(frame: int) -> list[mpimg.AxesImage]: plt.show() # %% -# Display output file from solve -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Display the output file from solve +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def write_file_contents_to_console(path): @@ -609,25 +683,29 @@ def write_file_contents_to_console(path): print(line, end="") +# Get the working directory of the solve solve_path = harmonic_acoustics.WorkingDir solve_out_path = Path(solve_path) / "solve.out" +# Check if the solve output file exists and write its contents to the console if solve_out_path: write_file_contents_to_console(solve_out_path) # %% -# Project tree -# ~~~~~~~~~~~~ +# Print the project tree +# ~~~~~~~~~~~~~~~~~~~~~~ app.print_tree() # %% -# Cleanup -# ~~~~~~~ -# Save project +# Clean up the project +# ~~~~~~~~~~~~~~~~~~~~ +# Save the project mechdat_file = output_path / "harmonic_acoustics.mechdat" app.save(str(mechdat_file)) + +# Refresh the app app.new() -# delete example file +# Delete the example file delete_downloads() diff --git a/examples/01_basic/modal_acoustics_analysis.py b/examples/01_basic/modal_acoustics_analysis.py index 114271df..c57bbdac 100644 --- a/examples/01_basic/modal_acoustics_analysis.py +++ b/examples/01_basic/modal_acoustics_analysis.py @@ -33,7 +33,7 @@ import Ansys # %% -# Embed mechanical and set global variables +# Create an instance of the Mechanical embedded application app = App(globals=globals()) print(app) @@ -52,6 +52,7 @@ def set_camera_and_display_image( graphics_image_export_settings, image_output_path: Path, image_name: str, + set_fit: bool = False, ) -> None: """Set the camera to fit the model and display the image. @@ -67,9 +68,13 @@ def set_camera_and_display_image( The path to save the exported image. image_name : str The name of the exported image file. + set_fit: bool, Optional + If True, set the camera to fit the mesh. + If False, do not set the camera to fit the mesh. """ - # Set the camera to fit the mesh - camera.SetFit() + if set_fit: + # Set the camera to fit the mesh + camera.SetFit() # Export the mesh image with the specified settings image_path = image_output_path / image_name graphics.ExportImage( @@ -116,13 +121,16 @@ def display_image( # %% -# Configure graphics for image export -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Configure the graphics for image export +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ graphics = app.Graphics camera = graphics.Camera +# Set the camera orientation to isometric view camera.SetSpecificViewOrientation(ViewOrientationType.Iso) + +# Set the image export format and settings image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() settings_720p.Resolution = GraphicsResolutionType.EnhancedResolution @@ -132,18 +140,22 @@ def display_image( settings_720p.CurrentGraphicsDisplay = False # %% -# Download geometry and materials files -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Download the geometry and material files +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Download the geometry file from the ansys/example-data repository geometry_path = download_file("sloshing_geometry.agdb", "pymechanical", "embedding") +# Download the water material file from the ansys/example-data repository mat_path = download_file("Water_material_explicit.xml", "pymechanical", "embedding") - # %% # Import the geometry # ~~~~~~~~~~~~~~~~~~~ +# Define the model model = app.Model + +# Add the geometry import group and set its preferences geometry_import_group = model.GeometryImportGroup geometry_import = geometry_import_group.AddGeometryImport() geometry_import_format = ( @@ -151,12 +163,15 @@ def display_image( ) geometry_import_preferences = Ansys.ACT.Mechanical.Utilities.GeometryImportPreferences() geometry_import_preferences.ProcessNamedSelections = True + +# Import the geometry file with the specified format and preferences geometry_import.Import( geometry_path, geometry_import_format, geometry_import_preferences ) +# Set the camera to fit the model and display the image set_camera_and_display_image( - camera, graphics, settings_720p, output_path, "geometry.png" + camera, graphics, settings_720p, output_path, "geometry.png", set_fit=True ) # %% @@ -170,252 +185,259 @@ def display_image( materials = model.Materials # %% -# Import material setup analysis -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Add modal acoustic analysis and import the material +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Add a modal acoustic analysis to the model model.AddModalAcousticAnalysis() +# Set the unit system to Standard MKS app.ExtAPI.Application.ActiveUnitSystem = MechanicalUnitSystem.StandardMKS +# Import the water material from the specified XML file materials.Import(mat_path) -print("Material Import Done !") # %% -# Get all required named selections and assign materials -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -acst_bodies = [ - i - for i in named_selections.GetChildren[ - Ansys.ACT.Automation.Mechanical.NamedSelection - ](True) - if i.Name == "Acoustic_bodies" -][0] -struct_bodies = [ - i - for i in named_selections.GetChildren[ - Ansys.ACT.Automation.Mechanical.NamedSelection - ](True) - if i.Name == "Structural_bodies" -][0] -top_bodies = [ - i - for i in named_selections.GetChildren[ - Ansys.ACT.Automation.Mechanical.NamedSelection - ](True) - if i.Name == "top_bodies" -][0] -cont_bodies = [ - i - for i in named_selections.GetChildren[ - Ansys.ACT.Automation.Mechanical.NamedSelection - ](True) - if i.Name == "container_bodies" -][0] -cont_V1 = [ - i - for i in named_selections.GetChildren[ - Ansys.ACT.Automation.Mechanical.NamedSelection - ](True) - if i.Name == "Cont_V1" -][0] -cont_V2 = [ - i - for i in named_selections.GetChildren[ - Ansys.ACT.Automation.Mechanical.NamedSelection - ](True) - if i.Name == "Cont_V2" -][0] -cont_V3 = [ - i - for i in named_selections.GetChildren[ - Ansys.ACT.Automation.Mechanical.NamedSelection - ](True) - if i.Name == "Cont_V3" -][0] -cont_face1 = [ - i - for i in named_selections.GetChildren[ - Ansys.ACT.Automation.Mechanical.NamedSelection - ](True) - if i.Name == "Cont_face1" -][0] -cont_face2 = [ - i - for i in named_selections.GetChildren[ - Ansys.ACT.Automation.Mechanical.NamedSelection - ](True) - if i.Name == "Cont_face2" -][0] -cont_face3 = [ - i - for i in named_selections.GetChildren[ - Ansys.ACT.Automation.Mechanical.NamedSelection - ](True) - if i.Name == "Cont_face3" -][0] -cont_face4 = [ - i - for i in named_selections.GetChildren[ - Ansys.ACT.Automation.Mechanical.NamedSelection - ](True) - if i.Name == "Cont_face4" -][0] -free_faces = [ - i - for i in named_selections.GetChildren[ - Ansys.ACT.Automation.Mechanical.NamedSelection - ](True) - if i.Name == "Free_faces" -][0] -fsi_faces = [ - i - for i in named_selections.GetChildren[ - Ansys.ACT.Automation.Mechanical.NamedSelection - ](True) - if i.Name == "FSI_faces" -][0] - -solid1 = [ - i - for i in geometry.GetChildren[Ansys.ACT.Automation.Mechanical.Body](True) - if i.Name == "Solid1" -][0] -solid2 = [ - i - for i in geometry.GetChildren[Ansys.ACT.Automation.Mechanical.Body](True) - if i.Name == "Solid2" -][0] -solid3 = [ - i - for i in geometry.GetChildren[Ansys.ACT.Automation.Mechanical.Body](True) - if i.Name == "Solid3" -][0] -solid4 = [ - i - for i in geometry.GetChildren[Ansys.ACT.Automation.Mechanical.Body](True) - if i.Name == "Solid4" -][0] +# Assign material to solid bodies +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# %% -# Assign material water to acoustic parts +def get_solid_set_material(name: str) -> None: + """Get the solid body by name and assign the material. + + Parameters + ---------- + name : str + The name of the solid body to get. + """ + # Get the solid body by name + solid = [ + i + for i in geometry.GetChildren[Ansys.ACT.Automation.Mechanical.Body](True) + if i.Name == name + ][0] + + # Assign material water to acoustic parts + solid.Material = "WATER" + + +# Assign material water to acoustic parts for solids 1 to 4 +for i in range(1, 5): + solid_name = f"Solid{i}" + get_solid_set_material(solid_name) -solid1.Material = "WATER" -solid2.Material = "WATER" -solid3.Material = "WATER" -solid4.Material = "WATER" # %% -# Mesh -# ~~~~ +# Add mesh methods, sizings, and generate the mesh +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +def get_named_selection(name: str) -> Ansys.ACT.Automation.Mechanical.NamedSelection: + """Get the named selection by name. + + Parameters + ---------- + name : str + The name of the named selection to get. + + Returns + ------- + Ansys.ACT.Automation.Mechanical.NamedSelection + The named selection object. + """ + return [ + child + for child in named_selections.GetChildren[ + Ansys.ACT.Automation.Mechanical.NamedSelection + ](True) + if child.Name == name + ][0] + + +def set_mesh_properties( + mesh_element, + named_selection, + method_type=None, + element_size=None, + behavior=None, +): + """Set the properties for mesh automatic methods and sizings. + + Parameters + ---------- + mesh_element + The mesh element to set properties for. + named_selection : Ansys.ACT.Automation.Mechanical.NamedSelection + The named selection to set the location for the mesh element. + method_type : MethodType, optional + The method type for the mesh (default is None). + element_size : Quantity, optional + The element size for the mesh (default is None). + behavior : SizingBehavior, optional + The sizing behavior for the mesh (default is None). + """ + mesh_element.Location = named_selection + if method_type: + mesh_element.Method = method_type + if element_size: + mesh_element.ElementSize = element_size + if behavior: + mesh_element.Behavior = behavior + +# Set the mesh element order to quadratic mesh.ElementOrder = ElementOrder.Quadratic +# Add an automatic mesh method method1 = mesh.AddAutomaticMethod() -method1.Location = acst_bodies -method1.Method = MethodType.AllTriAllTet +acst_bodies = get_named_selection("Acoustic_bodies") +# Set the automatic method location to the acoustic bodies and the method type to AllTriAllTet +set_mesh_properties(method1, acst_bodies, MethodType.AllTriAllTet) +# Add an automatic mesh method method2 = mesh.AddAutomaticMethod() -method2.Location = top_bodies -method2.Method = MethodType.Automatic +top_bodies = get_named_selection("top_bodies") +# Set the automatic method location to the top bodies and the method type to Automatic +set_mesh_properties(method2, top_bodies, MethodType.Automatic) # Add mesh sizing - sizing1 = mesh.AddSizing() -sizing1.Location = top_bodies -sizing1.ElementSize = Quantity("0.2 [m]") -sizing1.Behavior = SizingBehavior.Hard +# Set the mesh sizing location to the top bodies, the element size to 0.2m, and +# the sizing behavior to hard +set_mesh_properties( + sizing1, top_bodies, element_size=Quantity("0.2 [m]"), behavior=SizingBehavior.Hard +) # Add mesh sizing - sizing2 = mesh.AddSizing() -sizing2.Location = acst_bodies -sizing2.ElementSize = Quantity("0.2 [m]") -sizing2.Behavior = SizingBehavior.Hard - -# Add mesh method +# Set the mesh sizing location to the acoustic bodies, the element size to 0.2m, and +# the sizing behavior to hard +set_mesh_properties( + sizing2, acst_bodies, element_size=Quantity("0.2 [m]"), behavior=SizingBehavior.Hard +) +# Add an automatic mesh method method3 = mesh.AddAutomaticMethod() -method3.Location = cont_bodies -method3.Method = MethodType.Sweep +container_bodies = get_named_selection("container_bodies") +# Set the automatic method location to the container bodies and the method type to Sweep +set_mesh_properties(method3, container_bodies, MethodType.Sweep) +# Set the source target selection to 4 method3.SourceTargetSelection = 4 +# Generate the mesh and display the image mesh.GenerateMesh() - set_camera_and_display_image(camera, graphics, settings_720p, output_path, "mesh.png") # %% -# Insert contacts -# ~~~~~~~~~~~~~~~ -# Contact 1 +# Set up the contact regions in the connection group +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +def set_contact_region_properties( + contact_region, + source_location, + target_location, + contact_formulation=ContactFormulation.MPC, + contact_behavior=ContactBehavior.Asymmetric, + pinball_region=ContactPinballType.Radius, + pinball_radius=Quantity("0.25 [m]"), + set_target_before_src=False, +): + """Set the properties for the contact region. + + Parameters + ---------- + contact_region : Ansys.ACT.Automation.Mechanical.ContactRegion + The contact region to set properties for. + source_location : Ansys.ACT.Automation.Mechanical.NamedSelection + The source location for the contact region. + target_location : Ansys.ACT.Automation.Mechanical.NamedSelection + The target location for the contact region. + contact_formulation : ContactFormulation, optional + The contact formulation for the contact region (default is MPC). + contact_behavior : ContactBehavior, optional + The contact behavior for the contact region (default is Asymmetric). + pinball_region : ContactPinballType, optional + The pinball region type for the contact region (default is Radius). + pinball_radius : Quantity, optional + The pinball radius for the contact region (default is 0.25 m). + set_target_before_src : bool, optional + Whether to set the target location before the source location (default is False). + """ + # If the target location is set before the source location + if set_target_before_src: + contact_region.TargetLocation = get_named_selection(target_location) + contact_region.SourceLocation = source_location + else: + contact_region.SourceLocation = get_named_selection(source_location) + contact_region.TargetLocation = get_named_selection(target_location) + contact_region.ContactFormulation = contact_formulation + contact_region.Behavior = contact_behavior + contact_region.PinballRegion = pinball_region + contact_region.PinballRadius = pinball_radius + + +# Add a connection group to the model connection_group = connections.AddConnectionGroup() -contact_region_1 = connection_group.AddContactRegion() -contact_region_1.SourceLocation = cont_V1 -contact_region_1.TargetLocation = cont_face1 -contact_region_1.ContactFormulation = ContactFormulation.MPC -contact_region_1.Behavior = ContactBehavior.Asymmetric -contact_region_1.PinballRegion = ContactPinballType.Radius -contact_region_1.PinballRadius = Quantity("0.25 [m]") -# %% -# Contact 2 +# Add the first contact region to the connection group +contact_region_1 = connection_group.AddContactRegion() +# Set the source location to the Cont_V1 named selection and the target location to the Cont_face1 +# named selection +set_contact_region_properties(contact_region_1, "Cont_V1", "Cont_face1") +# Add the second contact region to the connection group contact_region_2 = connection_group.AddContactRegion() -contact_region_2.SourceLocation = cont_V2 -contact_region_2.TargetLocation = cont_face2 -contact_region_2.ContactFormulation = ContactFormulation.MPC -contact_region_2.Behavior = ContactBehavior.Asymmetric -contact_region_2.PinballRegion = ContactPinballType.Radius -contact_region_2.PinballRadius = Quantity("0.25 [m]") - -# %% -# Contact 3 +# Set the source location to the Cont_V2 named selection and the target location to the Cont_face2 +# named selection +set_contact_region_properties(contact_region_2, "Cont_V2", "Cont_face2") +# Add the third contact region to the connection group contact_region_3 = connection_group.AddContactRegion() -contact_region_3.SourceLocation = cont_V3 -contact_region_3.TargetLocation = cont_face3 -contact_region_3.ContactFormulation = ContactFormulation.MPC -contact_region_3.Behavior = ContactBehavior.Asymmetric -contact_region_3.PinballRegion = ContactPinballType.Radius -contact_region_3.PinballRadius = Quantity("0.25 [m]") - -# %% -# Contact 3 +# Set the source location to the Cont_V3 named selection and the target location to the Cont_face3 +# named selection +set_contact_region_properties(contact_region_3, "Cont_V3", "Cont_face3") +# Set the selection manager sel_manager = app.ExtAPI.SelectionManager -cnv4 = DataModel.GeoData.Assemblies[0].Parts[1].Bodies[0].Vertices[3] -cont_V4 = sel_manager.CreateSelectionInfo(SelectionTypeEnum.GeometryEntities) -cont_V4.Entities = [cnv4] - -# %% -# Contact 4 - +# Get the contact vertex from the geometry +contact_vertex = DataModel.GeoData.Assemblies[0].Parts[1].Bodies[0].Vertices[3] +# Create a selection info object for the contact vertex +contact_vertex_4 = sel_manager.CreateSelectionInfo(SelectionTypeEnum.GeometryEntities) +# Set the contact vertex as the selected entity +contact_vertex_4.Entities = [contact_vertex] + +# Add the fourth contact region to the connection group contact_region_4 = connection_group.AddContactRegion() -contact_region_4.TargetLocation = cont_face4 -contact_region_4.SourceLocation = cont_V4 -contact_region_4.ContactFormulation = ContactFormulation.MPC -contact_region_4.Behavior = ContactBehavior.Asymmetric -contact_region_4.PinballRegion = ContactPinballType.Radius -contact_region_4.PinballRadius = Quantity("0.25 [m]") +# Set the target location to the contact vertex and the source location to the Cont_face4 +# named selection +set_contact_region_properties( + contact_region_4, contact_vertex_4, "Cont_face4", set_target_before_src=True +) # %% -# Fully define Modal Multiphysics region with two physics regions +# Fully define the modal multiphysics region with two physics regions +# Get the modal acoustic analysis object modal_acst = DataModel.Project.Model.Analyses[0] +# Get the acoustic region from the modal acoustic analysis acoustic_region = modal_acst.Children[2] +# Set the acoustic region to the acoustic bodies named selection acoustic_region.Location = acst_bodies - +# Add a physics region to the modal acoustic analysis structural_region = modal_acst.AddPhysicsRegion() +# Set the physics region to structural and rename it based on the definition structural_region.Structural = True structural_region.RenameBasedOnDefinition() -structural_region.Location = struct_bodies - +# Set the structural region to the structural bodies named selection +structural_region.Location = get_named_selection("Structural_bodies") # %% -# Analysis settings -# ~~~~~~~~~~~~~~~~~ +# Set up the analysis settings +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Get the analysis settings from the modal acoustic analysis analysis_settings = modal_acst.Children[1] +# Set the analysis settings properties analysis_settings.MaximumModesToFind = 12 analysis_settings.SearchRangeMinimum = Quantity("0.1 [Hz]") analysis_settings.SolverType = SolverType.Unsymmetric @@ -423,96 +445,98 @@ def display_image( analysis_settings.CalculateReactions = True # %% -# Boundary conditions and load -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Free surface +# Set the boundary conditions and load +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Add an acoustic free surface to the modal acoustic analysis free_surface = modal_acst.AddAcousticFreeSurface() -free_surface.Location = free_faces +# Set the free surface location to the free faces named selection +free_surface.Location = get_named_selection("Free_faces") # %% -# Solid fluid interface +# Add the solid fluid interface +# Add a fluid solid interface to the modal acoustic analysis fsi_object = modal_acst.AddFluidSolidInterface() -fsi_object.Location = fsi_faces +# Set the fluid solid interface location to the FSI faces named selection +fsi_object.Location = get_named_selection("FSI_faces") # %% -# Gravity +# Add the gravity load +# Add gravity to the modal acoustic analysis acceleration = modal_acst.AddAcceleration() +# Set the components and the Y-component of the acceleration to +# 9.81 m/s^2 (gravitational acceleration) acceleration.DefineBy = LoadDefineBy.Components acceleration.YComponent.Output.DiscreteValues = [Quantity("9.81 [m sec^-1 sec^-1]")] # %% -# Fixed Support +# Add fixed support -fv1 = DataModel.GeoData.Assemblies[0].Parts[1].Bodies[0].Vertices[0] -fv2 = DataModel.GeoData.Assemblies[0].Parts[1].Bodies[1].Vertices[0] -fv3 = DataModel.GeoData.Assemblies[0].Parts[1].Bodies[2].Vertices[0] -fv4 = DataModel.GeoData.Assemblies[0].Parts[1].Bodies[3].Vertices[0] +# Get vertices from the geometry +vertices = [] +for body in range(0, 4): + vertices.append(DataModel.GeoData.Assemblies[0].Parts[1].Bodies[body].Vertices[0]) +# Create a selection info object for the geometry entities fvert = sel_manager.CreateSelectionInfo(SelectionTypeEnum.GeometryEntities) -fvert.Entities = [fv1, fv2, fv3, fv4] +# Set the list of vertices as the geometry entities +fvert.Entities = vertices + +# Add a fixed support to the modal acoustic analysis fixed_support = modal_acst.AddFixedSupport() +# Set the location of the fixed support to the geometry entities fixed_support.Location = fvert +# Activate the modal acoustic analysis and display the image modal_acst.Activate() - set_camera_and_display_image( camera, graphics, settings_720p, output_path, "geometry.png" ) # %% -# Add results -# ~~~~~~~~~~~ -# Add 10 modes - -soln = model.Analyses[0].Solution -total_deformation_1 = soln.AddTotalDeformation() -total_deformation_2 = soln.AddTotalDeformation() -total_deformation_2.Mode = 2 -total_deformation_3 = soln.AddTotalDeformation() -total_deformation_3.Mode = 3 -total_deformation_4 = soln.AddTotalDeformation() -total_deformation_4.Mode = 4 -total_deformation_5 = soln.AddTotalDeformation() -total_deformation_5.Mode = 5 -total_deformation_6 = soln.AddTotalDeformation() -total_deformation_6.Mode = 6 -total_deformation_7 = soln.AddTotalDeformation() -total_deformation_7.Mode = 7 -total_deformation_8 = soln.AddTotalDeformation() -total_deformation_8.Mode = 8 -total_deformation_9 = soln.AddTotalDeformation() -total_deformation_9.Mode = 9 -total_deformation_10 = soln.AddTotalDeformation() -total_deformation_10.Mode = 10 +# Add results to the solution +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Get the solution object from the modal acoustic analysis +solution = model.Analyses[0].Solution + +# Add 10 total deformation results, setting the mode for every result except the first +total_deformation_results = [] +for mode in range(1, 11): + total_deformation = solution.AddTotalDeformation() + if mode > 1: + total_deformation.Mode = mode + total_deformation_results.append(total_deformation) # %% -# Add acoustic pressure +# Add the acoustic pressure result to the solution -acoustic_pressure_result = soln.AddAcousticPressureResult() +acoustic_pressure_result = solution.AddAcousticPressureResult() # %% -# Add force reaction scoped to fixed Support +# Scope the force reaction to the fixed Support -force_reaction_1 = soln.AddForceReaction() +# Add a force reaction to the solution +force_reaction_1 = solution.AddForceReaction() +# Set the boundary condition selection to the fixed support force_reaction_1.BoundaryConditionSelection = fixed_support # %% -# Solve -# ~~~~~ +# Solve the solution +# ~~~~~~~~~~~~~~~~~~ -soln.Solve(True) +solution.Solve(True) # sphinx_gallery_start_ignore -assert soln.Status == SolutionStatusType.Done, "Solution status is not 'Done'" +assert solution.Status == SolutionStatusType.Done, "Solution status is not 'Done'" # sphinx_gallery_end_ignore # %% -# Messages -# ~~~~~~~~ +# Print messages +# ~~~~~~~~~~~~~~ messages = app.ExtAPI.Application.Messages if messages: @@ -523,17 +547,19 @@ def display_image( # %% -# Results -# ~~~~~~~ -# Total deformation - mode 1 +# Display the results +# ~~~~~~~~~~~~~~~~~~~ -app.Tree.Activate([total_deformation_1]) +# %% +# Activate the first total deformation result and display the image + +app.Tree.Activate([total_deformation_results[0]]) set_camera_and_display_image( - camera, graphics, settings_720p, output_path, "total_deformation.png" + camera, graphics, settings_720p, output_path, "total_deformation.png", set_fit=True ) # %% -# Acoustic pressure +# Activate the acoustic pressure result and display the image app.Tree.Activate([acoustic_pressure_result]) set_camera_and_display_image( @@ -541,55 +567,48 @@ def display_image( ) # %% -# Display all modal frequency, force reaction -# and acoustic pressure values - -frequency_1 = total_deformation_1.ReportedFrequency.Value -frequency_2 = total_deformation_2.ReportedFrequency.Value -frequency_3 = total_deformation_3.ReportedFrequency.Value -frequency_4 = total_deformation_4.ReportedFrequency.Value -frequency_5 = total_deformation_5.ReportedFrequency.Value -frequency_6 = total_deformation_6.ReportedFrequency.Value -frequency_7 = total_deformation_7.ReportedFrequency.Value -frequency_8 = total_deformation_8.ReportedFrequency.Value -frequency_9 = total_deformation_9.ReportedFrequency.Value -frequency_10 = total_deformation_10.ReportedFrequency.Value +# Display all modal frequency, force reaction, and acoustic pressure values + +print("Modal Acoustic Results") +print("----------------------") +# Print the frequency values for each mode +for result in total_deformation_results: + frequency_value = result.ReportedFrequency.Value + print(f"Frequency for mode {i}: ", frequency_value) + +# Get the maximum and minimum values of the acoustic pressure result pressure_result_max = acoustic_pressure_result.Maximum.Value pressure_result_min = acoustic_pressure_result.Minimum.Value +# Get the force reaction values for the x and z axes force_reaction_1_x = force_reaction_1.XAxis.Value force_reaction_1_z = force_reaction_1.ZAxis.Value -print("Modal Acoustic Results") -print("----------------------") -print("Frequency for mode 1 : ", frequency_1) -print("Frequency for mode 2 : ", frequency_2) -print("Frequency for mode 3 : ", frequency_3) -print("Frequency for mode 4 : ", frequency_4) -print("Frequency for mode 5 : ", frequency_5) -print("Frequency for mode 6 : ", frequency_6) -print("Frequency for mode 7 : ", frequency_7) -print("Frequency for mode 8 : ", frequency_8) -print("Frequency for mode 9 : ", frequency_9) -print("Frequency for mode 10 : ", frequency_10) +# Print the results print("Acoustic pressure minimum : ", pressure_result_min) print("Acoustic pressure Maximum : ", pressure_result_max) print("Force reaction x-axis : ", force_reaction_1_x) print("Force reaction z-axis : ", force_reaction_1_z) # %% -# Total deformation animation for mode 10 +# Play the total deformation animation for mode 10 +# Set the animation export format to GIF animation_export_format = ( Ansys.Mechanical.DataModel.Enums.GraphicsAnimationExportFormat.GIF ) + +# Set the export settings for the animation settings_720p = Ansys.Mechanical.Graphics.AnimationExportSettings() settings_720p.Width = 1280 settings_720p.Height = 720 -deformation_gif = output_path / "total_deformation_10.gif" -total_deformation_10.ExportAnimation( +# Export the total deformation animation for the last result +deformation_gif = ( + output_path / f"total_deformation_{len(total_deformation_results)}.gif" +) +total_deformation_results[-1].ExportAnimation( str(deformation_gif), animation_export_format, settings_720p ) @@ -638,21 +657,21 @@ def update_animation(frame: int) -> list[mpimg.AxesImage]: plt.show() # %% -# Project tree -# ~~~~~~~~~~~~ +# Print the project tree +# ~~~~~~~~~~~~~~~~~~~~~~ app.print_tree() # %% -# Cleanup -# ~~~~~~~ -# Save project +# Clean up the downloaded files and app +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Save the project file mechdat_file = output_path / "modal_acoustics.mechdat" app.save(str(mechdat_file)) -app.new() -# %% -# Delete example file +# Refresh the app +app.new() +# Delete example files delete_downloads() diff --git a/examples/01_basic/steady_state_thermal_analysis.py b/examples/01_basic/steady_state_thermal_analysis.py index 5e6db0b0..bd53102a 100644 --- a/examples/01_basic/steady_state_thermal_analysis.py +++ b/examples/01_basic/steady_state_thermal_analysis.py @@ -29,7 +29,7 @@ import Ansys # %% -# Embed mechanical and set global variables +# Create an instance of the Mechanical embedded application app = App(globals=globals()) print(app) diff --git a/examples/01_basic/topology_optimization_cantilever_beam.py b/examples/01_basic/topology_optimization_cantilever_beam.py index 17873673..7caa12fe 100644 --- a/examples/01_basic/topology_optimization_cantilever_beam.py +++ b/examples/01_basic/topology_optimization_cantilever_beam.py @@ -26,7 +26,7 @@ import Ansys # %% -# Embed Mechanical and set global variables +# Create an instance of the Mechanical embedded application app = App(globals=globals()) print(app) diff --git a/examples/01_basic/valve.py b/examples/01_basic/valve.py index 9482f50e..b003777a 100644 --- a/examples/01_basic/valve.py +++ b/examples/01_basic/valve.py @@ -24,7 +24,7 @@ import Ansys # %% -# Embed mechanical and set global variables +# Create an instance of the Mechanical embedded application app = App(globals=globals()) print(app) diff --git a/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py b/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py index 45d90302..87844632 100644 --- a/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py +++ b/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py @@ -59,7 +59,7 @@ import Ansys # %% -# Embed mechanical and set global variables +# Create an instance of the Mechanical embedded application app = App(globals=globals()) print(app) @@ -181,7 +181,7 @@ def display_image( camera.SetSpecificViewOrientation(ViewOrientationType.Iso) camera.SetFit() -image_export_format = Ansys.Mechanical.DataModel.Enums.GraphicsImageExportFormat.PNG +image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() settings_720p.Resolution = ( Ansys.Mechanical.DataModel.Enums.GraphicsResolutionType.EnhancedResolution diff --git a/examples/02_technology_showcase/conact_wear_simulation.py b/examples/02_technology_showcase/conact_wear_simulation.py index cfda2a56..7e8515ab 100644 --- a/examples/02_technology_showcase/conact_wear_simulation.py +++ b/examples/02_technology_showcase/conact_wear_simulation.py @@ -39,7 +39,7 @@ import Ansys # %% -# Embed mechanical and set global variables +# Create an instance of the Mechanical embedded application app = App(globals=globals()) print(app) diff --git a/examples/02_technology_showcase/non_linear_analysis_rubber_boot_seal.py b/examples/02_technology_showcase/non_linear_analysis_rubber_boot_seal.py index 380896d6..f88ba398 100644 --- a/examples/02_technology_showcase/non_linear_analysis_rubber_boot_seal.py +++ b/examples/02_technology_showcase/non_linear_analysis_rubber_boot_seal.py @@ -32,7 +32,7 @@ import Ansys # %% -# Embed mechanical and set global variables +# Create an instance of the Mechanical embedded application app = App(globals=globals()) print(app) From 58a5cde8744f379165b18487ff4d811b6b2f3f82 Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Wed, 30 Apr 2025 14:57:59 -0400 Subject: [PATCH 14/24] add comments to examples --- examples/01_basic/modal_acoustics_analysis.py | 4 +- .../01_basic/steady_state_thermal_analysis.py | 477 ++++++++++++------ 2 files changed, 313 insertions(+), 168 deletions(-) diff --git a/examples/01_basic/modal_acoustics_analysis.py b/examples/01_basic/modal_acoustics_analysis.py index c57bbdac..fb5035e0 100644 --- a/examples/01_basic/modal_acoustics_analysis.py +++ b/examples/01_basic/modal_acoustics_analysis.py @@ -663,7 +663,7 @@ def update_animation(frame: int) -> list[mpimg.AxesImage]: app.print_tree() # %% -# Clean up the downloaded files and app +# Clean up the app and downloaded files # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Save the project file @@ -673,5 +673,5 @@ def update_animation(frame: int) -> list[mpimg.AxesImage]: # Refresh the app app.new() -# Delete example files +# Delete the example files delete_downloads() diff --git a/examples/01_basic/steady_state_thermal_analysis.py b/examples/01_basic/steady_state_thermal_analysis.py index bd53102a..a6aaa749 100644 --- a/examples/01_basic/steady_state_thermal_analysis.py +++ b/examples/01_basic/steady_state_thermal_analysis.py @@ -118,8 +118,11 @@ def display_image( graphics = app.Graphics camera = graphics.Camera +# Set the camera orientation to isometric view 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 = GraphicsResolutionType.EnhancedResolution @@ -128,19 +131,21 @@ def display_image( settings_720p.Height = 720 settings_720p.CurrentGraphicsDisplay = False - # %% -# Download and import geometry -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Download the geometry file. +# Download the geometry file +# ~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Download the geometry file from the ansys/example-data repository geometry_path = download_file("LONGBAR.x_t", "pymechanical", "embedding") # %% # Import the geometry +# ~~~~~~~~~~~~~~~~~~~ +# Define the model model = app.Model +# Add the geometry import group and set its preferences geometry_import_group = model.GeometryImportGroup geometry_import = geometry_import_group.AddGeometryImport() geometry_import_format = ( @@ -148,21 +153,31 @@ def display_image( ) geometry_import_preferences = Ansys.ACT.Mechanical.Utilities.GeometryImportPreferences() geometry_import_preferences.ProcessNamedSelections = True + +# Import the geometry file with the specified format and preferences geometry_import.Import( geometry_path, geometry_import_format, geometry_import_preferences ) +# Visualize the model in 3D app.plot() - # %% # Add steady state thermal analysis # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Add a steady state thermal analysis to the model model.AddSteadyStateThermalAnalysis() +# Set the Mechanical unit system to Standard MKS app.ExtAPI.Application.ActiveUnitSystem = MechanicalUnitSystem.StandardMKS + +# Get the steady state thermal analysis stat_therm = model.Analyses[0] + +# Add a coordinate system to the model coordinate_systems = model.CoordinateSystems + +# Add two coordinate systems lcs1 = coordinate_systems.AddCoordinateSystem() lcs1.OriginX = Quantity("0 [m]") @@ -173,172 +188,274 @@ def display_image( # %% # Create named selections and construction geometry # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Create named selections - -face1 = model.AddNamedSelection() -face1.ScopingMethod = GeometryDefineByType.Worksheet -face1.Name = "Face1" -gen_crt1 = face1.GenerationCriteria -crt1 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() -crt1.Active = True -crt1.Action = SelectionActionType.Add -crt1.EntityType = SelectionType.GeoFace -crt1.Criterion = SelectionCriterionType.LocationZ -crt1.Operator = SelectionOperatorType.Equal -crt1.Value = Quantity("20 [m]") -gen_crt1.Add(crt1) + + +def setup_named_selection(name, scoping_method=GeometryDefineByType.Worksheet): + """Create a named selection with the specified scoping method and name. + + Parameters + ---------- + name : str + The name of the named selection. + scoping_method : GeometryDefineByType + The scoping method for the named selection. + + Returns + ------- + Ansys.ACT.Automation.Mechanical.NamedSelection + The created named selection. + """ + ns = model.AddNamedSelection() + ns.ScopingMethod = scoping_method + ns.Name = name + return ns + + +def add_generation_criteria( + named_selection, + value, + set_active_action_criteria=True, + active=True, + action=SelectionActionType.Add, + entity_type=SelectionType.GeoFace, + criterion=SelectionCriterionType.Size, + operator=SelectionOperatorType.Equal, +): + """Add generation criteria to the named selection. + + Parameters + ---------- + named_selection : Ansys.ACT.Automation.Mechanical.NamedSelection + The named selection to which the criteria will be added. + value : Quantity + The value for the criteria. + active : bool + Whether the criteria is active. + action : SelectionActionType + The action type for the criteria. + entity_type : SelectionType + The entity type for the criteria. + criterion : SelectionCriterionType + The criterion type for the criteria. + operator : SelectionOperatorType + The operator for the criteria. + """ + generation_criteria = named_selection.GenerationCriteria + criteria = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() + + set_criteria_properties( + criteria, + value, + set_active_action_criteria, + active, + action, + entity_type, + criterion, + operator, + ) + + if set_active_action_criteria: + generation_criteria.Add(criteria) + + +def set_criteria_properties( + criteria, + value, + set_active_action_criteria=True, + active=True, + action=SelectionActionType.Add, + entity_type=SelectionType.GeoFace, + criterion=SelectionCriterionType.Size, + operator=SelectionOperatorType.Equal, +): + """Set the properties of the generation criteria. + + Parameters + ---------- + criteria : Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion + The generation criteria to set properties for. + active : bool + Whether the criteria is active. + action : SelectionActionType + The action type for the criteria. + entity_type : SelectionType + The entity type for the criteria. + criterion : SelectionCriterionType + The criterion type for the criteria. + operator : SelectionOperatorType + The operator for the criteria. + """ + if set_active_action_criteria: + criteria.Active = active + criteria.Action = action + + criteria.EntityType = entity_type + criteria.Criterion = criterion + criteria.Operator = operator + criteria.Value = value + + return criteria + + +# Add a named selection to the model +face1 = setup_named_selection("Face1") +add_generation_criteria( + face1, Quantity("20 [m]"), criterion=SelectionCriterionType.LocationZ +) face1.Activate() face1.Generate() -face2 = model.AddNamedSelection() -face2.ScopingMethod = GeometryDefineByType.Worksheet -face2.Name = "Face2" -gen_crt2 = face2.GenerationCriteria -crt1 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() -crt1.Active = True -crt1.Action = SelectionActionType.Add -crt1.EntityType = SelectionType.GeoFace -crt1.Criterion = SelectionCriterionType.LocationZ -crt1.Operator = SelectionOperatorType.Equal -crt1.Value = Quantity("0 [m]") -gen_crt2.Add(crt1) +face2 = setup_named_selection("Face2") +add_generation_criteria( + face2, Quantity("0 [m]"), criterion=SelectionCriterionType.LocationZ +) face2.Activate() face2.Generate() -face3 = model.AddNamedSelection() -face3.ScopingMethod = GeometryDefineByType.Worksheet -face3.Name = "Face3" -gen_crt3 = face3.GenerationCriteria -crt1 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() -crt1.Active = True -crt1.Action = SelectionActionType.Add -crt1.EntityType = SelectionType.GeoFace -crt1.Criterion = SelectionCriterionType.LocationX -crt1.Operator = SelectionOperatorType.Equal -crt1.Value = Quantity("1 [m]") -gen_crt3.Add(crt1) -crt2 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() -crt2.Active = True -crt2.Action = SelectionActionType.Filter -crt2.EntityType = SelectionType.GeoFace -crt2.Criterion = SelectionCriterionType.LocationY -crt2.Operator = SelectionOperatorType.Equal -crt2.Value = Quantity("2 [m]") -gen_crt3.Add(crt2) -crt3 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() -crt3.Active = True -crt3.Action = SelectionActionType.Filter -crt3.EntityType = SelectionType.GeoFace -crt3.Criterion = SelectionCriterionType.LocationZ -crt3.Operator = SelectionOperatorType.Equal -crt3.Value = Quantity("12 [m]") -gen_crt3.Add(crt3) -crt4 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() -crt4.Active = True -crt4.Action = SelectionActionType.Add -crt4.EntityType = SelectionType.GeoFace -crt4.Criterion = SelectionCriterionType.LocationZ -crt4.Operator = SelectionOperatorType.Equal -crt4.Value = Quantity("4.5 [m]") -gen_crt3.Add(crt4) -crt5 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() -crt5.Active = True -crt5.Action = SelectionActionType.Filter -crt5.EntityType = SelectionType.GeoFace -crt5.Criterion = SelectionCriterionType.LocationY -crt5.Operator = SelectionOperatorType.Equal -crt5.Value = Quantity("2 [m]") -gen_crt3.Add(crt5) +face3 = setup_named_selection("Face3") +add_generation_criteria( + face3, Quantity("1 [m]"), criterion=SelectionCriterionType.LocationX +) +add_generation_criteria( + face3, + Quantity("2 [m]"), + criterion=SelectionCriterionType.LocationY, + action=SelectionActionType.Filter, +) +add_generation_criteria( + face3, + Quantity("12 [m]"), + criterion=SelectionCriterionType.LocationZ, + action=SelectionActionType.Filter, +) +add_generation_criteria( + face3, Quantity("4.5 [m]"), criterion=SelectionCriterionType.LocationZ +) +add_generation_criteria( + face3, + Quantity("2 [m]"), + criterion=SelectionCriterionType.LocationY, + action=SelectionActionType.Filter, +) face3.Activate() face3.Generate() -body1 = model.AddNamedSelection() -body1.ScopingMethod = GeometryDefineByType.Worksheet -body1.Name = "Body1" +body1 = setup_named_selection("Body1") body1.GenerationCriteria.Add(None) -body1.GenerationCriteria[0].EntityType = SelectionType.GeoFace -body1.GenerationCriteria[0].Criterion = SelectionCriterionType.LocationZ -body1.GenerationCriteria[0].Operator = SelectionOperatorType.Equal -body1.GenerationCriteria[0].Value = Quantity("1 [m]") +set_criteria_properties( + body1.GenerationCriteria[0], + Quantity("1 [m]"), + set_active_action_criteria=False, + criterion=SelectionCriterionType.LocationZ, +) body1.GenerationCriteria.Add(None) -body1.GenerationCriteria[1].EntityType = SelectionType.GeoFace -body1.GenerationCriteria[1].Criterion = SelectionCriterionType.LocationZ -body1.GenerationCriteria[1].Operator = SelectionOperatorType.Equal -body1.GenerationCriteria[1].Value = Quantity("1 [m]") +set_criteria_properties( + body1.GenerationCriteria[1], + Quantity("1 [m]"), + set_active_action_criteria=False, + criterion=SelectionCriterionType.LocationZ, +) body1.Generate() # %% # Create construction geometry +# Add construction geometry to the model construction_geometry = model.AddConstructionGeometry() -Path = construction_geometry.AddPath() -Path.StartYCoordinate = Quantity(2, "m") -Path.StartZCoordinate = Quantity(20, "m") -Path.StartZCoordinate = Quantity(20, "m") -Path.EndXCoordinate = Quantity(2, "m") +# Add a path to the construction geometry +construction_geom_path = construction_geometry.AddPath() + +# Set the coordinate system for the construction geometry path +construction_geom_path.StartYCoordinate = Quantity(2, "m") +construction_geom_path.StartZCoordinate = Quantity(20, "m") +construction_geom_path.StartZCoordinate = Quantity(20, "m") +construction_geom_path.EndXCoordinate = Quantity(2, "m") + +# Add a surface to the construction geometry surface = construction_geometry.AddSurface() +# Set the coordinate system for the surface surface.CoordinateSystem = lcs2 +# Update the solids in the construction geometry construction_geometry.UpdateAllSolids() # %% -# Define boundary condition and add results -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Add temperature boundary conditions +# Define the boundary condition and add results +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +def set_loc_and_output(temp, location, values): + """Add a temperature set output to the boundary condition. + + Parameters + ---------- + temp : Ansys.Mechanical.DataModel.SteadyStateThermal.Temperature + The temperature boundary condition. + location : Ansys.Mechanical.DataModel.Geometry.GeometryObject + The location of the temperature boundary condition. + values : list[Quantity] + The list of values for the temperature. + """ + temp.Location = location + temp.Magnitude.Output.DiscreteValues = [Quantity(value) for value in values] + + +def set_inputs_and_outputs( + condition, + input_quantities: list = ["0 [sec]", "1 [sec]", "2 [sec]"], + output_quantities: list = ["22[C]", "30[C]", "40[C]"], +): + """Set the temperature inputs for the boundary condition. + Parameters + ---------- + condition : Ansys.Mechanical.DataModel.SteadyStateThermal.Temperature + The temperature boundary condition. + inputs : list[Quantity] + The list of input values for the temperature. + """ + # Set the magnitude for temperature or the ambient temperature for radiation + if "Temperature" in str(type(condition)): + prop = condition.Magnitude + elif "Radiation" in str(type(condition)): + prop = condition.AmbientTemperature + + # Set the inputs and outputs for the temperature or radiation + prop.Inputs[0].DiscreteValues = [Quantity(value) for value in input_quantities] + prop.Output.DiscreteValues = [Quantity(value) for value in output_quantities] + + +# Add temperature boundary conditions to the steady state thermal analysis temp = stat_therm.AddTemperature() -temp.Location = face1 -temp.Magnitude.Output.DiscreteValues = [Quantity("22[C]"), Quantity("30[C]")] +set_loc_and_output(temp, face1, ["22[C]", "30[C]"]) +# Add temperature boundary conditions to the steady state thermal analysis temp2 = stat_therm.AddTemperature() -temp2.Location = face2 -temp2.Magnitude.Output.DiscreteValues = [Quantity("22[C]"), Quantity("60[C]")] - -temp.Magnitude.Inputs[0].DiscreteValues = [ - Quantity("0 [sec]"), - Quantity("1 [sec]"), - Quantity("2 [sec]"), -] -temp.Magnitude.Output.DiscreteValues = [ - Quantity("22[C]"), - Quantity("30[C]"), - Quantity("40[C]"), -] - -temp2.Magnitude.Inputs[0].DiscreteValues = [ - Quantity("0 [sec]"), - Quantity("1 [sec]"), - Quantity("2 [sec]"), -] -temp2.Magnitude.Output.DiscreteValues = [ - Quantity("22[C]"), - Quantity("50[C]"), - Quantity("80[C]"), -] +set_loc_and_output(temp2, face2, ["22[C]", "60[C]"]) + +# Set the temperature inputs and outputs for temp +set_inputs_and_outputs(temp) + +# Set the temperature inputs and outputs for temp2 +set_inputs_and_outputs(temp2, output_quantities=["22[C]", "50[C]", "80[C]"]) # %% # Add radiation +# Add a radiation boundary condition to the steady state thermal analysis radiation = stat_therm.AddRadiation() radiation.Location = face3 -radiation.AmbientTemperature.Inputs[0].DiscreteValues = [ - Quantity("0 [sec]"), - Quantity("1 [sec]"), - Quantity("2 [sec]"), -] -radiation.AmbientTemperature.Output.DiscreteValues = [ - Quantity("22[C]"), - Quantity("30[C]"), - Quantity("40[C]"), -] +set_inputs_and_outputs(radiation) radiation.Correlation = RadiationType.SurfaceToSurface # %% -# Analysis settings +# Set up the analysis settings +# Set the analysis settings for the steady state thermal analysis analysis_settings = stat_therm.AnalysisSettings analysis_settings.NumberOfSteps = 2 analysis_settings.CalculateVolumeEnergy = True +# Activate the static thermal analysis and display the image stat_therm.Activate() set_camera_and_display_image( camera, graphics, settings_720p, output_path, "bc_steady_state.png" @@ -349,65 +466,89 @@ def display_image( # ~~~~~~~~~~~ # Temperature +# Get the solution object for the steady state thermal analysis stat_therm_soln = model.Analyses[0].Solution + +# Add four temperature results to the solution temp_rst = stat_therm_soln.AddTemperature() temp_rst.By = SetDriverStyle.MaximumOverTime +# Set the temperature location to the body1 named selection temp_rst2 = stat_therm_soln.AddTemperature() temp_rst2.Location = body1 +# Set the temperature location to the construction geometry path temp_rst3 = stat_therm_soln.AddTemperature() -temp_rst3.Location = Path +temp_rst3.Location = construction_geom_path +# Set the temperaature location to the construction geometry surface temp_rst4 = stat_therm_soln.AddTemperature() temp_rst4.Location = surface # %% -# Total and directional heat flux +# Add the total and directional heat flux to the solution total_heat_flux = stat_therm_soln.AddTotalHeatFlux() directional_heat_flux = stat_therm_soln.AddTotalHeatFlux() + +# Set the thermal result type and normal orientation for the directional heat flux directional_heat_flux.ThermalResultType = TotalOrDirectional.Directional directional_heat_flux.NormalOrientation = NormalOrientationType.ZAxis +# Set the coordinate system's primary axis for the directional heat flux lcs2.PrimaryAxisDefineBy = CoordinateSystemAlignmentType.GlobalZ directional_heat_flux.CoordinateSystem = lcs2 + +# Set the display option for the directional heat flux directional_heat_flux.DisplayOption = ResultAveragingType.Averaged # %% -# Thermal error +# Add thermal error and temperature probes +# Add a thermal error to the solution thermal_error = stat_therm_soln.AddThermalError() -# %% -# Temperature probe - +# Add a temperature probe to the solution temp_probe = stat_therm_soln.AddTemperatureProbe() + +# Set the temperature probe location to the face1 named selection temp_probe.GeometryLocation = face1 + +# Set the temperature probe location method to the coordinate system temp_probe.LocationMethod = LocationDefinitionMethod.CoordinateSystem temp_probe.CoordinateSystemSelection = lcs2 # %% -# Heat flux probe +# Add a heat flux probe hflux_probe = stat_therm_soln.AddHeatFluxProbe() + +# Set the location method for the heat flux probe hflux_probe.LocationMethod = LocationDefinitionMethod.CoordinateSystem +# Set the coordinate system for the heat flux probe hflux_probe.CoordinateSystemSelection = lcs2 +# Set the result selection to the z-axis for the heat flux probe hflux_probe.ResultSelection = ProbeDisplayFilter.ZAxis # %% -# Reaction probe +# Add a reaction probe +# Update the analysis settings to allow output control nodal forces analysis_settings.NodalForces = OutputControlsNodalForcesType.Yes + +# Add a reaction probe to the solution reaction_probe = stat_therm_soln.AddReactionProbe() +# Set the reaction probe geometry location to the face1 named selection reaction_probe.LocationMethod = LocationDefinitionMethod.GeometrySelection reaction_probe.GeometryLocation = face1 # %% -# Radiation probe +# Add a radiation probe radiation_probe = stat_therm_soln.AddRadiationProbe() +# Set the radiation probe boundary condition to the radiation boundary condition radiation_probe.BoundaryConditionSelection = radiation +# Display all results for the radiation probe radiation_probe.ResultSelection = ProbeDisplayFilter.All @@ -415,6 +556,7 @@ def display_image( # Solve # ~~~~~ +# Solve the steady state thermal analysis solution stat_therm_soln.Solve(True) # sphinx_gallery_start_ignore @@ -424,8 +566,8 @@ def display_image( # sphinx_gallery_end_ignore # %% -# Messages -# ~~~~~~~~ +# Print messages +# ~~~~~~~~~~~~~~ messages = app.ExtAPI.Application.Messages if messages: @@ -436,8 +578,8 @@ def display_image( # Display results # ~~~~~~~~~~~~~~~ -# Total body temperature +# Activate the total body temperature and display the image app.Tree.Activate([temp_rst]) set_camera_and_display_image( camera, graphics, settings_720p, output_path, "total_body_temp.png" @@ -446,6 +588,7 @@ def display_image( # %% # Temperature on part of the body +# Activate the temperature on part of the body and display the image app.Tree.Activate([temp_rst2]) set_camera_and_display_image( camera, graphics, settings_720p, output_path, "part_temp_body.png" @@ -454,6 +597,7 @@ def display_image( # %% # Temperature distribution along the specific path +# Activate the temperature distribution along the specific path and display the image app.Tree.Activate([temp_rst3]) set_camera_and_display_image( camera, graphics, settings_720p, output_path, "path_temp_distribution.png" @@ -462,17 +606,20 @@ def display_image( # %% # Temperature of bottom surface +# Activate the temperature of the bottom surface and display the image app.Tree.Activate([temp_rst4]) set_camera_and_display_image( camera, graphics, settings_720p, output_path, "bottom_surface_temp.png" ) # %% -# Export directional heat flux animation -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Directional heat flux +# Export the directional heat flux animation +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Activate the directional heat flux app.Tree.Activate([directional_heat_flux]) + +# Set the animation export format and settings animation_export_format = ( Ansys.Mechanical.DataModel.Enums.GraphicsAnimationExportFormat.GIF ) @@ -480,6 +627,7 @@ def display_image( settings_720p.Width = 1280 settings_720p.Height = 720 +# Export the directional heat flux animation as a GIF directional_heat_flux_gif = output_path / "directional_heat_flux.gif" directional_heat_flux.ExportAnimation( str(directional_heat_flux_gif), animation_export_format, settings_720p @@ -517,7 +665,7 @@ def update_animation(frame: int) -> list[mpimg.AxesImage]: # Create the animation using the figure, update_animation function, and the GIF frames # Set the interval between frames to 200 milliseconds and repeat the animation -FuncAnimation( +ani = FuncAnimation( figure, update_animation, frames=range(gif.n_frames), @@ -530,38 +678,35 @@ def update_animation(frame: int) -> list[mpimg.AxesImage]: plt.show() # %% -# Display output file from solve -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - -def write_file_contents_to_console(path): - """Write file contents to console.""" - with open(path, "rt") as file: - for line in file: - print(line, end="") - +# Display the output file from the solve +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Get the working directory for the steady state thermal analysis solve_path = stat_therm.WorkingDir +# Get the path to the solve.out file solve_out_path = solve_path + "solve.out" +# Print the output of the solve.out file if applicable if solve_out_path: - write_file_contents_to_console(solve_out_path) + with open(solve_out_path, "rt") as file: + for line in file: + print(line, end="") # %% -# Project tree -# ~~~~~~~~~~~~ +# Print the project tree +# ~~~~~~~~~~~~~~~~~~~~~~ app.print_tree() # %% -# Cleanup -# ~~~~~~~ -# Save project +# Clean up the app and downloaded files +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Save the project file mechdat_path = output_path / "steady_state_thermal.mechdat" app.save(str(mechdat_path)) -app.new() -# %% -# Delete example files +# Refresh the app +app.new() +# Delete the example files delete_downloads() From c3a928b85d63e579486496d718647cc249b9e7ef Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Wed, 30 Apr 2025 16:33:57 -0400 Subject: [PATCH 15/24] update topology optimization comments --- .../topology_optimization_cantilever_beam.py | 138 ++++++++---------- 1 file changed, 59 insertions(+), 79 deletions(-) diff --git a/examples/01_basic/topology_optimization_cantilever_beam.py b/examples/01_basic/topology_optimization_cantilever_beam.py index 7caa12fe..d87478c8 100644 --- a/examples/01_basic/topology_optimization_cantilever_beam.py +++ b/examples/01_basic/topology_optimization_cantilever_beam.py @@ -15,12 +15,10 @@ from pathlib import Path from typing import TYPE_CHECKING -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 if TYPE_CHECKING: import Ansys @@ -31,7 +29,6 @@ app = App(globals=globals()) print(app) - # %% # Set the image output path and create functions to fit the camera and display images # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -115,7 +112,10 @@ def display_image( graphics = app.Graphics camera = graphics.Camera +# Set the camera orientation to the front view camera.SetSpecificViewOrientation(ViewOrientationType.Front) + +# Set the image export format and settings image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() settings_720p.Resolution = GraphicsResolutionType.EnhancedResolution @@ -125,38 +125,46 @@ def display_image( settings_720p.CurrentGraphicsDisplay = False # %% -# Import structural analsys -# ~~~~~~~~~~~~~~~~~~~~~~~~~ -# Download ``.mechdat`` file +# Import the structural analysis model +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Download ``.mechdat`` file structural_mechdat_file = download_file( "cantilever.mechdat", "pymechanical", "embedding" ) + +# Open the project file app.open(structural_mechdat_file) + +# Define the model +model = app.Model + +# Get the structural analysis object struct = model.Analyses[0] # sphinx_gallery_start_ignore assert struct.ObjectState == ObjectState.Solved # sphinx_gallery_end_ignore + +# Get the structural analysis object's solution and solve it struct_sln = struct.Solution struct_sln.Solve(True) + # sphinx_gallery_start_ignore assert struct_sln.Status == SolutionStatusType.Done, "Solution status is not 'Done'" # sphinx_gallery_end_ignore # %% -# Display structural analsys results -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Total deformation +# Display the structural analysis results +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Activate the total deformation result and display the image struct_sln.Children[1].Activate() set_camera_and_display_image( camera, graphics, settings_720p, output_path, "total_deformation.png" ) -# %% -# Equivalent stress - +# Activate the equivalent stress result and display the image struct_sln.Children[2].Activate() set_camera_and_display_image( camera, graphics, settings_720p, output_path, "equivalent_stress.png" @@ -166,44 +174,43 @@ def display_image( # Topology optimization # ~~~~~~~~~~~~~~~~~~~~~ -# Set MKS unit system - +# Set the MKS unit system app.ExtAPI.Application.ActiveUnitSystem = MechanicalUnitSystem.StandardMKS -# Get structural analysis and link to topology optimization - +# Add the topology optimization analysis to the model and transfer data from the +# structural analysis topology_optimization = model.AddTopologyOptimizationAnalysis() topology_optimization.TransferDataFrom(struct) +# Get the optimization region from the data model optimization_region = DataModel.GetObjectsByType( DataModelObjectCategory.OptimizationRegion )[0] +# Set the optimization region's boundary condition to all loads and supports optimization_region.BoundaryCondition = BoundaryConditionType.AllLoadsAndSupports +# Set the optimization region's optimization type to topology density optimization_region.OptimizationType = OptimizationType.TopologyDensity # sphinx_gallery_start_ignore assert topology_optimization.ObjectState == ObjectState.NotSolved # sphinx_gallery_end_ignore -# Insert volume response constraint object for topology optimization -# Delete mass response constraint - +# Delete the mass response constraint from the topology optimization mass_constraint = topology_optimization.Children[3] mass_constraint.Delete() -# Add volume response constraint - +# Add a volume response constraint to the topology optimization volume_constraint = topology_optimization.AddVolumeConstraint() -# Insert member size manufacturing constraint - +# Add a member size manufacturing constraint to the topology optimization mem_size_manufacturing_constraint = ( topology_optimization.AddMemberSizeManufacturingConstraint() ) +# Set the constraint's minimum to manual and its minimum size to 2.4m mem_size_manufacturing_constraint.Minimum = ManuMemberSizeControlledType.Manual mem_size_manufacturing_constraint.MinSize = Quantity("2.4 [m]") - +# Activate the topology optimization analysis and display the image topology_optimization.Activate() set_camera_and_display_image( camera, graphics, settings_720p, output_path, "boundary_conditions.png" @@ -213,15 +220,18 @@ def display_image( # Solve # ~~~~~ +# Get the topology optimization analysis solution top_opt_sln = topology_optimization.Solution +# Solve the solution top_opt_sln.Solve(True) + # sphinx_gallery_start_ignore assert top_opt_sln.Status == SolutionStatusType.Done, "Solution status is not 'Done'" # sphinx_gallery_end_ignore # %% -# Messages -# ~~~~~~~~ +# Print messages +# ~~~~~~~~~~~~~~ messages = app.ExtAPI.Application.Messages if messages: @@ -234,22 +244,31 @@ def display_image( # Display results # ~~~~~~~~~~~~~~~ +# Get the topology density result and activate it top_opt_sln.Children[1].Activate() topology_density = top_opt_sln.Children[1] # %% -# Add smoothing to the STL +# Add smoothing to the stereolithography (STL) +# Add smoothing to the topology density result topology_density.AddSmoothing() + +# Evaluate all results for the topology optimization solution topology_optimization.Solution.EvaluateAllResults() + +# Activate the topology density result after smoothing and display the image topology_density.Children[0].Activate() set_camera_and_display_image( camera, graphics, settings_720p, output_path, "topo_opitimized_smooth.png" ) # %% -# Export animation +# Export the animation +app.Tree.Activate([topology_density]) + +# Set the animation export format and settings animation_export_format = ( Ansys.Mechanical.DataModel.Enums.GraphicsAnimationExportFormat.GIF ) @@ -257,59 +276,21 @@ def display_image( settings_720p.Width = 1280 settings_720p.Height = 720 +# Export the animation of the topology density result topology_optimized_gif = output_path / "topology_opitimized.gif" topology_density.ExportAnimation( str(topology_optimized_gif), animation_export_format, settings_720p ) +# Use saved GIF file to display the animation since matplotlib.FuncAnimation +# does not work for this animation in Sphinx -def update_animation(frame: int) -> list[mpimg.AxesImage]: - """Update the animation frame for the GIF. - - Parameters - ---------- - frame : int - The frame number to update the animation. - - Returns - ------- - list[mpimg.AxesImage] - A list containing the updated image for the animation. - """ - # Seeks to the given frame in this sequence file - gif.seek(frame) - # Set the image array to the current frame of the GIF - image.set_data(gif.convert("RGBA")) - # Return the updated image - return [image] - - -# Open the GIF file and create an animation -gif = Image.open(topology_optimized_gif) -# Set the subplots for the animation and turn off the axis -figure, axes = plt.subplots(figsize=(16, 9)) -axes.axis("off") -# Change the color of the image -image = axes.imshow(gif.convert("RGBA")) - -# Create the animation using the figure, update_animation function, and the GIF frames -# Set the interval between frames to 200 milliseconds and repeat the animation -FuncAnimation( - figure, - update_animation, - frames=range(gif.n_frames), - interval=100, - repeat=True, - blit=True, -) - -# Show the animation -plt.show() +# .. image:: /_static/basic/Topo_opitimized.gif # %% # Review the results -# Print topology density results +# Print the topology density results print("Topology Density Results") print("Minimum Density: ", topology_density.Minimum) print("Maximum Density: ", topology_density.Maximum) @@ -321,23 +302,22 @@ def update_animation(frame: int) -> list[mpimg.AxesImage]: print("Final Mass: ", topology_density.FinalMass.Value) print("Percent Mass of Original: ", topology_density.PercentMassOfOriginal) - # %% -# Project tree -# ~~~~~~~~~~~~ +# Display the project tree +# ~~~~~~~~~~~~~~~~~~~~~~~~ app.print_tree() # %% -# Cleanup -# ~~~~~~~ -# Save project +# Clean up the app and downloaded files +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Save the project file mechdat_file = output_path / "cantilever_beam_topology_optimization.mechdat" app.save(str(mechdat_file)) + +# Refresh the app app.new() -# %% # Delete the example files - delete_downloads() From dc97fd0b269c31441a1aa1908ce7fd3938381005 Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Wed, 30 Apr 2025 16:49:04 -0400 Subject: [PATCH 16/24] update comments in valve.py --- examples/01_basic/valve.py | 111 ++++++++++++++++++++++++------------- 1 file changed, 74 insertions(+), 37 deletions(-) diff --git a/examples/01_basic/valve.py b/examples/01_basic/valve.py index b003777a..2ffa31c5 100644 --- a/examples/01_basic/valve.py +++ b/examples/01_basic/valve.py @@ -113,7 +113,10 @@ def display_image( graphics = app.Graphics camera = graphics.Camera +# Set the camera orientation to the front view camera.SetSpecificViewOrientation(ViewOrientationType.Iso) + +# Set the image export format and settings image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() settings_720p.Resolution = GraphicsResolutionType.EnhancedResolution @@ -122,90 +125,123 @@ def display_image( settings_720p.Height = 720 settings_720p.CurrentGraphicsDisplay = False - # %% -# Download geometry and import -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Download geometry +# Download and import the geometry file +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Download the geometry file geometry_path = download_file("Valve.pmdb", "pymechanical", "embedding") # %% -# Import geometry +# Import the geometry +# Define the model model = app.Model +# Add a geometry import to the geometry import group geometry_import = model.GeometryImportGroup.AddGeometryImport() + +# Set the geometry import settings geometry_import_format = ( Ansys.Mechanical.DataModel.Enums.GeometryImportPreference.Format.Automatic ) geometry_import_preferences = Ansys.ACT.Mechanical.Utilities.GeometryImportPreferences() geometry_import_preferences.ProcessNamedSelections = True + +# Import the geometry file with the specified settings geometry_import.Import( geometry_path, geometry_import_format, geometry_import_preferences ) +# Visualize the model in 3D app.plot() # %% # Assign materials and mesh the geometry # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Add the material assignment to the model materials material_assignment = model.Materials.AddMaterialAssignment() + +# Set the material to structural steel material_assignment.Material = "Structural Steel" -sel = app.ExtAPI.SelectionManager.CreateSelectionInfo( + +# Create selection information for the geometry entities +selection_info = app.ExtAPI.SelectionManager.CreateSelectionInfo( Ansys.ACT.Interfaces.Common.SelectionTypeEnum.GeometryEntities ) -sel.Ids = [ + +# Get the geometric bodies from the model and add their IDs to the selection info IDs list +selection_info.Ids = [ body.GetGeoBody().Id for body in model.Geometry.GetChildren( Ansys.Mechanical.DataModel.Enums.DataModelObjectCategory.Body, True ) ] -material_assignment.Location = sel +# Set the material assignment location to the selected geometry entities +material_assignment.Location = selection_info # %% -# Define mesh settings, generate mesh +# Define the mesh settings and generate the mesh +# Define the mesh mesh = model.Mesh +# Set the mesh element size to 25mm mesh.ElementSize = Quantity(25, "mm") + +# Generate the mesh mesh.GenerateMesh() + +# Activate the mesh and display the image app.Tree.Activate([mesh]) set_camera_and_display_image(camera, graphics, settings_720p, output_path, "mesh.png") # %% -# Define analysis and boundary conditions -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Define the static structural analysis and boundary conditions +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Add a static structural analysis to the model analysis = model.AddStaticStructuralAnalysis() +# Add a fixed support to the analysis fixed_support = analysis.AddFixedSupport() +# Set the fixed support location to the "NSFixedSupportFaces" object fixed_support.Location = app.ExtAPI.DataModel.GetObjectsByName("NSFixedSupportFaces")[0] +# Add a frictionless support to the analysis frictionless_support = analysis.AddFrictionlessSupport() +# Set the frictionless support location to the "NSFrictionlessSupportFaces" object frictionless_support.Location = app.ExtAPI.DataModel.GetObjectsByName( "NSFrictionlessSupportFaces" )[0] +# Add pressure to the analysis pressure = analysis.AddPressure() +# Set the pressure location to the "NSInsideFaces" object pressure.Location = app.ExtAPI.DataModel.GetObjectsByName("NSInsideFaces")[0] +# Set the pressure magnitude's input and output values pressure.Magnitude.Inputs[0].DiscreteValues = [Quantity("0 [s]"), Quantity("1 [s]")] pressure.Magnitude.Output.DiscreteValues = [Quantity("0 [Pa]"), Quantity("15 [MPa]")] +# Activate the analysis and display the image analysis.Activate() set_camera_and_display_image( camera, graphics, settings_720p, output_path, "boundary_conditions.png" ) # %% -# Add results +# Add results to the analysis solution +# Define the solution for the analysis solution = analysis.Solution + +# Add the total deformation and equivalent stress results to the solution deformation = solution.AddTotalDeformation() stress = solution.AddEquivalentStress() # %% -# Solve +# Solve the solution solution.Solve(True) @@ -214,8 +250,8 @@ def display_image( # sphinx_gallery_end_ignore # %% -# Messages -# ~~~~~~~~ +# Print the messages +# ~~~~~~~~~~~~~~~~~~ messages = app.ExtAPI.Application.Messages if messages: @@ -229,24 +265,27 @@ def display_image( # ~~~~~~~ # %% -# Total deformation +# Show the total deformation +# Activate the total deformation result and display the image app.Tree.Activate([deformation]) set_camera_and_display_image( camera, graphics, settings_720p, output_path, "total_deformation_valve.png" ) # %% -# Stress +# Show the equivalent stress +# Activate the equivalent stress result and display the image app.Tree.Activate([stress]) set_camera_and_display_image( camera, graphics, settings_720p, output_path, "stress_valve.png" ) # %% -# Export stress animation +# Export the stress animation +# Set the animation export format and settings animation_export_format = ( Ansys.Mechanical.DataModel.Enums.GraphicsAnimationExportFormat.GIF ) @@ -254,6 +293,7 @@ def display_image( settings_720p.Width = 1280 settings_720p.Height = 720 +# Export the animation of the equivalent stress result valve_gif = output_path / "valve.gif" stress.ExportAnimation(str(valve_gif), animation_export_format, settings_720p) @@ -302,38 +342,35 @@ def update_animation(frame: int) -> list[mpimg.AxesImage]: plt.show() # %% -# Display output file from solve -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - -def write_file_contents_to_console(path): - """Write file contents to console.""" - with open(path, "rt") as file: - for line in file: - print(line, end="") - +# Display the output file from the solve +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Get the path to the solve output file solve_path = analysis.WorkingDir +# Get the solve output file path solve_out_path = solve_path + "solve.out" +# If the solve output file exists, print its contents if solve_out_path: - write_file_contents_to_console(solve_out_path) + with open(solve_out_path, "rt") as file: + for line in file: + print(line, end="") # %% -# Project tree -# ~~~~~~~~~~~~ +# Print the project tree +# ~~~~~~~~~~~~~~~~~~~~~~ app.print_tree() # %% -# Cleanup -# ~~~~~~~ -# Save project +# Clean up the project +# ~~~~~~~~~~~~~~~~~~~~ +# Save the project mechdat_file = output_path / "valve.mechdat" app.save(str(mechdat_file)) -app.new() -# %% -# delete example files +# Refresh the app +app.new() +# Delete the example files delete_downloads() From 968cfc347a9a03c15eba50245efb27423194ec1b Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Wed, 7 May 2025 15:32:07 -0400 Subject: [PATCH 17/24] update contact wear simulation file --- examples/01_basic/valve.py | 2 +- ...mulation.py => contact_wear_simulation.py} | 319 +++++++++++------- 2 files changed, 203 insertions(+), 118 deletions(-) rename examples/02_technology_showcase/{conact_wear_simulation.py => contact_wear_simulation.py} (60%) diff --git a/examples/01_basic/valve.py b/examples/01_basic/valve.py index 2ffa31c5..b9589150 100644 --- a/examples/01_basic/valve.py +++ b/examples/01_basic/valve.py @@ -113,7 +113,7 @@ def display_image( graphics = app.Graphics camera = graphics.Camera -# Set the camera orientation to the front view +# Set the camera orientation to the isometric view camera.SetSpecificViewOrientation(ViewOrientationType.Iso) # Set the image export format and settings diff --git a/examples/02_technology_showcase/conact_wear_simulation.py b/examples/02_technology_showcase/contact_wear_simulation.py similarity index 60% rename from examples/02_technology_showcase/conact_wear_simulation.py rename to examples/02_technology_showcase/contact_wear_simulation.py index 7e8515ab..a6605526 100644 --- a/examples/02_technology_showcase/conact_wear_simulation.py +++ b/examples/02_technology_showcase/contact_wear_simulation.py @@ -128,7 +128,10 @@ def display_image( graphics = app.Graphics camera = graphics.Camera +# Set the camera orientation to the front view camera.SetSpecificViewOrientation(ViewOrientationType.Front) + +# Set the image export format and settings image_export_format = GraphicsImageExportFormat.PNG settings_720p = Ansys.Mechanical.Graphics.GraphicsImageExportSettings() settings_720p.Resolution = GraphicsResolutionType.EnhancedResolution @@ -136,50 +139,61 @@ def display_image( settings_720p.Width = 1280 settings_720p.Height = 720 settings_720p.CurrentGraphicsDisplay = False + +# Rotate the camera on the y-axis camera.Rotate(180, CameraAxisType.ScreenY) # %% -# Download geometry and materials files -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Download the geometry and material files +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Download the geometry and material files from the specified paths geometry_path = download_file("example_07_td43_wear.agdb", "pymechanical", "00_basic") mat1_path = download_file("example_07_Mat_Copper.xml", "pymechanical", "00_basic") mat2_path = download_file("example_07_Mat_Steel.xml", "pymechanical", "00_basic") # %% -# Import geometry -# ~~~~~~~~~~~~~~~ +# Import the geometry +# ~~~~~~~~~~~~~~~~~~~ +# Define the model model = app.Model +# Add a geometry import to the geometry import group geometry_import = model.GeometryImportGroup.AddGeometryImport() + +# Set the geometry import 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.ProcessCoordinateSystems = True + +# Import the geometry using the specified settings geometry_import.Import( geometry_path, geometry_import_format, geometry_import_preferences ) +# Visualize the model in 3D app.plot() # %% -# Import materials -# ~~~~~~~~~~~~~~~~ +# Import the materials +# ~~~~~~~~~~~~~~~~~~~~ +# Define the materials for the model materials = model.Materials + +# Import the copper and steel materials materials.Import(mat1_path) materials.Import(mat2_path) -print("Material import done !") - # %% -# Setup the Analysis -# ~~~~~~~~~~~~~~~~~~ -# Set up the unit system +# Set up the analysis +# ~~~~~~~~~~~~~~~~~~~ +# Set up the unit system app.ExtAPI.Application.ActiveUnitSystem = MechanicalUnitSystem.StandardNMM # %% @@ -192,46 +206,63 @@ def display_image( named_selections = model.NamedSelections # %% -# Add static structural analysis +# Add the static structural analysis model.AddStaticStructuralAnalysis() static_structural_analysis = model.Analyses[0] + +# Store the static structural analysis solution stat_struct_soln = static_structural_analysis.Solution -stat_struct_analysis_settings = static_structural_analysis.Children[0] + +# Get the analysis settings for the static structural analysis +analysis_settings = static_structural_analysis.Children[0] # %% -# Store name selection - -curve_named_selection = [x for x in app.Tree.AllObjects if x.Name == "curve"][0] -dia_named_selection = [x for x in app.Tree.AllObjects if x.Name == "dia"][0] -ver_edge1 = [x for x in app.Tree.AllObjects if x.Name == "v1"][0] -ver_edge2 = [x for x in app.Tree.AllObjects if x.Name == "v2"][0] -hor_edge1 = [x for x in app.Tree.AllObjects if x.Name == "h1"][0] -hor_edge2 = [x for x in app.Tree.AllObjects if x.Name == "h2"][0] -all_bodies_named_selection = [x for x in app.Tree.AllObjects if x.Name == "all_bodies"][ - 0 -] +# Store named selection + + +def get_named_selection(name: str): + """Get the named selection by name.""" + return [obj for obj in app.Tree.AllObjects if obj.Name == name][0] + + +curve_named_selection = get_named_selection("curve") +dia_named_selection = get_named_selection("dia") +ver_edge1 = get_named_selection("v1") +ver_edge2 = get_named_selection("v2") +hor_edge1 = get_named_selection("h1") +hor_edge2 = get_named_selection("h2") +all_bodies_named_selection = get_named_selection("all_bodies") # %% -# Assign material to bodies and change behavior to axisymmetric +# Assign material to the bodies and change the behavior to axi-symmetric +# Set the model's 2D behavior to axi-symmetric geometry.Model2DBehavior = Model2DBehavior.AxiSymmetric -surface1 = geometry.Children[0].Children[0] -surface1.Material = "Steel" -surface1.Dimension = ShellBodyDimension.Two_D -surface2 = geometry.Children[1].Children[0] -surface2.Material = "Copper" -surface2.Dimension = ShellBodyDimension.Two_D +def set_material_and_dimension( + surface_child_index, material, dimension=ShellBodyDimension.Two_D +): + """Set the material and dimension for a given surface.""" + surface = geometry.Children[surface_child_index].Children[0] + surface.Material = material + surface.Dimension = dimension + + +# Set the material and dimensions for the surface +set_material_and_dimension(0, "Steel") +set_material_and_dimension(1, "Copper") # %% # Change contact settings +# Add a contact region between the hemispherical ring and the flat ring contact_region = connections.AddContactRegion() +# Set the source and target locations for the contact region contact_region.SourceLocation = named_selections.Children[6] contact_region.TargetLocation = named_selections.Children[3] -# contact_region.FlipContactTarget() +# Set contact region properties contact_region.ContactType = ContactType.Frictionless contact_region.Behavior = ContactBehavior.Asymmetric contact_region.ContactFormulation = ContactFormulation.AugmentedLagrange @@ -259,134 +290,183 @@ def display_image( cmd1.AppendText(archard_wear_model) # %% -# Insert remote point +# Insert a remote point +# Add a remote point to the model remote_point = model.AddRemotePoint() +# Set the remote point location to the center of the hemispherical ring remote_point.Location = dia_named_selection remote_point.Behavior = LoadBehavior.Rigid # %% -# Mesh -# ~~~~ +# Set properties for the mesh +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Set the mesh element order and size mesh.ElementOrder = ElementOrder.Linear mesh.ElementSize = Quantity("1 [mm]") -edge_sizing1 = mesh.AddSizing() -edge_sizing1.Location = hor_edge1 -edge_sizing1.Type = SizingType.NumberOfDivisions -edge_sizing1.NumberOfDivisions = 70 -edge_sizing2 = mesh.AddSizing() -edge_sizing2.Location = hor_edge2 -edge_sizing2.Type = SizingType.NumberOfDivisions -edge_sizing2.NumberOfDivisions = 70 +def add_edge_sizing_and_properties( + mesh, location, divisions, sizing_type=SizingType.NumberOfDivisions +): + """Set the sizing properties for a given mesh. -edge_sizing3 = mesh.AddSizing() -edge_sizing3.Location = ver_edge1 -edge_sizing3.Type = SizingType.NumberOfDivisions -edge_sizing3.NumberOfDivisions = 35 - -edge_sizing4 = mesh.AddSizing() -edge_sizing4.Location = ver_edge2 -edge_sizing4.Type = SizingType.NumberOfDivisions -edge_sizing4.NumberOfDivisions = 35 + Parameters + ---------- + mesh : Ansys.Mechanical.DataModel.Mesh + The mesh object to set the properties for. + location : Ansys.Mechanical.DataModel.NamedSelection + The location of the edge to set the sizing for. + divisions : int + The number of divisions for the edge. + sizing_type : SizingType + The type of sizing to apply (default is NumberOfDivisions). + """ + edge_sizing = mesh.AddSizing() + edge_sizing.Location = location + edge_sizing.Type = sizing_type + edge_sizing.NumberOfDivisions = divisions -edge_sizing5 = mesh.AddSizing() -edge_sizing5.Location = dia_named_selection -edge_sizing5.Type = SizingType.NumberOfDivisions -edge_sizing5.NumberOfDivisions = 40 -edge_sizing6 = mesh.AddSizing() -edge_sizing6.Location = curve_named_selection -edge_sizing6.Type = SizingType.NumberOfDivisions -edge_sizing6.NumberOfDivisions = 60 +# Add edge sizing and properties to the mesh for each named selection +add_edge_sizing_and_properties(mesh, hor_edge1, 70) +add_edge_sizing_and_properties(mesh, hor_edge2, 70) +add_edge_sizing_and_properties(mesh, ver_edge1, 35) +add_edge_sizing_and_properties(mesh, ver_edge2, 35) +add_edge_sizing_and_properties(mesh, dia_named_selection, 40) +add_edge_sizing_and_properties(mesh, curve_named_selection, 60) +# Generate the mesh and display the image mesh.GenerateMesh() set_camera_and_display_image(camera, graphics, settings_720p, output_path, "mesh.png") # %% -# Analysis settings -# ~~~~~~~~~~~~~~~~~ - -stat_struct_analysis_settings.NumberOfSteps = 2 -stat_struct_analysis_settings.CurrentStepNumber = 1 -stat_struct_analysis_settings.AutomaticTimeStepping = AutomaticTimeStepping.On -stat_struct_analysis_settings.DefineBy = TimeStepDefineByType.Time -stat_struct_analysis_settings.InitialTimeStep = Quantity("0.1 [s]") -stat_struct_analysis_settings.MinimumTimeStep = Quantity("0.0001 [s]") -stat_struct_analysis_settings.MaximumTimeStep = Quantity("1 [s]") -stat_struct_analysis_settings.CurrentStepNumber = 2 -stat_struct_analysis_settings.Activate() -stat_struct_analysis_settings.StepEndTime = Quantity("4 [s]") -stat_struct_analysis_settings.AutomaticTimeStepping = AutomaticTimeStepping.On -stat_struct_analysis_settings.DefineBy = TimeStepDefineByType.Time -stat_struct_analysis_settings.InitialTimeStep = Quantity("0.01 [s]") -stat_struct_analysis_settings.MinimumTimeStep = Quantity("0.000001 [s]") -stat_struct_analysis_settings.MaximumTimeStep = Quantity("0.02 [s]") - -stat_struct_analysis_settings.LargeDeflection = True +# Set the analysis settings +# ~~~~~~~~~~~~~~~~~~~~~~~~~ + + +def set_time_steps(initial, min, max): + """Set the time step properties for the analysis settings. + + Parameters + ---------- + initial : str + The initial time step value. + min : str + The minimum time step value. + max : str + The maximum time step value. + """ + analysis_settings.InitialTimeStep = Quantity(initial) + analysis_settings.MinimumTimeStep = Quantity(min) + analysis_settings.MaximumTimeStep = Quantity(max) + + +# Set the analysis settings for the static structural analysis +analysis_settings.NumberOfSteps = 2 +analysis_settings.CurrentStepNumber = 1 +analysis_settings.AutomaticTimeStepping = AutomaticTimeStepping.On +analysis_settings.DefineBy = TimeStepDefineByType.Time +set_time_steps(initial="0.1 [s]", min="0.0001 [s]", max="1 [s]") +analysis_settings.CurrentStepNumber = 2 +analysis_settings.Activate() +analysis_settings.StepEndTime = Quantity("4 [s]") +analysis_settings.AutomaticTimeStepping = AutomaticTimeStepping.On +analysis_settings.DefineBy = TimeStepDefineByType.Time +set_time_steps(initial="0.01 [s]", min="0.000001 [s]", max="0.02 [s]") +analysis_settings.LargeDeflection = True # %% # Insert loading and boundary conditions # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Add a fixed support to the model fixed_support = static_structural_analysis.AddFixedSupport() +# Set the fixed support location to the first horizontal edge fixed_support.Location = hor_edge1 +# Add a remote displacement to the model remote_displacement = static_structural_analysis.AddRemoteDisplacement() +# Set the remote displacement location to the remote point remote_displacement.Location = remote_point +# Add the values for the x-component and rotation about the z-axis remote_displacement.XComponent.Output.DiscreteValues = [Quantity("0[mm]")] remote_displacement.RotationZ.Output.DiscreteValues = [Quantity("0[deg]")] +# Add a remote force to the model remote_force = static_structural_analysis.AddRemoteForce() +# Set the remote force location to the remote point remote_force.Location = remote_point +# Set the remote force values for the y-component remote_force.DefineBy = LoadDefineBy.Components remote_force.YComponent.Output.DiscreteValues = [Quantity("-150796320 [N]")] -# Nonlinear Adaptivity does not support contact criterion yet hence command snippet used - +# Nonlinear adaptivity does not support contact criterion yet so a command snippet is used instead nonlinear_adaptivity = """NLADAPTIVE,all,add,contact,wear,0.50 NLADAPTIVE,all,on,all,all,1,,4 NLADAPTIVE,all,list,all,all""" + +# Add the nonlinear adaptivity command snippet to the static structural analysis cmd2 = static_structural_analysis.AddCommandSnippet() cmd2.AppendText(nonlinear_adaptivity) cmd2.StepSelectionMode = SequenceSelectionType.All +# Activate the static structural analysis and display the mesh image static_structural_analysis.Activate() set_camera_and_display_image(camera, graphics, settings_720p, output_path, "mesh.png") # %% -# Insert results -# ~~~~~~~~~~~~~~ +# Add results to the solution +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +def set_properties_for_result( + result, + display_time, + orientation_type=NormalOrientationType.YAxis, + display_option=ResultAveragingType.Unaveraged, +): + """Set the properties for a given result.""" + result.NormalOrientation = orientation_type + result.DisplayTime = Quantity(display_time) + result.DisplayOption = display_option + +# Add total deformation to the solution total_deformation = stat_struct_soln.AddTotalDeformation() +# Add normal stress to the solution normal_stress1 = stat_struct_soln.AddNormalStress() -normal_stress1.NormalOrientation = NormalOrientationType.YAxis -normal_stress1.DisplayTime = Quantity("1 [s]") -normal_stress1.DisplayOption = ResultAveragingType.Unaveraged - +set_properties_for_result(normal_stress1, display_time="1 [s]") normal_stress2 = stat_struct_soln.AddNormalStress() -normal_stress2.NormalOrientation = NormalOrientationType.YAxis -normal_stress2.DisplayTime = Quantity("4 [s]") -normal_stress2.DisplayOption = ResultAveragingType.Unaveraged +set_properties_for_result(normal_stress1, display_time="4 [s]") +# Add a contact tool to the solution contact_tool = stat_struct_soln.AddContactTool() contact_tool.ScopingMethod = GeometryDefineByType.Geometry +# Add selections for the contact tool selection1 = app.ExtAPI.SelectionManager.AddSelection(all_bodies_named_selection) selection2 = app.ExtAPI.SelectionManager.CurrentSelection +# Set the contact tool location to the current selection contact_tool.Location = selection2 +# Clear the selection app.ExtAPI.SelectionManager.ClearSelection() -contact_pressure1 = contact_tool.AddPressure() -contact_pressure1.DisplayTime = Quantity("1 [s]") -contact_pressure2 = contact_tool.AddPressure() -contact_pressure2.DisplayTime = Quantity("4 [s]") + +def add_contact_pressure(contact_tool, display_time): + """Add a contact pressure to the contact tool.""" + contact_pressure = contact_tool.AddPressure() + contact_pressure.DisplayTime = Quantity(display_time) + + +# Add pressure to the contact tool +add_contact_pressure(contact_tool, display_time="0 [s]") +add_contact_pressure(contact_tool, display_time="4 [s]") # %% -# Solve -# ~~~~~ +# Solve the static structural analysis +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ stat_struct_soln.Solve(True) # sphinx_gallery_start_ignore @@ -398,27 +478,15 @@ def display_image( # %% # Postprocessing # ~~~~~~~~~~~~~~ -# Normal stress +# Activate the first normal stress result and display the image app.Tree.Activate([normal_stress1]) set_camera_and_display_image( camera, graphics, settings_720p, output_path, "normal_stress.png" ) # %% -# Total deformation animation - -animation_export_format = ( - Ansys.Mechanical.DataModel.Enums.GraphicsAnimationExportFormat.GIF -) -settings_720p = Ansys.Mechanical.Graphics.AnimationExportSettings() -settings_720p.Width = 1280 -settings_720p.Height = 720 - -total_deformation_gif = output_path / "total_deformation.gif" -total_deformation.ExportAnimation( - str(total_deformation_gif), animation_export_format, settings_720p -) +# Display the total deformation animation def update_animation(frame: int) -> list[mpimg.AxesImage]: @@ -442,6 +510,21 @@ def update_animation(frame: int) -> list[mpimg.AxesImage]: return [image] +# Set the animatione export format +animation_export_format = ( + Ansys.Mechanical.DataModel.Enums.GraphicsAnimationExportFormat.GIF +) +# Set the animation export settings +settings_720p = Ansys.Mechanical.Graphics.AnimationExportSettings() +settings_720p.Width = 1280 +settings_720p.Height = 720 + +# Export the animation +total_deformation_gif = output_path / "total_deformation.gif" +total_deformation.ExportAnimation( + str(total_deformation_gif), animation_export_format, settings_720p +) + # Open the GIF file and create an animation gif = Image.open(total_deformation_gif) # Set the subplots for the animation and turn off the axis @@ -465,19 +548,21 @@ def update_animation(frame: int) -> list[mpimg.AxesImage]: plt.show() # %% -# Project tree -# ~~~~~~~~~~~~ +# Print the project tree +# ~~~~~~~~~~~~~~~~~~~~~~ app.print_tree() # %% -# Cleanup -# ~~~~~~~ -# Save project +# Clean up the project +# ~~~~~~~~~~~~~~~~~~~~ +# Save the project file mechdat_file = output_path / "contact_wear.mechdat" app.save(str(mechdat_file)) + +# Refresh the app app.new() -# delete example file +# Delete the downloaded files delete_downloads() From bfb1ae8f9e2d3029b97723277d8ad217b3019795 Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Wed, 7 May 2025 17:43:45 -0400 Subject: [PATCH 18/24] update non linear analysis script --- .../non_linear_analysis_rubber_boot_seal.py | 642 +++++++++++------- 1 file changed, 387 insertions(+), 255 deletions(-) diff --git a/examples/02_technology_showcase/non_linear_analysis_rubber_boot_seal.py b/examples/02_technology_showcase/non_linear_analysis_rubber_boot_seal.py index f88ba398..c5254867 100644 --- a/examples/02_technology_showcase/non_linear_analysis_rubber_boot_seal.py +++ b/examples/02_technology_showcase/non_linear_analysis_rubber_boot_seal.py @@ -121,10 +121,13 @@ def display_image( graphics = app.Graphics camera = graphics.Camera +# Set the camera orientation to the isometric view camera.SetSpecificViewOrientation( Ansys.Mechanical.DataModel.Enums.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 = GraphicsResolutionType.EnhancedResolution @@ -134,8 +137,8 @@ def display_image( settings_720p.CurrentGraphicsDisplay = False # %% -# Download geometry and materials files -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Download the geometry and material files +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ geometry_path = download_file( "example_05_td26_Rubber_Boot_Seal.agdb", "pymechanical", "00_basic" @@ -145,357 +148,482 @@ def display_image( # %% # Import geometry and material # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Import material +# Define the model model = app.Model +# Define the materials materials = model.Materials + +# Import the material materials.Import(mat_path) -print("Material import done !") # %% -# Import geometry +# Import the geometry +# Add a geometry import to the geometry import group for the model geometry_import = model.GeometryImportGroup.AddGeometryImport() + +# Set the geometry import format and preferences 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.ProcessCoordinateSystems = True + +# Import the geometry with the specified format and preferences geometry_import.Import( geometry_path, geometry_import_format, geometry_import_preferences ) +# Visualize the imported geometry in 3D app.plot() # %% -# Setup the Analysis -# ~~~~~~~~~~~~~~~~~~ -# Set up the unit system +# Set up the analysis +# ~~~~~~~~~~~~~~~~~~~ +# Set the active unit system and angle unit app.ExtAPI.Application.ActiveUnitSystem = MechanicalUnitSystem.StandardNMM app.ExtAPI.Application.ActiveAngleUnit = AngleUnitType.Radian # %% # Store all main tree nodes as variables +# Define the geometry for the model geometry = model.Geometry +# Get the part and solid objects from the geometry part1 = [x for x in app.Tree.AllObjects if x.Name == "Part"][0] part2 = [x for x in app.Tree.AllObjects if x.Name == "Solid"][1] + +# Define the coordinate systems coordinate_systems = model.CoordinateSystems -gcs = coordinate_systems.Children[0] +geometry_coordinate_systems = coordinate_systems.Children[0] # %% -# Add static structural analysis +# Add a static structural analysis +# Add a static structural analysis to the model model.AddStaticStructuralAnalysis() + +# Get the static structural analysis from the model static_structural_analysis = model.Analyses[0] + +# Get the analysis settings, solution, and solution information analysis_settings = static_structural_analysis.Children[0] stat_struct_soln = static_structural_analysis.Solution soln_info = stat_struct_soln.SolutionInformation # %% -# Define named selection and coordinate system +# Define named selections and coordinate systems + + +def get_named_selection( + named_selections, name: str +) -> Ansys.ACT.Automation.Mechanical.NamedSelection: + """Get a named selection by its name. + + Parameters + ---------- + named_selections : Ansys.ACT.Automation.Mechanical.NamedSelections + The named selections object to search in. + name : str + The name of the named selection to retrieve. + + Returns + ------- + Ansys.ACT.Automation.Mechanical.NamedSelection + The named selection object. + """ + return [ + child + for child in named_selections.GetChildren[ + Ansys.ACT.Automation.Mechanical.NamedSelection + ](True) + if child.Name == name + ][0] -named_selections = app.ExtAPI.DataModel.Project.Model.NamedSelections -top_face = [ - i - for i in named_selections.GetChildren[ - Ansys.ACT.Automation.Mechanical.NamedSelection - ](True) - if i.Name == "Top_Face" -][0] -bottom_face = [ - i - for i in named_selections.GetChildren[ - Ansys.ACT.Automation.Mechanical.NamedSelection - ](True) - if i.Name == "Bottom_Face" -][0] -symm_faces30 = [ - i - for i in named_selections.GetChildren[ - Ansys.ACT.Automation.Mechanical.NamedSelection - ](True) - if i.Name == "Symm_Faces30" -][0] -faces2 = [ - i - for i in named_selections.GetChildren[ - Ansys.ACT.Automation.Mechanical.NamedSelection - ](True) - if i.Name == "Faces2" -][0] -cyl_faces2 = [ - i - for i in named_selections.GetChildren[ - Ansys.ACT.Automation.Mechanical.NamedSelection - ](True) - if i.Name == "Cyl_Faces2" -][0] -rubber_bodies30 = [ - i - for i in named_selections.GetChildren[ - Ansys.ACT.Automation.Mechanical.NamedSelection - ](True) - if i.Name == "Rubber_Bodies30" -][0] -inner_faces30 = [ - i - for i in named_selections.GetChildren[ - Ansys.ACT.Automation.Mechanical.NamedSelection - ](True) - if i.Name == "Inner_Faces30" -][0] -outer_faces30 = [ - i - for i in named_selections.GetChildren[ - Ansys.ACT.Automation.Mechanical.NamedSelection - ](True) - if i.Name == "Outer_Faces30" -][0] -shaft_face = [ - i - for i in named_selections.GetChildren[ - Ansys.ACT.Automation.Mechanical.NamedSelection - ](True) - if i.Name == "Shaft_Face" -][0] -symm_faces15 = [ - i - for i in named_selections.GetChildren[ - Ansys.ACT.Automation.Mechanical.NamedSelection - ](True) - if i.Name == "Symm_Faces15" -][0] +named_selections = app.ExtAPI.DataModel.Project.Model.NamedSelections +top_face = get_named_selection(named_selections, "Top_Face") +bottom_face = get_named_selection(named_selections, "Bottom_Face") +symm_faces30 = get_named_selection(named_selections, "Symm_Faces30") +faces2 = get_named_selection(named_selections, "Faces2") +cyl_faces2 = get_named_selection(named_selections, "Cyl_Faces2") +rubber_bodies30 = get_named_selection(named_selections, "Rubber_Bodies30") +inner_faces30 = get_named_selection(named_selections, "Inner_Faces30") +outer_faces30 = get_named_selection(named_selections, "Outer_Faces30") +shaft_face = get_named_selection(named_selections, "Shaft_Face") +symm_faces15 = get_named_selection(named_selections, "Symm_Faces15") + +# Add a coordinate system and set its origin y-coordinate lcs1 = coordinate_systems.AddCoordinateSystem() lcs1.OriginY = Quantity("97[mm]") # %% # Assign material +# Set the material for the rubber boot part part1.Material = "Boot" +# Set the stiffness behavior for the rubber boot part part2.StiffnessBehavior = StiffnessBehavior.Rigid # %% # Define connections + +def add_contact_region_and_props( + body, + target_location, + src_location, + set_src_first: bool = True, + contact_type=ContactType.Frictional, + friction_coefficient=0.2, + behavior=ContactBehavior.Asymmetric, + small_sliding=ContactSmallSlidingType.Off, + detection_method=ContactDetectionPoint.OnGaussPoint, + update_stiffness=UpdateContactStiffness.EachIteration, +): + """Add a contact region and set its properties. + + Parameters + ---------- + body : Ansys.ACT.Automation.Mechanical.Body + The body to which the contact region is added. + target_location : Ansys.ACT.Automation.Mechanical.NamedSelection + The target location for the contact region. + src_location : Ansys.ACT.Automation.Mechanical.NamedSelection + The source location for the contact region. + set_src_first : bool + Whether to set the source location first. + contact_type : ContactType + The type of contact (default is Frictional). + friction_coefficient : float + The friction coefficient for the contact region (default is 0.2). + behavior : ContactBehavior + The behavior of the contact region (default is Asymmetric). + small_sliding : ContactSmallSlidingType + The small sliding type for the contact region (default is Off). + detection_method : ContactDetectionPoint + The detection method for the contact region (default is OnGaussPoint). + update_stiffness : UpdateContactStiffness + The update stiffness method for the contact region (default is EachIteration). + + Returns + ------- + Ansys.ACT.Automation.Mechanical.ContactRegion + The created contact region. + """ + # Add a contact region to the connection or child connection + contact_region = body.AddContactRegion() + # Set the source and target locations for the contact region + if set_src_first: + contact_region.SourceLocation = src_location + contact_region.TargetLocation = target_location + else: + contact_region.TargetLocation = target_location + contact_region.SourceLocation = src_location + # Set the contact type, friction coefficient, behavior, small sliding, + # detection method, and update stiffness for the contact region + contact_region.ContactType = contact_type + contact_region.FrictionCoefficient = friction_coefficient + contact_region.Behavior = behavior + contact_region.SmallSliding = small_sliding + contact_region.DetectionMethod = detection_method + contact_region.UpdateStiffness = update_stiffness + + return contact_region + + +# Add a contact region to the connections connections = model.Connections -contact_region1 = connections.AddContactRegion() -contact_region1.TargetLocation = shaft_face -contact_region1.SourceLocation = inner_faces30 -contact_region1.ContactType = ContactType.Frictional -contact_region1.FrictionCoefficient = 0.2 -contact_region1.Behavior = ContactBehavior.Asymmetric -contact_region1.SmallSliding = ContactSmallSlidingType.Off -contact_region1.DetectionMethod = ContactDetectionPoint.OnGaussPoint -contact_region1.UpdateStiffness = UpdateContactStiffness.EachIteration +contact_region1 = add_contact_region_and_props( + connections, + target_location=shaft_face, + src_location=inner_faces30, + set_src_first=False, +) +# Set interface treatment and target properties contact_region1.InterfaceTreatment = ContactInitialEffect.AddOffsetRampedEffects contact_region1.TargetGeometryCorrection = TargetCorrection.Smoothing contact_region1.TargetOrientation = TargetOrientation.Cylinder -contact_region1.TargetStartingPoint = gcs +contact_region1.TargetStartingPoint = geometry_coordinate_systems contact_region1.TargetEndingPoint = lcs1 +# Add a contact region to the child connections conts = connections.Children[0] -contact_region2 = conts.AddContactRegion() -contact_region2.SourceLocation = inner_faces30 -contact_region2.TargetLocation = inner_faces30 -contact_region2.ContactType = ContactType.Frictional -contact_region2.FrictionCoefficient = 0.2 -contact_region2.Behavior = ContactBehavior.Asymmetric -contact_region2.SmallSliding = ContactSmallSlidingType.Off -contact_region2.DetectionMethod = ContactDetectionPoint.NodalProjectedNormalFromContact -contact_region2.UpdateStiffness = UpdateContactStiffness.EachIteration +contact_region2 = add_contact_region_and_props( + conts, + target_location=inner_faces30, + src_location=inner_faces30, + detection_method=ContactDetectionPoint.NodalProjectedNormalFromContact, +) +# Set the stiffness value type and factor contact_region2.NormalStiffnessValueType = ElementControlsNormalStiffnessType.Factor contact_region2.NormalStiffnessFactor = 1 -contact_region3 = conts.AddContactRegion() -contact_region3.SourceLocation = outer_faces30 -contact_region3.TargetLocation = outer_faces30 -contact_region3.ContactType = ContactType.Frictional -contact_region3.FrictionCoefficient = 0.2 -contact_region3.Behavior = ContactBehavior.Asymmetric -contact_region3.SmallSliding = ContactSmallSlidingType.Off -contact_region3.DetectionMethod = ContactDetectionPoint.NodalProjectedNormalFromContact -contact_region3.UpdateStiffness = UpdateContactStiffness.EachIteration +# Add a contact region to the child connections +contact_region3 = add_contact_region_and_props( + conts, + target_location=outer_faces30, + src_location=outer_faces30, + detection_method=ContactDetectionPoint.NodalProjectedNormalFromContact, +) +# Set the stiffness value type and factor contact_region3.NormalStiffnessValueType = ElementControlsNormalStiffnessType.Factor contact_region3.NormalStiffnessFactor = 1 # %% -# Mesh -# ~~~~ +# Add face meshing and sizing +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Define the mesh for the model mesh = model.Mesh + +# Add face meshing to the mesh face_mesh = mesh.AddFaceMeshing() +# Set the location of the face mesh to the shaft face +# and set the internal number of divisions to 1 face_mesh.Location = shaft_face face_mesh.InternalNumberOfDivisions = 1 +# Add sizing to the mesh mesh_size = mesh.AddSizing() +# Set the location of the mesh size to the symmetry faces +# and set the element size to 2 mm mesh_size.Location = symm_faces15 mesh_size.ElementSize = Quantity("2 [mm]") - mesh.ElementOrder = ElementOrder.Linear mesh.Resolution = 2 +# Generate the mesh and display the image mesh.GenerateMesh() set_camera_and_display_image(camera, graphics, settings_720p, output_path, "mesh.png") # %% # Define remote points # ~~~~~~~~~~~~~~~~~~~~ -# scope them to the top and bottom faces of rigid shaft -remote_point01 = model.AddRemotePoint() -remote_point01.Location = bottom_face -remote_point01.Behavior = LoadBehavior.Rigid -remote_point02 = model.AddRemotePoint() -remote_point02.Location = top_face -remote_point02.Behavior = LoadBehavior.Rigid +def add_remote_point( + model, + location, + behavior=LoadBehavior.Rigid, +): + """Add a remote point to the model. -# %% -# Analysis settings -# ~~~~~~~~~~~~~~~~~ + Parameters + ---------- + model : Ansys.ACT.Automation.Mechanical.Model + The model to which the remote point is added. + location : Ansys.ACT.Automation.Mechanical.NamedSelection + The location of the remote point. + behavior : LoadBehavior + The behavior of the remote point (default is Rigid). + + Returns + ------- + Ansys.ACT.Automation.Mechanical.RemotePoint + The created remote point. + """ + remote_point = model.AddRemotePoint() + remote_point.Location = location + remote_point.Behavior = behavior + + return remote_point + +remote_point01 = add_remote_point(model, bottom_face) +remote_point02 = add_remote_point(model, top_face) + +# %% +# Set the analysis settings +# ~~~~~~~~~~~~~~~~~~~~~~~~~ + + +def set_analysis_settings( + analysis_settings, + current_step_number: int, + initial_substeps: int, + minimum_substeps: int, + store_results_at_value: int, + automatic_time_stepping: bool = AutomaticTimeStepping.On, + define_by: TimeStepDefineByType = TimeStepDefineByType.Substeps, + maximum_substeps: int = 1000, + store_results_at: TimePointsOptions = TimePointsOptions.EquallySpacedPoints, +): + analysis_settings.CurrentStepNumber = current_step_number + analysis_settings.AutomaticTimeStepping = automatic_time_stepping + analysis_settings.DefineBy = define_by + analysis_settings.InitialSubsteps = initial_substeps + analysis_settings.MinimumSubsteps = minimum_substeps + analysis_settings.MaximumSubsteps = maximum_substeps + analysis_settings.StoreResultsAt = store_results_at + analysis_settings.StoreResulsAtValue = store_results_at_value + + +# Activate the analysis settings analysis_settings.Activate() analysis_settings.LargeDeflection = True analysis_settings.Stabilization = StabilizationType.Off - analysis_settings.NumberOfSteps = 2 -analysis_settings.CurrentStepNumber = 1 -analysis_settings.AutomaticTimeStepping = AutomaticTimeStepping.On -analysis_settings.DefineBy = TimeStepDefineByType.Substeps -analysis_settings.InitialSubsteps = 5 -analysis_settings.MinimumSubsteps = 5 -analysis_settings.MaximumSubsteps = 1000 -analysis_settings.StoreResultsAt = TimePointsOptions.EquallySpacedPoints -analysis_settings.StoreResulsAtValue = 5 - -analysis_settings.CurrentStepNumber = 2 -analysis_settings.AutomaticTimeStepping = AutomaticTimeStepping.On -analysis_settings.DefineBy = TimeStepDefineByType.Substeps -analysis_settings.InitialSubsteps = 10 -analysis_settings.MinimumSubsteps = 10 -analysis_settings.MaximumSubsteps = 1000 -analysis_settings.StoreResultsAt = TimePointsOptions.EquallySpacedPoints -analysis_settings.StoreResulsAtValue = 10 - -analysis_settings.CurrentStepNumber = 3 -analysis_settings.AutomaticTimeStepping = AutomaticTimeStepping.On -analysis_settings.DefineBy = TimeStepDefineByType.Substeps -analysis_settings.InitialSubsteps = 30 -analysis_settings.MinimumSubsteps = 30 -analysis_settings.MaximumSubsteps = 1000 -analysis_settings.StoreResultsAt = TimePointsOptions.EquallySpacedPoints -analysis_settings.StoreResulsAtValue = 20 + +set_analysis_settings( + analysis_settings, + current_step_number=1, + initial_substeps=5, + minimum_substeps=5, + store_results_at_value=5, +) + +set_analysis_settings( + analysis_settings, + current_step_number=2, + initial_substeps=10, + minimum_substeps=10, + store_results_at_value=10, +) + +set_analysis_settings( + analysis_settings, + current_step_number=3, + initial_substeps=30, + minimum_substeps=30, + store_results_at_value=20, +) soln_info.NewtonRaphsonResiduals = 4 # %% -# Loads and boundary conditions -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Set load and boundary conditions +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +def set_input_output_values( + remote_displacement, + x_input_values, + x_output_values, + y_input_values, + y_output_values, + z_input_values, + z_output_values, + rotation_x_input_values, + rotation_x_output_values, + rotation_y_input_values, + rotation_y_output_values, + rotation_z_input_values, + rotation_z_output_values, +): + remote_displacement.XComponent.Inputs[0].DiscreteValues = convert_to_quantity( + x_input_values + ) + remote_displacement.XComponent.Output.DiscreteValues = convert_to_quantity( + x_output_values + ) + remote_displacement.YComponent.Inputs[0].DiscreteValues = convert_to_quantity( + y_input_values + ) + remote_displacement.YComponent.Output.DiscreteValues = convert_to_quantity( + y_output_values + ) + remote_displacement.ZComponent.Inputs[0].DiscreteValues = convert_to_quantity( + z_input_values + ) + remote_displacement.ZComponent.Output.DiscreteValues = convert_to_quantity( + z_output_values + ) + remote_displacement.RotationX.Inputs[0].DiscreteValues = convert_to_quantity( + rotation_x_input_values + ) + remote_displacement.RotationX.Output.DiscreteValues = convert_to_quantity( + rotation_x_output_values + ) + remote_displacement.RotationY.Inputs[0].DiscreteValues = convert_to_quantity( + rotation_y_input_values + ) + remote_displacement.RotationY.Output.DiscreteValues = convert_to_quantity( + rotation_y_output_values + ) + remote_displacement.RotationZ.Inputs[0].DiscreteValues = convert_to_quantity( + rotation_z_input_values + ) + remote_displacement.RotationZ.Output.DiscreteValues = convert_to_quantity( + rotation_z_output_values + ) + + +def convert_to_quantity(quantity_list): + values, unit = quantity_list + return [Quantity(f"{value} [{unit}]") for value in values] + remote_displacement = static_structural_analysis.AddRemoteDisplacement() remote_displacement.Location = remote_point01 -remote_displacement.XComponent.Inputs[0].DiscreteValues = [ - Quantity("0 [s]"), - Quantity("1 [s]"), - Quantity("2 [s]"), - Quantity("3 [s]"), -] -remote_displacement.XComponent.Output.DiscreteValues = [ - Quantity("0 [mm]"), - Quantity("0 [mm]"), - Quantity("0 [mm]"), - Quantity("0 [mm]"), -] -remote_displacement.YComponent.Inputs[0].DiscreteValues = [ - Quantity("0 [s]"), - Quantity("1 [s]"), - Quantity("2 [s]"), - Quantity("3 [s]"), -] -remote_displacement.YComponent.Output.DiscreteValues = [ - Quantity("0 [mm]"), - Quantity("0 [mm]"), - Quantity("-10 [mm]"), - Quantity("-10 [mm]"), -] -remote_displacement.ZComponent.Inputs[0].DiscreteValues = [ - Quantity("0 [s]"), - Quantity("1 [s]"), - Quantity("2 [s]"), - Quantity("3 [s]"), -] -remote_displacement.ZComponent.Output.DiscreteValues = [ - Quantity("0 [mm]"), - Quantity("0 [mm]"), - Quantity("0 [mm]"), - Quantity("0 [mm]"), -] - -remote_displacement.RotationX.Inputs[0].DiscreteValues = [ - Quantity("0 [s]"), - Quantity("1 [s]"), - Quantity("2 [s]"), - Quantity("3 [s]"), -] -remote_displacement.RotationX.Output.DiscreteValues = [ - Quantity("0 [rad]"), - Quantity("0 [rad]"), - Quantity("0 [rad]"), - Quantity("0 [rad]"), -] -remote_displacement.RotationY.Inputs[0].DiscreteValues = [ - Quantity("0 [s]"), - Quantity("1 [s]"), - Quantity("2 [s]"), - Quantity("3 [s]"), -] -remote_displacement.RotationY.Output.DiscreteValues = [ - Quantity("0 [rad]"), - Quantity("0 [rad]"), - Quantity("0 [rad]"), - Quantity("0 [rad]"), -] -remote_displacement.RotationZ.Inputs[0].DiscreteValues = [ - Quantity("0 [s]"), - Quantity("1 [s]"), - Quantity("2 [s]"), - Quantity("3 [s]"), -] -remote_displacement.RotationZ.Output.DiscreteValues = [ - Quantity("0 [rad]"), - Quantity("0 [rad]"), - Quantity("0 [rad]"), - Quantity("0.55 [rad]"), -] - -frictionless_support1 = static_structural_analysis.AddFrictionlessSupport() -frictionless_support1.Location = symm_faces30 -frictionless_support1.Name = "Symmetry_BC" -frictionless_support2 = static_structural_analysis.AddFrictionlessSupport() -frictionless_support2.Location = faces2 -frictionless_support2.Name = "Boot_Bottom_BC" -frictionless_support3 = static_structural_analysis.AddFrictionlessSupport() -frictionless_support3.Location = cyl_faces2 -frictionless_support3.Name = "Boot_Radial_BC" +set_input_output_values( + remote_displacement, + x_input_values=([0, 1, 2, 3], "s"), + x_output_values=([0, 0, 0, 0], "mm"), + y_input_values=([0, 1, 2, 3], "s"), + y_output_values=([0, 0, -10, -10], "mm"), + z_input_values=([0, 1, 2, 3], "s"), + z_output_values=([0, 0, 0, 0], "mm"), + rotation_x_input_values=([0, 1, 2, 3], "s"), + rotation_x_output_values=([0, 0, 0, 0], "rad"), + rotation_y_input_values=([0, 1, 2, 3], "s"), + rotation_y_output_values=([0, 0, 0, 0], "rad"), + rotation_z_input_values=([0, 1, 2, 3], "s"), + rotation_z_output_values=([0, 0, 0, 0.55], "rad"), +) + + +def add_frictionless_support( + static_structural_analysis, + location, + name: str, +): + """Add a frictionless support to the static structural analysis. + + Parameters + ---------- + static_structural_analysis : Ansys.ACT.Automation.Mechanical.StaticStructuralAnalysis + The static structural analysis object. + location : Ansys.ACT.Automation.Mechanical.NamedSelection + The location of the frictionless support. + name : str + The name of the frictionless support. + + Returns + ------- + Ansys.ACT.Automation.Mechanical.FrictionlessSupport + The created frictionless support. + """ + frictionless_support = static_structural_analysis.AddFrictionlessSupport() + frictionless_support.Location = location + frictionless_support.Name = name + + return frictionless_support + + +add_frictionless_support(static_structural_analysis, symm_faces30, "Symmetry_BC") +add_frictionless_support(static_structural_analysis, faces2, "Boot_Bottom_BC") +add_frictionless_support(static_structural_analysis, cyl_faces2, "Boot_Radial_BC") # %% # Add results # ~~~~~~~~~~~ +# Add total deformation results to the solution total_deformation = static_structural_analysis.Solution.AddTotalDeformation() total_deformation.Location = rubber_bodies30 +# Add equivalent stress results to the solution equivalent_stress = static_structural_analysis.Solution.AddEquivalentStress() equivalent_stress.Location = rubber_bodies30 # %% -# Solve -# ~~~~~ +# Solve the static structural analysis +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ static_structural_analysis.Solution.Solve(True) @@ -508,9 +636,8 @@ def display_image( # %% # Postprocessing # ~~~~~~~~~~~~~~ -# Total deformation - +# Activate the total deformation result and display the image app.Tree.Activate([total_deformation]) set_camera_and_display_image( camera, graphics, settings_720p, output_path, "total_deformation.png" @@ -519,6 +646,7 @@ def display_image( # %% # Equivalent stress +# Activate the equivalent stress result and display the image app.Tree.Activate([equivalent_stress]) set_camera_and_display_image( camera, graphics, settings_720p, output_path, "equivalent_stress.png" @@ -527,18 +655,6 @@ def display_image( # %% # Total deformation animation -animation_export_format = ( - Ansys.Mechanical.DataModel.Enums.GraphicsAnimationExportFormat.GIF -) -settings_720p = Ansys.Mechanical.Graphics.AnimationExportSettings() -settings_720p.Width = 1280 -settings_720p.Height = 720 - -total_deformation_gif = output_path / "total_deformation.gif" -total_deformation.ExportAnimation( - str(total_deformation_gif), animation_export_format, settings_720p -) - def update_animation(frame: int) -> list[mpimg.AxesImage]: """Update the animation frame for the GIF. @@ -561,6 +677,20 @@ def update_animation(frame: int) -> list[mpimg.AxesImage]: return [image] +# Set the animation export format and settings +animation_export_format = ( + Ansys.Mechanical.DataModel.Enums.GraphicsAnimationExportFormat.GIF +) +settings_720p = Ansys.Mechanical.Graphics.AnimationExportSettings() +settings_720p.Width = 1280 +settings_720p.Height = 720 + +# Export the total deformation animation as a GIF +total_deformation_gif = output_path / "total_deformation.gif" +total_deformation.ExportAnimation( + str(total_deformation_gif), animation_export_format, settings_720p +) + # Open the GIF file and create an animation gif = Image.open(total_deformation_gif) # Set the subplots for the animation and turn off the axis @@ -584,13 +714,15 @@ def update_animation(frame: int) -> list[mpimg.AxesImage]: plt.show() # %% -# Cleanup -# ~~~~~~~ -# Save project +# Clean up the project +# ~~~~~~~~~~~~~~~~~~~~ +# Save the mechdat file mechdat_file = output_path / "non_linear_rubber_boot_seal.mechdat" app.save(str(mechdat_file)) + +# Refresh the app app.new() -# delete example file +# Delete the example files delete_downloads() From 2dfc6e2d39d58fe7902a4ca5ecafa1ac6c553cc5 Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Mon, 12 May 2025 10:27:10 -0400 Subject: [PATCH 19/24] update rotor blade inverse solve example --- .../Rotor_Blade_Inverse_solve.py | 517 ++++++++++-------- requirements/requirements_doc.txt | 4 +- 2 files changed, 283 insertions(+), 238 deletions(-) diff --git a/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py b/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py index 87844632..decc8852 100644 --- a/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py +++ b/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py @@ -142,32 +142,25 @@ def display_image( # %% -# Download required files -# ~~~~~~~~~~~~~~~~~~~~~~~ -# Download the geometry file +# Download the required files +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Download the geometry file geometry_path = download_file( "example_10_td_055_Rotor_Blade_Geom.pmdb", "pymechanical", "embedding" ) -# %% # Download the material file - mat_path = download_file( "example_10_td_055_Rotor_Blade_Mat_File.xml", "pymechanical", "embedding" ) -# %% # Download the CFX pressure data - cfx_data_path = download_file( "example_10_CFX_ExportResults_FT_10P_EO2.csv", "pymechanical", "embedding" ) - -# %% -# Download required Temperature file - +# Download the temperature data file temp_data_path = download_file( "example_10_Temperature_Data.txt", "pymechanical", "embedding" ) @@ -176,11 +169,15 @@ def display_image( # 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 = ( @@ -188,19 +185,21 @@ def display_image( ) settings_720p.Background = Ansys.Mechanical.DataModel.Enums.GraphicsBackgroundType.White settings_720p.Width = 1280 -# settings_720p.Capture = Ansys.Mechanical.DataModel.Enums.GraphicsCaptureType.ImageOnly settings_720p.Height = 720 settings_720p.CurrentGraphicsDisplay = False # %% -# Import geometry -# ~~~~~~~~~~~~~~~ -# Reads geometry file and display +# 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 ) @@ -209,10 +208,13 @@ def display_image( 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() # %% @@ -220,10 +222,12 @@ def display_image( # ~~~~~~~~~~~~~~~~ # Import material from xml file and assign it to bodies +# Define and import the materials materials = model.Materials materials.Import(mat_path) -part1 = [x for x in app.Tree.AllObjects if x.Name == "Component2\Rotor11"][0] +# Assign the imported material to the components +part1 = [x for x in app.Tree.AllObjects if x.Name == r"Component2\Rotor11"][0] part2 = [x for x in app.Tree.AllObjects if x.Name == "Component3"][0] part2_blade1 = part2.Children[0] part2_blade2 = part2.Children[1] @@ -234,8 +238,9 @@ def display_image( part2_blade3.Material = "MAT1 (Setup, File1)" # %% -# Define units system and store variables -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Define the units system and store variables +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + # Select MKS units app.ExtAPI.Application.ActiveUnitSystem = MechanicalUnitSystem.StandardMKS @@ -249,33 +254,59 @@ def display_image( # %% # Define named selection # ~~~~~~~~~~~~~~~~~~~~~~ + + +def get_named_selection(ns_list: list) -> dict: + """Get the named selection by name. + + Parameters + ---------- + ns_list : list + A list of named selection names to retrieve. + + Returns + ------- + dict + A dictionary containing the named selection objects. + """ + ns_dict = {} + for name in ns_list: + ns_dict[name] = [obj for obj in app.Tree.AllObjects if obj.Name == name][0] + return ns_dict + + # Create NS for named selection -blade_ns = [x for x in app.Tree.AllObjects if x.Name == "Blade"][0] -blade_surface_ns = [x for x in app.Tree.AllObjects if x.Name == "Blade_Surf"][0] -fix_support_ns = [x for x in app.Tree.AllObjects if x.Name == "Fix_Support"][0] -blade_hub_ns = [x for x in app.Tree.AllObjects if x.Name == "Blade_Hub"][0] -hub_contact_ns = [x for x in app.Tree.AllObjects if x.Name == "Hub_Contact"][0] -blade_target_ns = [x for x in app.Tree.AllObjects if x.Name == "Blade_Target"][0] -hub_low_ns = [x for x in app.Tree.AllObjects if x.Name == "Hub_Low"][0] -hub_high_ns = [x for x in app.Tree.AllObjects if x.Name == "Hub_High"][0] -blade1_ns = [x for x in app.Tree.AllObjects if x.Name == "Blade1"][0] -blade1_source_ns = [x for x in app.Tree.AllObjects if x.Name == "Blade1_Source"][0] -blade1_target_ns = [x for x in app.Tree.AllObjects if x.Name == "Blade1_Target"][0] -blade2_ns = [x for x in app.Tree.AllObjects if x.Name == "Blade2"][0] -blade2_source_ns = [x for x in app.Tree.AllObjects if x.Name == "Blade2_Source"][0] -blade2_target_ns = [x for x in app.Tree.AllObjects if x.Name == "Blade2_Target"][0] -blade3_ns = [x for x in app.Tree.AllObjects if x.Name == "Blade3"][0] -blade3_source_ns = [x for x in app.Tree.AllObjects if x.Name == "Blade3_Source"][0] -blade3_target_ns = [x for x in app.Tree.AllObjects if x.Name == "Blade3_Target"][0] +named_selections_names = [ + "Blade", + "Blade_Surf", + "Fix_Support", + "Blade_Hub", + "Hub_Contact", + "Blade_Target", + "Hub_Low", + "Hub_High", + "Blade1", + "Blade1_Source", + "Blade1_Target", + "Blade2", + "Blade2_Source", + "Blade2_Target", + "Blade3", + "Blade3_Source", + "Blade3_Target", +] +ns_dict = get_named_selection(named_selections_names) # %% -# Define coordinate system -# ~~~~~~~~~~~~~~~~~~~~~~~~ -# Create cylindrical coordinate system +# Define a coordinate system +# ~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Define the coordinate systems coordinate_systems = model.CoordinateSystems +# Add a coordinate system coord_system = coordinate_systems.AddCoordinateSystem() +# Create cylindrical coordinate system coord_system.CoordinateSystemType = ( Ansys.ACT.Interfaces.Analysis.CoordinateSystemTypeEnum.Cylindrical ) @@ -283,319 +314,333 @@ def display_image( coord_system.OriginDefineBy = CoordinateSystemAlignmentType.Fixed # %% -# Define contacts -# ~~~~~~~~~~~~~~~ +# Add contact regions +# ~~~~~~~~~~~~~~~~~~~ # Define connections - connections = model.Connections +# Add a contact region contact_region1 = connections.AddContactRegion() +# Set the contact region's source and target locations contact_region1.SourceLocation = named_selections.Children[6] contact_region1.TargetLocation = named_selections.Children[5] +# Set the contact region's behavior to auto asymmetric contact_region1.Behavior = ContactBehavior.AutoAsymmetric +# Set the contact region's contact formulation to MPC contact_region1.ContactFormulation = ContactFormulation.MPC # %% -# Define mesh settings and generate mesh -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - +# Define the mesh settings and generate the mesh +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +def add_automatic_method( + mesh, + location_index: int, + source_loc_index: int = None, + target_loc_index: int = None, + method=MethodType.Sweep, + source_target_selection=2, + sweep_number_divisions=5, + set_src_target_properties: bool = True, +): + """Add an automatic method to the mesh.""" + automatic_method = mesh.AddAutomaticMethod() + automatic_method.Location = named_selections.Children[location_index] + automatic_method.Method = method + if set_src_target_properties: + automatic_method.SourceTargetSelection = source_target_selection + if source_loc_index: + automatic_method.SourceLocation = named_selections.Children[ + source_loc_index + ] + if target_loc_index: + automatic_method.TargetLocation = named_selections.Children[ + target_loc_index + ] + automatic_method.SweepNumberDivisions = sweep_number_divisions + + +# Define the mesh mesh = model.Mesh + +# Set the mesh settings mesh.ElementSize = Quantity(0.004, "m") mesh.UseAdaptiveSizing = False mesh.MaximumSize = Quantity(0.004, "m") mesh.ShapeChecking = 0 -automatic_method_Hub = mesh.AddAutomaticMethod() -automatic_method_Hub.Location = named_selections.Children[0] -automatic_method_Hub.Method = MethodType.Sweep -automatic_method_Hub.SweepNumberDivisions = 6 - -match_control_Hub = mesh.AddMatchControl() -match_control_Hub.LowNamedSelection = named_selections.Children[7] -match_control_Hub.HighNamedSelection = named_selections.Children[8] -cyc_coordinate_system = coordinate_systems.Children[1] -match_control_Hub.RotationAxis = cyc_coordinate_system - -sizing_Blade = mesh.AddSizing() -selection = named_selections.Children[5] -sizing_Blade.Location = selection -# sizing_Blade.ElementSize = Quantity(1e-3, "m") -sizing_Blade.ElementSize = Quantity(1e-2, "m") -sizing_Blade.CaptureCurvature = True -sizing_Blade.CurvatureNormalAngle = Quantity(0.31, "rad") -# sizing_Blade.LocalMinimumSize = Quantity(0.00025, "m") -sizing_Blade.LocalMinimumSize = Quantity(0.0005, "m") - -automatic_method_Blade1 = mesh.AddAutomaticMethod() -selection = named_selections.Children[9] -automatic_method_Blade1.Location = selection -automatic_method_Blade1.Method = MethodType.Sweep -automatic_method_Blade1.SourceTargetSelection = 2 -selection = named_selections.Children[10] -automatic_method_Blade1.SourceLocation = selection -selection = named_selections.Children[11] -automatic_method_Blade1.TargetLocation = selection -automatic_method_Blade1.SweepNumberDivisions = 5 - -automatic_method_Blade2 = mesh.AddAutomaticMethod() -selection = named_selections.Children[12] -automatic_method_Blade2.Location = selection -automatic_method_Blade2.Method = MethodType.Sweep -automatic_method_Blade2.SourceTargetSelection = 2 -selection = named_selections.Children[13] -automatic_method_Blade2.SourceLocation = selection -selection = named_selections.Children[14] -automatic_method_Blade2.TargetLocation = selection -automatic_method_Blade2.SweepNumberDivisions = 5 - -automatic_method_Blade3 = mesh.AddAutomaticMethod() -selection = named_selections.Children[15] -automatic_method_Blade3.Location = selection -automatic_method_Blade3.Method = MethodType.Sweep -automatic_method_Blade3.SourceTargetSelection = 2 -selection = named_selections.Children[16] -automatic_method_Blade3.SourceLocation = selection -selection = named_selections.Children[17] -automatic_method_Blade3.TargetLocation = selection -automatic_method_Blade3.SweepNumberDivisions = 5 +# Add an automatic method for the hub +add_automatic_method( + mesh, location_index=0, sweep_number_divisions=6, set_src_target_properties=False +) + +# Add match control to the mesh +match_control_hub = mesh.AddMatchControl() +# Set the low and high named selections to named selections' children at indices 7 and 8 +match_control_hub.LowNamedSelection = named_selections.Children[7] +match_control_hub.HighNamedSelection = named_selections.Children[8] +# Set the rotation axis to the second child of the coordinate systems +match_control_hub.RotationAxis = coordinate_systems.Children[1] + +# Add sizing to the mesh +sizing_blade = mesh.AddSizing() +# Set properties for the sizing blade +sizing_blade.Location = named_selections.Children[5] +sizing_blade.ElementSize = Quantity(1e-2, "m") +sizing_blade.CaptureCurvature = True +sizing_blade.CurvatureNormalAngle = Quantity(0.31, "rad") +sizing_blade.LocalMinimumSize = Quantity(0.0005, "m") + +# Add automatic methods for each blade +add_automatic_method(mesh, 9, 10, 11) +add_automatic_method(mesh, 12, 13, 14) +add_automatic_method(mesh, 15, 16, 17) + +# Generate the mesh and display the image mesh.GenerateMesh() set_camera_and_display_image( camera, graphics, settings_720p, output_path, "blade_mesh.png" ) # %% -# Define analysis settings -# ~~~~~~~~~~~~~~~~~~~~~~~~ -# Setup static structural settings with inverse solve +# Define the analysis settings +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Add a static structural analysis to the model model.AddStaticStructuralAnalysis() static_structural_analysis = model.Analyses[0] + +# Set the analysis settings analysis_settings = app.ExtAPI.DataModel.Project.Model.Analyses[0].AnalysisSettings analysis_settings.AutomaticTimeStepping = AutomaticTimeStepping.On analysis_settings.NumberOfSubSteps = 10 +# Activate the analysis settings analysis_settings.Activate() +# Add a command snippet to the static structural analysis with the archard wear model cmd1 = static_structural_analysis.AddCommandSnippet() # Add convergence criterion using command snippet. archard_wear_model = """CNVTOL,U,1.0,5e-5,1,,""" cmd1.AppendText(archard_wear_model) +# Set the analysis settings for inverse solving analysis_settings.InverseOption = True analysis_settings.LargeDeflection = True # %% -# Define boundary conditions -# ~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Apply rotational velocity +# Define the boundary conditions +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Add rotational velocity to the static structural analysis rotational_velocity = static_structural_analysis.AddRotationalVelocity() rotational_velocity.DefineBy = LoadDefineBy.Components +# Set z-component input values for the rotational velocity rotational_velocity.ZComponent.Inputs[0].DiscreteValues = [ Quantity("0 [s]"), Quantity("1 [s]"), Quantity("2 [s]"), ] +# Set z-component output values for the rotational velocity rotational_velocity.ZComponent.Output.DiscreteValues = [ Quantity("0 [rad/s]"), Quantity("1680 [rad/s]"), Quantity("1680 [rad/s]"), ] -# Apply Fixed Support Condition - +# Add a fixed support to the static structural analysis fixed_support = static_structural_analysis.AddFixedSupport() -selection = named_selections.Children[3] -fixed_support.Location = selection +# Set the fixed support location to the named selection at index 3 +fixed_support.Location = named_selections.Children[3] # %% -# Import CFX pressure -# ~~~~~~~~~~~~~~~~~~~ -# Import CFX pressure data and apply it to structural blade surface - -imported_load_group = static_structural_analysis.AddImportedLoadExternalData() - -external_data_files = Ansys.Mechanical.ExternalData.ExternalDataFileCollection() -external_data_files.SaveFilesWithProject = False -external_data_file_1 = Ansys.Mechanical.ExternalData.ExternalDataFile() -external_data_files.Add(external_data_file_1) -external_data_file_1.Identifier = "File1" -external_data_file_1.Description = "" -external_data_file_1.IsMainFile = False -external_data_file_1.FilePath = cfx_data_path -external_data_file_1.ImportSettings = ( - Ansys.Mechanical.ExternalData.ImportSettingsFactory.GetSettingsForFormat( - Ansys.Mechanical.DataModel.MechanicalEnums.ExternalData.ImportFormat.Delimited - ) -) -import_settings = external_data_file_1.ImportSettings -import_settings.SkipRows = 17 -import_settings.SkipFooter = 0 -import_settings.Delimiter = "," -import_settings.AverageCornerNodesToMidsideNodes = False -import_settings.UseColumn( - 0, - Ansys.Mechanical.DataModel.MechanicalEnums.ExternalData.VariableType.XCoordinate, - "m", - "X Coordinate@A", -) -import_settings.UseColumn( - 1, - Ansys.Mechanical.DataModel.MechanicalEnums.ExternalData.VariableType.YCoordinate, - "m", - "Y Coordinate@B", -) -import_settings.UseColumn( - 2, - Ansys.Mechanical.DataModel.MechanicalEnums.ExternalData.VariableType.ZCoordinate, - "m", - "Z Coordinate@C", -) -import_settings.UseColumn( - 3, - Ansys.Mechanical.DataModel.MechanicalEnums.ExternalData.VariableType.Pressure, - "Pa", - "Pressure@D", -) - -imported_load_group.ImportExternalDataFiles(external_data_files) -imported_pressure = imported_load_group.AddImportedPressure() -selection = named_selections.Children[2] -imported_pressure.Location = selection -imported_pressure.AppliedBy = LoadAppliedBy.Direct -imported_pressure.ImportLoad() - -app.Tree.Activate([imported_pressure]) -set_camera_and_display_image( - camera, graphics, settings_720p, output_path, "imported_pressure.png" -) - -################################################################################### -# Import Temperature -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Import temperature data and apply it to structural blade +# Import and apply temperature and CFX pressure to the structural blade & its surface +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -imported_load_group = static_structural_analysis.AddImportedLoadExternalData() -external_data_files = Ansys.Mechanical.ExternalData.ExternalDataFileCollection() -external_data_files.SaveFilesWithProject = False -external_data_file_1 = Ansys.Mechanical.ExternalData.ExternalDataFile() -external_data_files.Add(external_data_file_1) -external_data_file_1.Identifier = "File1" -external_data_file_1.Description = "" -external_data_file_1.IsMainFile = False -external_data_file_1.FilePath = temp_data_path +def process_external_data( + external_data_path: str, + skip_rows: int, + skip_footer: int, + data_type: str, + location_index: int, +) -> None: + """Process the external data file and set its properties. -external_data_file_1.ImportSettings = ( - Ansys.Mechanical.ExternalData.ImportSettingsFactory.GetSettingsForFormat( + Parameters + ---------- + external_data_path : str + The path to the external data file. + skip_rows : int + The number of rows to skip at the beginning of the file. + skip_footer : int + The number of rows to skip at the end of the file. + data_type : str + The type of data to process ('pressure' or 'temperature'). + location_index : int + The index of the named selection to apply the data to. + """ + # Add imported load external data to the static structural analysis + imported_load_group = static_structural_analysis.AddImportedLoadExternalData() + + external_data_files = Ansys.Mechanical.ExternalData.ExternalDataFileCollection() + external_data_files.SaveFilesWithProject = False + file = Ansys.Mechanical.ExternalData.ExternalDataFile() + external_data_files.Add(file) + + file.Identifier = "File1" + file.Description = "" + file.IsMainFile = False + file.FilePath = external_data_path + # Set the file format to delimited + file.ImportSettings = Ansys.Mechanical.ExternalData.ImportSettingsFactory.GetSettingsForFormat( Ansys.Mechanical.DataModel.MechanicalEnums.ExternalData.ImportFormat.Delimited ) -) -import_settings = external_data_file_1.ImportSettings -import_settings.SkipRows = 0 -import_settings.SkipFooter = 0 -import_settings.Delimiter = "," -import_settings.AverageCornerNodesToMidsideNodes = False -import_settings.UseColumn( - 0, - Ansys.Mechanical.DataModel.MechanicalEnums.ExternalData.VariableType.XCoordinate, - "m", - "X Coordinate@A", -) -import_settings.UseColumn( - 1, - Ansys.Mechanical.DataModel.MechanicalEnums.ExternalData.VariableType.YCoordinate, - "m", - "Y Coordinate@B", -) -import_settings.UseColumn( - 2, - Ansys.Mechanical.DataModel.MechanicalEnums.ExternalData.VariableType.ZCoordinate, - "m", - "Z Coordinate@C", -) -import_settings.UseColumn( - 3, - Ansys.Mechanical.DataModel.MechanicalEnums.ExternalData.VariableType.Temperature, - "C", - "Temperature@D", -) -imported_load_group.ImportExternalDataFiles(external_data_files) -imported_body_temperature = imported_load_group.AddImportedBodyTemperature() + # Set up import settings for the external data file + import_settings = file.ImportSettings + import_settings.SkipRows = skip_rows + import_settings.SkipFooter = skip_footer + import_settings.Delimiter = "," + import_settings.AverageCornerNodesToMidsideNodes = False + import_settings.UseColumn( + 0, + Ansys.Mechanical.DataModel.MechanicalEnums.ExternalData.VariableType.XCoordinate, + "m", + "X Coordinate@A", + ) + import_settings.UseColumn( + 1, + Ansys.Mechanical.DataModel.MechanicalEnums.ExternalData.VariableType.YCoordinate, + "m", + "Y Coordinate@B", + ) + import_settings.UseColumn( + 2, + Ansys.Mechanical.DataModel.MechanicalEnums.ExternalData.VariableType.ZCoordinate, + "m", + "Z Coordinate@C", + ) + if data_type == "pressure": + import_settings.UseColumn( + 3, + Ansys.Mechanical.DataModel.MechanicalEnums.ExternalData.VariableType.Pressure, + "Pa", + "Pressure@D", + ) + elif data_type == "temperature": + import_settings.UseColumn( + 3, + Ansys.Mechanical.DataModel.MechanicalEnums.ExternalData.VariableType.Temperature, + "C", + "Temperature@D", + ) + # Import external data files to the imported load group + imported_load_group.ImportExternalDataFiles(external_data_files) + if data_type == "pressure": + # Add imported pressure to the imported load group + added_obj = imported_load_group.AddImportedPressure() + elif data_type == "temperature": + # Add imported body temperature to the imported load group + added_obj = imported_load_group.AddImportedBodyTemperature() + # Set properties for the imported pressure + added_obj.Location = named_selections.Children[location_index] + if data_type == "pressure": + added_obj.AppliedBy = LoadAppliedBy.Direct + added_obj.ImportLoad() + + # Activate the imported pressure or temperature and display the image + app.Tree.Activate([added_obj]) + set_camera_and_display_image( + camera, graphics, settings_720p, output_path, f"imported_{data_type}.png" + ) -selection = named_selections.Children[1] -imported_body_temperature.Location = selection -imported_body_temperature.ImportLoad() -app.Tree.Activate([imported_body_temperature]) -set_camera_and_display_image( - camera, graphics, settings_720p, output_path, "imported_temperature.png" +# Import and apply CFX pressure to the structural blade surface +process_external_data( + cfx_data_path, skip_rows=17, skip_footer=0, data_type="pressure", location_index=2 +) +# Import temperature data and apply it to structural blade +process_external_data( + temp_data_path, + skip_rows=0, + skip_footer=0, + data_type="temperature", + location_index=1, ) # %% -# Postprocessing -# ~~~~~~~~~~~~~~ -# Insert results +# Add results to the solution +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Define the static structural analysis solution solution = static_structural_analysis.Solution +# Add total deformation results to the solution total_deformation1 = solution.AddTotalDeformation() total_deformation1.DisplayTime = Quantity("1 [s]") +# Add equivalent stress results to the solution equivalent_stress1 = solution.AddEquivalentStress() equivalent_stress1.DisplayTime = Quantity("1 [s]") +# Add equivalent total strain results to the solution equivalent_total_strain1 = solution.AddEquivalentTotalStrain() equivalent_total_strain1.DisplayTime = Quantity("1 [s]") +# Add thermal strain results to the solution thermal_strain1 = solution.AddThermalStrain() thermal_strain1.DisplayTime = Quantity("1 [s]") - # %% -# Run Solution -# ~~~~~~~~~~~~ -# Solve inverse analysis on blade model +# Solve the solution +# ~~~~~~~~~~~~~~~~~~ +# Solve the inverse analysis on the blade model solution.Solve(True) soln_status = solution.Status # %% # Postprocessing # ~~~~~~~~~~~~~~ -# Evaluate results and export screenshots +# Evaluate the results and export screenshots # %% # Total deformation +# Activate the total deformation results app.Tree.Activate([total_deformation1]) +# Set the extra model display to no wireframe graphics.ViewOptions.ResultPreference.ExtraModelDisplay = ( Ansys.Mechanical.DataModel.MechanicalEnums.Graphics.ExtraModelDisplay.NoWireframe ) +# Set the camera to fit the model and export the image set_camera_and_display_image( camera, graphics, settings_720p, output_path, "total_deformation.png" ) # %% -# Equivalent stress +# Thermal strain +# Activate the thermal strain results app.Tree.Activate([thermal_strain1]) +# Set the camera to fit the model and export the image set_camera_and_display_image( camera, graphics, settings_720p, output_path, "thermal_strain.png" ) # %% -# Cleanup -# ~~~~~~~ -# Save project +# Clean up +# ~~~~~~~~ +# Save the project mechdat_file = output_path / "blade_inverse.mechdat" app.save(str(mechdat_file)) -app.new() -# %% -# Delete example file +# Refresh the app +app.new() +# Delete the example file delete_downloads() diff --git a/requirements/requirements_doc.txt b/requirements/requirements_doc.txt index ef9be155..d6eb92ef 100644 --- a/requirements/requirements_doc.txt +++ b/requirements/requirements_doc.txt @@ -1,3 +1,3 @@ #PyMechanical -ansys-mechanical-core[doc]==0.11.14 -ansys-mechanical-core[viz]==0.11.14 \ No newline at end of file +ansys-mechanical-core[doc]==0.11.16 +ansys-mechanical-core[graphics]==0.11.16 \ No newline at end of file From e0a27367fdea11af6b6df755b358f916c83dcbca Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Tue, 13 May 2025 11:03:54 -0400 Subject: [PATCH 20/24] adjust comments/sections --- examples/00_tips/tips_01.py | 17 +- examples/00_tips/tips_02.py | 9 +- examples/00_tips/tips_03.py | 10 +- examples/01_basic/bolt_pretension.py | 202 +++++++++++++----- .../fracture_analysis_contact_debonding.py | 128 ++++++----- examples/01_basic/harmonic_acoustics.py | 102 ++++----- examples/01_basic/modal_acoustics_analysis.py | 80 ++++--- .../01_basic/steady_state_thermal_analysis.py | 87 +++++--- .../topology_optimization_cantilever_beam.py | 13 +- examples/01_basic/valve.py | 43 ++-- .../Rotor_Blade_Inverse_solve.py | 70 +++--- .../contact_wear_simulation.py | 27 ++- .../non_linear_analysis_rubber_boot_seal.py | 176 ++++++++------- 13 files changed, 592 insertions(+), 372 deletions(-) diff --git a/examples/00_tips/tips_01.py b/examples/00_tips/tips_01.py index ad9596c1..8fd781f2 100644 --- a/examples/00_tips/tips_01.py +++ b/examples/00_tips/tips_01.py @@ -3,34 +3,35 @@ 3D visualization ---------------- -Visualize 3D imported geometry +The following example demonstrates how to visualize imported geometry in 3D. """ # %% -# Import necessary libraries -# ~~~~~~~~~~~~~~~~~~~~~~~~~~ - +# Import the necessary libraries +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ from ansys.mechanical.core import App from ansys.mechanical.core.examples import delete_downloads, download_file # %% # Create an instance of the Mechanical embedded application +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ app = App(globals=globals()) print(app) # %% -# Download and import geometry file -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Download and import the geometry file +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# %% # Download the geometry file geometry_path = download_file("Valve.pmdb", "pymechanical", "embedding") -# Define the model +# %% +# Define the model and import the geometry file model = app.Model -# Import the geometry file geometry_import = model.GeometryImportGroup.AddGeometryImport() geometry_import.Import(geometry_path) diff --git a/examples/00_tips/tips_02.py b/examples/00_tips/tips_02.py index 184dd0b8..eeb57963 100644 --- a/examples/00_tips/tips_02.py +++ b/examples/00_tips/tips_02.py @@ -3,12 +3,13 @@ Export image ------------ -Export image and display +The following example demonstrates how to export an image of the imported geometry +and display it using matplotlib. """ # %% -# Import necessary libraries -# ~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Import the necessary libraries +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ from pathlib import Path @@ -17,6 +18,7 @@ # %% # Create an instance of the Mechanical embedded application +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Create an instance of the App class app = App() @@ -31,6 +33,7 @@ # Download and import the geometry file # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# %% # Download the geometry file geometry_path = download_file("Valve.pmdb", "pymechanical", "embedding") diff --git a/examples/00_tips/tips_03.py b/examples/00_tips/tips_03.py index 32633852..e725b728 100644 --- a/examples/00_tips/tips_03.py +++ b/examples/00_tips/tips_03.py @@ -1,21 +1,21 @@ """.. _ref_tips_03: Project tree --------------------- +------------ -Display the heirarchial Mechanical project structure. +The following example demonstrates how to print the heirarchial Mechanical project structure. """ # %% -# Import necessary libraries -# ~~~~~~~~~~~~~~~~~~~~~~~~~~ - +# Import the necessary libraries +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ from ansys.mechanical.core import App from ansys.mechanical.core.examples import delete_downloads, download_file # %% # Create an instance of the Mechanical embedded application +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ app = App(globals=globals()) print(app) diff --git a/examples/01_basic/bolt_pretension.py b/examples/01_basic/bolt_pretension.py index cae5ac98..14ce652a 100644 --- a/examples/01_basic/bolt_pretension.py +++ b/examples/01_basic/bolt_pretension.py @@ -27,6 +27,7 @@ # %% # Create an instance of the Mechanical embedded application +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ app = App() print(app) @@ -103,9 +104,10 @@ app.plot() # %% -# Download and import material -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Download and import the materials +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# %% # Download the material files from the ansys/example-data repository copper_material_file_path = download_file( "example_06_Mat_Copper.xml", "pymechanical", "00_basic" @@ -114,6 +116,7 @@ "example_06_Mat_Steel.xml", "pymechanical", "00_basic" ) +# %% # Add materials to the model and import the material files model_materials = model.Materials model_materials.Import(copper_material_file_path) @@ -130,13 +133,15 @@ # Define analysis and unit system # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# %% # Add static structural analysis to the model model.AddStaticStructuralAnalysis() static_structural = model.Analyses[0] static_structural_solution = static_structural.Solution static_structural_analysis_setting = static_structural.Children[0] -# Store named selections +# %% +# Store the named selections named_selections_dictionary = {} named_selections_list = [ "block3_block2_cont", @@ -153,6 +158,7 @@ "block2_block1_targ", ] +# %% # Get tree objects for each named selection for named_selection in named_selections_list: named_selections_dictionary[named_selection] = [ @@ -161,6 +167,7 @@ if tree_obj.Name == str(named_selection) ][0] +# %% # Create dictionary with material assignment for each model.Geometry.Children index children_materials = { 0: "Steel", @@ -171,6 +178,7 @@ 5: "Steel", } +# %% # Assign surface materials to the model.Geometry bodies geometry = model.Geometry for children_index, material_name in children_materials.items(): @@ -181,11 +189,13 @@ # Add and define a coordinate system # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Add coordinate systems to the model +# %% +# Add a coordinate system to the model coordinate_systems = model.CoordinateSystems coordinate_system = coordinate_systems.AddCoordinateSystem() -# Define the coordinate system +# %% +# Define the coordinate system and set its axis properties coordinate_system.OriginDefineBy = CoordinateSystemAlignmentType.Fixed coordinate_system.OriginX = Quantity(-195, "mm") coordinate_system.OriginY = Quantity(100, "mm") @@ -193,10 +203,13 @@ coordinate_system.PrimaryAxis = CoordinateSystemAxisType.PositiveZAxis # %% -# Add and define contact regions -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Create functions to set contact regions' locations, types, and other advanced contact settings +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# %% +# Add a contact region to the body with the specified source location, target location, +# and contact type def set_contact_region_locations_and_types( body: typing.Union[ Ansys.ACT.Automation.Mechanical.Connections, @@ -233,6 +246,8 @@ def set_contact_region_locations_and_types( return contact_region +# %% +# Set the friction coefficient, small sliding, and update stiffness settings for the contact region def advanced_contact_settings( contact_region: Ansys.ACT.Automation.Mechanical.Connections.ContactRegion, friction_coefficient: int, @@ -258,6 +273,8 @@ def advanced_contact_settings( contact_region.UpdateStiffness = update_stiffness +# %% +# Add a command snippet to the contact region with the specified Archard Wear Model def add_command_snippet( contact_region: Ansys.ACT.Automation.Mechanical.Connections.ContactRegion, archard_wear_model: str, @@ -275,12 +292,20 @@ def add_command_snippet( contact_region_cmd.AppendText(archard_wear_model) +# %% +# Add and define contact regions +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# %% # Set up the model connections and delete the existing connections for ConnectionGroups connections = model.Connections for connection in connections.Children: if connection.DataModelObjectCategory == DataModelObjectCategory.ConnectionGroup: connection.Delete() +# %% +# Set the archard wear model and get the named selections from the model + # Set the archard wear model archard_wear_model = """keyopt,cid,9,5 rmodif,cid,10,0.00 @@ -289,6 +314,7 @@ def add_command_snippet( # Get named selections from the model for contact regions named_selections = model.NamedSelections +# %% # Add a contact region for the model's named selections Children 0 and 1 with the specified # contact type contact_region = set_contact_region_locations_and_types( @@ -307,9 +333,11 @@ def add_command_snippet( # Add a command snippet to the contact region with the specified Archard Wear Model add_command_snippet(contact_region, archard_wear_model) +# %% # Set the connection group for the contact regions connection_group = connections.Children[0] +# %% # Add a contact region for the model's named selections Children 2 and 3 with the specified # contact type contact_region_2 = set_contact_region_locations_and_types( @@ -320,6 +348,7 @@ def add_command_snippet( ) contact_region_2.ContactFormulation = ContactFormulation.MPC +# %% # Add a contact region for the model's named selections Children 4 and 5 with the specified # contact type contact_region_3 = set_contact_region_locations_and_types( @@ -338,6 +367,7 @@ def add_command_snippet( # Add a command snippet to the contact region with the specified Archard Wear Model add_command_snippet(contact_region_3, archard_wear_model) +# %% # Add a contact region for the model's named selections Children 6 and 7 with the specified # contact type contact_region_4 = set_contact_region_locations_and_types( @@ -348,6 +378,7 @@ def add_command_snippet( ) contact_region_4.ContactFormulation = ContactFormulation.MPC +# %% # Add a contact region for the model's named selections Children 8 and 9 with the specified # contact type contact_region_5 = set_contact_region_locations_and_types( @@ -358,6 +389,7 @@ def add_command_snippet( ) contact_region_5.ContactFormulation = ContactFormulation.MPC +# %% # Add a contact region for the model's named selections Children 10 and 11 with the specified # contact type contact_region_6 = set_contact_region_locations_and_types( @@ -377,12 +409,25 @@ def add_command_snippet( add_command_snippet(contact_region_6, archard_wear_model) # %% -# Add mesh methods, sizing, and face meshing -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Create functions to set the method location, mesh sizing, and element size +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -def set_method_location(method, object_name: str, location_type: str = ""): - """Set the location of the method based on the specified name and location type.""" +# %% +# Set the method location for the specified method and object name +def set_method_location(method, object_name: str, location_type: str = "") -> None: + """Set the location of the method based on the specified name and location type. + + Parameters + ---------- + method : Ansys.ACT.Automation.Mechanical.MeshMethod + The method to set the location for. + object_name : str + The name of the object to set the location for. + location_type : str, optional + The type of location to set for the method. Can be "source", "target", or empty string. + Default is an empty string. + """ # Get the tree object for the specified name tree_obj_list = [ tree_obj @@ -399,8 +444,20 @@ def set_method_location(method, object_name: str, location_type: str = ""): method.Location = tree_obj_list -def add_mesh_sizing(mesh, object_name: str, element_size: Quantity): - """Add a mesh sizing to the mesh with the specified name, quantity value, and measurement.""" +# %% +# Add a mesh sizing to the mesh with the specified name, quantity value, and measurement +def add_mesh_sizing(mesh, object_name: str, element_size: Quantity) -> None: + """Add a mesh sizing to the mesh with the specified name, quantity value, and measurement. + + Parameters + ---------- + mesh : Ansys.ACT.Automation.Mechanical.Mesh + The mesh to add the sizing to. + object_name : str + The name of the object to set the sizing for. + element_size : Quantity + The element size for the mesh sizing. + """ # Add sizing to the mesh body_sizing = mesh.AddSizing() # Get the tree object for the specified name @@ -413,24 +470,34 @@ def add_mesh_sizing(mesh, object_name: str, element_size: Quantity): body_sizing.ElementSize = element_size +# %% +# Add mesh methods, sizing, and face meshing +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# %% +# Add the mesh sizing to the bodies_5 and shank objects + # Get the mesh for the model mesh = model.Mesh # Add the mesh sizing to the bodies_5 and shank objects add_mesh_sizing(mesh=mesh, object_name="bodies_5", element_size=Quantity(15, "mm")) add_mesh_sizing(mesh=mesh, object_name="shank", element_size=Quantity(7, "mm")) +# %% # Add an automatic method to the mesh and set the method type hex_method = mesh.AddAutomaticMethod() hex_method.Method = MethodType.Automatic # Set the method location for the all_bodies object set_method_location(method=hex_method, object_name="all_bodies") +# %% # Add face meshing to the mesh and set the MappedMesh property to False face_meshing = mesh.AddFaceMeshing() face_meshing.MappedMesh = False # Set the method location for the face meshing set_method_location(method=face_meshing, object_name="shank_face") +# %% # Add an automatic method to the mesh, set the method type, and set the source target selection sweep_method = mesh.AddAutomaticMethod() sweep_method.Method = MethodType.Sweep @@ -444,6 +511,7 @@ def add_mesh_sizing(mesh, object_name: str, element_size: Quantity): method=sweep_method, object_name="shank_face2", location_type="target" ) +# %% # Activate and generate the mesh mesh.Activate() mesh.GenerateMesh() @@ -460,6 +528,8 @@ def add_mesh_sizing(mesh, object_name: str, element_size: Quantity): ) +# %% +# Create a function to display the image using matplotlib def display_image( image_path: str, pyplot_figsize_coordinates: tuple = (16, 9), @@ -484,6 +554,7 @@ def display_image( plt.show() +# %% # Display the mesh image display_image(mesh_image_path) @@ -656,52 +727,61 @@ def display_image( # Display the results # ~~~~~~~~~~~~~~~~~~~ -# Create a list with the total deformation, equivalent stress 1, and equivalent stress 2 objects -tree_obj_list = [total_deformation, equivalent_stress_1, equivalent_stress_2] - -# Activate each of the objects in the list and export and display the images -for tree_obj in tree_obj_list: - # Activate the object - app.Tree.Activate([tree_obj]) - # Set the camera to fit the model - camera.SetFit() - # Set the image name and path for the object - image_path = str(output_path / f"{tree_obj}.png") - # Export the image of the object - app.Graphics.ExportImage( - image_path, image_export_format, graphics_image_export_settings - ) - # Display the image of the object - display_image(image_path) - # %% -# Export and display the contact status animation -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Total deformation -# Get the post contact tool status -post_contact_tool_status = post_contact_tool.Children[0] +# Activate the object +app.Tree.Activate([total_deformation]) +# Set the camera to fit the model +camera.SetFit() +# Set the image name and path for the object +image_path = str(output_path / f"total_deformation.png") +# Export the image of the object +app.Graphics.ExportImage( + image_path, image_export_format, graphics_image_export_settings +) +# Display the image of the object +display_image(image_path) -# Activate the post contact tool status in the tree -app.Tree.Activate([post_contact_tool_status]) +# %% +# Equivalent stress on all bodies +# Activate the object +app.Tree.Activate([equivalent_stress_1]) # Set the camera to fit the model camera.SetFit() +# Set the image name and path for the object +image_path = str(output_path / f"equivalent_stress_all_bodies.png") +# Export the image of the object +app.Graphics.ExportImage( + image_path, image_export_format, graphics_image_export_settings +) +# Display the image of the object +display_image(image_path) -# Set the animation export format and settings -animation_export_format = GraphicsAnimationExportFormat.GIF -animation_export_settings = Ansys.Mechanical.Graphics.AnimationExportSettings() -animation_export_settings.Width = 1280 -animation_export_settings.Height = 720 - -# Set the path for the contact status GIF -contact_status_gif_path = str(output_path / "contact_status.gif") +# %% +# Equivalent stress on the shank -# Export the contact status animation to a GIF file -post_contact_tool_status.ExportAnimation( - contact_status_gif_path, animation_export_format, animation_export_settings +# Activate the object +app.Tree.Activate([equivalent_stress_2]) +# Set the camera to fit the model +camera.SetFit() +# Set the image name and path for the object +image_path = str(output_path / f"equivalent_stress_shank.png") +# Export the image of the object +app.Graphics.ExportImage( + image_path, image_export_format, graphics_image_export_settings ) +# Display the image of the object +display_image(image_path) + +# %% +# Export and display the contact status animation +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# %% +# Create a function to update the animation frames def update_animation(frame: int) -> list[mpimg.AxesImage]: """Update the animation frame for the GIF. @@ -723,6 +803,32 @@ def update_animation(frame: int) -> list[mpimg.AxesImage]: return [image] +# %% +# Export and display the contact status animation + +# Get the post contact tool status +post_contact_tool_status = post_contact_tool.Children[0] + +# Activate the post contact tool status in the tree +app.Tree.Activate([post_contact_tool_status]) + +# Set the camera to fit the model +camera.SetFit() + +# Set the animation export format and settings +animation_export_format = GraphicsAnimationExportFormat.GIF +animation_export_settings = Ansys.Mechanical.Graphics.AnimationExportSettings() +animation_export_settings.Width = 1280 +animation_export_settings.Height = 720 + +# Set the path for the contact status GIF +contact_status_gif_path = str(output_path / "contact_status.gif") + +# Export the contact status animation to a GIF file +post_contact_tool_status.ExportAnimation( + contact_status_gif_path, animation_export_format, animation_export_settings +) + # Open the GIF file and create an animation gif = Image.open(contact_status_gif_path) # Set the subplots for the animation and turn off the axis diff --git a/examples/01_basic/fracture_analysis_contact_debonding.py b/examples/01_basic/fracture_analysis_contact_debonding.py index a462d526..f7ef2668 100644 --- a/examples/01_basic/fracture_analysis_contact_debonding.py +++ b/examples/01_basic/fracture_analysis_contact_debonding.py @@ -10,8 +10,8 @@ """ # %% -# Import necessary libraries -# ~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Import the necessary libraries +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ from pathlib import Path from typing import TYPE_CHECKING @@ -28,9 +28,9 @@ # %% # Create an instance of the Mechanical embedded application +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -app = App() # globals=globals() -app.update_globals(globals()) +app = App(globals=globals()) print(app) # %% @@ -52,8 +52,8 @@ graphics_image_export_settings.Height = 720 # %% -# Set the image output path and create functions to fit the camera and display images -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Create functions to set camera and display images +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Set the path for the output files (images, gifs, mechdat) output_path = Path.cwd() / "out" @@ -127,8 +127,8 @@ def display_image( # %% -# Import the geometry -# ~~~~~~~~~~~~~~~~~~~ +# Download and import the geometry file +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Set the model model = app.Model @@ -161,8 +161,8 @@ def display_image( app.plot() # %% -# Material import, named selections, and connections -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Download and import the material files +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Download the material files from the ansys/example-data repository mat1_path = download_file( @@ -178,8 +178,8 @@ def display_image( model_materials.Import(mat2_path) # %% -# Add automatic connections to the model -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Add connections to the model +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Add connections to the model add_connections = model.AddConnections() @@ -191,8 +191,8 @@ def display_image( connections.CreateAutomaticConnections() # %% -# Define the static structural analysis and settings -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Add a static structural analysis to the model +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Add a static structural analysis to the model model.AddStaticStructuralAnalysis() @@ -203,8 +203,8 @@ def display_image( app.ExtAPI.Application.ActiveUnitSystem = MechanicalUnitSystem.StandardNMM # %% -# Define the geometry, activate it, and set the 2D behavior -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Activate the geometry and set the 2D behavior +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Define the geometry for the model geometry = model.Geometry @@ -214,6 +214,7 @@ def display_image( geometry.Model2DBehavior = Model2DBehavior.PlaneStrain +# %% # Create a function to get the child object by name # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -226,8 +227,8 @@ def get_child_object(body, child_type, name: str): # %% -# Get the Part 2 object from the tree, activate it, and set the material -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Activate the part 2 object and set its material +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Get the Part 2 object from the tree part2_object = [ @@ -245,6 +246,9 @@ def get_child_object(body, child_type, name: str): # %% Define the contact and contact regions # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# %% +# Activate the contact region + # Get the contact from the connection group contact = get_child_object( connections, Ansys.ACT.Automation.Mechanical.Connections.ConnectionGroup, "Contacts" @@ -257,6 +261,9 @@ def get_child_object(body, child_type, name: str): # Activate the contact region contact_region.Activate() +# %% +# Set properties for the contact region + # Define the model named selections named_selections = model.NamedSelections # Set the source location to the high edge named selection @@ -273,8 +280,8 @@ def get_child_object(body, child_type, name: str): contact_region.ContactFormulation = ContactFormulation.PurePenalty # %% -# Define the mesh controls and generate mesh -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Generate the mesh +# ~~~~~~~~~~~~~~~~~ # Define the mesh for the model mesh = model.Mesh @@ -290,6 +297,10 @@ def get_child_object(body, child_type, name: str): mesh.ElementSize = Quantity("0.75 [mm]") +# %% +# Create a function to add sizing to the mesh + + def add_sizing( mesh: Ansys.ACT.Automation.Mechanical.MeshControls.Mesh, name: str, @@ -317,10 +328,12 @@ def add_sizing( sizing.Behavior = behavior +# %% # Add sizing to the mesh for the short and long edges add_sizing(mesh, "Short_Edges", Quantity("0.75 [mm]"), SizingBehavior.Hard) add_sizing(mesh, "Long_Edges", Quantity("0.5 [mm]"), SizingBehavior.Hard) +# %% # Add sizing to the mesh for both faces sizing_mesh_both_faces = mesh.AddFaceMeshing() sizing_mesh_both_faces.Location = get_child_object( @@ -339,8 +352,8 @@ def add_sizing( ) # %% -# Add contact debonding object -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Add a contact debonding object +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Activate the model model.Activate() @@ -394,6 +407,9 @@ def add_sizing( # Add displacements to the static structural analysis # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# %% +# Create a function to add displacement to the static structural analysis + def add_displacement( static_structural_analysis: Ansys.ACT.Automation.Mechanical.Analysis, @@ -430,19 +446,21 @@ def add_displacement( return displacement -# Add displacement to the static structural analysis +# %% +# Add displacements to the static structural analysis + displacement1_vertex = add_displacement( static_structural_analysis, named_selections, "Disp1_Vertex", Quantity("10 [mm]") ) -# Add another displacement to the static structural analysis displacement2_vertex = add_displacement( static_structural_analysis, named_selections, "Disp2_Vertex", Quantity("-10 [mm]") ) -# Activate the static structural analysis +# %% +# Set the camera to fit the model and display the image of the boundary conditions + static_structural_analysis.Activate() -# Set the camera to fit the model and display the image of the boundary conditions set_camera_and_display_image( camera, graphics, @@ -484,8 +502,8 @@ def add_displacement( # sphinx_gallery_end_ignore # %% -# Messages -# ~~~~~~~~ +# Print messages from the solve +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ messages = app.ExtAPI.Application.Messages if messages: @@ -495,12 +513,13 @@ def add_displacement( print("No [Info]/[Warning]/[Error] Messages") # %% -# Activate the directional deformation and force reactions and display their images -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Activate the reactions and display the images +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# %% +# Directional deformation -# Activate the directional deformation directional_deformation.Activate() -# Set the camera to fit the model and display the image of the directional deformation set_camera_and_display_image( camera, graphics, @@ -509,30 +528,20 @@ def add_displacement( "directional_deformation.png", ) -# Activate the force reaction +# %% +# Force reaction + force_reaction.Activate() -# Set the camera to fit the model and display the image of the force reaction set_camera_and_display_image( camera, graphics, graphics_image_export_settings, output_path, "force_reaction.png" ) # %% -# Export animation -# ~~~~~~~~~~~~~~~~ - -# Set the animation export format and settings -animation_export_format = GraphicsAnimationExportFormat.GIF -animation_export_settings = Ansys.Mechanical.Graphics.AnimationExportSettings() -animation_export_settings.Width = 1280 -animation_export_settings.Height = 720 - -# Set the path for the contact status GIF -force_reaction_gif_path = output_path / "force_reaction.gif" +# Export the animation +# ~~~~~~~~~~~~~~~~~~~~ -# Export the force reaction animation to a GIF file -force_reaction.ExportAnimation( - str(force_reaction_gif_path), animation_export_format, animation_export_settings -) +# %% +# Create a function to update the animation frame def update_animation(frame: int) -> list[mpimg.AxesImage]: @@ -556,6 +565,23 @@ def update_animation(frame: int) -> list[mpimg.AxesImage]: return [image] +# %% +# Display the animation of the force reaction + +# Set the animation export format and settings +animation_export_format = GraphicsAnimationExportFormat.GIF +animation_export_settings = Ansys.Mechanical.Graphics.AnimationExportSettings() +animation_export_settings.Width = 1280 +animation_export_settings.Height = 720 + +# Set the path for the contact status GIF +force_reaction_gif_path = output_path / "force_reaction.gif" + +# Export the force reaction animation to a GIF file +force_reaction.ExportAnimation( + str(force_reaction_gif_path), animation_export_format, animation_export_settings +) + # Open the GIF file and create an animation gif = Image.open(force_reaction_gif_path) # Set the subplots for the animation and turn off the axis @@ -579,8 +605,8 @@ def update_animation(frame: int) -> list[mpimg.AxesImage]: plt.show() # %% -# Display output file from the solve -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Display the output file from the solve +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Get the working directory for the static structural analysis solve_path = Path(static_structural_analysis.WorkingDir) diff --git a/examples/01_basic/harmonic_acoustics.py b/examples/01_basic/harmonic_acoustics.py index 689924b5..7c1db89c 100644 --- a/examples/01_basic/harmonic_acoustics.py +++ b/examples/01_basic/harmonic_acoustics.py @@ -32,8 +32,8 @@ """ # %% -# Import necessary libraries -# ~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Import the necessary libraries +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ from pathlib import Path from typing import TYPE_CHECKING @@ -50,14 +50,15 @@ # %% # Create an instance of the Mechanical embedded application +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ app = App() app.update_globals(globals()) print(app) # %% -# Set the image output path and create functions to fit the camera and display images -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Create functions to set camera and display images +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Set the path for the output files (images, gifs, mechdat) output_path = Path.cwd() / "out" @@ -244,6 +245,9 @@ def display_image( # Create named selections # ~~~~~~~~~~~~~~~~~~~~~~~ +# %% +# Create functions to set up named selections and add generation criteria + def setup_named_selection(scoping_method, name): """Create a named selection with the specified scoping method and name. @@ -305,7 +309,9 @@ def add_generation_criteria( generation_criteria.Add(criteria) +# %% # Add a named selection for the surface velocity and define its generation criteria + sf_velo = setup_named_selection(GeometryDefineByType.Worksheet, "sf_velo") add_generation_criteria(sf_velo, Quantity("3e6 [mm^2]")) add_generation_criteria( @@ -318,7 +324,9 @@ def add_generation_criteria( sf_velo.Activate() sf_velo.Generate() +# %% # Add named selections for the absorption faces and define its generation criteria + abs_face = setup_named_selection(GeometryDefineByType.Worksheet, "abs_face") add_generation_criteria(abs_face, Quantity("1.5e6 [mm^2]")) add_generation_criteria( @@ -331,7 +339,9 @@ def add_generation_criteria( abs_face.Activate() abs_face.Generate() +# %% # Add named selections for the pressure faces and define its generation criteria + pres_face = setup_named_selection(GeometryDefineByType.Worksheet, "pres_face") add_generation_criteria(pres_face, Quantity("1.5e6 [mm^2]")) add_generation_criteria( @@ -344,7 +354,9 @@ def add_generation_criteria( pres_face.Activate() pres_face.Generate() +# %% # Add named selections for the acoustic region and define its generation criteria + acoustic_region = setup_named_selection( GeometryDefineByType.Worksheet, "acoustic_region" ) @@ -491,7 +503,7 @@ def add_generation_criteria( pe_display = pe_response.TimeHistoryDisplay # %% -# Add the acoustic total and directional velocity results +# Create a function to set the properties of the acoustic velocity result def set_properties( @@ -511,13 +523,12 @@ def set_properties( return element -# Add the acoustic total velocity result and set its frequency to 30 Hz -# and its location to the pressure face named selection +# %% +# Add the acoustic total and directional velocity results + acoustic_total_velocity_2 = solution.AddAcousticTotalVelocityResult() set_properties(acoustic_total_velocity_2, Quantity("30 [Hz]"), pres_face) -# Add the acoustic directional velocity result and set its frequency to 10 Hz, -# its location to the pressure face named selection, and its orientation to the Z-axis acoustic_directional_velocity_3 = solution.AddAcousticDirectionalVelocityResult() set_properties( acoustic_directional_velocity_3, @@ -526,13 +537,12 @@ def set_properties( normal_orientation=NormalOrientationType.ZAxis, ) -# Add the acoustic velocity frequency response and set its frequency -# to 68 Hz and its location to the absorption face named selection +# %% +# Add the acoustic kinetic and potential energy results + acoustic_ke = solution.AddAcousticKineticEnergy() set_properties(acoustic_ke, Quantity("68 [Hz]"), abs_face) -# Add the acoustic potential energy frequency response and set its frequency -# to 10 Hz and its location to the absorption face named selection acoustic_pe = solution.AddAcousticPotentialEnergy() set_properties(acoustic_pe, Quantity("10 [Hz]"), abs_face) @@ -564,7 +574,6 @@ def set_properties( # %% # Display the total acoustic pressure result -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ app.Tree.Activate([acoustic_pressure_result_1]) set_camera_and_display_image( @@ -573,7 +582,6 @@ def set_properties( # %% # Display the total acoustic velocity -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ app.Tree.Activate([acoustic_pressure_result_1]) set_camera_and_display_image( @@ -582,7 +590,6 @@ def set_properties( # %% # Display the acoustic sound pressure level -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ app.Tree.Activate([acoustic_spl]) set_camera_and_display_image( @@ -591,7 +598,6 @@ def set_properties( # %% # Display the acoustic directional velocity -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ app.Tree.Activate([acoustic_directional_velocity_3]) set_camera_and_display_image( @@ -600,16 +606,39 @@ def set_properties( # %% # Display the acoustic kinetic energy -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ app.Tree.Activate([acoustic_ke]) set_camera_and_display_image( camera, graphics, settings_720p, output_path, "kinetic_energy.png" ) +# %% +# Create a function to update the animation frames + + +def update_animation(frame: int) -> list[mpimg.AxesImage]: + """Update the animation frame for the GIF. + + Parameters + ---------- + frame : int + The frame number to update the animation. + + Returns + ------- + list[mpimg.AxesImage] + A list containing the updated image for the animation. + """ + # Seeks to the given frame in this sequence file + gif.seek(frame) + # Set the image array to the current frame of the GIF + image.set_data(gif.convert("RGBA")) + # Return the updated image + return [image] + + # %% # Display the total acoustic pressure animation -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # Set the animation export format to GIF animation_export_format = ( @@ -635,28 +664,6 @@ def set_properties( # Change the color of the image image = axes.imshow(gif.convert("RGBA")) - -def update_animation(frame: int) -> list[mpimg.AxesImage]: - """Update the animation frame for the GIF. - - Parameters - ---------- - frame : int - The frame number to update the animation. - - Returns - ------- - list[mpimg.AxesImage] - A list containing the updated image for the animation. - """ - # Seeks to the given frame in this sequence file - gif.seek(frame) - # Set the image array to the current frame of the GIF - image.set_data(gif.convert("RGBA")) - # Return the updated image - return [image] - - # Create the animation using the figure, update_animation function, and the GIF frames # Set the interval between frames to 200 milliseconds and repeat the animation ani = FuncAnimation( @@ -675,20 +682,15 @@ def update_animation(frame: int) -> list[mpimg.AxesImage]: # Display the output file from solve # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -def write_file_contents_to_console(path): - """Write file contents to console.""" - with open(path, "rt") as file: - for line in file: - print(line, end="") - - # Get the working directory of the solve solve_path = harmonic_acoustics.WorkingDir solve_out_path = Path(solve_path) / "solve.out" + # Check if the solve output file exists and write its contents to the console if solve_out_path: - write_file_contents_to_console(solve_out_path) + with solve_out_path.open("rt") as file: + for line in file: + print(line, end="") # %% # Print the project tree diff --git a/examples/01_basic/modal_acoustics_analysis.py b/examples/01_basic/modal_acoustics_analysis.py index fb5035e0..b7b86e7e 100644 --- a/examples/01_basic/modal_acoustics_analysis.py +++ b/examples/01_basic/modal_acoustics_analysis.py @@ -16,8 +16,8 @@ """ # %% -# Import necessary libraries -# ~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Import the necessary libraries +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ from pathlib import Path from typing import TYPE_CHECKING @@ -34,13 +34,14 @@ # %% # Create an instance of the Mechanical embedded application +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ app = App(globals=globals()) print(app) # %% -# Set the image output path and create functions to fit the camera and display images -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Create functions to set camera and display images +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Set the path for the output files (images, gifs, mechdat) output_path = Path.cwd() / "out" @@ -149,8 +150,8 @@ def display_image( mat_path = download_file("Water_material_explicit.xml", "pymechanical", "embedding") # %% -# Import the geometry -# ~~~~~~~~~~~~~~~~~~~ +# Import and display the geometry +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Define the model model = app.Model @@ -226,8 +227,11 @@ def get_solid_set_material(name: str) -> None: # %% -# Add mesh methods, sizings, and generate the mesh -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Add mesh methods and sizings +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# %% +# Create a function to get the named selection by name def get_named_selection(name: str) -> Ansys.ACT.Automation.Mechanical.NamedSelection: @@ -252,6 +256,10 @@ def get_named_selection(name: str) -> Ansys.ACT.Automation.Mechanical.NamedSelec ][0] +# %% +# Create a function to set the mesh properties + + def set_mesh_properties( mesh_element, named_selection, @@ -283,10 +291,11 @@ def set_mesh_properties( mesh_element.Behavior = behavior -# Set the mesh element order to quadratic +# %% +# Add automatic mesh methods + mesh.ElementOrder = ElementOrder.Quadratic -# Add an automatic mesh method method1 = mesh.AddAutomaticMethod() acst_bodies = get_named_selection("Acoustic_bodies") # Set the automatic method location to the acoustic bodies and the method type to AllTriAllTet @@ -298,7 +307,9 @@ def set_mesh_properties( # Set the automatic method location to the top bodies and the method type to Automatic set_mesh_properties(method2, top_bodies, MethodType.Automatic) +# %% # Add mesh sizing + sizing1 = mesh.AddSizing() # Set the mesh sizing location to the top bodies, the element size to 0.2m, and # the sizing behavior to hard @@ -306,7 +317,6 @@ def set_mesh_properties( sizing1, top_bodies, element_size=Quantity("0.2 [m]"), behavior=SizingBehavior.Hard ) -# Add mesh sizing sizing2 = mesh.AddSizing() # Set the mesh sizing location to the acoustic bodies, the element size to 0.2m, and # the sizing behavior to hard @@ -314,6 +324,9 @@ def set_mesh_properties( sizing2, acst_bodies, element_size=Quantity("0.2 [m]"), behavior=SizingBehavior.Hard ) +# %% +# Add a mesh method for the container bodies + # Add an automatic mesh method method3 = mesh.AddAutomaticMethod() container_bodies = get_named_selection("container_bodies") @@ -322,7 +335,9 @@ def set_mesh_properties( # Set the source target selection to 4 method3.SourceTargetSelection = 4 +# %% # Generate the mesh and display the image + mesh.GenerateMesh() set_camera_and_display_image(camera, graphics, settings_720p, output_path, "mesh.png") @@ -516,7 +531,7 @@ def set_contact_region_properties( acoustic_pressure_result = solution.AddAcousticPressureResult() # %% -# Scope the force reaction to the fixed Support +# Scope the force reaction to the fixed support # Add a force reaction to the solution force_reaction_1 = solution.AddForceReaction() @@ -592,25 +607,7 @@ def set_contact_region_properties( print("Force reaction z-axis : ", force_reaction_1_z) # %% -# Play the total deformation animation for mode 10 - -# Set the animation export format to GIF -animation_export_format = ( - Ansys.Mechanical.DataModel.Enums.GraphicsAnimationExportFormat.GIF -) - -# Set the export settings for the animation -settings_720p = Ansys.Mechanical.Graphics.AnimationExportSettings() -settings_720p.Width = 1280 -settings_720p.Height = 720 - -# Export the total deformation animation for the last result -deformation_gif = ( - output_path / f"total_deformation_{len(total_deformation_results)}.gif" -) -total_deformation_results[-1].ExportAnimation( - str(deformation_gif), animation_export_format, settings_720p -) +# Create a function to update the animation frames def update_animation(frame: int) -> list[mpimg.AxesImage]: @@ -634,6 +631,27 @@ def update_animation(frame: int) -> list[mpimg.AxesImage]: return [image] +# %% +# Play the total deformation animation for mode 10 + +# Set the animation export format to GIF +animation_export_format = ( + Ansys.Mechanical.DataModel.Enums.GraphicsAnimationExportFormat.GIF +) + +# Set the export settings for the animation +settings_720p = Ansys.Mechanical.Graphics.AnimationExportSettings() +settings_720p.Width = 1280 +settings_720p.Height = 720 + +# Export the total deformation animation for the last result +deformation_gif = ( + output_path / f"total_deformation_{len(total_deformation_results)}.gif" +) +total_deformation_results[-1].ExportAnimation( + str(deformation_gif), animation_export_format, settings_720p +) + # Open the GIF file and create an animation gif = Image.open(deformation_gif) # Set the subplots for the animation and turn off the axis diff --git a/examples/01_basic/steady_state_thermal_analysis.py b/examples/01_basic/steady_state_thermal_analysis.py index a6aaa749..44a97b69 100644 --- a/examples/01_basic/steady_state_thermal_analysis.py +++ b/examples/01_basic/steady_state_thermal_analysis.py @@ -12,8 +12,8 @@ """ # %% -# Import necessary libraries -# ~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Import the necessary libraries +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ from pathlib import Path from typing import TYPE_CHECKING @@ -30,13 +30,14 @@ # %% # Create an instance of the Mechanical embedded application +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ app = App(globals=globals()) print(app) # %% -# Set the image output path and create functions to fit the camera and display images -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Create functions to set camera and display images +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Set the path for the output files (images, gifs, mechdat) output_path = Path.cwd() / "out" @@ -189,6 +190,9 @@ def display_image( # Create named selections and construction geometry # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# %% +# Create a function to add a named selection + def setup_named_selection(name, scoping_method=GeometryDefineByType.Worksheet): """Create a named selection with the specified scoping method and name. @@ -211,6 +215,10 @@ def setup_named_selection(name, scoping_method=GeometryDefineByType.Worksheet): return ns +# %% +# Create a function to add generation criteria to the named selection + + def add_generation_criteria( named_selection, value, @@ -258,6 +266,10 @@ def add_generation_criteria( generation_criteria.Add(criteria) +# %% +# Create a function to set the properties of the generation criteria + + def set_criteria_properties( criteria, value, @@ -297,7 +309,9 @@ def set_criteria_properties( return criteria -# Add a named selection to the model +# %% +# Add named selections to the model + face1 = setup_named_selection("Face1") add_generation_criteria( face1, Quantity("20 [m]"), criterion=SelectionCriterionType.LocationZ @@ -382,6 +396,9 @@ def set_criteria_properties( # Define the boundary condition and add results # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# %% +# Create a function to set the location and output for the temperature boundary condition + def set_loc_and_output(temp, location, values): """Add a temperature set output to the boundary condition. @@ -399,6 +416,10 @@ def set_loc_and_output(temp, location, values): temp.Magnitude.Output.DiscreteValues = [Quantity(value) for value in values] +# %% +# Create a function to set the inputs and outputs for the temperature boundary condition + + def set_inputs_and_outputs( condition, input_quantities: list = ["0 [sec]", "1 [sec]", "2 [sec]"], @@ -424,18 +445,15 @@ def set_inputs_and_outputs( prop.Output.DiscreteValues = [Quantity(value) for value in output_quantities] +# %% # Add temperature boundary conditions to the steady state thermal analysis + temp = stat_therm.AddTemperature() set_loc_and_output(temp, face1, ["22[C]", "30[C]"]) - -# Add temperature boundary conditions to the steady state thermal analysis temp2 = stat_therm.AddTemperature() set_loc_and_output(temp2, face2, ["22[C]", "60[C]"]) -# Set the temperature inputs and outputs for temp set_inputs_and_outputs(temp) - -# Set the temperature inputs and outputs for temp2 set_inputs_and_outputs(temp2, output_quantities=["22[C]", "50[C]", "80[C]"]) # %% @@ -450,7 +468,6 @@ def set_inputs_and_outputs( # %% # Set up the analysis settings -# Set the analysis settings for the steady state thermal analysis analysis_settings = stat_therm.AnalysisSettings analysis_settings.NumberOfSteps = 2 analysis_settings.CalculateVolumeEnergy = True @@ -464,7 +481,9 @@ def set_inputs_and_outputs( # %% # Add results # ~~~~~~~~~~~ -# Temperature + +# %% +# Add temperature results to the solution # Get the solution object for the steady state thermal analysis stat_therm_soln = model.Analyses[0].Solution @@ -551,10 +570,9 @@ def set_inputs_and_outputs( # Display all results for the radiation probe radiation_probe.ResultSelection = ProbeDisplayFilter.All - # %% -# Solve -# ~~~~~ +# Solve the solution +# ~~~~~~~~~~~~~~~~~~ # Solve the steady state thermal analysis solution stat_therm_soln.Solve(True) @@ -616,24 +634,9 @@ def set_inputs_and_outputs( # Export the directional heat flux animation # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Activate the directional heat flux -app.Tree.Activate([directional_heat_flux]) - -# Set the animation export format and settings -animation_export_format = ( - Ansys.Mechanical.DataModel.Enums.GraphicsAnimationExportFormat.GIF -) -settings_720p = Ansys.Mechanical.Graphics.AnimationExportSettings() -settings_720p.Width = 1280 -settings_720p.Height = 720 - -# Export the directional heat flux animation as a GIF -directional_heat_flux_gif = output_path / "directional_heat_flux.gif" -directional_heat_flux.ExportAnimation( - str(directional_heat_flux_gif), animation_export_format, settings_720p -) - +# %% +# Create a function to update the animation frames def update_animation(frame: int) -> list[mpimg.AxesImage]: """Update the animation frame for the GIF. @@ -655,6 +658,26 @@ def update_animation(frame: int) -> list[mpimg.AxesImage]: return [image] +# %% +# Show the directional heat flux animation + +# Activate the directional heat flux +app.Tree.Activate([directional_heat_flux]) + +# Set the animation export format and settings +animation_export_format = ( + Ansys.Mechanical.DataModel.Enums.GraphicsAnimationExportFormat.GIF +) +settings_720p = Ansys.Mechanical.Graphics.AnimationExportSettings() +settings_720p.Width = 1280 +settings_720p.Height = 720 + +# Export the directional heat flux animation as a GIF +directional_heat_flux_gif = output_path / "directional_heat_flux.gif" +directional_heat_flux.ExportAnimation( + str(directional_heat_flux_gif), animation_export_format, settings_720p +) + # Open the GIF file and create an animation gif = Image.open(directional_heat_flux_gif) # Set the subplots for the animation and turn off the axis diff --git a/examples/01_basic/topology_optimization_cantilever_beam.py b/examples/01_basic/topology_optimization_cantilever_beam.py index d87478c8..81c45724 100644 --- a/examples/01_basic/topology_optimization_cantilever_beam.py +++ b/examples/01_basic/topology_optimization_cantilever_beam.py @@ -9,8 +9,8 @@ """ # %% -# Import necessary libraries -# ~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Import the necessary libraries +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ from pathlib import Path from typing import TYPE_CHECKING @@ -25,13 +25,14 @@ # %% # Create an instance of the Mechanical embedded application +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ app = App(globals=globals()) print(app) # %% -# Set the image output path and create functions to fit the camera and display images -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Create functions to set camera and display images +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Set the path for the output files (images, gifs, mechdat) output_path = Path.cwd() / "out" @@ -217,8 +218,8 @@ def display_image( ) # %% -# Solve -# ~~~~~ +# Solve the solution +# ~~~~~~~~~~~~~~~~~~ # Get the topology optimization analysis solution top_opt_sln = topology_optimization.Solution diff --git a/examples/01_basic/valve.py b/examples/01_basic/valve.py index b9589150..20129f8e 100644 --- a/examples/01_basic/valve.py +++ b/examples/01_basic/valve.py @@ -7,8 +7,8 @@ """ # %% -# Import necessary libraries -# ~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Import the necessary libraries +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ from pathlib import Path from typing import TYPE_CHECKING @@ -25,13 +25,14 @@ # %% # Create an instance of the Mechanical embedded application +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ app = App(globals=globals()) print(app) # %% -# Set the image output path and create functions to fit the camera and display images -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Create functions to set camera and display images +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Set the path for the output files (images, gifs, mechdat) output_path = Path.cwd() / "out" @@ -158,7 +159,7 @@ def display_image( # %% # Assign materials and mesh the geometry -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Add the material assignment to the model materials material_assignment = model.Materials.AddMaterialAssignment() @@ -282,22 +283,9 @@ def display_image( camera, graphics, settings_720p, output_path, "stress_valve.png" ) -# %% -# Export the stress animation - -# Set the animation export format and settings -animation_export_format = ( - Ansys.Mechanical.DataModel.Enums.GraphicsAnimationExportFormat.GIF -) -settings_720p = Ansys.Mechanical.Graphics.AnimationExportSettings() -settings_720p.Width = 1280 -settings_720p.Height = 720 - -# Export the animation of the equivalent stress result -valve_gif = output_path / "valve.gif" -stress.ExportAnimation(str(valve_gif), animation_export_format, settings_720p) - +# %% +# Create a function to update the animation frames def update_animation(frame: int) -> list[mpimg.AxesImage]: """Update the animation frame for the GIF. @@ -319,6 +307,21 @@ def update_animation(frame: int) -> list[mpimg.AxesImage]: return [image] +# %% +# Export the stress animation + +# Set the animation export format and settings +animation_export_format = ( + Ansys.Mechanical.DataModel.Enums.GraphicsAnimationExportFormat.GIF +) +settings_720p = Ansys.Mechanical.Graphics.AnimationExportSettings() +settings_720p.Width = 1280 +settings_720p.Height = 720 + +# Export the animation of the equivalent stress result +valve_gif = output_path / "valve.gif" +stress.ExportAnimation(str(valve_gif), animation_export_format, settings_720p) + # Open the GIF file and create an animation gif = Image.open(valve_gif) # Set the subplots for the animation and turn off the axis diff --git a/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py b/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py index decc8852..7d6ccc38 100644 --- a/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py +++ b/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py @@ -47,6 +47,10 @@ """ +# %% +# Import the necessary libraries +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + from pathlib import Path from typing import TYPE_CHECKING @@ -60,13 +64,14 @@ # %% # Create an instance of the Mechanical embedded application +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ app = App(globals=globals()) print(app) # %% -# Set the image output path and create functions to fit the camera and display images -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Create functions to set camera and display images +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Set the path for the output files (images, gifs, mechdat) output_path = Path.cwd() / "out" @@ -220,7 +225,9 @@ def display_image( # %% # Assign materials # ~~~~~~~~~~~~~~~~ -# Import material from xml file and assign it to bodies + +# %% +# Import material from the xml file and assign it to bodies # Define and import the materials materials = model.Materials @@ -255,6 +262,9 @@ def display_image( # Define named selection # ~~~~~~~~~~~~~~~~~~~~~~ +# %% +# Create a function to get named selections by name + def get_named_selection(ns_list: list) -> dict: """Get the named selection by name. @@ -275,7 +285,8 @@ def get_named_selection(ns_list: list) -> dict: return ns_dict -# Create NS for named selection +# %% +# Create a dictionary of named selections named_selections_names = [ "Blade", @@ -299,12 +310,10 @@ def get_named_selection(ns_list: list) -> dict: ns_dict = get_named_selection(named_selections_names) # %% -# Define a coordinate system -# ~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Add a coordinate system +# ~~~~~~~~~~~~~~~~~~~~~~~ -# Define the coordinate systems coordinate_systems = model.CoordinateSystems -# Add a coordinate system coord_system = coordinate_systems.AddCoordinateSystem() # Create cylindrical coordinate system coord_system.CoordinateSystemType = ( @@ -317,22 +326,31 @@ def get_named_selection(ns_list: list) -> dict: # Add contact regions # ~~~~~~~~~~~~~~~~~~~ -# Define connections connections = model.Connections -# Add a contact region contact_region1 = connections.AddContactRegion() -# Set the contact region's source and target locations contact_region1.SourceLocation = named_selections.Children[6] contact_region1.TargetLocation = named_selections.Children[5] -# Set the contact region's behavior to auto asymmetric contact_region1.Behavior = ContactBehavior.AutoAsymmetric -# Set the contact region's contact formulation to MPC contact_region1.ContactFormulation = ContactFormulation.MPC # %% # Define the mesh settings and generate the mesh # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# %% +# Set the mesh settings + +mesh = model.Mesh + +# Set the mesh settings +mesh.ElementSize = Quantity(0.004, "m") +mesh.UseAdaptiveSizing = False +mesh.MaximumSize = Quantity(0.004, "m") +mesh.ShapeChecking = 0 + +# %% +# Create a function to add an automatic method to the mesh + def add_automatic_method( mesh, @@ -361,20 +379,14 @@ def add_automatic_method( automatic_method.SweepNumberDivisions = sweep_number_divisions -# Define the mesh -mesh = model.Mesh - -# Set the mesh settings -mesh.ElementSize = Quantity(0.004, "m") -mesh.UseAdaptiveSizing = False -mesh.MaximumSize = Quantity(0.004, "m") -mesh.ShapeChecking = 0 - # Add an automatic method for the hub add_automatic_method( mesh, location_index=0, sweep_number_divisions=6, set_src_target_properties=False ) +# %% +# Add match control and sizing to the mesh + # Add match control to the mesh match_control_hub = mesh.AddMatchControl() # Set the low and high named selections to named selections' children at indices 7 and 8 @@ -392,12 +404,16 @@ def add_automatic_method( sizing_blade.CurvatureNormalAngle = Quantity(0.31, "rad") sizing_blade.LocalMinimumSize = Quantity(0.0005, "m") -# Add automatic methods for each blade +# %% +# Add automatic methods for each blad + add_automatic_method(mesh, 9, 10, 11) add_automatic_method(mesh, 12, 13, 14) add_automatic_method(mesh, 15, 16, 17) +# %% # Generate the mesh and display the image + mesh.GenerateMesh() set_camera_and_display_image( camera, graphics, settings_720p, output_path, "blade_mesh.png" @@ -459,6 +475,9 @@ def add_automatic_method( # Import and apply temperature and CFX pressure to the structural blade & its surface # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# %% +# Create a function to process the CFX pressure and temperature data files + def process_external_data( external_data_path: str, @@ -605,7 +624,6 @@ def process_external_data( # %% # Postprocessing # ~~~~~~~~~~~~~~ -# Evaluate the results and export screenshots # %% # Total deformation @@ -632,8 +650,8 @@ def process_external_data( ) # %% -# Clean up -# ~~~~~~~~ +# Clean up the project and downloaded files +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Save the project mechdat_file = output_path / "blade_inverse.mechdat" diff --git a/examples/02_technology_showcase/contact_wear_simulation.py b/examples/02_technology_showcase/contact_wear_simulation.py index a6605526..e36b8ada 100644 --- a/examples/02_technology_showcase/contact_wear_simulation.py +++ b/examples/02_technology_showcase/contact_wear_simulation.py @@ -22,8 +22,8 @@ """ # %% -# Import necessary libraries -# ~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Import the necessary libraries +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ from pathlib import Path from typing import TYPE_CHECKING @@ -40,13 +40,14 @@ # %% # Create an instance of the Mechanical embedded application +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ app = App(globals=globals()) print(app) # %% -# Set the image output path and create functions to fit the camera and display images -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Create functions to set camera and display images +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Set the path for the output files (images, gifs, mechdat) output_path = Path.cwd() / "out" @@ -235,7 +236,7 @@ def get_named_selection(name: str): all_bodies_named_selection = get_named_selection("all_bodies") # %% -# Assign material to the bodies and change the behavior to axi-symmetric +# Assign material to the bodies # Set the model's 2D behavior to axi-symmetric geometry.Model2DBehavior = Model2DBehavior.AxiSymmetric @@ -346,7 +347,7 @@ def add_edge_sizing_and_properties( # ~~~~~~~~~~~~~~~~~~~~~~~~~ -def set_time_steps(initial, min, max): +def set_time_steps(initial: str, min: str, max: str) -> None: """Set the time step properties for the analysis settings. Parameters @@ -453,6 +454,9 @@ def set_properties_for_result( # Clear the selection app.ExtAPI.SelectionManager.ClearSelection() +# %% +# Add contact pressure to the contact tool + def add_contact_pressure(contact_tool, display_time): """Add a contact pressure to the contact tool.""" @@ -465,8 +469,8 @@ def add_contact_pressure(contact_tool, display_time): add_contact_pressure(contact_tool, display_time="4 [s]") # %% -# Solve the static structural analysis -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Solve the solution +# ~~~~~~~~~~~~~~~~~~ stat_struct_soln.Solve(True) # sphinx_gallery_start_ignore @@ -486,7 +490,7 @@ def add_contact_pressure(contact_tool, display_time): ) # %% -# Display the total deformation animation +# Create a function to update the animation frame def update_animation(frame: int) -> list[mpimg.AxesImage]: @@ -510,7 +514,10 @@ def update_animation(frame: int) -> list[mpimg.AxesImage]: return [image] -# Set the animatione export format +# %% +# Display the total deformation animation + +# Set the animation export format animation_export_format = ( Ansys.Mechanical.DataModel.Enums.GraphicsAnimationExportFormat.GIF ) diff --git a/examples/02_technology_showcase/non_linear_analysis_rubber_boot_seal.py b/examples/02_technology_showcase/non_linear_analysis_rubber_boot_seal.py index c5254867..a5b17a30 100644 --- a/examples/02_technology_showcase/non_linear_analysis_rubber_boot_seal.py +++ b/examples/02_technology_showcase/non_linear_analysis_rubber_boot_seal.py @@ -15,8 +15,8 @@ """ # %% -# Import necessary libraries -# ~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Import the necessary libraries +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ from pathlib import Path from typing import TYPE_CHECKING @@ -33,13 +33,14 @@ # %% # Create an instance of the Mechanical embedded application +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ app = App(globals=globals()) print(app) # %% -# Set the image output path and create functions to fit the camera and display images -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Create functions to set camera and display images +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Set the path for the output files (images, gifs, mechdat) output_path = Path.cwd() / "out" @@ -216,7 +217,7 @@ def display_image( soln_info = stat_struct_soln.SolutionInformation # %% -# Define named selections and coordinate systems +# Create a function to get named selections def get_named_selection( @@ -245,6 +246,9 @@ def get_named_selection( ][0] +# %% +# Define named selections and coordinate systems + named_selections = app.ExtAPI.DataModel.Project.Model.NamedSelections top_face = get_named_selection(named_selections, "Top_Face") bottom_face = get_named_selection(named_selections, "Bottom_Face") @@ -270,7 +274,7 @@ def get_named_selection( part2.StiffnessBehavior = StiffnessBehavior.Rigid # %% -# Define connections +# Create a function to add a contact region and set its properties def add_contact_region_and_props( @@ -336,6 +340,9 @@ def add_contact_region_and_props( return contact_region +# %% +# Add contact regions + # Add a contact region to the connections connections = model.Connections contact_region1 = add_contact_region_and_props( @@ -402,8 +409,8 @@ def add_contact_region_and_props( set_camera_and_display_image(camera, graphics, settings_720p, output_path, "mesh.png") # %% -# Define remote points -# ~~~~~~~~~~~~~~~~~~~~ +# Add remote points +# ~~~~~~~~~~~~~~~~~ def add_remote_point( @@ -438,8 +445,11 @@ def add_remote_point( remote_point02 = add_remote_point(model, top_face) # %% -# Set the analysis settings -# ~~~~~~~~~~~~~~~~~~~~~~~~~ +# Configure the analysis settings +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# %% +# Define a function to set the analysis settings def set_analysis_settings( @@ -463,7 +473,9 @@ def set_analysis_settings( analysis_settings.StoreResulsAtValue = store_results_at_value -# Activate the analysis settings +# %% +# Configure the analysis settings + analysis_settings.Activate() analysis_settings.LargeDeflection = True analysis_settings.Stabilization = StabilizationType.Off @@ -499,82 +511,79 @@ def set_analysis_settings( # Set load and boundary conditions # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +remote_displacement = static_structural_analysis.AddRemoteDisplacement() +remote_displacement.Location = remote_point01 + +# %% +# Define a function to convert a list of values to quantities -def set_input_output_values( - remote_displacement, - x_input_values, - x_output_values, - y_input_values, - y_output_values, - z_input_values, - z_output_values, - rotation_x_input_values, - rotation_x_output_values, - rotation_y_input_values, - rotation_y_output_values, - rotation_z_input_values, - rotation_z_output_values, -): - remote_displacement.XComponent.Inputs[0].DiscreteValues = convert_to_quantity( - x_input_values - ) - remote_displacement.XComponent.Output.DiscreteValues = convert_to_quantity( - x_output_values - ) - remote_displacement.YComponent.Inputs[0].DiscreteValues = convert_to_quantity( - y_input_values - ) - remote_displacement.YComponent.Output.DiscreteValues = convert_to_quantity( - y_output_values - ) - remote_displacement.ZComponent.Inputs[0].DiscreteValues = convert_to_quantity( - z_input_values - ) - remote_displacement.ZComponent.Output.DiscreteValues = convert_to_quantity( - z_output_values - ) - remote_displacement.RotationX.Inputs[0].DiscreteValues = convert_to_quantity( - rotation_x_input_values - ) - remote_displacement.RotationX.Output.DiscreteValues = convert_to_quantity( - rotation_x_output_values - ) - remote_displacement.RotationY.Inputs[0].DiscreteValues = convert_to_quantity( - rotation_y_input_values - ) - remote_displacement.RotationY.Output.DiscreteValues = convert_to_quantity( - rotation_y_output_values - ) - remote_displacement.RotationZ.Inputs[0].DiscreteValues = convert_to_quantity( - rotation_z_input_values - ) - remote_displacement.RotationZ.Output.DiscreteValues = convert_to_quantity( - rotation_z_output_values - ) +def convert_to_quantity(quantity_list: tuple) -> list: + """Convert a list of values to quantities. + + Parameters + ---------- + quantity_list : tuple + A tuple containing a list of values and the unit. -def convert_to_quantity(quantity_list): + Returns + ------- + list + A list of quantities with the specified unit. + """ values, unit = quantity_list return [Quantity(f"{value} [{unit}]") for value in values] -remote_displacement = static_structural_analysis.AddRemoteDisplacement() -remote_displacement.Location = remote_point01 -set_input_output_values( - remote_displacement, - x_input_values=([0, 1, 2, 3], "s"), - x_output_values=([0, 0, 0, 0], "mm"), - y_input_values=([0, 1, 2, 3], "s"), - y_output_values=([0, 0, -10, -10], "mm"), - z_input_values=([0, 1, 2, 3], "s"), - z_output_values=([0, 0, 0, 0], "mm"), - rotation_x_input_values=([0, 1, 2, 3], "s"), - rotation_x_output_values=([0, 0, 0, 0], "rad"), - rotation_y_input_values=([0, 1, 2, 3], "s"), - rotation_y_output_values=([0, 0, 0, 0], "rad"), - rotation_z_input_values=([0, 1, 2, 3], "s"), - rotation_z_output_values=([0, 0, 0, 0.55], "rad"), -) +# %% +# Set the input values for all remote displacement components + +input_values = convert_to_quantity(([0, 1, 2, 3], "s")) + +# %% +# Set the X component input and output values + +x_component = remote_displacement.XComponent +x_component.Inputs[0].DiscreteValues = input_values +x_component.Output.DiscreteValues = convert_to_quantity(([0, 0, 0, 0], "mm")) + +# %% +# Set the Y component input and output values + +y_component = remote_displacement.YComponent +y_component.Inputs[0].DiscreteValues = input_values +y_component.Output.DiscreteValues = convert_to_quantity(([0, 0, -10, -10], "mm")) + +# %% +# Set the Z component input and output values + +z_component = remote_displacement.ZComponent +z_component.Inputs[0].DiscreteValues = input_values +z_component.Output.DiscreteValues = convert_to_quantity(([0, 0, 0, 0], "mm")) + +# %% +# Set the rotation X component input and output values + +rotation_x = remote_displacement.RotationX +rotation_x.Inputs[0].DiscreteValues = input_values +rotation_x.Output.DiscreteValues = convert_to_quantity(([0, 0, 0, 0], "rad")) + +# %% +# Set the rotation X component input and output values + +rotation_y = remote_displacement.RotationY +rotation_y.Inputs[0].DiscreteValues = input_values +rotation_y.Output.DiscreteValues = convert_to_quantity(([0, 0, 0, 0], "rad")) + +# %% +# Set the rotation Z component input and output values + +rotation_z = remote_displacement.RotationZ +rotation_z.Inputs[0].DiscreteValues = input_values +rotation_z.Output.DiscreteValues = convert_to_quantity(([0, 0, 0, 0.55], "rad")) + +# %% +# Add frictionless support to the static structural analysis def add_frictionless_support( @@ -582,7 +591,7 @@ def add_frictionless_support( location, name: str, ): - """Add a frictionless support to the static structural analysis. + """Add frictionless support to the static structural analysis. Parameters ---------- @@ -653,7 +662,7 @@ def add_frictionless_support( ) # %% -# Total deformation animation +# Create a function to set the animation for the GIF def update_animation(frame: int) -> list[mpimg.AxesImage]: @@ -677,6 +686,9 @@ def update_animation(frame: int) -> list[mpimg.AxesImage]: return [image] +# %% +# Show the total deformation animation + # Set the animation export format and settings animation_export_format = ( Ansys.Mechanical.DataModel.Enums.GraphicsAnimationExportFormat.GIF From 6f2b83bb3f82aaa36d44c2eacc913a2a84524e2b Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Tue, 13 May 2025 12:20:38 -0400 Subject: [PATCH 21/24] fix sections and wording --- examples/00_tips/tips_01.py | 4 +- examples/00_tips/tips_02.py | 4 +- examples/00_tips/tips_03.py | 4 +- examples/01_basic/bolt_pretension.py | 26 ++++--- .../fracture_analysis_contact_debonding.py | 32 +++++---- examples/01_basic/harmonic_acoustics.py | 42 +++++------- examples/01_basic/modal_acoustics_analysis.py | 16 +++-- .../01_basic/steady_state_thermal_analysis.py | 4 +- .../topology_optimization_cantilever_beam.py | 16 +++-- examples/01_basic/valve.py | 23 ++++--- .../Rotor_Blade_Inverse_solve.py | 68 +++++++++---------- .../contact_wear_simulation.py | 22 ++++-- .../non_linear_analysis_rubber_boot_seal.py | 16 ++--- 13 files changed, 147 insertions(+), 130 deletions(-) diff --git a/examples/00_tips/tips_01.py b/examples/00_tips/tips_01.py index 8fd781f2..080c84e2 100644 --- a/examples/00_tips/tips_01.py +++ b/examples/00_tips/tips_01.py @@ -14,8 +14,8 @@ from ansys.mechanical.core.examples import delete_downloads, download_file # %% -# Create an instance of the Mechanical embedded application -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Initialize the embedded application +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ app = App(globals=globals()) print(app) diff --git a/examples/00_tips/tips_02.py b/examples/00_tips/tips_02.py index eeb57963..c0e22471 100644 --- a/examples/00_tips/tips_02.py +++ b/examples/00_tips/tips_02.py @@ -17,8 +17,8 @@ from ansys.mechanical.core.examples import delete_downloads, download_file # %% -# Create an instance of the Mechanical embedded application -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Initialize the embedded application +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Create an instance of the App class app = App() diff --git a/examples/00_tips/tips_03.py b/examples/00_tips/tips_03.py index e725b728..10c1fb71 100644 --- a/examples/00_tips/tips_03.py +++ b/examples/00_tips/tips_03.py @@ -14,8 +14,8 @@ from ansys.mechanical.core.examples import delete_downloads, download_file # %% -# Create an instance of the Mechanical embedded application -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Initialize the embedded application +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ app = App(globals=globals()) print(app) diff --git a/examples/01_basic/bolt_pretension.py b/examples/01_basic/bolt_pretension.py index 14ce652a..e286444f 100644 --- a/examples/01_basic/bolt_pretension.py +++ b/examples/01_basic/bolt_pretension.py @@ -1,18 +1,18 @@ """.. _ref_bolt_pretension: -Bolt Pretension +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 +equivalent stresses, contact, and bolt. """ # %% -# Import necessary libraries -# ~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Import the necessary libraries +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ from pathlib import Path import typing @@ -26,8 +26,8 @@ from matplotlib.animation import FuncAnimation # %% -# Create an instance of the Mechanical embedded application -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Initialize the embedded application +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ app = App() print(app) @@ -179,7 +179,7 @@ } # %% -# Assign surface materials to the model.Geometry bodies +# Assign surface materials to the ``model.Geometry`` bodies geometry = model.Geometry for children_index, material_name in children_materials.items(): surface = geometry.Children[children_index].Children[0] @@ -203,8 +203,8 @@ coordinate_system.PrimaryAxis = CoordinateSystemAxisType.PositiveZAxis # %% -# Create functions to set contact regions' locations, types, and other advanced contact settings -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Create functions for contact region set up +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # %% @@ -409,8 +409,8 @@ def add_command_snippet( add_command_snippet(contact_region_6, archard_wear_model) # %% -# Create functions to set the method location, mesh sizing, and element size -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Create functions to set up the mesh +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # %% @@ -475,11 +475,9 @@ def add_mesh_sizing(mesh, object_name: str, element_size: Quantity) -> None: # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # %% -# Add the mesh sizing to the bodies_5 and shank objects +# Add the mesh sizing to the ``bodies_5`` and ``shank`` objects -# Get the mesh for the model mesh = model.Mesh -# Add the mesh sizing to the bodies_5 and shank objects add_mesh_sizing(mesh=mesh, object_name="bodies_5", element_size=Quantity(15, "mm")) add_mesh_sizing(mesh=mesh, object_name="shank", element_size=Quantity(7, "mm")) diff --git a/examples/01_basic/fracture_analysis_contact_debonding.py b/examples/01_basic/fracture_analysis_contact_debonding.py index f7ef2668..792c1e53 100644 --- a/examples/01_basic/fracture_analysis_contact_debonding.py +++ b/examples/01_basic/fracture_analysis_contact_debonding.py @@ -1,6 +1,6 @@ """.. _ref_contact: -Fracture Analysis - Contact debonding +Fracture analysis - contact debonding ------------------------------------- The following example demonstrates the use of the Contact Debonding @@ -27,8 +27,8 @@ import Ansys # %% -# Create an instance of the Mechanical embedded application -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Initialize the embedded application +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ app = App(globals=globals()) print(app) @@ -227,24 +227,25 @@ def get_child_object(body, child_type, name: str): # %% -# Activate the part 2 object and set its material -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Activate the ``Part 2`` object and set its material +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Get the Part 2 object from the tree +# Get the ``Part 2`` object from the tree part2_object = [ tree_obj for tree_obj in app.Tree.AllObjects if tree_obj.Name == "Part 2" ][0] -# Activate the Part 2 object +# Activate the ``Part 2`` object part2_object.Activate() -# Set the material for the Part 2 object +# Set the material for the ``Part 2`` object part2_object.Material = get_child_object( model_materials, Ansys.ACT.Automation.Mechanical.Material, "Interface Body Material" ).Name -# %% Define the contact and contact regions -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# %% +# Define the contact and contact regions +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # %% # Activate the contact region @@ -470,27 +471,30 @@ def add_displacement( ) # %% -# Add directional deformation and force reaction results to the solution -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Add results to the solution +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Activate the static structural analysis solution static_structural_analysis_solution.Activate() +# %% # Add directional deformation to the static structural analysis solution + directional_deformation = ( static_structural_analysis_solution.AddDirectionalDeformation() ) # Set the orientation of the directional deformation to Y-axis directional_deformation.NormalOrientation = NormalOrientationType.YAxis +# %% # Add the force reaction to the static structural analysis solution force_reaction = static_structural_analysis_solution.AddForceReaction() # Set the boundary condition selection to the vertex named selection force_reaction.BoundaryConditionSelection = displacement1_vertex # %% -# Activate the static structural analysis and solve the solution -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Solve the solution +# ~~~~~~~~~~~~~~~~~~ static_structural_analysis.Activate() static_structural_analysis_solution.Solve(True) diff --git a/examples/01_basic/harmonic_acoustics.py b/examples/01_basic/harmonic_acoustics.py index 7c1db89c..5db573ed 100644 --- a/examples/01_basic/harmonic_acoustics.py +++ b/examples/01_basic/harmonic_acoustics.py @@ -49,8 +49,8 @@ import Ansys # %% -# Create an instance of the Mechanical embedded application -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Initialize the embedded application +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ app = App() app.update_globals(globals()) @@ -215,20 +215,18 @@ def display_image( app.ExtAPI.Application.ActiveUnitSystem = MechanicalUnitSystem.StandardMKS # %% -# Import and assign materials +# Import and assign the materials -# Import the material file mat.Import(mat_path) -# Assign the material to geometry.Children bodies that are not suppressed +# Assign the material to the ``geometry.Children`` bodies that are not suppressed for child in range(geometry.Children.Count): if child not in suppressed_indices: geometry.Children[child].Material = "Air" # %% -# Create coordinate system +# Create a coordinate system -# Add a coordinate system and set its properties lcs1 = coordinate_systems.AddCoordinateSystem() lcs1.OriginX = Quantity("0 [mm]") lcs1.OriginY = Quantity("0 [mm]") @@ -246,7 +244,7 @@ def display_image( # ~~~~~~~~~~~~~~~~~~~~~~~ # %% -# Create functions to set up named selections and add generation criteria +# Create a function to set up named selections def setup_named_selection(scoping_method, name): @@ -270,6 +268,10 @@ def setup_named_selection(scoping_method, name): return ns +# %% +# Create a function to add generation criteria to the named selection + + def add_generation_criteria( named_selection, value, @@ -382,45 +384,37 @@ def add_generation_criteria( analysis_settings.CalculateVolumeEnergy = True # %% -# Boundary conditions and load -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Set the boundary conditions and load +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Get the harmonic acoustics analysis harmonic_acoustics = model.Analyses[0] # %% -# Acoustic region +# Set the location for the acoustics region from the harmonic acoustics analysis -# Get the acoustics region from the harmonic acoustics analysis -# and set its location to the acoustic region named selection acoustics_region = [ child for child in harmonic_acoustics.Children if child.Name == "Acoustics Region" ][0] acoustics_region.Location = acoustic_region # %% -# Surface velocity - # Add a surface velocity boundary condition to the harmonic acoustics analysis -# and set its location to the sf_velo named selection + surface_velocity = harmonic_acoustics.AddAcousticSurfaceVelocity() surface_velocity.Location = sf_velo surface_velocity.Magnitude.Output.DiscreteValues = [Quantity("5000 [mm s-1]")] # %% -# Acoustic pressure - # Add an acoustic pressure boundary condition to the harmonic acoustics analysis -# and set its location to the pres_face named selection + acoustic_pressure = harmonic_acoustics.AddAcousticPressure() acoustic_pressure.Location = pres_face acoustic_pressure.Magnitude = Quantity("1.5e-7 [MPa]") # %% -# Acoustic absoption surface - # Add an acoustic absorption surface to the harmonic acoustics analysis -# and set its location to the abs_face named selection + absorption_surface = harmonic_acoustics.AddAcousticAbsorptionSurface() absorption_surface.Location = abs_face absorption_surface.AbsorptionCoefficient.Output.DiscreteValues = [Quantity("0.02")] @@ -679,8 +673,8 @@ def update_animation(frame: int) -> list[mpimg.AxesImage]: plt.show() # %% -# Display the output file from solve -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Display the output file from the solve +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Get the working directory of the solve solve_path = harmonic_acoustics.WorkingDir diff --git a/examples/01_basic/modal_acoustics_analysis.py b/examples/01_basic/modal_acoustics_analysis.py index b7b86e7e..2f652589 100644 --- a/examples/01_basic/modal_acoustics_analysis.py +++ b/examples/01_basic/modal_acoustics_analysis.py @@ -33,8 +33,8 @@ import Ansys # %% -# Create an instance of the Mechanical embedded application -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Initialize the embedded application +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ app = App(globals=globals()) print(app) @@ -345,6 +345,9 @@ def set_mesh_properties( # Set up the contact regions in the connection group # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# %% +# Create a function to set the contact region properties + def set_contact_region_properties( contact_region, @@ -390,6 +393,9 @@ def set_contact_region_properties( contact_region.PinballRadius = pinball_radius +# %% +# Add contact regions and set their properties + # Add a connection group to the model connection_group = connections.AddConnectionGroup() @@ -632,7 +638,7 @@ def update_animation(frame: int) -> list[mpimg.AxesImage]: # %% -# Play the total deformation animation for mode 10 +# Play the total deformation animation # Set the animation export format to GIF animation_export_format = ( @@ -681,8 +687,8 @@ def update_animation(frame: int) -> list[mpimg.AxesImage]: app.print_tree() # %% -# Clean up the app and downloaded files -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Clean up the project +# ~~~~~~~~~~~~~~~~~~~~ # Save the project file mechdat_file = output_path / "modal_acoustics.mechdat" diff --git a/examples/01_basic/steady_state_thermal_analysis.py b/examples/01_basic/steady_state_thermal_analysis.py index 44a97b69..2ecb083b 100644 --- a/examples/01_basic/steady_state_thermal_analysis.py +++ b/examples/01_basic/steady_state_thermal_analysis.py @@ -29,8 +29,8 @@ import Ansys # %% -# Create an instance of the Mechanical embedded application -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Initialize the embedded application +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ app = App(globals=globals()) print(app) diff --git a/examples/01_basic/topology_optimization_cantilever_beam.py b/examples/01_basic/topology_optimization_cantilever_beam.py index 81c45724..61cf2a25 100644 --- a/examples/01_basic/topology_optimization_cantilever_beam.py +++ b/examples/01_basic/topology_optimization_cantilever_beam.py @@ -24,8 +24,8 @@ import Ansys # %% -# Create an instance of the Mechanical embedded application -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Initialize the embedded application +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ app = App(globals=globals()) print(app) @@ -159,13 +159,17 @@ def display_image( # Display the structural analysis results # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# %% # Activate the total deformation result and display the image + struct_sln.Children[1].Activate() set_camera_and_display_image( camera, graphics, settings_720p, output_path, "total_deformation.png" ) +# %% # Activate the equivalent stress result and display the image + struct_sln.Children[2].Activate() set_camera_and_display_image( camera, graphics, settings_720p, output_path, "equivalent_stress.png" @@ -283,9 +287,7 @@ def display_image( str(topology_optimized_gif), animation_export_format, settings_720p ) -# Use saved GIF file to display the animation since matplotlib.FuncAnimation -# does not work for this animation in Sphinx - +# %% # .. image:: /_static/basic/Topo_opitimized.gif # %% @@ -310,8 +312,8 @@ def display_image( app.print_tree() # %% -# Clean up the app and downloaded files -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Clean up the project +# ~~~~~~~~~~~~~~~~~~~~ # Save the project file mechdat_file = output_path / "cantilever_beam_topology_optimization.mechdat" diff --git a/examples/01_basic/valve.py b/examples/01_basic/valve.py index 20129f8e..6125eea4 100644 --- a/examples/01_basic/valve.py +++ b/examples/01_basic/valve.py @@ -1,6 +1,6 @@ """.. _ref_basic_valve: -Basic Valve Implementation +Basic valve implementation -------------------------- This example demonstrates a basic implementation of a valve in Python. @@ -24,8 +24,8 @@ import Ansys # %% -# Create an instance of the Mechanical embedded application -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Initialize the embedded application +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ app = App(globals=globals()) print(app) @@ -158,8 +158,8 @@ def display_image( app.plot() # %% -# Assign materials and mesh the geometry -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Assign the materials and mesh the geometry +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Add the material assignment to the model materials material_assignment = model.Materials.AddMaterialAssignment() @@ -198,8 +198,8 @@ def display_image( set_camera_and_display_image(camera, graphics, settings_720p, output_path, "mesh.png") # %% -# Define the static structural analysis and boundary conditions -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Add a static structural analysis and apply boundary conditions +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Add a static structural analysis to the model analysis = model.AddStaticStructuralAnalysis() @@ -243,6 +243,7 @@ def display_image( # %% # Solve the solution +# ~~~~~~~~~~~~~~~~~~ solution.Solve(True) @@ -262,11 +263,11 @@ def display_image( print("No [Info]/[Warning]/[Error] messages") # %% -# Results -# ~~~~~~~ +# Display the results +# ~~~~~~~~~~~~~~~~~~~ # %% -# Show the total deformation +# Show the total deformation image # Activate the total deformation result and display the image app.Tree.Activate([deformation]) @@ -275,7 +276,7 @@ def display_image( ) # %% -# Show the equivalent stress +# Show the equivalent stress image # Activate the equivalent stress result and display the image app.Tree.Activate([stress]) diff --git a/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py b/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py index 7d6ccc38..d4af27cd 100644 --- a/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py +++ b/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py @@ -63,8 +63,8 @@ import Ansys # %% -# Create an instance of the Mechanical embedded application -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Initialize the embedded application +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ app = App(globals=globals()) print(app) @@ -245,8 +245,8 @@ def display_image( part2_blade3.Material = "MAT1 (Setup, File1)" # %% -# Define the units system and store variables -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Define the unit system and store variables +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Select MKS units app.ExtAPI.Application.ActiveUnitSystem = MechanicalUnitSystem.StandardMKS @@ -259,8 +259,8 @@ def display_image( named_selections = model.NamedSelections # %% -# Define named selection -# ~~~~~~~~~~~~~~~~~~~~~~ +# Define the named selections +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~ # %% # Create a function to get named selections by name @@ -485,22 +485,8 @@ def process_external_data( skip_footer: int, data_type: str, location_index: int, -) -> None: - """Process the external data file and set its properties. - - Parameters - ---------- - external_data_path : str - The path to the external data file. - skip_rows : int - The number of rows to skip at the beginning of the file. - skip_footer : int - The number of rows to skip at the end of the file. - data_type : str - The type of data to process ('pressure' or 'temperature'). - location_index : int - The index of the named selection to apply the data to. - """ +): + """Process the external data file and set its properties.""" # Add imported load external data to the static structural analysis imported_load_group = static_structural_analysis.AddImportedLoadExternalData() @@ -570,19 +556,26 @@ def process_external_data( added_obj.AppliedBy = LoadAppliedBy.Direct added_obj.ImportLoad() - # Activate the imported pressure or temperature and display the image - app.Tree.Activate([added_obj]) - set_camera_and_display_image( - camera, graphics, settings_720p, output_path, f"imported_{data_type}.png" - ) + return added_obj +# %% # Import and apply CFX pressure to the structural blade surface -process_external_data( + +pressure = process_external_data( cfx_data_path, skip_rows=17, skip_footer=0, data_type="pressure", location_index=2 ) -# Import temperature data and apply it to structural blade -process_external_data( + +# Activate the imported pressure or temperature and display the image +app.Tree.Activate([pressure]) +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, f"imported_pressure.png" +) + +# %% +# Import and apply temperature to the structural blade + +temperature = process_external_data( temp_data_path, skip_rows=0, skip_footer=0, @@ -590,6 +583,13 @@ def process_external_data( location_index=1, ) +# Activate the imported temperature and display the image +app.Tree.Activate([temperature]) +set_camera_and_display_image( + camera, graphics, settings_720p, output_path, f"imported_temperature.png" +) + + # %% # Add results to the solution # ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -626,7 +626,7 @@ def process_external_data( # ~~~~~~~~~~~~~~ # %% -# Total deformation +# Display the total deformation image # Activate the total deformation results app.Tree.Activate([total_deformation1]) @@ -640,7 +640,7 @@ def process_external_data( ) # %% -# Thermal strain +# Display the thermal strain image # Activate the thermal strain results app.Tree.Activate([thermal_strain1]) @@ -650,8 +650,8 @@ def process_external_data( ) # %% -# Clean up the project and downloaded files -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Clean up the project +# ~~~~~~~~~~~~~~~~~~~~ # Save the project mechdat_file = output_path / "blade_inverse.mechdat" diff --git a/examples/02_technology_showcase/contact_wear_simulation.py b/examples/02_technology_showcase/contact_wear_simulation.py index e36b8ada..9ea5d89a 100644 --- a/examples/02_technology_showcase/contact_wear_simulation.py +++ b/examples/02_technology_showcase/contact_wear_simulation.py @@ -39,8 +39,8 @@ import Ansys # %% -# Create an instance of the Mechanical embedded application -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Initialize the embedded application +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ app = App(globals=globals()) print(app) @@ -219,7 +219,7 @@ def display_image( analysis_settings = static_structural_analysis.Children[0] # %% -# Store named selection +# Store the named selections as variables def get_named_selection(name: str): @@ -256,7 +256,7 @@ def set_material_and_dimension( set_material_and_dimension(1, "Copper") # %% -# Change contact settings +# Configure settings for the contact region # Add a contact region between the hemispherical ring and the flat ring contact_region = connections.AddContactRegion() @@ -307,6 +307,9 @@ def set_material_and_dimension( mesh.ElementOrder = ElementOrder.Linear mesh.ElementSize = Quantity("1 [mm]") +# %% +# Create a function to add edge sizing and properties + def add_edge_sizing_and_properties( mesh, location, divisions, sizing_type=SizingType.NumberOfDivisions @@ -330,7 +333,9 @@ def add_edge_sizing_and_properties( edge_sizing.NumberOfDivisions = divisions +# %% # Add edge sizing and properties to the mesh for each named selection + add_edge_sizing_and_properties(mesh, hor_edge1, 70) add_edge_sizing_and_properties(mesh, hor_edge2, 70) add_edge_sizing_and_properties(mesh, ver_edge1, 35) @@ -338,7 +343,9 @@ def add_edge_sizing_and_properties( add_edge_sizing_and_properties(mesh, dia_named_selection, 40) add_edge_sizing_and_properties(mesh, curve_named_selection, 60) +# %% # Generate the mesh and display the image + mesh.GenerateMesh() set_camera_and_display_image(camera, graphics, settings_720p, output_path, "mesh.png") @@ -346,6 +353,9 @@ def add_edge_sizing_and_properties( # Set the analysis settings # ~~~~~~~~~~~~~~~~~~~~~~~~~ +# %% +# Create a function to set time steps for the analysis settings + def set_time_steps(initial: str, min: str, max: str) -> None: """Set the time step properties for the analysis settings. @@ -364,7 +374,9 @@ def set_time_steps(initial: str, min: str, max: str) -> None: analysis_settings.MaximumTimeStep = Quantity(max) +# %% # Set the analysis settings for the static structural analysis + analysis_settings.NumberOfSteps = 2 analysis_settings.CurrentStepNumber = 1 analysis_settings.AutomaticTimeStepping = AutomaticTimeStepping.On @@ -483,7 +495,9 @@ def add_contact_pressure(contact_tool, display_time): # Postprocessing # ~~~~~~~~~~~~~~ +# %% # Activate the first normal stress result and display the image + app.Tree.Activate([normal_stress1]) set_camera_and_display_image( camera, graphics, settings_720p, output_path, "normal_stress.png" diff --git a/examples/02_technology_showcase/non_linear_analysis_rubber_boot_seal.py b/examples/02_technology_showcase/non_linear_analysis_rubber_boot_seal.py index a5b17a30..15a11c79 100644 --- a/examples/02_technology_showcase/non_linear_analysis_rubber_boot_seal.py +++ b/examples/02_technology_showcase/non_linear_analysis_rubber_boot_seal.py @@ -32,8 +32,8 @@ import Ansys # %% -# Create an instance of the Mechanical embedded application -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Initialize the embedded application +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ app = App(globals=globals()) print(app) @@ -147,16 +147,14 @@ def display_image( mat_path = download_file("example_05_Boot_Mat.xml", "pymechanical", "00_basic") # %% -# Import geometry and material -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Import the geometry and material +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Define the model -model = app.Model +# %% +# Import the material -# Define the materials +model = app.Model materials = model.Materials - -# Import the material materials.Import(mat_path) # %% From 33a9490229d0726d1965b0cab34e5974ce246427 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 13 May 2025 17:58:37 +0000 Subject: [PATCH 22/24] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../contact_wear_simulation.py | 22 +++++++++++++++++++ .../non_linear_analysis_rubber_boot_seal.py | 22 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/examples/02_technology_showcase/contact_wear_simulation.py b/examples/02_technology_showcase/contact_wear_simulation.py index 9ea5d89a..502b0b89 100644 --- a/examples/02_technology_showcase/contact_wear_simulation.py +++ b/examples/02_technology_showcase/contact_wear_simulation.py @@ -1,3 +1,25 @@ +# Copyright (C) 2023 - 2025 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. + """.. _ref_contact_wear_simulation: Contact Surface Wear Simulation diff --git a/examples/02_technology_showcase/non_linear_analysis_rubber_boot_seal.py b/examples/02_technology_showcase/non_linear_analysis_rubber_boot_seal.py index 15a11c79..e6410fe5 100644 --- a/examples/02_technology_showcase/non_linear_analysis_rubber_boot_seal.py +++ b/examples/02_technology_showcase/non_linear_analysis_rubber_boot_seal.py @@ -1,3 +1,25 @@ +# Copyright (C) 2023 - 2025 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. + """.. _ref_non_linear_analysis_rubber_boot_seal: Nonlinear Analysis of a Rubber Boot Seal Model From 05a7dba33e78ed2c1abd05d080ce3eec56513388 Mon Sep 17 00:00:00 2001 From: Kerry McAdams Date: Tue, 20 May 2025 17:10:21 -0400 Subject: [PATCH 23/24] address most suggestions --- examples/00_tips/tips_01.py | 4 +- examples/00_tips/tips_02.py | 4 +- examples/00_tips/tips_03.py | 4 +- examples/01_basic/bolt_pretension.py | 138 +++++++----------- .../fracture_analysis_contact_debonding.py | 29 +--- examples/01_basic/harmonic_acoustics.py | 23 ++- examples/01_basic/modal_acoustics_analysis.py | 21 +-- .../01_basic/steady_state_thermal_analysis.py | 21 ++- .../topology_optimization_cantilever_beam.py | 22 ++- examples/01_basic/valve.py | 16 +- .../Rotor_Blade_Inverse_solve.py | 10 +- .../contact_wear_simulation.py | 6 +- .../non_linear_analysis_rubber_boot_seal.py | 8 +- 13 files changed, 122 insertions(+), 184 deletions(-) diff --git a/examples/00_tips/tips_01.py b/examples/00_tips/tips_01.py index 72f3ab5c..81bbc014 100644 --- a/examples/00_tips/tips_01.py +++ b/examples/00_tips/tips_01.py @@ -74,5 +74,5 @@ # Delete the downloaded files delete_downloads() -# Refresh the app -app.new() +# Close the app +app.close() diff --git a/examples/00_tips/tips_02.py b/examples/00_tips/tips_02.py index c6c688be..7d1ffc51 100644 --- a/examples/00_tips/tips_02.py +++ b/examples/00_tips/tips_02.py @@ -138,5 +138,5 @@ def display_image(image_name) -> None: # Delete the downloaded files delete_downloads() -# Refresh the app -app.new() +# Close the app +app.close() diff --git a/examples/00_tips/tips_03.py b/examples/00_tips/tips_03.py index b62872b3..6dea8ed4 100644 --- a/examples/00_tips/tips_03.py +++ b/examples/00_tips/tips_03.py @@ -74,5 +74,5 @@ # Delete the downloaded files delete_downloads() -# Refresh the app -app.new() +# Close the app +app.close() diff --git a/examples/01_basic/bolt_pretension.py b/examples/01_basic/bolt_pretension.py index f7dbf1eb..56ae53ec 100644 --- a/examples/01_basic/bolt_pretension.py +++ b/examples/01_basic/bolt_pretension.py @@ -42,7 +42,6 @@ from PIL import Image from ansys.mechanical.core import App from ansys.mechanical.core.examples import delete_downloads, download_file -import clr from matplotlib import image as mpimg from matplotlib import pyplot as plt from matplotlib.animation import FuncAnimation @@ -57,14 +56,9 @@ # Import the enums and global variables instead of using app.update_globals(globals()) # or App(globals=globals()) from ansys.mechanical.core.embedding.enum_importer import * +from ansys.mechanical.core.embedding.global_importer import Quantity from ansys.mechanical.core.embedding.transaction import Transaction -clr.AddReference("System.Collections") -clr.AddReference("Ansys.ACT.WB1") -clr.AddReference("Ansys.Mechanical.DataModel") -import Ansys -from Ansys.Core.Units import Quantity - # %% # Configure graphics for image export # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -180,31 +174,29 @@ "block2_block1_targ", ] +# %% +# Set the unit system to Standard NMM + +app.ExtAPI.Application.ActiveUnitSystem = MechanicalUnitSystem.StandardNMM + # %% # Get tree objects for each named selection for named_selection in named_selections_list: - named_selections_dictionary[named_selection] = [ - tree_obj - for tree_obj in app.Tree.AllObjects - if tree_obj.Name == str(named_selection) - ][0] + named_selections_dictionary[named_selection] = app.DataModel.GetObjectsByName( + named_selection + )[0] # %% -# Create dictionary with material assignment for each model.Geometry.Children index -children_materials = { - 0: "Steel", - 1: "Copper", - 2: "Copper", - 3: "Steel", - 4: "Steel", - 5: "Steel", -} +# Create a list with material assignment for each ``model.Geometry.Children`` index +children_materials = ["Steel", "Copper", "Copper", "Steel", "Steel", "Steel"] # %% # Assign surface materials to the ``model.Geometry`` bodies geometry = model.Geometry -for children_index, material_name in children_materials.items(): +for children_index, material_name in enumerate(children_materials): + # Get the surface of the body surface = geometry.Children[children_index].Children[0] + # Assign the material to the surface surface.Material = material_name # %% @@ -323,7 +315,7 @@ def add_command_snippet( connections = model.Connections for connection in connections.Children: if connection.DataModelObjectCategory == DataModelObjectCategory.ConnectionGroup: - connection.Delete() + app.DataModel.Remove(connection) # %% # Set the archard wear model and get the named selections from the model @@ -436,8 +428,8 @@ def add_command_snippet( # %% -# Set the method location for the specified method and object name -def set_method_location(method, object_name: str, location_type: str = "") -> None: +# Set the mesh method location for the specified method and object name +def set_mesh_method_location(method, object_name: str, location_type: str = "") -> None: """Set the location of the method based on the specified name and location type. Parameters @@ -451,19 +443,15 @@ def set_method_location(method, object_name: str, location_type: str = "") -> No Default is an empty string. """ # Get the tree object for the specified name - tree_obj_list = [ - tree_obj - for tree_obj in app.Tree.AllObjects - if tree_obj.Name == str(object_name) - ][0] + tree_obj = app.DataModel.GetObjectsByName(object_name)[0] # Set the method location based on the specified location type if location_type == "source": - method.SourceLocation = tree_obj_list + method.SourceLocation = tree_obj elif location_type == "target": - method.TargetLocation = tree_obj_list + method.TargetLocation = tree_obj else: - method.Location = tree_obj_list + method.Location = tree_obj # %% @@ -483,11 +471,8 @@ def add_mesh_sizing(mesh, object_name: str, element_size: Quantity) -> None: # Add sizing to the mesh body_sizing = mesh.AddSizing() # Get the tree object for the specified name - body_sizing.Location = [ - tree_obj - for tree_obj in app.Tree.AllObjects - if tree_obj.Name == str(object_name) - ][0] + body_sizing.Location = app.DataModel.GetObjectsByName(object_name)[0] + # Set the element size to the mesh body_sizing.ElementSize = element_size @@ -508,14 +493,14 @@ def add_mesh_sizing(mesh, object_name: str, element_size: Quantity) -> None: hex_method = mesh.AddAutomaticMethod() hex_method.Method = MethodType.Automatic # Set the method location for the all_bodies object -set_method_location(method=hex_method, object_name="all_bodies") +set_mesh_method_location(method=hex_method, object_name="all_bodies") # %% # Add face meshing to the mesh and set the MappedMesh property to False face_meshing = mesh.AddFaceMeshing() face_meshing.MappedMesh = False # Set the method location for the face meshing -set_method_location(method=face_meshing, object_name="shank_face") +set_mesh_method_location(method=face_meshing, object_name="shank_face") # %% # Add an automatic method to the mesh, set the method type, and set the source target selection @@ -523,11 +508,11 @@ def add_mesh_sizing(mesh, object_name: str, element_size: Quantity) -> None: sweep_method.Method = MethodType.Sweep sweep_method.SourceTargetSelection = 2 # Set the method locations for the shank, shank_face, and shank_face2 objects -set_method_location(method=sweep_method, object_name="shank") -set_method_location( +set_mesh_method_location(method=sweep_method, object_name="shank") +set_mesh_method_location( method=sweep_method, object_name="shank_face", location_type="source" ) -set_method_location( +set_mesh_method_location( method=sweep_method, object_name="shank_face2", location_type="target" ) @@ -596,9 +581,6 @@ def display_image( step_index, AutomaticTimeStepping.Off ) -# Activate the static structural analysis settings -static_structural_analysis_setting.Activate() - # Set the number of substeps for the static structural analysis # based on the step index with Transaction(): @@ -619,47 +601,47 @@ def display_image( # Add fixed support to the static structural analysis fixed_support = static_structural.AddFixedSupport() # Set the fixed support location for the block2_surface object -set_method_location(method=fixed_support, object_name="block2_surface") +set_mesh_method_location(method=fixed_support, object_name="block2_surface") # Create a new force on the static structural analysis tabular_force = static_structural.AddForce() # Set the force location for the bottom_surface object -set_method_location(method=tabular_force, object_name="bottom_surface") +set_mesh_method_location(method=tabular_force, object_name="bottom_surface") # Define the tabular force input and output components 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]"), + 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]"), + Quantity(0, "N"), + Quantity(0, "N"), + Quantity(5.0e005, "N"), + Quantity(0, "N"), + Quantity(-5.0e005, "N"), ] # Add a bolt presentation to the static structural analysis bolt_presentation = static_structural.AddBoltPretension() # Set the bolt presentation location for the shank_surface object -set_method_location(bolt_presentation, "shank_surface") +set_mesh_method_location(bolt_presentation, "shank_surface") # Define the bolt presentation input and output components bolt_presentation.Preload.Inputs[0].DiscreteValues = [ - Quantity("1[s]"), - Quantity("2[s]"), - Quantity("3[s]"), - Quantity("4[s]"), + Quantity(1, "s"), + Quantity(2, "s"), + Quantity(3, "s"), + Quantity(4, "s"), ] bolt_presentation.Preload.Output.DiscreteValues = [ - Quantity("6.1363e+005[N]"), - Quantity("0[N]"), - Quantity("0[N]"), - Quantity("0[N]"), + Quantity(6.1363e005, "N"), + Quantity(0, "N"), + Quantity(0, "N"), + Quantity(0, "N"), ] bolt_presentation.SetDefineBy(2, BoltLoadDefineBy.Lock) bolt_presentation.SetDefineBy(3, BoltLoadDefineBy.Lock) @@ -702,7 +684,7 @@ def display_image( # Add equivalent stress to the static structural solution and set the location for the shank object equivalent_stress_2 = static_structural_solution.AddEquivalentStress() -set_method_location(method=equivalent_stress_2, object_name="shank") +set_mesh_method_location(method=equivalent_stress_2, object_name="shank") # Add a force reaction to the static structural solution and set the boundary condition selection # to the fixed support @@ -729,19 +711,11 @@ def display_image( # sphinx_gallery_end_ignore # %% -# Print messages -# ~~~~~~~~~~~~~~ - -# Get messages from the application -messages = app.ExtAPI.Application.Messages - -# Print messages with severity levels [Info], [Warning], and [Error] -if messages: - for message in messages: - print(f"[{message.Severity}] {message.DisplayString}") -else: - print("No [Info]/[Warning]/[Error] messages") +# Show messages +# ~~~~~~~~~~~~~ +# Print all messages from Mechanical +app.messages.show() # %% # Display the results @@ -885,8 +859,8 @@ def update_animation(frame: int) -> list[mpimg.AxesImage]: bolt_presentation_mechdat_path = str(output_path / "bolt_pretension.mechdat") app.save(bolt_presentation_mechdat_path) -# Clear the project -app.new() +# Close the app +app.close() # Delete the example files delete_downloads() diff --git a/examples/01_basic/fracture_analysis_contact_debonding.py b/examples/01_basic/fracture_analysis_contact_debonding.py index f8ca17d4..7b682a8f 100644 --- a/examples/01_basic/fracture_analysis_contact_debonding.py +++ b/examples/01_basic/fracture_analysis_contact_debonding.py @@ -253,9 +253,7 @@ def get_child_object(body, child_type, name: str): # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Get the ``Part 2`` object from the tree -part2_object = [ - tree_obj for tree_obj in app.Tree.AllObjects if tree_obj.Name == "Part 2" -][0] +part2_object = app.DataModel.GetObjectsByName("Part 2")[0] # Activate the ``Part 2`` object part2_object.Activate() @@ -309,9 +307,6 @@ def get_child_object(body, child_type, name: str): # Define the mesh for the model mesh = model.Mesh -# Activate the mesh -mesh.Activate() - # Set the mesh element order to quadratic mesh.ElementOrder = ElementOrder.Quadratic # Turn off adaptive sizing @@ -416,9 +411,6 @@ def add_sizing( # Define boundary conditions # ~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Activate the static structural analysis -static_structural_analysis.Activate() - # Add fixed support to the static structural analysis fixed_support = static_structural_analysis.AddFixedSupport() # Set the fixed support location to the fixed edges named selection @@ -453,8 +445,6 @@ def add_displacement( y_component_value : str The value of the Y component for the displacement. """ - # Activate the static structural analysis - static_structural_analysis.Activate() # Add a displacement to the static structural analysis displacement = static_structural_analysis.AddDisplacement() # Set the location for the displacement to the named selection with the given name @@ -518,7 +508,6 @@ def add_displacement( # Solve the solution # ~~~~~~~~~~~~~~~~~~ -static_structural_analysis.Activate() static_structural_analysis_solution.Solve(True) # sphinx_gallery_start_ignore @@ -528,15 +517,11 @@ def add_displacement( # sphinx_gallery_end_ignore # %% -# Print messages from the solve -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Show messages +# ~~~~~~~~~~~~~ -messages = app.ExtAPI.Application.Messages -if messages: - for message in messages: - print(f"[{message.Severity}] {message.DisplayString}") -else: - print("No [Info]/[Warning]/[Error] Messages") +# Print all messages from Mechanical +app.messages.show() # %% # Activate the reactions and display the images @@ -659,8 +644,8 @@ def update_animation(frame: int) -> list[mpimg.AxesImage]: mechdat_path = output_path / "contact_debonding.mechdat" app.save(str(mechdat_path)) -# Clear the project -app.new() +# Close the app +app.close() # Delete the example files delete_downloads() diff --git a/examples/01_basic/harmonic_acoustics.py b/examples/01_basic/harmonic_acoustics.py index 5db573ed..346fa652 100644 --- a/examples/01_basic/harmonic_acoustics.py +++ b/examples/01_basic/harmonic_acoustics.py @@ -189,9 +189,9 @@ def display_image( # Suppress the bodies at the specified geometry.Children indices suppressed_indices = [0, 1, 2, 3, 4, 6, 9, 10] -for child in range(geometry.Children.Count): - if child in suppressed_indices: - geometry.Children[child].Suppressed = True +for index, child in enumerate(geometry.Children): + if index in suppressed_indices: + child.Suppressed = True # Visualize the model in 3D app.plot() @@ -551,16 +551,11 @@ def set_properties( # sphinx_gallery_end_ignore # %% -# Print messages -# ~~~~~~~~~~~~~~ - -messages = app.ExtAPI.Application.Messages -if messages: - for message in messages: - print(f"[{message.Severity}] {message.DisplayString}") -else: - print("No [Info]/[Warning]/[Error] Messages") +# Show messages +# ~~~~~~~~~~~~~ +# Print all messages from Mechanical +app.messages.show() # %% # Postprocessing @@ -700,8 +695,8 @@ def update_animation(frame: int) -> list[mpimg.AxesImage]: mechdat_file = output_path / "harmonic_acoustics.mechdat" app.save(str(mechdat_file)) -# Refresh the app -app.new() +# Close the app +app.close() # Delete the example file delete_downloads() diff --git a/examples/01_basic/modal_acoustics_analysis.py b/examples/01_basic/modal_acoustics_analysis.py index 57e9f297..c29ddee9 100644 --- a/examples/01_basic/modal_acoustics_analysis.py +++ b/examples/01_basic/modal_acoustics_analysis.py @@ -578,16 +578,11 @@ def set_contact_region_properties( # %% -# Print messages -# ~~~~~~~~~~~~~~ - -messages = app.ExtAPI.Application.Messages -if messages: - for message in messages: - print(f"[{message.Severity}] {message.DisplayString}") -else: - print("No [Info]/[Warning]/[Error] messages") +# Show messages +# ~~~~~~~~~~~~~ +# Print all messages from Mechanical +app.messages.show() # %% # Display the results @@ -616,9 +611,9 @@ def set_contact_region_properties( print("----------------------") # Print the frequency values for each mode -for result in total_deformation_results: +for index, result in enumerate(total_deformation_results, start=1): frequency_value = result.ReportedFrequency.Value - print(f"Frequency for mode {i}: ", frequency_value) + print(f"Frequency for mode {index}: ", frequency_value) # Get the maximum and minimum values of the acoustic pressure result pressure_result_max = acoustic_pressure_result.Maximum.Value @@ -716,8 +711,8 @@ def update_animation(frame: int) -> list[mpimg.AxesImage]: mechdat_file = output_path / "modal_acoustics.mechdat" app.save(str(mechdat_file)) -# Refresh the app -app.new() +# Close the app +app.close() # Delete the example files delete_downloads() diff --git a/examples/01_basic/steady_state_thermal_analysis.py b/examples/01_basic/steady_state_thermal_analysis.py index f4aacc28..3d292a8d 100644 --- a/examples/01_basic/steady_state_thermal_analysis.py +++ b/examples/01_basic/steady_state_thermal_analysis.py @@ -606,18 +606,15 @@ def set_inputs_and_outputs( # sphinx_gallery_end_ignore # %% -# Print messages -# ~~~~~~~~~~~~~~ +# Show messages +# ~~~~~~~~~~~~~ -messages = app.ExtAPI.Application.Messages -if messages: - for message in messages: - print(f"[{message.Severity}] {message.DisplayString}") -else: - print("No [Info]/[Warning]/[Error] messages") +# Print all messages from Mechanical +app.messages.show() -# Display results -# ~~~~~~~~~~~~~~~ +# %% +# Display the results +# ~~~~~~~~~~~~~~~~~~~ # Activate the total body temperature and display the image app.Tree.Activate([temp_rst]) @@ -750,8 +747,8 @@ def update_animation(frame: int) -> list[mpimg.AxesImage]: mechdat_path = output_path / "steady_state_thermal.mechdat" app.save(str(mechdat_path)) -# Refresh the app -app.new() +# Close the app +app.close() # Delete the example files delete_downloads() diff --git a/examples/01_basic/topology_optimization_cantilever_beam.py b/examples/01_basic/topology_optimization_cantilever_beam.py index 2669134c..d3434a25 100644 --- a/examples/01_basic/topology_optimization_cantilever_beam.py +++ b/examples/01_basic/topology_optimization_cantilever_beam.py @@ -224,7 +224,7 @@ def display_image( # Delete the mass response constraint from the topology optimization mass_constraint = topology_optimization.Children[3] -mass_constraint.Delete() +app.DataModel.Remove(mass_constraint) # Add a volume response constraint to the topology optimization volume_constraint = topology_optimization.AddVolumeConstraint() @@ -257,19 +257,15 @@ def display_image( # sphinx_gallery_end_ignore # %% -# Print messages -# ~~~~~~~~~~~~~~ +# Show messages +# ~~~~~~~~~~~~~ -messages = app.ExtAPI.Application.Messages -if messages: - for message in messages: - print(f"[{message.Severity}] {message.DisplayString}") -else: - print("No [Info]/[Warning]/[Error] messages") +# Print all messages from Mechanical +app.messages.show() # %% -# Display results -# ~~~~~~~~~~~~~~~ +# Display the results +# ~~~~~~~~~~~~~~~~~~~ # Get the topology density result and activate it top_opt_sln.Children[1].Activate() @@ -341,8 +337,8 @@ def display_image( mechdat_file = output_path / "cantilever_beam_topology_optimization.mechdat" app.save(str(mechdat_file)) -# Refresh the app -app.new() +# Close the app +app.close() # Delete the example files delete_downloads() diff --git a/examples/01_basic/valve.py b/examples/01_basic/valve.py index 02330249..8051f8e6 100644 --- a/examples/01_basic/valve.py +++ b/examples/01_basic/valve.py @@ -274,15 +274,11 @@ def display_image( # sphinx_gallery_end_ignore # %% -# Print the messages -# ~~~~~~~~~~~~~~~~~~ +# Show messages +# ~~~~~~~~~~~~~ -messages = app.ExtAPI.Application.Messages -if messages: - for message in messages: - print(f"[{message.Severity}] {message.DisplayString}") -else: - print("No [Info]/[Warning]/[Error] messages") +# Print all messages from Mechanical +app.messages.show() # %% # Display the results @@ -395,8 +391,8 @@ def update_animation(frame: int) -> list[mpimg.AxesImage]: mechdat_file = output_path / "valve.mechdat" app.save(str(mechdat_file)) -# Refresh the app -app.new() +# Close the app +app.close() # Delete the example files delete_downloads() diff --git a/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py b/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py index 59f78ad5..508531af 100644 --- a/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py +++ b/examples/02_technology_showcase/Rotor_Blade_Inverse_solve.py @@ -256,8 +256,8 @@ def display_image( materials.Import(mat_path) # Assign the imported material to the components -part1 = [x for x in app.Tree.AllObjects if x.Name == r"Component2\Rotor11"][0] -part2 = [x for x in app.Tree.AllObjects if x.Name == "Component3"][0] +part1 = app.DataModel.GetObjectsByName(r"Component2\Rotor11")[0] +part2 = app.DataModel.GetObjectsByName("Component3")[0] part2_blade1 = part2.Children[0] part2_blade2 = part2.Children[1] part2_blade3 = part2.Children[2] @@ -303,7 +303,7 @@ def get_named_selection(ns_list: list) -> dict: """ ns_dict = {} for name in ns_list: - ns_dict[name] = [obj for obj in app.Tree.AllObjects if obj.Name == name][0] + ns_dict[name] = app.DataModel.GetObjectsByName(name)[0] return ns_dict @@ -679,8 +679,8 @@ def process_external_data( mechdat_file = output_path / "blade_inverse.mechdat" app.save(str(mechdat_file)) -# Refresh the app -app.new() +# Close the app +app.close() # Delete the example file delete_downloads() diff --git a/examples/02_technology_showcase/contact_wear_simulation.py b/examples/02_technology_showcase/contact_wear_simulation.py index 502b0b89..9b57d840 100644 --- a/examples/02_technology_showcase/contact_wear_simulation.py +++ b/examples/02_technology_showcase/contact_wear_simulation.py @@ -246,7 +246,7 @@ def display_image( def get_named_selection(name: str): """Get the named selection by name.""" - return [obj for obj in app.Tree.AllObjects if obj.Name == name][0] + return app.DataModel.GetObjectsByName(name)[0] curve_named_selection = get_named_selection("curve") @@ -604,8 +604,8 @@ def update_animation(frame: int) -> list[mpimg.AxesImage]: mechdat_file = output_path / "contact_wear.mechdat" app.save(str(mechdat_file)) -# Refresh the app -app.new() +# Close the app +app.close() # Delete the downloaded files delete_downloads() diff --git a/examples/02_technology_showcase/non_linear_analysis_rubber_boot_seal.py b/examples/02_technology_showcase/non_linear_analysis_rubber_boot_seal.py index e6410fe5..47698685 100644 --- a/examples/02_technology_showcase/non_linear_analysis_rubber_boot_seal.py +++ b/examples/02_technology_showcase/non_linear_analysis_rubber_boot_seal.py @@ -215,8 +215,8 @@ def display_image( # Define the geometry for the model geometry = model.Geometry # Get the part and solid objects from the geometry -part1 = [x for x in app.Tree.AllObjects if x.Name == "Part"][0] -part2 = [x for x in app.Tree.AllObjects if x.Name == "Solid"][1] +part1 = app.DataModel.GetObjectsByName("Part")[0] +part2 = app.DataModel.GetObjectsByName("Solid")[1] # Define the coordinate systems coordinate_systems = model.CoordinateSystems @@ -753,8 +753,8 @@ def update_animation(frame: int) -> list[mpimg.AxesImage]: mechdat_file = output_path / "non_linear_rubber_boot_seal.mechdat" app.save(str(mechdat_file)) -# Refresh the app -app.new() +# Close the app +app.close() # Delete the example files delete_downloads() From 31088fdcd9302ed768f36c780432f20f0f2cbd94 Mon Sep 17 00:00:00 2001 From: Kerry McAdams Date: Wed, 28 May 2025 14:02:05 -0400 Subject: [PATCH 24/24] bump ansys-mechanical-core to 0.11.17 --- requirements/requirements_doc.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements/requirements_doc.txt b/requirements/requirements_doc.txt index be0295c6..999d5096 100644 --- a/requirements/requirements_doc.txt +++ b/requirements/requirements_doc.txt @@ -1,3 +1,3 @@ #PyMechanical -ansys-mechanical-core[doc]==0.11.16 -ansys-mechanical-core[graphics]==0.11.16 +ansys-mechanical-core[doc]==0.11.17 +ansys-mechanical-core[graphics]==0.11.17