From a10609da4b0d5c7f1efc8e0ec1324f7710de3e40 Mon Sep 17 00:00:00 2001
From: Devin <38879940+Devin-Crawford@users.noreply.github.com>
Date: Tue, 14 Jan 2025 08:10:16 +0100
Subject: [PATCH] DOCS: Update component_conversion.py (#294)
---
.../components/component_conversion.py | 118 ++++---
.../components/reuse_component.py | 288 +++++++++++-------
2 files changed, 258 insertions(+), 148 deletions(-)
diff --git a/examples/aedt_general/components/component_conversion.py b/examples/aedt_general/components/component_conversion.py
index abe8bf402..80ed9af3c 100644
--- a/examples/aedt_general/components/component_conversion.py
+++ b/examples/aedt_general/components/component_conversion.py
@@ -1,109 +1,145 @@
-# # Encrypted 3D component conversion
+# # Convert encrypted 3D components
#
-# This example shows how to convert an encrypted
-# 3D component from ACIS to Parasolid in different AEDT releases.
-# If you have models previous to Ansys AEDT 2023 R1 with an ACIS kernel,
-# you can convert it to Parasolid.
+# The 2023R1 release of Ansys Electronics Desktop (AEDT) implemented a new [solid modeling kernel](https://en.wikipedia.org/wiki/Geometric_modeling_kernel).
+#
+# This example demonstrates how to easily migrate encrypted
+# 3D components from older versions of AEDT
+# that relied on the ACIS modeling kernel, to the new
+# versions of AEDT that employ
+# the Parasolid kernel. Specifically, if your
+# encrypted 3D
+# components were created with version 22R2 or
+# earlier, you'll need to convert them
+# to a version ≥ 23R1 that supports the Parasolid modeler.
#
# Keywords: **HFSS**, **Encrypted**, **3D component**, **Modeler kernel**.
-
-#
-
-# ## Perform imports and define constants
#
-# Import the required packages.
+#
+
+# ## Prerequisites
#
+# ### Perform imports
+# +
import os
import tempfile
import time
-from pyaedt import Desktop, Hfss, settings
-from pyedb.misc.downloads import download_file
+from ansys.aedt.core import Desktop, Hfss, settings
+from ansys.aedt.core.downloads import download_file
+# -
-# Define constants.
+# ### Define constants
+# Constants help ensure consistency and avoid repetition throughout the example.
AEDT_VERSION = "2024.2"
OLD_AEDT_VERSION = "2024.1"
-NUM_CORES = 4
-NG_MODE = False # Open AEDT UI when it is launched.
+NG_MODE = False # Open AEDT UI when AEDT is launched.
-# ## Create temporary directory
+# ### Create temporary directory
+#
+# Create a temporary working directory.
+# The name of the working folder is stored in ``temp_folder.name``.
#
-# Create a temporary directory where downloaded data or
-# dumped data can be stored.
-# If you'd like to retrieve the project data for subsequent use,
-# the temporary folder name is given by ``temp_folder.name``.
+# > **Note:** The final cell in the notebook cleans up the temporary folder. If you want to
+# > retrieve the AEDT project and data, do so before executing the final cell in the notebook.
temp_folder = tempfile.TemporaryDirectory(suffix=".ansys")
-# ## Download encrypted example
+# ## Covert the encrypted component
#
-# Download the encrypted 3D component example.
+# ### Retrieve the component that will be converted
+#
+# The ``download_file()`` method provides access to a library
+# of examples and models from the Ansys GitHub organization:
+# [example-data repository](https://github.com/ansys/example-data/tree/master/pyaedt). Download the "old"
+# encrypted 3D component and define a name to use for the new, coverted component.
+# +
a3dcomp = download_file(
- directory="component_3d",
- filename="SMA_Edge_Connector_23r2_encrypted_password_ansys.a3dcomp",
+ source="component_3d",
+ name="SMA_Edge_Connector_23r2_encrypted_password_ansys.a3dcomp",
destination=temp_folder.name,
)
-# ## Enable multiple desktop support
+# Name of the converted 3D component:
+new_component_filename = os.path.join(temp_folder.name, r"SMA_Edge_Connector_encrypted.a3dcomp")
+# -
+
+# ### Enable multiple desktop instances.
+#
+# This example runs two versions of AEDT simultaneously.
+#
+# > **Note:** Both the old and new versions of AEDT must be installed on the machine
+# > where this example runs.
settings.use_multi_desktop = True
-# ## Prepare encrypted 3D component in ACIS
+# ### Load the encrypted 3D component.
#
-# Launch the old AEDT release.
+# Launch the old version of AEDT and load the encrypted component.
+# Pass the keyword argument ``aedt_process_id`` to ensure that the ``Hfss``
+# instance connects to the correct running version of HFSS. The encryption
+# password must be provided to enable conversion.
+# +
aedt_old = Desktop(new_desktop=True, version=OLD_AEDT_VERSION)
# Insert an empty HFSS design.
-
hfss1 = Hfss(aedt_process_id=aedt_old.aedt_process_id, solution_type="Terminal")
# Insert the encrypted 3D component.
+cmp = hfss1.modeler.insert_3d_component(input_file=a3dcomp, password="ansys")
-cmp = hfss1.modeler.insert_3d_component(comp_file=a3dcomp, password="ansys")
-
-# Open the 3D component in an HFSS design.
-
+# Open the 3D component definition.
app_comp = cmp.edit_definition(password="ansys")
+# -
-# ## Create an encrypted 3D component in Parasolid
+# ### Convert the encrypted 3D component
+#
+# Launch another instance of AEDT to enable conversion of the
+# 3D component.
#
-# Launch the new AEDT release
+# After the new version of AEDT is started, the process ID
+# is retrieved via the property ``aedt.aedt_process_id`` and is passed
+# as an argument to `Hfss()`. This ensures that the newly created
+# `hfss2` object
+# is connected to the
+# correct version and instance of AEDT.
-aedt = Desktop(new_desktop_session=True, specified_version=AEDT_VERSION)
+# +
+aedt = Desktop(new_desktop=True, version=AEDT_VERSION)
# Insert an empty HFSS design.
-
hfss2 = Hfss(aedt_process_id=aedt.aedt_process_id, solution_type="Terminal")
# Copy objects from the old design.
-
hfss2.copy_solid_bodies_from(design=app_comp, no_vacuum=False, no_pec=False)
# Create the new encrypted 3D component.
-
hfss2.modeler.create_3dcomponent(
- input_file=os.path.join(temp_folder.name, r"SMA_Edge_Connector_encrypted.a3dcomp"),
+ input_file=new_component_filename,
is_encrypted=True,
edit_password="ansys",
hide_contents=False,
allow_edit=True,
password_type="InternalPassword",
)
+# -
-# ## Release AEDT
+# ## Finish
+#
+# ### Save the projects
aedt.save_project()
aedt_old.save_project()
aedt.release_desktop()
aedt_old.release_desktop()
+print(f"The new encrypted 3D component can be retrieved from: {new_component_filename}")
# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.
time.sleep(3)
-# ## Clean up
+# ### Clean up
#
# All project files are saved in the folder ``temp_folder.name``.
# If you've run this example as a Jupyter notebook, you
diff --git a/examples/aedt_general/components/reuse_component.py b/examples/aedt_general/components/reuse_component.py
index b9e6a7f56..a0e63f900 100644
--- a/examples/aedt_general/components/reuse_component.py
+++ b/examples/aedt_general/components/reuse_component.py
@@ -1,201 +1,273 @@
# # 3D component creation and reuse
-
-# Here is a workflow for creating a 3D component and reusing it:
-#
-# Step 1: Create an antenna using PyAEDT and HFSS 3D Modeler. (The antenna can also be created using EDB and
-# HFSS 3D Layout).
-#
-# Step 2. Store the object as a 3D component on the disk.
-#
-# Step 3. Reuse the 3D component in another project.
#
-# Step 4. Parametrize and optimize the target design.
+# This example demonstrates how to create and use an HFSS 3D component by
+# performing the following:
+# 1. Create a patch antenna using the HFSS 3D Modeler.
+# 2. Save the antenna as a 3D component on the disk.
+# 3. Import multiple instances of patch antenna as
+# a 3D component in a new project to create a small array.
+# 5. Set up the new design for simulation and optimization.
#
-# Keywords: **AEDT**, **General**, **3D component**.
+# Keywords: **AEDT**, **Antenna**, **3D component**.
-# ## Perform imports and define constants
-# Import the required packages.
+# ## Prerequisites
+#
+# ### Perform imports
+# +
import os
import tempfile
import time
from ansys.aedt.core import Hfss
+# -
-# Define constants.
+# ### Define constants
+# Constants help ensure consistency and avoid repetition throughout the example.
AEDT_VERSION = "2024.2"
NG_MODE = False # Open AEDT UI when it is launched.
-# ## Create temporary directory
+# ### Create temporary directory
#
-# Create a temporary directory where downloaded data or
-# dumped data can be stored.
-# If you'd like to retrieve the project data for subsequent use,
-# the temporary folder name is given by ``temp_folder.name``.
+# Create a temporary working directory.
+# The name of the working folder is stored in ``temp_folder.name``.
+#
+# > **Note:** The final cell in the notebook cleans up the temporary folder. If you want to
+# > retrieve the AEDT project and data, do so before executing the final cell in the notebook.
+#
+# This example creates two projects defined in `project_names.
+# The first will be used to
+# create the patch antenna model and the 2nd project
+# will be used to demonstrate the use 3D components.
temp_folder = tempfile.TemporaryDirectory(suffix=".ansys")
+project_names = [os.path.join(temp_folder.name, "start_project.aedt"),
+ os.path.join(temp_folder.name, "final_project.aedt"),
+ ]
-# Create an HFSS object.
+# ### Launch HFSS
+# AEDT is started when an instance of the ``Hfss()`` class is
+# instantiated. An HFSS design is automatically inserted in the
+# AEDT project.
hfss = Hfss(
version=AEDT_VERSION,
- new_desktop=True,
+ design="build_comp",
+ new_desktop=True, # Set to False if you want to connect to an existing AEDT session.
close_on_exit=True,
non_graphical=NG_MODE,
solution_type="Modal",
)
-hfss.save_project(os.path.join(temp_folder.name, "example.aedt"))
+hfss.save_project(project_names[0])
-# ## Define variables
+# ## Model preparation
#
-# PyAEDT can create and store all variables available in AEDT (such as design, project,
-# and postprocessing).
+# ### Define parameters
+#
+# Parameters can be defined in the HFSS design and subsequently
+# used to optimiuze
+# performance, run parametric studies or
+# explore the impact of tolerance on performance.
-hfss["thick"] = "0.1mm"
+hfss["thickness"] = "0.1mm"
hfss["width"] = "1mm"
-# ## Create modeler objects
+# ### Build the antenna model
+#
+# The compact,
+# [pythonic syntax](https://docs.python-guide.org/writing/style/#code-style)
+# allows you to create the model from simple
+# primitives. This patch antenna is comprised of the FR-4 substrate, a rectangle,
+# and the coaxial
+# probe feed. Each primitive is of type ``Object3D``.
#
-# PyAEDT supports all modeler functionalities available in AEDT.
-# You can create, delete, and modify objects using all available Boolean operations.
-# PyAEDT can also fully access history.
+# > **Note: ** The feed length of the patch antenna is fixed and is not
+# > parametric in HFSS.
# +
substrate = hfss.modeler.create_box(
- ["-width", "-width", "-thick"],
- ["2*width", "2*width", "thick"],
+ ["-width", "-width", "-thickness"],
+ ["2*width", "2*width", "thickness"],
material="FR4_epoxy",
- name="sub",
+ name="substrate",
)
+feed_length = "0.1mm" # This parameter is defined only in Python and is not varied
+
patch = hfss.modeler.create_rectangle(
- "XY", ["-width/2", "-width/2", "0mm"], ["width", "width"], name="patch1"
+ "XY", ["-width/2", "-width/2", "0mm"], ["width", "width"], name="patch"
)
-via1 = hfss.modeler.create_cylinder(
+inner_conductor = hfss.modeler.create_cylinder(
2,
- ["-width/8", "-width/4", "-thick"],
+ ["-width/8", "-width/4", f"-thickness - {feed_length}"],
"0.01mm",
- "thick",
+ f"thickness + {feed_length}",
material="copper",
name="via_inner",
)
via_outer = hfss.modeler.create_cylinder(
2,
- ["-width/8", "-width/4", "-thick"],
+ ["-width/8", "-width/4", "-thickness"],
"0.025mm",
- "thick",
+ f"-{feed_length}",
material="Teflon_based",
name="via_teflon",
)
# -
-# ## Assign bundaries
-#
-# Most of HFSS boundaries and excitations are already available in PyAEDT.
-# You can easily assign a boundary to a face or to an object by taking advantage of
-# Object-Oriented Programming (OOP) available in PyAEDT.
-
-# ### Assign Perfect E boundary to sheets
+# ### Assign boundaries
#
-# Assign a Perfect E boundary to sheets.
+# Boundary conditions can be assigned to faces or bodies in the model
+# using methods of the ``Hfss`` class.
-hfss.assign_perfecte_to_sheets(patch)
+hfss.assign_perfecte_to_sheets(patch, name="patch_bc")
-# ### Assign boundaries to faces
+# ### Assign boundaries to the via
#
-# Assign boundaries to the top and bottom faces of an object.
+# The following statement selects the outer surface of the cylinder
+# ``via_outer``, excluding the upper and lower faces, and assigns
+# the "perfect conductor" boundary condition.
# +
-side_face = [
- i
- for i in via_outer.faces
- if i.id not in [via_outer.top_face_z.id, via_outer.bottom_face_z.id]
-]
-
-hfss.assign_perfecte_to_sheets(side_face)
-hfss.assign_perfecte_to_sheets(substrate.bottom_face_z)
+side_face = [i for i in via_outer.faces if i.id not in
+ [via_outer.top_face_z.id, via_outer.bottom_face_z.id]
+ ]
+
+hfss.assign_perfecte_to_sheets(side_face, name="feed_gnd")
+hfss.assign_perfecte_to_sheets(substrate.bottom_face_z, name="ground_plane")
+hfss.assign_perfecth_to_sheets(via_outer.top_face_z, name="feed_thru") # Ensure power flows through the ground plane.
+hfss.change_material_override(material_override=True) # Allow the probe feed to extend outside the substrate.
# -
-# ## Create wave port
+# ### Create wave port
#
-# You can assign a wave port to a sheet or to a face of an object.
+# A wave port is assigned to the bottom face of the via. Note that the property `via_outer.bottom_face_z`
+# is a ``FacePrimitive`` object.
-hfss.wave_port(
+p1 = hfss.wave_port(
via_outer.bottom_face_z,
name="P1",
+ create_pec_cap=True
)
-# ## Create 3D component
+# ### Query the object properties
#
-# Once the model is ready, you can create a 3D component.
-# Multiple options are available to partially select objects, coordinate systems,
-# boundaries, and mesh operations. You can also create encrypted 3D components.
+# Everything in Python is an object. You can use the object
+# properties to obtain detailed information as shown below:
-component_path = os.path.join(temp_folder.name, "component_test.aedbcomp")
-hfss.modeler.create_3dcomponent(component_path, "patch_antenna")
+out_str = f"A port named '{p1.name}' was assigned to a surface object"
+out_str += f" of type \n {type(via_outer.bottom_face_z)}\n"
+out_str += f"which is located at the bottom surface of the object '{via_outer.name}'\n"
+out_str += f"at the z-elevation: {via_outer.bottom_face_z.bottom_edge_z} "
+out_str += f"{hfss.modeler.model_units}\n"
+out_str += f"and has the face ID: {via_outer.bottom_face_z.id}."
+print(out_str)
-# ## Manage multiple project
+# ## Create 3D component
#
-# PyAEDT lets you control multiple projects, designs, and solution types at the same time.
+# You can now create a 3D component from the antenna model. The following statements
+# save the component to the specified location with the name "patch_antenna".
+
+component_path = os.path.join(temp_folder.name, "patch_antenna.a3dcomp")
+hfss.modeler.create_3dcomponent(component_path, name="patch_antenna")
+
+# A 2nd instance of HFSS is created to demonstrate how the new 3D component can be
+# used within a new design.
-new_project = os.path.join(temp_folder.name, "new_project.aedt")
hfss2 = Hfss(
version=AEDT_VERSION,
- project=new_project,
+ project=project_names[1],
design="new_design",
solution_type="Modal",
)
+hfss2.change_material_override(material_override=True)
-# ## Insert 3D component
-#
-# You can insert a 3D component without supplying additional information.
-# All needed information is read from the file itself.
-
-hfss2.modeler.insert_3d_component(component_path)
-
-# ## Parametrize 3D components
+# ### Insert 3D components
#
-# You can specify parameters for any 3D components.
+# Place 4 antennas to make a small array.
+# - The substrate thickness is modified by creating the parameter "p_thick" and
+# assigning it to the "thickness" parameter of the components.
+# - The first antenna is placed at the origin.
+# - The spacing between elements is defined by the parameter $2\times w$
-hfss2.modeler.user_defined_components["patch_antenna1"].parameters
-hfss2["p_thick"] = "1mm"
-hfss2.modeler.user_defined_components["patch_antenna1"].parameters["thick"] = "p_thick"
+# +
+# Define a parameter to use for the substrate thickness.
+hfss2["p_thick"] = "0.2mm"
+
+# Define a parameter to specify the patch width.
+hfss2["w"] = "1mm"
+
+# [x, y, z] location of the patch elements.
+positions = [["2*w", "w", 0], ["-2*w", "w", 0], [0, "2.5*w", 0]]
+
+# Keep track of patch elements and their coordinate systems in Python lists:
+elements = []
+cs = []
+
+# The first patch is located at the origin.
+elements.append(hfss2.modeler.insert_3d_component(component_path, name="patch_0"))
+elements[0].parameters["thickness"] = "p_thick"
+elements[0].parameters["width"] = "w"
+
+# Now place the other 3 patches:
+count = 1
+for p in positions:
+ cs.append(hfss2.modeler.create_coordinate_system(origin=p, name="cs_" + str(count))) # Create the patch coordinate system.
+ elements.append(hfss2.modeler.insert_3d_component(component_path, # Place the patch element.
+ coordinate_system=cs[-1].name,
+ name="patch_" + str(count))
+ )
+ count +=1
+
+ elements[-1].parameters["thickness"] = "p_thick"
+ elements[-1].parameters["width"] = "w"
+# -
-# ## Insert multiple 3D components
-#
-# There is no limit to the number of 3D components that can be inserted in a design.
-# These components can be the same or linked to different files.
+# You can inspect the component parameters.
-hfss2.modeler.create_coordinate_system(origin=[20, 20, 10], name="Second_antenna")
-ant2 = hfss2.modeler.insert_3d_component(
- component_path, coordinate_system="Second_antenna"
-)
+units = hfss2.modeler.model_units # Retrieve the length units as a string.
+for e in elements:
+ print(f"Component '{e.name}' is located at (x={e.center[0]} {units}, y={e.center[1]} {units})")
-# ## Move 3D components
+# ### Move 3D components
#
-# Move a 3D component by either changing its position or moving the relative coordinate system.
+# The position of each 3D component can be changed by modifying the ``origin``
+# of the corresponding coordinate system.
-hfss2.modeler.coordinate_systems[0].origin = [10, 10, 3]
+hfss2.modeler.coordinate_systems[0].origin = [0, "2*w", 0]
-# ## Create air region
+# ### Create air region
#
-# Create an air region and assign a boundary to a face or an object.
+# The volume of the solution domain is defined
+# by an air region object. The following cell creates the
+# region object and assigns the radiation boundary to the outer surfaces of
+# the region.
-hfss2.modeler.create_air_region(30, 30, 30, 30, 30, 30)
+hfss2.modeler.create_air_region( x_pos=2, y_pos=2, z_pos=2.5, x_neg=2, y_neg=2, z_neg=2, is_percentage=False)
hfss2.assign_radiation_boundary_to_faces(hfss2.modeler["Region"].faces)
-# ## Create setup and optimetrics analysis
+# ### Create solution setup and optimetrics analysis
#
-# Once a project is ready to be solved, use PyAEDT to create a setup and parametrics analysis.
-# All setup parameters can be edited.
+# Once a project is ready to be solved, define the solution setup and parametric analysis.
-setup1 = hfss2.create_setup()
-optim = hfss2.parametrics.add("p_thick", "0.2mm", "1.5mm", step=14)
+# +
+setup1 = hfss2.create_setup(RangeStart="60GHz", RangeEnd="80GHz")
+optim = hfss2.parametrics.add("w", start_point="0.8mm",
+ end_point="1.2mm",
+ step="0.05mm",
+ variation_type="LinearStep",
+ name="Sweep Patch Width")
+
+if hfss.valid_design:
+ print(f"The HFSS design '{hfss.design_name}' is ready to solve.")
+else:
+ print(f"Something is not quite right.")
+# -
-# ## Plot objects
+# ### Visualize the model
hfss2.modeler.fit_all()
hfss2.plot(
@@ -204,18 +276,20 @@
plot_air_objects=True,
)
-# ## Release AEDT
+# ## Finish
+#
+# ### Save the project
hfss2.save_project()
hfss2.release_desktop()
# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.
time.sleep(3)
-# ## Clean up
+# ### Clean up
#
# All project files are saved in the folder ``temp_folder.name``.
# If you've run this example as a Jupyter notebook, you
-# can retrieve those project files. The following cell removes
-# all temporary files, including the project folder.
+# can retrieve those project files. The following cell
+# removes all temporary files, including the project folder.
temp_folder.cleanup()