diff --git a/.gitignore b/.gitignore index 45ebf2285..0cff3d997 100644 --- a/.gitignore +++ b/.gitignore @@ -200,6 +200,7 @@ doc/source/api/* # Examples files downloaded when building docs examples/01_basic/out/* +examples/00_setup/out/* # pymechanical-specific mylocal.ip diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6302e4f27..f58936e6b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -21,7 +21,7 @@ repos: rev: 1.20.0 hooks: - id: blacken-docs - additional_dependencies: [black==24.10.0] + additional_dependencies: [black==25.9.0] - repo: https://github.com/pycqa/isort rev: 6.0.1 diff --git a/doc/changelog.d/1287.added.md b/doc/changelog.d/1287.added.md new file mode 100644 index 000000000..4401a2e6a --- /dev/null +++ b/doc/changelog.d/1287.added.md @@ -0,0 +1 @@ +Update examples with code snippets diff --git a/doc/source/conf.py b/doc/source/conf.py index aa8c0e945..2093caf93 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -241,6 +241,7 @@ "sidebar_pages": ["changelog", "index"], }, "ansys_sphinx_theme_autoapi": {"project": project, "templates": "_templates/autoapi"}, + "show_nav_level": 0, } if BUILD_CHEATSHEET: diff --git a/examples/00_setup/01_setup.py b/examples/00_setup/01_setup.py new file mode 100644 index 000000000..47da7be1b --- /dev/null +++ b/examples/00_setup/01_setup.py @@ -0,0 +1,120 @@ +# Copyright (C) 2022 - 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_setup: + +App +--- + +This section has helper scripts to start an embedded instance of Mechanical +Application and import/open a file. + +This is a prerequisite step for the other helper scripts in the following pages. + + +""" + +# %% +# Create an embedded instance and open an existing Mechanical File +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +from ansys.mechanical.core import App +from ansys.mechanical.core.examples import delete_downloads, download_file + +mechdat_path = download_file("cantilever.mechdat", "pymechanical", "embedding") + +# The following line creates an instance of the app, extracts the global API entry points, +# and merges them into your Python global variables. + +app = App(db_file=mechdat_path, globals=globals()) +print(app) + + +# Alternatively, you can use the update_globals method of the App class to +# update the global variables.The second argument, if set to False updates +# globals without enums like "SelectionTypeEnum" or "LoadDefineBy" +# app = App() +# app.update_globals(globals(), False) + +# For a specific version , use ; +# app = App(version=241) + +# %% +# Import a Geometry File +# ~~~~~~~~~~~~~~~~~~~~~~ + +# sphinx_gallery_start_ignore +app.new() +# sphinx_gallery_end_ignore + +geom_file_path = download_file("example_06_bolt_pret_geom.agdb", "pymechanical", "00_basic") +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.ProcessLines = True +geometry_import_preferences.NamedSelectionKey = "" +geometry_import_preferences.ProcessNamedSelections = True +geometry_import_preferences.ProcessMaterialProperties = True +geometry_import.Import(geom_file_path, geometry_import_format, geometry_import_preferences) + +# %% +# Set Units +# ~~~~~~~~~~~~~~~~~~~~~~~ + +ExtAPI.Application.ActiveUnitSystem = MechanicalUnitSystem.StandardNMM +ExtAPI.Application.ActiveAngleUnit = AngleUnitType.Radian +ExtAPI.Application.ActiveAngularVelocityUnit = AngularVelocityUnitType.RadianPerSecond + +# %% +# View messages in Mechanical using PyMechanical +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +app.messages.show() + + +# %% +# Plot and Print the Tree (To check model so far) +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Plot +app.plot() + +# Print the tree +app.print_tree() + + +# %% +# Save the model +# ~~~~~~~~~~~~~~~ +from pathlib import Path + +output_path = Path.cwd() / "out" +test_mechdat_path = str(output_path / "test.mechdat") +app.save_as(test_mechdat_path, overwrite=True) + + +# sphinx_gallery_start_ignore +# Close the app +app.close() +# Delete the downloaded files +delete_downloads() +# sphinx_gallery_end_ignore diff --git a/examples/00_setup/02_geometry.py b/examples/00_setup/02_geometry.py new file mode 100644 index 000000000..fa78225d0 --- /dev/null +++ b/examples/00_setup/02_geometry.py @@ -0,0 +1,315 @@ +# Copyright (C) 2022 - 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_geometry: + +Geometry +-------- + +This section contains a few utility scripts for working with Geometry, +including importing, analyzing, and accessing geometric data, as well +as utilizing it for downstream preprocessing operations in Mechanical +simulations. Coordinate Systems too are covered here. +""" + +# %% +# Import Geometry +# ~~~~~~~~~~~~~~~ + +from ansys.mechanical.core import App +from ansys.mechanical.core.examples import delete_downloads, download_file + +app = App(globals=globals()) + +# Download the geometry file for the example +geom_file_path = download_file("example_06_bolt_pret_geom.agdb", "pymechanical", "00_basic") +# Alternatively, you can specify a local file path +# or geom_file_path = r"C:\geometry.agdb" + +# Import the geometry into the Mechanical model +geometry_import = Model.GeometryImportGroup.AddGeometryImport() +geometry_import_format = Ansys.Mechanical.DataModel.Enums.GeometryImportPreference.Format.Automatic +geometry_import_preferences = Ansys.ACT.Mechanical.Utilities.GeometryImportPreferences() + +# Set preferences for geometry import +geometry_import_preferences.ProcessLines = True +geometry_import_preferences.NamedSelectionKey = "" +geometry_import_preferences.ProcessNamedSelections = True +geometry_import_preferences.ProcessMaterialProperties = True + +# Perform the geometry import +geometry_import.Import(geom_file_path, geometry_import_format, geometry_import_preferences) + +# Plot the imported geometry +app.plot() + +# Print the tree structure of the Mechanical model +app.print_tree() + + +# %% +# Get all bodies +# ~~~~~~~~~~~~~~~~~ + +# Retrieve all body objects from the geometry +body_objects = Model.Geometry.GetChildren(DataModelObjectCategory.Body, True) +# Alternatively, use the following method: +# bodies_objects = Model.Geometry.GetChildren(Ansys.ACT.Automation.Mechanical.Body, True) + +# Extract geometric body wrappers for each body object +bodies = [body.GetGeoBody() for body in body_objects] # GeoBodyWrapper +# or +# import itertools +# nested_list = [x.Bodies for x in ExtAPI.DataModel.GeoData.Assemblies[0].AllParts] +# bodies = list(itertools.chain(*nested_list)) + +# Access details of the first body object and its geometric properties +bo = body_objects[0] # Access Object Details and RMB options +b = bodies[0] # Access Geometric Properties: 'Area', 'GeoData', 'Centroid', 'Faces', etc. + +# %% +# Find Body with Largest Volume +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Set the active unit system to Standard NMM +ExtAPI.Application.ActiveUnitSystem = MechanicalUnitSystem.StandardNMM + +# Create a list of body names, volumes, and IDs for unsuppressed bodies +body_names_volumes = [] +for body in body_objects: + if body.Suppressed == 0 and body.Volume: + body_names_volumes.append((body.Name, body.Volume, body.GetGeoBody().Id)) + +# Sort the list and retrieve the body with the largest volume +sorted_name_vol = sorted(body_names_volumes) +bodyname, volu, bodyid = sorted_name_vol.pop() + +# Print details of the largest body +print(f"Unit System is: {ExtAPI.Application.ActiveUnitSystem}") +print(f"Name of the Largest Body: '{bodyname}'") +print(f"Its Volume: {round(volu.Value, 2)} {volu.Unit}") +print(f"Its id: {bodyid}") + +# %% +# Find Body by its ID +# ~~~~~~~~~~~~~~~~~~~~~~ +# Retrieve a body object using its ID +b2 = DataModel.GeoData.GeoEntityById(bodyid) +print(f"Body Name: {b2.Name}, Body Id: {b2.Id}") + +# %% +# Find the Part that the body belongs to +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Retrieve the name of a body and the part it belongs to using its ID +body_name = DataModel.GeoData.GeoEntityById(59).Name +part_name = DataModel.GeoData.GeoEntityById(59).Part.Name +print(f"The Body named '{body_name}' belongs to the part named '{part_name}'") + +# %% +# Find Body by its ID AND print its Faces, Centroid, etc. +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Retrieve a body object and its faces, centroids, etc. +body2 = DataModel.GeoData.GeoEntityById(bodyid) + +# Get face IDs and centroids for each face +face_ids = [face.Id for face in body2.Faces] +centroids_of_each_face = [DataModel.GeoData.GeoEntityById(face_id).Centroid for face_id in face_ids] + +# Print face IDs and their centroids +for face_id, centroid in zip(face_ids, centroids_of_each_face): + print(face_id, list(centroid)) + +# %% +# Get all Vertices +# ~~~~~~~~~~~~~~~~~~~ + +# Retrieve all vertex IDs from the geometry +vertices = [] +geo = DataModel.GeoData +for asm in geo.Assemblies: + for part in asm.Parts: + for body in part.Bodies: + for i in range(0, body.Vertices.Count): + vertices.append(body.Vertices[i].Id) +print(vertices) + +# %% +# Get all edges of a given length +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Retrieve all edges with a specified length +ExtAPI.Application.ActiveUnitSystem = MechanicalUnitSystem.StandardNMM +use_length = 0.100 + +geo = DataModel.GeoData +edgelist = [] + +# Iterate through assemblies, parts, and bodies to find edges of the given length +for asm in geo.Assemblies: + for part in asm.Parts: + for body in part.Bodies: + for edge in body.Edges: + if abs(edge.Length - use_length) <= use_length * 0.01: + edgelist.append(edge.Id) +print(edgelist) + +# %% +# Get all circular edges of a given radius +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Retrieve all circular edges with a specified radius +import math + +radius = 0.018 # Target radius +circumference = 2 * math.pi * radius # Calculate circumference + +geo = DataModel.GeoData +circlelist = [] + +# Iterate through assemblies, parts, and bodies to find circular edges +for asm in geo.Assemblies: + for part in asm.Parts: + for body in part.Bodies: + for edge in body.Edges: + if ( + abs(edge.Length - circumference) <= circumference * 0.01 + and str(edge.CurveType) == "GeoCurveCircle" + ): + circlelist.append(edge.Id) +print(circlelist) + +# %% +# Get Radius of a selected edge +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Retrieve the radius of a specific edge if it is circular +my_edge = DataModel.GeoData.GeoEntityById(27) +my_edge_radius = my_edge.Radius if str(my_edge.CurveType) == "GeoCurveCircle" else 0.0 +print(my_edge_radius) + +# %% +# Create a Named Selection from a list of body Ids +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Create a named selection for a list of body IDs +mylist = [bodyid] + +selection_manager = ExtAPI.SelectionManager +selection = ExtAPI.SelectionManager.CreateSelectionInfo(SelectionTypeEnum.GeometryEntities) +selection.Ids = mylist +selection_manager.NewSelection(selection) + +ns2 = Model.AddNamedSelection() +ns2.Name = "bodies2" +ns2.Location = selection + +# %% +# Find a Named Selection with a prefix +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Retrieve a named selection whose name starts with a specific prefix +NSall = Model.NamedSelections.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) +my_nsel = [i for i in NSall if i.Name.startswith("b")][0] +print(my_nsel.Name) + +# %% +# Create a Named Selection of all bodies with a cylindrical face +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +geo = DataModel.GeoData +cyl_body_ids = [] + +for asm in geo.Assemblies: + for part in asm.Parts: + for body in part.Bodies: + countcyl = 0 + for face in body.Faces: + if ( + face.SurfaceType + == Ansys.ACT.Interfaces.Geometry.GeoSurfaceTypeEnum.GeoSurfaceCylinder + ): + countcyl = countcyl + 1 + if countcyl != 0: + cyl_body_ids.append(body.Id) + +selection_manager = ExtAPI.SelectionManager +selection = ExtAPI.SelectionManager.CreateSelectionInfo(SelectionTypeEnum.GeometryEntities) +selection.Ids = cyl_body_ids + +ns2 = Model.AddNamedSelection() +ns2.Name = "bodies_with_cyl_face" +ns2.Location = selection +selection_manager.ClearSelection() + +# %% +# Modify material assignment +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Assign a specific material to all bodies in the model +allbodies = Model.GetChildren(DataModelObjectCategory.Body, True) +for body in allbodies: + body.Material = "Structural Steel" + +# %% +# Get all Coordinate Systems +# ~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Retrieve all coordinate systems in the model +tree_CS = Model.CoordinateSystems + +# %% +# Add a cylindrical coordinate system +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Create a new coordinate system +csys = Model.CoordinateSystems.AddCoordinateSystem() +# place csys origin at arbitrary (0,25,50) location +csys.SetOriginLocation(Quantity(0, "in"), Quantity(25, "in"), Quantity(50, "in")) +# set primary X axis to arbitrary (1,2,3) direction +csys.PrimaryAxisDirection = Vector3D(1, 2, 3) + +# %% +# Add a cartesian coordinate system at a location (0,25,50) inches +# with primary X axis towards an arbitrary (1,2,3) direction +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +csys = Model.CoordinateSystems.AddCoordinateSystem() +# place csys origin at arbitrary (0,25,50) location +csys.SetOriginLocation(Quantity(0, "in"), Quantity(25, "in"), Quantity(50, "in")) +# set primary X axis to arbitrary (1,2,3) direction +csys.PrimaryAxisDirection = Vector3D(1, 2, 3) + + +# %% +# Find a coordinate system by name +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Create a new coordinate system +csys = app.Model.CoordinateSystems.AddCoordinateSystem() +# place csys origin at arbitrary (0,25,50) location +csys.SetOriginLocation(Quantity(0, "in"), Quantity(25, "in"), Quantity(50, "in")) +# set primary X axis to arbitrary (1,2,3) direction +csys.PrimaryAxisDirection = Vector3D(1, 2, 3) + + +# sphinx_gallery_start_ignore +# Save the Mechanical database file +from pathlib import Path + +output_path = Path.cwd() / "out" +test_mechdat_path = str(output_path / "test.mechdat") +# app.save_as(test_mechdat_path, overwrite=True) + + +# Close the application and delete downloaded files +app.close() +delete_downloads() +# sphinx_gallery_end_ignore diff --git a/examples/00_setup/03_connections.py b/examples/00_setup/03_connections.py new file mode 100644 index 000000000..eac87ddb1 --- /dev/null +++ b/examples/00_setup/03_connections.py @@ -0,0 +1,207 @@ +# Copyright (C) 2022 - 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_connections: + +Connections +----------- + + +This section contains a few utility scripts for working with Connections. + +""" + +# sphinx_gallery_start_ignore +from ansys.mechanical.core import App +from ansys.mechanical.core.examples import delete_downloads, download_file + +app = App(globals=globals()) + +# Download the geometry file for the example +geom_file_path = download_file("example_06_bolt_pret_geom.agdb", "pymechanical", "00_basic") + +# Import the geometry into the Mechanical model +geometry_import = Model.GeometryImportGroup.AddGeometryImport() +geometry_import_format = Ansys.Mechanical.DataModel.Enums.GeometryImportPreference.Format.Automatic +geometry_import_preferences = Ansys.ACT.Mechanical.Utilities.GeometryImportPreferences() + +# Set preferences for geometry import +geometry_import_preferences.ProcessLines = True +geometry_import_preferences.NamedSelectionKey = "" +geometry_import_preferences.ProcessNamedSelections = True +geometry_import_preferences.ProcessMaterialProperties = True + +# Perform the geometry import +geometry_import.Import(geom_file_path, geometry_import_format, geometry_import_preferences) +# sphinx_gallery_end_ignore + +# Plot the imported geometry +app.plot() + +# Print the tree structure of the Mechanical model +app.print_tree() + +# %% +# Get information about all Contacts Defined +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Retrieve all contact regions defined in the model +all_contacts = Model.Connections.GetChildren(DataModelObjectCategory.ContactRegion, True) + +# Print count of all contact regions +numContacts = all_contacts.Count +print("There are %s contact regions" % (numContacts)) + +# Print details of each contact region +for contact in all_contacts: + print( + f"\n{contact.Parent.Name} > {contact.Name} : {contact.ContactType} : " + f"{contact.Suppressed} : {contact.ContactFormulation}" + ) + print("Contact: ", contact.ContactBodies, list(contact.SourceLocation.Ids)) + print("Target: ", contact.TargetBodies, list(contact.TargetLocation.Ids)) + + +# %% +# Create Automatic Connections on a chosen named selection +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Create a new connection group for automatic connections + +contactgroup = Model.Connections.AddConnectionGroup() +contactgroup.FaceFace = True +contactgroup.FaceEdge = contactgroup.FaceEdge.No +contactgroup.GroupBy = contactgroup.GroupBy.Faces +contactgroup.Priority = contactgroup.Priority.FaceOverEdge +contactgroup.InternalObject.DetectCylindricalFacesType = 1 + +# Retrieve a named selection for the connection group +NSall = Model.NamedSelections.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) +my_nsel = [i for i in NSall if i.Name == "bodies_5"][0] + +# Assign the named selection to the connection group and create automatic connections +contactgroup.Location = my_nsel +contactgroup.CreateAutomaticConnections() + +# Refresh the tree structure to reflect the changes +DataModel.Tree.Refresh() + +# %% +# Create a Contact region using face named selections +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Add a new contact region to the model +c = DataModel.Project.Model.Connections +c1 = c.AddContactRegion() + +# Retrieve named selections for the source and target locations +NSall = Model.NamedSelections.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) +a = [i for i in NSall if i.Name == "block1_washer_cont"][0] +c1.TargetLocation = a +a = [i for i in NSall if i.Name == "block1_washer_targ"][0] +c1.SourceLocation = a + + +# %% +# Insert a fixed body to ground joint +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +connections = Model.Connections +fixed_joint = connections.AddJoint() +fixed_joint.ConnectionType = JointScopingType.BodyToGround +fixed_joint.Type = JointType.Fixed +fixed_joint.MobileLocation = app.DataModel.GetObjectsByName("block1_washer_cont")[0] + + +# %% +# Insert a Joint using face IDs +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Define face IDs for the joint +face1 = 135 +face2 = 160 + + +from pathlib import Path # delete + +output_path = Path.cwd() / "out" # delete +test_mechdat_path = str(output_path / "temporarycheck.mechdat") # delete +app.save_as(test_mechdat_path, overwrite=True) # delete + +# Add a new joint to the model +j = Model.Connections.AddJoint() + +# Define the reference and mobile locations for the joint using face IDs +reference_scoping = ExtAPI.SelectionManager.CreateSelectionInfo(SelectionTypeEnum.GeometryEntities) +reference_scoping.Ids = [face1] +j.ReferenceLocation = reference_scoping + +mobile_scoping = ExtAPI.SelectionManager.CreateSelectionInfo(SelectionTypeEnum.GeometryEntities) +mobile_scoping.Ids = [face2] +j.MobileLocation = mobile_scoping + +# %% +# Define a ground to body spring with 1 N/m stiffness scoped to preexisting named selection +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +connections = Model.Connections +spring = connections.AddSpring() +spring.ConnectionType = JointScopingType.BodyToGround +spring.LongitudinalStiffness = Quantity(1, "N m^-1") +spring.MobileScopingMethod = GeometryDefineByType.Component +spring.MobileScopeLocation = app.DataModel.GetObjectsByName("block1_washer_cont")[0] + + +# %% +# Define a Bearing +# ~~~~~~~~~~~~~~~~ +# Add a new bearing connection to the model +brg = Model.Connections.AddBearing() + +# Set the reference rotation plane for the bearing +brg.ReferenceRotationPlane = RotationPlane.XY + +# Define stiffness values for the bearing +brg.StiffnessK11.Output.DiscreteValues = [Quantity("11 [N/m]")] +brg.StiffnessK22.Output.DiscreteValues = [Quantity("22 [N/m]")] +brg.StiffnessK21.Output.DiscreteValues = [Quantity("21 [N/m]")] +brg.StiffnessK12.Output.DiscreteValues = [Quantity("12 [N/m]")] + +# Define damping values for the bearing +brg.DampingC11.Output.DiscreteValues = [Quantity("111 [N sec m^-1]")] +brg.DampingC22.Output.DiscreteValues = [Quantity("122 [N sec m^-1]")] +brg.DampingC12.Output.DiscreteValues = [Quantity("112 [N sec m^-1]")] +brg.DampingC21.Output.DiscreteValues = [Quantity("121 [N sec m^-1]")] + +# Retrieve named selections for the reference and mobile locations +NSall = Model.NamedSelections.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) +brg.ReferenceLocation = [i for i in NSall if i.Name == "shank_surface"][0] +brg.MobileLocation = [i for i in NSall if i.Name == "shank_surface"][0] + + +# sphinx_gallery_start_ignore +# Save the Mechanical database file +from pathlib import Path + +output_path = Path.cwd() / "out" +test_mechdat_path = str(output_path / "test.mechdat") +# app.save_as(test_mechdat_path, overwrite=True) + + +# Close the application and delete downloaded files +app.close() +delete_downloads() +# sphinx_gallery_end_ignore diff --git a/examples/00_setup/04_named_selections.py b/examples/00_setup/04_named_selections.py new file mode 100644 index 000000000..ce45ce48b --- /dev/null +++ b/examples/00_setup/04_named_selections.py @@ -0,0 +1,189 @@ +# Copyright (C) 2022 - 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_named_selections: + +Named Selections +---------------- + +This section contains a few utility scripts for creating , finding and using Named Selections. +""" + +# sphinx_gallery_start_ignore +from ansys.mechanical.core import App +from ansys.mechanical.core.examples import delete_downloads, download_file + +app = App(globals=globals()) +# Download the geometry file for the example +geom_file_path = download_file("example_05_td26_Rubber_Boot_Seal.agdb", "pymechanical", "00_basic") + +# Import the geometry into the Mechanical model +geometry_import = Model.GeometryImportGroup.AddGeometryImport() +geometry_import_format = Ansys.Mechanical.DataModel.Enums.GeometryImportPreference.Format.Automatic +geometry_import_preferences = Ansys.ACT.Mechanical.Utilities.GeometryImportPreferences() + +# Set preferences for geometry import +geometry_import_preferences.ProcessLines = True +geometry_import_preferences.NamedSelectionKey = "" +geometry_import_preferences.ProcessNamedSelections = True +geometry_import_preferences.ProcessMaterialProperties = True + +# Perform the geometry import +geometry_import.Import(geom_file_path, geometry_import_format, geometry_import_preferences) +# sphinx_gallery_end_ignore + +# Plot the imported geometry +app.plot() + +# Print the tree structure of the Mechanical model +app.print_tree() + + +# %% +# Fetch all Named Selections +# ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Retrieve all named selections in the model +nsall = DataModel.GetObjectsByType(DataModelObjectCategory.NamedSelections.NamedSelection) + +# %% +# Delete a named selection +# ~~~~~~~~~~~~~~~~~~~~~~~~ +# Retrieve all named selections in the project +NSall = Model.NamedSelections.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) + +# Delete a named selection by its name +a = [i for i in NSall if i.Name == "Top_Face"][0] +a.Delete() + +# Alternative way to delete a named selection by name +b = DataModel.GetObjectsByName("Bottom_Face")[0] +b.Delete() + +# %% +# Create a named selection +# ~~~~~~~~~~~~~~~~~~~~~~~~ +# Create a new named selection for specific geometry entities +selection_manager = ExtAPI.SelectionManager +selection = ExtAPI.SelectionManager.CreateSelectionInfo(SelectionTypeEnum.GeometryEntities) +selection.Ids = [216, 221, 224] + +# Add the named selection to the model +ns2 = Model.AddNamedSelection() +ns2.Name = "faces" # Set the name of the named selection +ns2.Location = selection +selection_manager.ClearSelection() # Clear the selection after creation - delete + +# %% +# Create a Named Selection by Worksheet +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Create a named selection using worksheet criteria +NS1 = Model.AddNamedSelection() +NS1.ScopingMethod = GeometryDefineByType.Worksheet +GenerationCriteria = NS1.GenerationCriteria + +# Let us create a named selection "faces_for_support" +# using worksheet for all faces at y=0 or z=0 m + +# Add criteria to the worksheet for selecting entities +Criterion1 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() +Criterion1.Action = SelectionActionType.Add +Criterion1.EntityType = SelectionType.GeoFace +Criterion1.Criterion = SelectionCriterionType.LocationY +Criterion1.Operator = SelectionOperatorType.Equal +Criterion1.Value = Quantity("0 [m]") +GenerationCriteria.Add(Criterion1) + +Criterion2 = Ansys.ACT.Automation.Mechanical.NamedSelectionCriterion() +Criterion2.Action = SelectionActionType.Add +Criterion2.EntityType = SelectionType.GeoFace +Criterion2.Criterion = SelectionCriterionType.LocationZ +Criterion2.Operator = SelectionOperatorType.Equal +Criterion2.Value = Quantity("0 [m]") +GenerationCriteria.Add(Criterion2) + +# Generate the named selection based on the criteria +NS1.Name = "faces_for_support" +NS1.Generate() + + +# %% +# Extract all the details of a named selection worksheet named "faces_for_support" +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +NSall = app.Model.NamedSelections.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) +my_nsel = [i for i in NSall if i.Name == "faces_for_support"][0] + +worksheet = my_nsel.GenerationCriteria +for i in range(0, len(list(worksheet))): + print(worksheet[i].Action) + print(worksheet[i].EntityType) + print(worksheet[i].Criterion) + print(worksheet[i].Operator) + print(worksheet[i].Value) + print(worksheet[i].CoordinateSystem.Name) + + +# %% +# Find a Named Selection +# ~~~~~~~~~~~~~~~~~~~~~~ +# Retrieve all named selections in the project +NSall = Model.NamedSelections.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) + +# Find a specific named selection by its name +a = [i for i in NSall if i.Name == "Rubber_Bodies30"][0] + +# Access entities in the named selection +entities = a.Entities +print(entities[0].Volume) + +# %% +# Identify Named Selections based on Name and Type +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Retrieve all named selections in the project +NSall = Model.NamedSelections.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) + +# Filter named selections based on keywords in their names +keywords = ["Rubber_Bodies30", "Inner_Faces30", "Outer_Faces30"] +ns1 = [i for i in NSall if keywords[0] in i.Name] +ns2 = [i for i in NSall if keywords[1] in i.Name] +ns3 = [i for i in NSall if keywords[2] in i.Name] +filtered = ns1 + ns2 + ns3 + +# Further filter the named selections based on entity type +FaceNsels = [ + i for i in filtered if str(DataModel.GeoData.GeoEntityById(i.Ids[0]).Type) == "GeoFace" +] + + +# sphinx_gallery_start_ignore +# Save the mechdat +from pathlib import Path + +output_path = Path.cwd() / "out" +test_mechdat_path = str(output_path / "test.mechdat") +app.save_as(test_mechdat_path, overwrite=True) + + +# Close the application and delete downloaded files +app.close() +delete_downloads() +# sphinx_gallery_end_ignore diff --git a/examples/00_setup/05_mesh.py b/examples/00_setup/05_mesh.py new file mode 100644 index 000000000..492cf3c64 --- /dev/null +++ b/examples/00_setup/05_mesh.py @@ -0,0 +1,161 @@ +# Copyright (C) 2022 - 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_mesh: + +Mesh +---- + +This section contains a few utility scripts for setting local and global Mesh Controls. + +""" + +# sphinx_gallery_start_ignore +from ansys.mechanical.core import App +from ansys.mechanical.core.examples import delete_downloads, download_file + +app = App(globals=globals()) + +# Download and import the geometry file +geom_file_path = download_file("example_06_bolt_pret_geom.agdb", "pymechanical", "00_basic") +geometry_import = Model.GeometryImportGroup.AddGeometryImport() + +# Define 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.ProcessLines = True +geometry_import_preferences.NamedSelectionKey = "" +geometry_import_preferences.ProcessNamedSelections = True +geometry_import_preferences.ProcessMaterialProperties = True + +# Import the geometry into the project +geometry_import.Import(geom_file_path, geometry_import_format, geometry_import_preferences) +# sphinx_gallery_end_ignore + + +# Plot the imported geometry +app.plot() + +# Print the Mechanical tree structure +app.print_tree() + +# %% +# Set Global Mesh Settings +# ~~~~~~~~~~~~~~~~~~~~~~~~ +mesh = Model.Mesh +mesh.ElementSize = Quantity("37 [mm]") +mesh.ElementOrder = ElementOrder.Linear + + +# %% +# Insert a Local Meshing Control for a Named Selection +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Get all named selections and pick the one named "shank" +NSall = Model.NamedSelections.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) +use_nsel = [i for i in NSall if i.Name == "shank"][0] + +# Add an Automatic Method mesh control scoped to the named selection +ms = Model.Mesh.AddAutomaticMethod() +ms.Location = use_nsel +ms.Method = ms.Method.AllTriAllTet +ms.Algorithm = ms.Algorithm.PatchConforming + + +# %% +# Generate Mesh +# ~~~~~~~~~~~~~ +# Generate the mesh and print mesh object state +Model.Mesh.GenerateMesh() +print(Model.Mesh.ObjectState) + + +# %% +# Get Element Count of a meshed body +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Access mesh data +meshdata = DataModel.MeshDataByName("Global") +print(use_nsel.Ids[0]) + +# Retrieve body entity from geometry +geoBody = DataModel.GeoData.GeoEntityById(use_nsel.Ids[0]) +body = Model.Geometry.GetBody(geoBody) + +# Get mesh region corresponding to that body and print element count +meshregion = meshdata.MeshRegionById(geoBody.Id) +print(body.Name, meshregion.ElementCount) + +# %% +# Clear generated mesh +# ~~~~~~~~~~~~~~~~~~~~~~~~ +Model.Mesh.ClearGeneratedData() + + +# %% +# Insert a Sweep Method (Scoping Method: Named Selection) +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Get all named selections and pick the one named "bodies_5" +NSall = Model.NamedSelections.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) +use_nsel = [i for i in NSall if i.Name == "bodies_5"][0] + +# Add a sweep meshing method scoped to the named selection +mesh = Model.Mesh +mesh_method = mesh.AddAutomaticMethod() +mesh_method.Location = use_nsel +mesh_method.Method = MethodType.Sweep + +# %% +# Insert a Mesh Sizing Control (Scoping Method: Geometry Selection) +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Get all named selections and pick the one containing "bottom_surface" +NSall = Model.NamedSelections.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) +ns = [i for i in NSall if "bottom_surface" in i.Name][0] + +# Extract bottom face and its edges +bot_face = DataModel.GeoData.GeoEntityById(ns.Ids[0]) +body_ids = [edge.Id for edge in bot_face.Edges] + +# Create a geometry selection object from edges +sel = ExtAPI.SelectionManager.CreateSelectionInfo(SelectionTypeEnum.GeometryEntities) +sel.Ids = body_ids + +# Apply mesh sizing control to the selection +mesh = Model.Mesh +mesh_sizing = mesh.AddSizing() +mesh_sizing.Location = sel +mesh_sizing.Behavior = SizingBehavior.Hard + + +# sphinx_gallery_start_ignore +# Save the project as a .mechdat file (currently commented out) + +from pathlib import Path + +output_path = Path.cwd() / "out" +test_mechdat_path = str(output_path / "test5.mechdat") +# app.save_as(test_mechdat_path, overwrite=True) + + +# Close the Mechanical application +app.close() +# Delete any downloaded example files +delete_downloads() +# sphinx_gallery_end_ignore diff --git a/examples/00_setup/06_loads.py b/examples/00_setup/06_loads.py new file mode 100644 index 000000000..6fcd70b9d --- /dev/null +++ b/examples/00_setup/06_loads.py @@ -0,0 +1,454 @@ +# Copyright (C) 2022 - 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_loads: + +Loads and BCs +------------- + +This script contains helper examples for applying loads and boundary +conditions in Ansys Mechanical. Analysis Settings too are covered here. +""" + +# sphinx_gallery_start_ignore + +from ansys.mechanical.core import App +from ansys.mechanical.core.examples import delete_downloads, download_file + +app = App(globals=globals()) +geom_file_path = download_file("example_06_bolt_pret_geom.agdb", "pymechanical", "00_basic") +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.ProcessLines = True +geometry_import_preferences.NamedSelectionKey = "" +geometry_import_preferences.ProcessNamedSelections = True +geometry_import_preferences.ProcessMaterialProperties = True +geometry_import.Import(geom_file_path, geometry_import_format, geometry_import_preferences) + +# Generate mesh for the imported geometry +Model.Mesh.GenerateMesh() + +# Create named selections for fixed support and force application +selection_manager = ExtAPI.SelectionManager +selection = ExtAPI.SelectionManager.CreateSelectionInfo(SelectionTypeEnum.GeometryEntities) +selection.Ids = [30] + +ns2 = Model.AddNamedSelection() +ns2.Name = "fixed" +ns2.Location = selection +selection_manager.ClearSelection() + +selection_manager = ExtAPI.SelectionManager +selection = ExtAPI.SelectionManager.CreateSelectionInfo(SelectionTypeEnum.GeometryEntities) +selection.Ids = [94] + +ns2 = Model.AddNamedSelection() +ns2.Name = "force" +ns2.Location = selection +selection_manager.ClearSelection() + +# sphinx_gallery_end_ignore + +# Plot +app.plot() + +# Print the tree +app.print_tree() + +# %% +# Add an Analysis +# ~~~~~~~~~~~~~~~ +# Create a static structural analysis +analysis = Model.AddStaticStructuralAnalysis() + +# %% Apply Bolt Pretension by Face ID +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +analysis_settings = Model.Analyses[0].AnalysisSettings +analysis_settings.NumberOfSteps = 6 + +# Define coordinate system at face ID = 39 +selection = ExtAPI.SelectionManager.CreateSelectionInfo(SelectionTypeEnum.GeometryEntities) +selection.Ids = [39] +csys1 = Model.CoordinateSystems.AddCoordinateSystem() +csys1.OriginLocation = selection +csys1.Name = "cyl" + +# Apply bolt pretension load +pretension = Model.Analyses[0].AddBoltPretension() +pretension.Location = selection +pretension.CoordinateSystem = csys1 +pretension.SetDefineBy(1, BoltLoadDefineBy.Load) +pretension.Preload.Output.SetDiscreteValue(0, Quantity("1500[N]")) +# Lock the bolt for remaining steps +for i in range(2, analysis_settings.NumberOfSteps + 1): + pretension.SetDefineBy(int(i), BoltLoadDefineBy.Lock) + +# %% +# Apply a Fixed Support +# ~~~~~~~~~~~~~~~~~~~~~ +# Define a fixed support boundary condition on a specific geometry entity. + +support = Model.Analyses[0].AddFixedSupport() +support_scoping = ExtAPI.SelectionManager.CreateSelectionInfo(SelectionTypeEnum.GeometryEntities) +support_scoping.Ids = [30] +support.Location = support_scoping + +# %% +# Apply a Pressure on the First Face of the First Body +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +pressure = Model.Analyses[0].AddPressure() +part1 = Model.Geometry.Children[0] +body1 = part1.Children[0] +face1 = body1.GetGeoBody().Faces[0] # First face of first body +selection = ExtAPI.SelectionManager.CreateSelectionInfo(SelectionTypeEnum.GeometryEntities) +selection.Entities = [face1] +pressure.Location = selection +pressure.Magnitude.Inputs[0].DiscreteValues = [Quantity("0 [s]"), Quantity("1 [s]")] +pressure.Magnitude.Output.DiscreteValues = [Quantity("10 [Pa]"), Quantity("20 [Pa]")] + +# %% +# Apply a Pressure as a Formula +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +pressure = Model.Analyses[0].AddPressure() +pressure_scoping = ExtAPI.SelectionManager.CreateSelectionInfo(SelectionTypeEnum.GeometryEntities) +pressure_scoping.Ids = [95] +pressure.Location = pressure_scoping +pressure.Magnitude.Output.Formula = "10*time" + +# %% +# Apply a Force +# ~~~~~~~~~~~~~ +force = Model.Analyses[0].AddForce() +force_scoping = ExtAPI.SelectionManager.CreateSelectionInfo(SelectionTypeEnum.GeometryEntities) +force_scoping.Ids = [63] +force.Location = force_scoping +force.Magnitude.Output.DiscreteValues = [Quantity("11.3 [N]"), Quantity("12.85 [N]")] + +# %% +# Apply Force by Components +# ~~~~~~~~~~~~~~~~~~~~~~~~~ +force = Model.Analyses[0].AddForce() +force_scoping = ExtAPI.SelectionManager.CreateSelectionInfo(SelectionTypeEnum.GeometryEntities) +force_scoping.Ids = [63] +force.Location = force_scoping +force.DefineBy = LoadDefineBy.Components +force.ZComponent.Output.DiscreteValues = [Quantity("0 [N]"), Quantity("-9 [N]")] + +# %% +# Add a remote displacement with 6 degrees of freedom fixed +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +remote_disp = analysis.AddRemoteDisplacement() +remote_disp.XComponent.Output.DiscreteValues = [Quantity("0 [mm]")] +remote_disp.YComponent.Output.DiscreteValues = [Quantity("0 [mm]")] +remote_disp.ZComponent.Output.DiscreteValues = [Quantity("0 [mm]")] +remote_disp.RotationX.Output.DiscreteValues = [Quantity("0 [deg]")] +remote_disp.RotationY.Output.DiscreteValues = [Quantity("0 [deg]")] +remote_disp.RotationZ.Output.DiscreteValues = [Quantity("0 [deg]")] + + +# %% +# Apply Nodal Forces by Components +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +nodes_list = [16, 2329] +force_quantities_list = ["100 [N]", "-200 [N]"] + +# Loop through nodes and apply nodal force +for i in range(len(nodes_list)): + N1 = ExtAPI.SelectionManager.CreateSelectionInfo(SelectionTypeEnum.MeshNodes) + N1.Ids = [nodes_list[i]] + ExtAPI.SelectionManager.NewSelection(N1) + + NS = Model.AddNamedSelection() + NS.Name = "Node_" + str(nodes_list[i]) + + Force1 = Model.Analyses[0].AddNodalForce() + Force1.Location = NS + Force1.Name = "NodeAtNode_" + str(nodes_list[i]) + Force1.YComponent.Output.DiscreteValues = [Quantity(force_quantities_list[i])] + Force1.DivideLoadByNodes = False + +# %% +# Apply Force and Fixed Support using Named Selections +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Create named selections for force and fixed support +selection_manager = ExtAPI.SelectionManager +selection = ExtAPI.SelectionManager.CreateSelectionInfo(SelectionTypeEnum.GeometryEntities) +selection.Ids = [65] + +ns2 = Model.AddNamedSelection() +ns2.Name = "fixed" +ns2.Location = selection +selection_manager.ClearSelection() + +selection = ExtAPI.SelectionManager.CreateSelectionInfo(SelectionTypeEnum.GeometryEntities) +selection.Ids = [65] + +ns2 = Model.AddNamedSelection() +ns2.Name = "force" +ns2.Location = selection +selection_manager.ClearSelection() + +# Retrieve named selections +NSall = Model.NamedSelections.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) +for_fixed_supp = [i for i in NSall if i.Name.startswith("fixed")][0] +for_force = [i for i in NSall if i.Name.startswith("force")][0] + +# Apply load and support via named selections +f = Model.Analyses[0].AddForce() +f.Location = for_force +f.Name = "Force1" +f.Magnitude.Output.DiscreteValues = [Quantity("10 [N]")] + +fs = Model.Analyses[0].AddFixedSupport() +fs.Location = for_fixed_supp +fs.Name = "FixedSupport1" + +# %% +# Apply Radiation - Thermal Analysis +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +analysis2 = Model.AddSteadyStateThermalAnalysis() +radn = analysis2.AddRadiation() + +e = radn.Emissivity +e.Output.DiscreteValues = [Quantity("0.36")] + +t = radn.AmbientTemperature +t.Inputs[0].DiscreteValues = [Quantity("0 [sec]"), Quantity("1 [sec]")] +t.Output.DiscreteValues = [Quantity("22 [C]"), Quantity("2302 [C]")] + +# %% +# Add a temperature load applied to a named selection +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +temp_bc = analysis2.AddTemperature() +temp_bc.Location = app.DataModel.GetObjectsByName("fixed")[0] +temp_bc.Magnitude.Output.DiscreteValues = [Quantity("22[C]"), Quantity("60[C]")] +temp_bc.Magnitude.Inputs[0].DiscreteValues = [ + Quantity("0 [sec]"), + Quantity("1 [sec]"), + Quantity("2 [sec]"), +] +temp_bc.Magnitude.Output.DiscreteValues = [Quantity("22[C]"), Quantity("50[C]"), Quantity("80[C]")] + + +# %% +# # %% +# Create a convection load +# ~~~~~~~~~~~~~~~~~~~~~~~~ +# analysis = app.Model.AddSteadyStateThermalAnalysis() +try: + named_sel = app.Model.NamedSelections.Children[0] +except: + print("Named Selection not found") + +convection = Model.Analyses[0].AddConvection() +if named_sel != None: + convection.Location = named_sel + +convection.AmbientTemperature.Inputs[0].DiscreteValues = [ + Quantity("0 [s]"), + Quantity("1 [s]"), +] # Set the time values +convection.AmbientTemperature.Output.DiscreteValues = [ + Quantity("760 [C]"), + Quantity("800 [C]"), +] # Set the Ambient Temperature values +convection.FilmCoefficient.Inputs[0].DiscreteValues = [ + Quantity("0 [s]"), + Quantity("1 [s]"), +] # Set the time values +convection.FilmCoefficient.Output.DiscreteValues = [ + Quantity("100 [W m^-1 m^-1 K^-1]"), + Quantity("150 [W m^-1 m^-1 K^-1]"), +] # Set the HTC values + + +# %% +# Apply Tabular Pressure for 5 Load Steps +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +pressureLoad = Model.Analyses[0].AddPressure() +pressureLoad.Magnitude.Inputs[0].DiscreteValues = [ + Quantity("0 [sec]"), + Quantity("1 [sec]"), + Quantity("2 [sec]"), + Quantity("3 [sec]"), + Quantity("4 [sec]"), + Quantity("5 [sec]"), +] +pressureLoad.Magnitude.Output.DiscreteValues = [ + Quantity("0 [MPa]"), + Quantity("10 [MPa]"), + Quantity("30 [MPa]"), + Quantity("25 [MPa]"), + Quantity("-30 [MPa]"), + Quantity("100 [MPa]"), +] + +# %% +# Applying Direct FE Type Boundary Conditions +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Retrieve coordinate system named "cyl" and named selection "force" +CSall = Model.CoordinateSystems.GetChildren[Ansys.ACT.Automation.Mechanical.CoordinateSystem](True) +a = [i for i in CSall if i.Name == "cyl"][0] +NSall = Model.NamedSelections.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) +n = [i for i in NSall if i.Name == "force"][0] + +# Nodal Force +nf = Model.Analyses[0].AddNodalForce() +nf.Location = n +nf.YComponent.Inputs[0].DiscreteValues = [Quantity("0 [sec]"), Quantity("1 [sec]")] +nf.IndependentVariable = LoadVariableVariationType.YValue +nf.XYZFunctionCoordinateSystem = a +nf.YComponent.Output.DiscreteValues = [Quantity("0 [N]"), Quantity("100[N]")] + +# Nodal Displacement +nodal_displacement = Model.Analyses[0].AddNodalDisplacement() +nodal_displacement.Location = n +nodal_displacement.YComponent.Inputs[0].DiscreteValues = [Quantity("0 [sec]"), Quantity("1 [sec]")] +nodal_displacement.IndependentVariable = LoadVariableVariationType.YValue +nodal_displacement.XYZFunctionCoordinateSystem = a +nodal_displacement.YComponent.Output.DiscreteValues = [Quantity("0 [mm]"), Quantity("100[mm]")] + +# Nodal Pressure +nodal_pressure = Model.Analyses[0].AddNodalPressure() +nodal_pressure.Location = n +nodal_pressure.Magnitude.Inputs[0].DiscreteValues = [Quantity("0 [sec]"), Quantity("1 [sec]")] +nodal_pressure.IndependentVariable = LoadVariableVariationType.YValue +nodal_pressure.XYZFunctionCoordinateSystem = a +nodal_pressure.Magnitude.Output.DiscreteValues = [Quantity("0 [Pa]"), Quantity("100[Pa]")] + + +# %% +# Set Automatic Time Stepping setting for a specific Load Step +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +analysis_settings = Model.Analyses[0].AnalysisSettings +analysis_settings.CurrentStepNumber = 1 +print(analysis_settings.AutomaticTimeStepping) + + +# %% +# Set Step end time +# ~~~~~~~~~~~~~~~~~ +analysis_settings.CurrentStepNumber = 5 +analysis_settings.StepEndTime = Quantity("0.1 [sec]") + +# %% +# Define Load steps with end times +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +analysis_settings.NumberOfSteps = 3 + +analysis_settings.CurrentStepNumber = 1 +analysis_settings.StepEndTime = Quantity("1.0 [sec]") + +analysis_settings.CurrentStepNumber = 2 +analysis_settings.StepEndTime = Quantity("10.0 [sec]") + +analysis_settings.CurrentStepNumber = 3 +analysis_settings.StepEndTime = Quantity("100.0 [sec]") + + +# %% +# Define substep sizing using times +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +analysis_settings.CurrentStepNumber = 1 +analysis_settings.StepEndTime = Quantity("0.1 [sec]") +analysis_settings.AutomaticTimeStepping = analysis_settings.AutomaticTimeStepping.On +analysis_settings.DefineBy = analysis_settings.DefineBy.Time +analysis_settings.InitialTimeStep = Quantity("0.005 [s]") +analysis_settings.MaximumTimeStep = Quantity("0.5 [s]") +analysis_settings.MinimumTimeStep = Quantity("0.0005 [s]") + + +# %% +# Define substep sizing using steps +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +analysis_settings.CurrentStepNumber = 1 +analysis_settings.StepEndTime = Quantity("0.1 [sec]") +analysis_settings.AutomaticTimeStepping = analysis_settings.AutomaticTimeStepping.On +analysis_settings.DefineBy = analysis_settings.DefineBy.Substeps +analysis_settings.InitialSubsteps = 15 +analysis_settings.MinimumSubsteps = 5 +analysis_settings.MaximumSubsteps = 50 + +# %% +# Set Iterative solver type for solution +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +analysis_settings.SolverType = SolverType.Iterative + +# other options from dir(SolverType) : +# analysis_settings.SolverType = SolverType.Direct +# analysis_settings.SolverType = SolverType.FullDamped +# analysis_settings.SolverType=SolverType.ProgramControlled +# analysis_settings.SolverType=SolverType.ReducedDamped +# analysis_settings.SolverType=SolverType.Subspace +# analysis_settings.SolverType=SolverType.Supernode +# analysis_settings.SolverType=SolverType.Unsymmetric + + +# %% +# Change the solver unit system +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +analysis_settings.SolverUnits = SolverUnitsControlType.Manual +analysis_settings.SolverUnitSystem = WBUnitSystemType.ConsistentMKS + +# %% +# Get path to the Solver files directory +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +solve_dir = analysis_settings.ScratchSolverFilesDirectory +print(solve_dir) + +# To get path to the scratch Solver files directory for an unsaved file +# solve_dir = analysis_settings.SolverFilesDirectory + + +# %% +# Solve an analysis +# ~~~~~~~~~~~~~~~~~ +Model.Analyses[0].Solution.Activate() +Model.Analyses[0].Solution.Solve(True) + + +# %% +# Set the step end time and time steps in Transient structural analysis +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# analysis = app.Model.AddTransientStructuralAnalysis() +analysis_settings = analysis.AnalysisSettings +analysis_settings.SetStepEndTime(1, Quantity("0.4 [s]")) +analysis_settings.SetInitialTimeStep(1, Quantity("0.0001 [s]")) +analysis_settings.SetMinimumTimeStep(1, Quantity("0.0000001 [s]")) +analysis_settings.SetMaximumTimeStep(1, Quantity("0.01 [s]")) + + +# sphinx_gallery_start_ignore +# Save the project as a mechdat file (currently commented out) + +from pathlib import Path + +output_path = Path.cwd() / "out" +test_mechdat_path = str(output_path / "test_loads.mechdat") +# app.save_as(test_mechdat_path, overwrite=True) + +# Close Mechanical application +app.close() +# Delete downloaded files +delete_downloads() +# sphinx_gallery_end_ignore diff --git a/examples/00_setup/07_results.py b/examples/00_setup/07_results.py new file mode 100644 index 000000000..8b04c4aa2 --- /dev/null +++ b/examples/00_setup/07_results.py @@ -0,0 +1,192 @@ +# Copyright (C) 2022 - 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_results: + +Results +------- + +This section contains a few utility scripts for result objects. + +""" + +# sphinx_gallery_start_ignore +import os + +# Import Mechanical API core and example utilities +from ansys.mechanical.core import App +from ansys.mechanical.core.examples import delete_downloads, download_file + +# Download an example Mechanical database (.mechdat file) +mechdat_path = download_file("example_03_simple_bolt_new.mechdat", "pymechanical", "00_basic") + +# Launch Mechanical and open the example database +app = App(db_file=mechdat_path, globals=globals()) +print(app) + + +# sphinx_gallery_end_ignore + + +# Plot the geometry of the model +app.plot() + +# Print the Mechanical tree structure +app.print_tree() + +# %% +# Solve +# ~~~~~ +# Access the first analysis system (Static Structural) +static_struct = app.DataModel.AnalysisList[0] + +# Clear any previously generated solution data +static_struct.Solution.ClearGeneratedData() +print("Solution Status:", static_struct.Solution.Status) + +# Run the solver +static_struct.Solution.Solve() +print("Solution Status:", static_struct.Solution.Status) + + +# %% +# Results that are accessible for GetResult +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# List names of results already available in the solution +result_names = static_struct.GetResultsData().ResultNames +print("Available Results:", ", ".join(result_names)) + + +# %% +# List Result Objects that can be added +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Show all available result objects that can be inserted into the solution +all_results = [x for x in dir(static_struct) if str(x)[:3] == "Add"] +print(all_results) + +# %% +# Insert a Result +# ~~~~~~~~~~~~~~~ + +# Add a Total Deformation result and evaluate it +total_deformation = static_struct.Solution.AddTotalDeformation() +total_deformation.EvaluateAllResults() + + +# %% Access max and min of a result +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Retrieve the minimum and maximum values for total deformation +minimum_deformation = total_deformation.Minimum +maximum_deformation = total_deformation.Maximum +print(f"Minimum Deformation: {minimum_deformation}") +print(f"Maximum Deformation: {maximum_deformation}") + +# %% +# Get Results by Node Number +# ~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Extract displacement ("U") results for a specific node ID +node_number = 2000 +result_data = static_struct.GetResultsData() +node_values = result_data.GetResult("U").GetNodeValues(node_number) +print(f"Node {node_number} Values:", node_values) + +# %% +# Access other results +# ~~~~~~~~~~~~~~~~~~~~ + + +# Insert a command snippet into the solution (for custom APDL/commands) +cs = static_struct.Solution.AddCommandSnippet() + +# %% +# Fatigue Results +# ~~~~~~~~~~~~~~~ +# Add a Fatigue Tool to the solution + +solution = static_struct.Solution +fatigue_tool = solution.AddFatigueTool() + +# Insert a Safety Factor calculation under the fatigue tool +safety_factor = fatigue_tool.AddSafetyFactor() + +# Scope safety factor evaluation to specific mesh nodes +selection = ExtAPI.SelectionManager.CreateSelectionInfo(SelectionTypeEnum.MeshNodes) +selection.Ids = [1, 2] +safety_factor.Location = selection + +# Get the minimum safety factor value +minimum = safety_factor.Minimum +print("Safety Factor Minimum:", minimum) + +# Export safety factor results to a text file +fname = "safety_factor_results.txt" +safety_factor.ExportToTextFile(fname) + +# %% +# User-defined Result +# ~~~~~~~~~~~~~~~~~~~ +# Insert a User-Defined Result object +user_result = static_struct.Solution.AddUserDefinedResult() +print("User-defined Result Added:", user_result) + +# %% +# Get number of result sets +# ~~~~~~~~~~~~~~~~~~~~~~~~~ +# Retrieve the number of available result sets (time/frequency steps) + +reader = static_struct.GetResultsData() +result_set_count = reader.ListTimeFreq.Count +print("Number of Result Sets:", result_set_count) +reader.Dispose() + +# %% +# Export all results in the tree to PNG (2D image) files +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Iterate over all result objects and export each one to an image +results = DataModel.GetObjectsByType(DataModelObjectCategory.Result) +for result in results: + result.Activate() + Graphics.Camera.SetSpecificViewOrientation(ViewOrientationType.Front) + image_path = os.path.join(os.getcwd(), "out", result.Name + ".png") + Graphics.ExportImage( + str(image_path), + GraphicsImageExportFormat.PNG, + Ansys.Mechanical.Graphics.GraphicsImageExportSettings(), + ) +print("Done with Exporting Results") + + +# sphinx_gallery_start_ignore +# Save the project as a .mechdat file +from pathlib import Path + +output_path = Path.cwd() / "out" +test_mechdat_path = str(output_path / "test.mechdat") +# app.save_as(test_mechdat_path, overwrite=True) + + +# Close Mechanical application + +app.close() +# Delete the downloaded files +delete_downloads() +# sphinx_gallery_end_ignore diff --git a/examples/00_setup/08_tree_objects.py b/examples/00_setup/08_tree_objects.py new file mode 100644 index 000000000..92e337182 --- /dev/null +++ b/examples/00_setup/08_tree_objects.py @@ -0,0 +1,224 @@ +# Copyright (C) 2022 - 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_tree_objects: + +Tree Objects +------------ + +This section contains a few utility scripts for working with Tree Objects. + +""" + +# sphinx_gallery_start_ignore +from ansys.mechanical.core import App +from ansys.mechanical.core.examples import delete_downloads, download_file + +# Initialize the Mechanical application +app = App(globals=globals()) + +# Download and import the geometry file +geom_file_path = download_file("Valve.pmdb", "pymechanical", "embedding") +geometry_import = Model.GeometryImportGroup.AddGeometryImport() +geometry_import_format = Ansys.Mechanical.DataModel.Enums.GeometryImportPreference.Format.Automatic + +# Define geometry import format and preferences +geometry_import_preferences = Ansys.ACT.Mechanical.Utilities.GeometryImportPreferences() +geometry_import_preferences.ProcessLines = True +geometry_import_preferences.NamedSelectionKey = "" +geometry_import_preferences.ProcessNamedSelections = True +geometry_import_preferences.ProcessMaterialProperties = True + +# Import the geometry into the project +geometry_import.Import(geom_file_path, geometry_import_format, geometry_import_preferences) +# sphinx_gallery_end_ignore + + +# Plot the imported geometry +app.plot() + +# Print the Mechanical tree structure +app.print_tree() + + +# %% +# Accessing Geometry +# ~~~~~~~~~~~~~~~~~~ +# Access a specific geometry entity by its ID. + +body = DataModel.GeoData.GeoEntityById(312) + + +# %% +# Accessing Mesh Data +# ~~~~~~~~~~~~~~~~~~~ +# Access specific mesh data by name and ID. + +node = DataModel.MeshDataByName("Global").NodeById(555) +element = DataModel.MeshDataByName("Global").ElementById(444) + +# %% +# Accessing All Objects and Child Objects +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Examples of accessing all objects, bodies, named selections, and contact regions. + +# Retrieve all objects in the tree +AllObj = Model.GetChildren(DataModelObjectCategory.DataModelObject, True) + +# Retrieve all bodies +all_bodies = Model.GetChildren(DataModelObjectCategory.Body, True) + +# Retrieve all named selections +ns_all = DataModel.GetObjectsByType(DataModelObjectCategory.NamedSelections.NamedSelection) + +# Retrieve all contact regions +abc = DataModel.GetObjectsByType(DataModelObjectCategory.ContactRegion) +all_contacts = Model.Connections.GetChildren(DataModelObjectCategory.ContactRegion, True) + +# Access a specific contact region by name +my_contact = [contact for contact in all_contacts if contact.Name == "Contact Region"][0] + +# Retrieve all result objects of a specific type (e.g., Normal Stress) +all_norm_stress = DataModel.GetObjectsByType(DataModelObjectCategory.Result.NormalStress) + +# Retrieve other objects such as remote points and analyses +all_remote_points = DataModel.GetObjectsByType(DataModelObjectCategory.RemotePoint) +ana = DataModel.Tree.GetObjectsByType(DataModelObjectCategory.Analysis) + +# Using the ACT Automation API to retrieve specific objects +all_contacts2 = Model.Connections.GetChildren[ + Ansys.ACT.Automation.Mechanical.Connections.ContactRegion +](True) +all_remote_points2 = Model.GetChildren[Ansys.ACT.Automation.Mechanical.RemotePoint](True) +all_folders = Model.GetChildren[Ansys.ACT.Automation.Mechanical.TreeGroupingFolder](True) + +# %% +# Finding Duplicate Objects by Name +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Identify duplicate objects in the project tree based on their names. + +import collections + +# Retrieve all objects and their names +AllObj = Model.GetChildren(DataModelObjectCategory.DataModelObject, True) +AllObjNames = [x.Name for x in AllObj] + +# Find duplicate names +duplicates_by_name = [item for item, count in collections.Counter(AllObjNames).items() if count > 1] +print(duplicates_by_name) + + +# sphinx_gallery_start_ignore +# Add a static structural analysis and equivalent stress result for testing +static_struct = Model.AddStaticStructuralAnalysis() +static_struct.Solution.AddEquivalentStress() +# sphinx_gallery_end_ignore + + +# %% +# Using DataObjects and GetByName +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Access specific data objects by their names. +c1 = "Solution" +c2 = "Equivalent Stress" +c = DataModel.AnalysisList[0].DataObjects.GetByName(c1).DataObjects.GetByName(c2) + +# %% +# Using DataObjects, NamesByType, and GetByName +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Access and filter contact regions based on their properties. + +new_contact_list = [] +dataobjects = DataModel.AnalysisList[0].DataObjects +for group in dataobjects: + print(group.Type) + +# Retrieve names of all contact groups +names = dataobjects.NamesByType("ContactGroup") +for name in names: + connet_data_objects = dataobjects.GetByName(name).DataObjects + c_names = connet_data_objects.Names + for c_name in c_names: + type_c = connet_data_objects.GetByName(c_name).Type + if type_c == "ConnectionGroup": + contacts_list = connet_data_objects.GetByName(c_name).DataObjects.NamesByType( + "ContactRegion" + ) + for contact in contacts_list: + contact_type = ( + connet_data_objects.GetByName(c_name) + .DataObjects.GetByName(contact) + .PropertyValue("ContactType") + ) + contact_state = ( + connet_data_objects.GetByName(c_name) + .DataObjects.GetByName(contact) + .PropertyValue("Suppressed") + ) + if contact_state == 0 and contact_type == 1: + new_contact_list.append(contact) +print(new_contact_list) + +# %% +# Using GetObjectsByName +# ~~~~~~~~~~~~~~~~~~~~~~ +# Access a specific object by its name. +bb = DataModel.GetObjectsByName("Connector\Solid1")[0] + +# %% +# Accessing a Named Selection +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Access specific named selections by their names. + +NSall = Model.NamedSelections.GetChildren[Ansys.ACT.Automation.Mechanical.NamedSelection](True) +my_nsel = [i for i in NSall if i.Name.startswith("NSF")][0] +my_nsel2 = [i for i in NSall if i.Name == "NSInsideFaces"][0] + +# %% +# Get All Unsuppressed Bodies and Point Masses +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Example of getting all unsuppressed bodies and point masses. + +# Retrieve all unsuppressed bodies +all_bodies = Model.GetChildren(DataModelObjectCategory.Body, True) +all_bodies = [i for i in all_bodies if not i.Suppressed] +print(len(all_bodies)) + +# Retrieve all unsuppressed point masses +all_pm = Model.GetChildren(DataModelObjectCategory.PointMass, True) +all_pm = [i for i in all_pm if not i.Suppressed] + + +# sphinx_gallery_start_ignore +# Save the Mechanical database file +from pathlib import Path + +output_path = Path.cwd() / "out" +test_mechdat_path = str(output_path / "test.mechdat") +# app.save_as(test_mechdat_path, overwrite=True) + + +# Close the application and delete downloaded files +app.close() +delete_downloads() +# sphinx_gallery_end_ignore diff --git a/examples/00_setup/readme.txt b/examples/00_setup/readme.txt new file mode 100644 index 000000000..cc85d5066 --- /dev/null +++ b/examples/00_setup/readme.txt @@ -0,0 +1,6 @@ +Setup +----- + + +This directory contains a collection of helper scripts for Embedded Instance of PyMechanical.Each script focuses on a specific stage in the Ansys Mechanical workflow, providing utility and automation for common tasks. +