diff --git a/doc/make.bat b/doc/make.bat
index a0b34980b..9a3a99f10 100644
--- a/doc/make.bat
+++ b/doc/make.bat
@@ -41,6 +41,7 @@ goto end
:html
%SPHINXBUILD% -M html %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% -v %O%
+goto end
:pdf
%SPHINXBUILD% -M latex %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
diff --git a/doc/source/conf.py b/doc/source/conf.py
index 0075cf4be..2d868341b 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -195,7 +195,12 @@ def check_example_error(app, pagename, templatename, context, doctree):
"""
# Check if the HTML contains an error message
if pagename.startswith("examples") and not pagename.endswith("/index"):
- if any(map(lambda msg: msg in context["body"], ["UsageError", "NameError"])):
+ if any(
+ map(
+ lambda msg: msg in context["body"],
+ ["UsageError", "NameError", "DeadKernelError", "NotebookError"],
+ )
+ ):
logger.error(f"An error was detected in file {pagename}")
app.builder.config.html_context["build_error"] = True
diff --git a/examples/00-EDB/01_edb_example.py b/examples/00-EDB/01_edb_example.py
new file mode 100644
index 000000000..9384fd3c2
--- /dev/null
+++ b/examples/00-EDB/01_edb_example.py
@@ -0,0 +1,207 @@
+# # EDB: SIwave DC-IR Analysis
+#
+# This example demonstrates the use of EDB to interact with a PCB
+# layout and run DC-IR analysis in SIwave.
+# Perform required imports
+
+# +
+import os
+import tempfile
+import time
+
+from ansys.pyaedt.examples.constants import EDB_VERSION
+import pyaedt
+
+temp_dir = tempfile.TemporaryDirectory(suffix=".ansys")
+targetfile = pyaedt.downloads.download_file("edb/ANSYS-HSD_V1.aedb", destination=temp_dir.name)
+
+siwave_file = os.path.join(os.path.dirname(targetfile), "ANSYS-HSD_V1.siw")
+print(targetfile)
+aedt_file = targetfile[:-4] + "aedt"
+# -
+
+# ## Launch Ansys Electronics Database (EDB)
+#
+# Instantiate an instance of the `pyaedt.Edb` class using SI units.
+
+# +
+if os.path.exists(aedt_file):
+ os.remove(aedt_file)
+
+# Select EDB version (change it manually if needed, e.g. "2023.2")
+edb_version = EDB_VERSION
+print(f"EDB version: {edb_version}")
+
+edb = pyaedt.Edb(edbpath=targetfile, edbversion=edb_version)
+# -
+
+# ## Identify nets and components
+#
+# The ``Edb.nets.netlist`` and ``Edb.components.components`` properties contain information
+# about all of the nets and components. The following cell uses this information to print the
+# number of nets and components.
+
+print("Nets {}".format(len(edb.nets.netlist)))
+start = time.time()
+print("Components {}".format(len(edb.components.components.keys())))
+print("elapsed time = ", time.time() - start)
+
+# ## Identify pin positions
+#
+# This code shows how to obtain all pins for a specific component and
+# print the ``[x, y]`` position of each pin.
+
+pins = edb.components["U2"].pins
+count = 0
+for pin in edb.components["U2"].pins.values():
+ if count < 10: # Only print the first 10 pin coordinates.
+ print(pin.position)
+ elif count == 10:
+ print("...and many more.")
+ else:
+ pass
+ count += 1
+
+# Get all nets connected to a specific component. Print
+# the pin and the name of the net that it is connected to.
+
+connections = edb.components.get_component_net_connection_info("U2")
+n_print = 0 # Counter to limit the number of printed lines.
+print_max = 15
+for m in range(len(connections["pin_name"])):
+ ref_des = connections["refdes"][m]
+ pin_name = connections["pin_name"][m]
+ net_name = connections["net_name"][m]
+ if net_name != "" and (n_print < print_max):
+ print('{}, pin {} -> net "{}"'.format(ref_des, pin_name, net_name))
+ n_print += 1
+ elif n_print == print_max:
+ print("...and many more.")
+ n_print += 1
+
+# Compute rats.
+
+rats = edb.components.get_rats()
+
+# ## Identify connected nets
+#
+# The ``get_dcconnected_net_list()`` method retrieves a list of
+# all DC-connected power nets. Each group of connected nets is returned
+# as a [set](https://docs.python.org/3/tutorial/datastructures.html#sets).
+# The first argument to the method is the list of ground nets, which are
+# not considered in the search for connected nets.
+
+GROUND_NETS = ["GND", "GND_DP"]
+dc_connected_net_list = edb.nets.get_dcconnected_net_list(GROUND_NETS)
+for pnets in dc_connected_net_list:
+ print(pnets)
+
+# ## Power Tree
+#
+# The power tree provides connectivity through all components from the VRM to
+# the device.
+
+VRM = "U1"
+OUTPUT_NET = "AVCC_1V3"
+powertree_df, component_list_columns, net_group = edb.nets.get_powertree(OUTPUT_NET, GROUND_NETS)
+
+# Print some information about the power tree.
+
+print_columns = ["refdes", "pin_name", "component_partname"]
+ncol = [component_list_columns.index(c) for c in print_columns]
+
+# This prints the header. Replace "pin_name" with "pin" to
+# make the header align with the values.
+
+# +
+print("\t".join(print_columns).replace("pin_name", "pin"))
+
+for el in powertree_df:
+ s = ""
+ count = 0
+ for e in el:
+ if count in ncol:
+ s += "{}\t".format(e)
+ count += 1
+ s.rstrip()
+ print(s)
+# -
+
+# ## Remove unused components
+#
+# Delete all RLC components that are connected with only one pin.
+# The ``Edb.components.delete_single_pin_rlc()`` method
+# provides a useful way to
+# remove components that are not needed for the simulation.
+
+edb.components.delete_single_pin_rlc()
+
+# You can also remove unused components explicitly by name.
+
+edb.components.delete("C380")
+
+# Nets can also be removed explicitly.
+
+edb.nets.delete("PDEN")
+
+# Print the top and bottom elevation of the stackup obtained using
+# the ``Edb.stackup.limits()`` method.
+
+s = 'Top layer name: "{top}", Elevation: {top_el:.2f} '
+s += 'mm\nBottom layer name: "{bot}", Elevation: {bot_el:2f} mm'
+top, top_el, bot, bot_el = edb.stackup.limits()
+print(s.format(top=top, top_el=top_el * 1e3, bot=bot, bot_el=bot_el * 1e3))
+
+# ## Set up for SIwave DCIR analysis
+#
+# Create a voltage source and then set up a DCIR analysis.
+
+edb.siwave.create_voltage_source_on_net("U1", "AVCC_1V3", "U1", "GND", 1.3, 0, "V1")
+edb.siwave.create_current_source_on_net("IC2", "NetD3_2", "IC2", "GND", 1.0, 0, "I1")
+setup = edb.siwave.add_siwave_dc_analysis("myDCIR_4")
+setup.use_dc_custom_settings = True
+setup.set_dc_slider = 0
+setup.add_source_terminal_to_ground("V1", 1)
+
+# ## Solve
+#
+# Save the modifications and run the analysis in SIwave.
+
+edb.save_edb()
+edb.nets.plot(None, "1_Top", plot_components_on_top=True)
+
+siw_file = edb.solve_siwave()
+
+# ## Export results
+#
+# Export all quantities calculated from the DC-IR analysis.
+# The following method runs SIwave in batch mode from the command line.
+# Results are written to the edb folder.
+
+outputs = edb.export_siwave_dc_results(
+ siw_file,
+ setup.name,
+)
+
+# Close EDB. After EDB is closed, it can be opened by AEDT.
+
+edb.close_edb()
+
+# ## View Layout in SIwave
+#
+# The SIwave user interface can be visualized and manipulated
+# using the SIwave user interface. This command works on Window OS only.
+
+# +
+# siwave = pyaedt.Siwave("2023.2")
+# siwave.open_project(siwave_file)
+# report_file = os.path.join(temp_folder,'Ansys.htm')
+
+# siwave.export_siwave_report("myDCIR_4", report_file)
+# siwave.close_project()
+# siwave.quit_application()
+# -
+
+# Clean up the temporary files and directory.
+
+temp_dir.cleanup()
diff --git a/examples/00-EDB/02_edb_to_ipc2581.py b/examples/00-EDB/02_edb_to_ipc2581.py
new file mode 100644
index 000000000..0dace03b1
--- /dev/null
+++ b/examples/00-EDB/02_edb_to_ipc2581.py
@@ -0,0 +1,73 @@
+# # EDB: IPC2581 export
+#
+# This example shows how you can use PyAEDT to export an IPC2581 file.
+#
+# Perform required imports, which includes importing a section.
+
+# +
+import os
+import tempfile
+
+from ansys.pyaedt.examples.constants import EDB_VERSION
+import pyaedt
+
+# -
+
+# ## Download the AEDB file and copy it in the temporary folder.
+
+temp_dir = tempfile.TemporaryDirectory(suffix=".ansys")
+targetfile = pyaedt.downloads.download_file("edb/ANSYS-HSD_V1.aedb", destination=temp_dir.name)
+ipc2581_file_name = os.path.join(temp_dir.name, "Ansys_Hsd.xml")
+print(targetfile)
+
+# ## Launch EDB
+#
+# Launch the `pyaedt.Edb` class, using EDB 2023.
+# > Note that length dimensions passed to EDB are in SI units.
+
+# +
+# Select EDB version (change it manually if needed, e.g. "2023.2")
+edb_version = EDB_VERSION
+print(f"EDB version: {edb_version}")
+
+edb = pyaedt.Edb(edbpath=targetfile, edbversion=edb_version)
+# -
+
+# ## Parametrize the width of a trace.
+
+edb.modeler.parametrize_trace_width(
+ "A0_N", parameter_name=pyaedt.generate_unique_name("Par"), variable_value="0.4321mm"
+)
+
+# ## Create a cutout and plot it.
+
+signal_list = []
+for net in edb.nets.netlist:
+ if "PCIe" in net:
+ signal_list.append(net)
+power_list = ["GND"]
+edb.cutout(
+ signal_list=signal_list,
+ reference_list=power_list,
+ extent_type="ConvexHull",
+ expansion_size=0.002,
+ use_round_corner=False,
+ number_of_threads=4,
+ remove_single_pin_components=True,
+ use_pyaedt_extent_computing=True,
+ extent_defeature=0,
+)
+edb.nets.plot(None, None, color_by_net=True)
+
+# ## Export the EDB to an IPC2581 file.
+
+edb.export_to_ipc2581(ipc2581_file_name, "inch")
+print("IPC2581 File has been saved to {}".format(ipc2581_file_name))
+
+# ## Close EDB
+
+edb.close_edb()
+
+# ## Clean up the temporary directory
+
+temp_dir.cleanup()
diff --git a/examples/00-EDB/03_5G_antenna_example_parametrics.py b/examples/00-EDB/03_5G_antenna_example_parametrics.py
new file mode 100644
index 000000000..16e97e25b
--- /dev/null
+++ b/examples/00-EDB/03_5G_antenna_example_parametrics.py
@@ -0,0 +1,384 @@
+# # EDB: Layout Components
+#
+# This example shows how you can use EDB to create a parametric component using
+# 3D Layout and use it in HFSS 3D.
+
+# ## Perform required imports
+#
+# Perform required imports, which includes importing the ``Hfss3dlayout`` object
+# and initializing it on version 2023 R2.
+
+# +
+import os
+import tempfile
+
+from ansys.pyaedt.examples.constants import EDB_VERSION
+import pyaedt
+
+# -
+
+# ## Set non-graphical mode
+
+non_graphical = False
+
+# ## Create data classes
+#
+# Data classes are useful to do calculations and store variables.
+# There are three data classes: ``Patch``, ``Line``, and ``Array``.
+
+# +
+class Patch:
+ def __init__(self, width=0.0, height=0.0, position=0.0):
+ self.width = width
+ self.height = height
+ self.position = position
+
+ @property
+ def points(self):
+ return [
+ [self.position, "-{}/2".format(self.height)],
+ ["{} + {}".format(self.position, self.width), "-{}/2".format(self.height)],
+ ["{} + {}".format(self.position, self.width), "{}/2".format(self.height)],
+ [self.position, "{}/2".format(self.height)],
+ ]
+
+
+class Line:
+ def __init__(self, length=0.0, width=0.0, position=0.0):
+ self.length = length
+ self.width = width
+ self.position = position
+
+ @property
+ def points(self):
+ return [
+ [self.position, "-{}/2".format(self.width)],
+ ["{} + {}".format(self.position, self.length), "-{}/2".format(self.width)],
+ ["{} + {}".format(self.position, self.length), "{}/2".format(self.width)],
+ [self.position, "{}/2".format(self.width)],
+ ]
+
+
+class LinearArray:
+ def __init__(self, nb_patch=1, array_length=10e-3, array_width=5e-3):
+ self.nbpatch = nb_patch
+ self.length = array_length
+ self.width = array_width
+
+ @property
+ def points(self):
+ return [
+ [-1e-3, "-{}/2-1e-3".format(self.width)],
+ ["{}+1e-3".format(self.length), "-{}/2-1e-3".format(self.width)],
+ ["{}+1e-3".format(self.length), "{}/2+1e-3".format(self.width)],
+ [-1e-3, "{}/2+1e-3".format(self.width)],
+ ]
+
+
+# -
+
+# ## Launch EDB
+#
+# PyAEDT.Edb allows to open existing Edb project or create a new empty project.
+
+# +
+temp_dir = tempfile.TemporaryDirectory(suffix=".ansys")
+aedb_path = os.path.join(temp_dir.name, "linear_array.aedb")
+
+# Select EDB version (change it manually if needed, e.g. "2023.2")
+edb_version = EDB_VERSION
+print(f"EDB version: {edb_version}")
+
+# Create an instance of the Edb class.
+edb = pyaedt.Edb(edbpath=aedb_path, edbversion=edb_version)
+# -
+
+# Add stackup layers
+
+edb.stackup.add_layer("Virt_GND")
+edb.stackup.add_layer(
+ "Gap", "Virt_GND", layer_type="dielectric", thickness="0.05mm", material="Air"
+)
+edb.stackup.add_layer("GND", "Gap")
+edb.stackup.add_layer(
+ "Substrat", "GND", layer_type="dielectric", thickness="0.5mm", material="Duroid (tm)"
+)
+edb.stackup.add_layer("TOP", "Substrat")
+
+# Create the the first patch and feed line using the ``Patch``, ``Line``classes defined above.
+#
+# Define parameters:
+
+# +
+edb["w1"] = 1.4e-3
+edb["h1"] = 1.2e-3
+edb["initial_position"] = 0.0
+edb["l1"] = 2.4e-3
+edb["trace_w"] = 0.3e-3
+
+first_patch = Patch(width="w1", height="h1", position="initial_position")
+edb.modeler.create_polygon(first_patch.points, "TOP", net_name="Array_antenna")
+# -
+
+# First line
+
+first_line = Line(length="l1", width="trace_w", position=first_patch.width)
+edb.modeler.create_polygon(first_line.points, "TOP", net_name="Array_antenna")
+
+# Now use the ``LinearArray`` class to create the array.
+
+# +
+edb["w2"] = 2.29e-3
+edb["h2"] = 3.3e-3
+edb["l2"] = 1.9e-3
+edb["trace_w2"] = 0.2e-3
+
+patch = Patch(width="w2", height="h2")
+line = Line(length="l2", width="trace_w2")
+linear_array = LinearArray(nb_patch=8, array_width=patch.height)
+
+current_patch = 1
+current_position = "{} + {}".format(first_line.position, first_line.length)
+
+while current_patch <= linear_array.nbpatch:
+ patch.position = current_position
+ edb.modeler.create_polygon(patch.points, "TOP", net_name="Array_antenna")
+ current_position = "{} + {}".format(current_position, patch.width)
+ if current_patch < linear_array.nbpatch:
+ line.position = current_position
+ edb.modeler.create_polygon(line.points, "TOP", net_name="Array_antenna")
+ current_position = "{} + {}".format(current_position, line.length)
+ current_patch += 1
+
+linear_array.length = current_position
+# -
+
+# Add the ground conductor.
+
+edb.modeler.create_polygon(linear_array.points, "GND", net_name="GND")
+
+# Add the connector pin to use to assign the port.
+
+edb.padstacks.create(
+ padstackname="Connector_pin", holediam="100um", paddiam="0", antipaddiam="200um"
+)
+con_pin = edb.padstacks.place(
+ ["{}/4.0".format(first_patch.width), 0],
+ "Connector_pin",
+ net_name="Array_antenna",
+ fromlayer="TOP",
+ tolayer="GND",
+ via_name="coax",
+)
+
+# Add a connector ground.
+
+edb.modeler.create_polygon(first_patch.points, "Virt_GND", net_name="GND")
+edb.padstacks.create("gnd_via", "100um", "0", "0")
+edb["via_spacing"] = 0.2e-3
+con_ref1 = edb.padstacks.place(
+ [
+ "{} + {}".format(first_patch.points[0][0], "via_spacing"),
+ "{} + {}".format(first_patch.points[0][1], "via_spacing"),
+ ],
+ "gnd_via",
+ fromlayer="GND",
+ tolayer="Virt_GND",
+ net_name="GND",
+)
+con_ref2 = edb.padstacks.place(
+ [
+ "{} + {}".format(first_patch.points[1][0], "-via_spacing"),
+ "{} + {}".format(first_patch.points[1][1], "via_spacing"),
+ ],
+ "gnd_via",
+ fromlayer="GND",
+ tolayer="Virt_GND",
+ net_name="GND",
+)
+con_ref3 = edb.padstacks.place(
+ [
+ "{} + {}".format(first_patch.points[2][0], "-via_spacing"),
+ "{} + {}".format(first_patch.points[2][1], "-via_spacing"),
+ ],
+ "gnd_via",
+ fromlayer="GND",
+ tolayer="Virt_GND",
+ net_name="GND",
+)
+con_ref4 = edb.padstacks.place(
+ [
+ "{} + {}".format(first_patch.points[3][0], "via_spacing"),
+ "{} + {}".format(first_patch.points[3][1], "-via_spacing"),
+ ],
+ "gnd_via",
+ fromlayer="GND",
+ tolayer="Virt_GND",
+ net_name="GND",
+)
+
+# Define the port.
+
+edb.padstacks.set_solderball(con_pin, "Virt_GND", isTopPlaced=False, ballDiam=0.1e-3)
+port_name = edb.padstacks.create_coax_port(con_pin)
+
+# Display the model using the ``Edb.nets.plot()`` method.
+
+edb.nets.plot()
+
+# The EDB is complete. Now close the EDB and import it into HFSS as a "Layout Component".
+
+edb.save_edb()
+edb.close_edb()
+print("EDB saved correctly to {}. You can import in AEDT.".format(aedb_path))
+
+# ## 3D component in HFSS
+#
+# First create an instance of the ``pyaedt.Hfss`` class. If you set
+# > ``non_graphical = False
+#
+# then AEDT user interface will be visible after the following cell is executed.
+# It is now possible to monitor the progress in the UI as each of the following cells is executed.
+# All commands can be run without the UI by changing the value of ``non_graphical``.
+
+h3d = pyaedt.Hfss(
+ projectname="Demo_3DComp",
+ designname="Linear_Array",
+ specified_version="2023.2",
+ new_desktop_session=True,
+ non_graphical=non_graphical,
+ close_on_exit=True,
+ solution_type="Terminal",
+)
+
+# Set units to ``mm``.
+
+h3d.modeler.model_units = "mm"
+
+# ## Import the EDB as a 3D component
+#
+# One or more layout components can be imported into HFSS.
+# The combination of layout data and 3D CAD data helps streamline model creation and setup.
+
+component = h3d.modeler.insert_layout_component(aedb_path, parameter_mapping=True)
+
+# ## Expose the component parameters
+#
+# If a layout component is parametric, you can expose and change parameters in HFSS
+
+# +
+component.parameters
+
+w1_name = "{}_{}".format("w1", h3d.modeler.user_defined_component_names[0])
+h3d[w1_name] = 0.0015
+# -
+
+# ### Radiation Boundary Assignment
+#
+# The 3D domain includes the air volume surrounding the antenna.
+# This antenna will be simulted from 20 GHz - 50 GHz.
+#
+# A "radiation boundary" will be assigned to the outer boundaries of the domain.
+# This boundary should be roughly one quarter wavelength away from the radiating structure:
+#
+# $$ \lambda/4 = \frac{c_0}{4 f} \approx 2.8mm $$
+
+# +
+h3d.modeler.fit_all()
+
+h3d.modeler.create_air_region(2.8, 2.8, 2.8, 2.8, 2.8, 2.8, is_percentage=False)
+h3d.assign_radiation_boundary_to_objects("Region")
+# -
+
+# ### Set up analysis
+#
+# The finite element mesh is adapted iteratively.
+# The maximum number of adaptive passes is set using the ``MaximumPasses`` property.
+# This model converges such that the $S_{11}$ is independent of the mesh.
+# The default accuracy setting is:
+# $$ \max(|\Delta S|) < 0.02 $$
+
+setup = h3d.create_setup()
+setup.props["Frequency"] = "20GHz"
+setup.props["MaximumPasses"] = 10
+
+# Specify properties of the frequency sweep:
+
+sweep1 = setup.add_sweep(sweepname="20GHz_to_50GHz")
+sweep1.props["RangeStart"] = "20GHz"
+sweep1.props["RangeEnd"] = "50GHz"
+sweep1.update()
+
+# Solve the project
+
+h3d.analyze()
+
+# ## Plot results outside AEDT
+#
+# Plot results using Matplotlib.
+
+trace = h3d.get_traces_for_plot()
+solution = h3d.post.get_solution_data(trace[0])
+solution.plot()
+
+# ## Plot far fields in AEDT
+#
+# Plot radiation patterns in AEDT.
+
+# +
+variations = {}
+variations["Freq"] = ["20GHz"]
+variations["Theta"] = ["All"]
+variations["Phi"] = ["All"]
+h3d.insert_infinite_sphere(name="3D")
+
+new_report = h3d.post.reports_by_category.far_field(
+ "db(RealizedGainTotal)", h3d.nominal_adaptive, "3D"
+)
+new_report.variations = variations
+new_report.primary_sweep = "Theta"
+new_report.create("Realized2D")
+# -
+
+# ## Plot far fields in AEDT
+#
+# Plot radiation patterns in AEDT
+
+new_report.report_type = "3D Polar Plot"
+new_report.secondary_sweep = "Phi"
+new_report.create("Realized3D")
+
+# ## Plot far fields outside AEDT
+#
+# Plot radiation patterns outside AEDT
+
+solutions_custom = new_report.get_solution_data()
+solutions_custom.plot_3d()
+
+# ## Plot E Field on nets and layers
+#
+# Plot E Field on nets and layers in AEDT
+
+h3d.post.create_fieldplot_layers_nets(
+ [["TOP", "Array_antenna"]],
+ "Mag_E",
+ intrinsics={"Freq": "20GHz", "Phase": "0deg"},
+ plot_name="E_Layers",
+)
+
+# ## Close AEDT
+#
+# After the simulation completes, the application can be released from the
+# :func:`pyaedt.Desktop.release_desktop` method.
+# All methods provide for saving the project before closing AEDT.
+
+h3d.save_project(os.path.join(temp_dir.name, "test_layout.aedt"))
+h3d.release_desktop()
+
+# ### Clean up the temporary directory
+#
+# The following command removes the project and the temporary directory.
+# If you'd like to save this project, save it to a folder of your choice prior
+# to running the following cell.
+
+temp_dir.cleanup()
diff --git a/examples/00-EDB/04_edb_parametrized_design.py b/examples/00-EDB/04_edb_parametrized_design.py
new file mode 100644
index 000000000..d0edeca28
--- /dev/null
+++ b/examples/00-EDB/04_edb_parametrized_design.py
@@ -0,0 +1,363 @@
+# # EDB: fully parametrized design
+#
+# This example shows how to use the EDB interface along with HFSS 3D Layout to create and solve a
+# parameterized layout. The layout shows a differential via transition on a printed circuit board
+# with back-to-back microstrip to stripline transitions.
+# The model is fully parameterized to enable investigation of the transition performance on the
+# many degrees of freedom.
+#
+# The resulting model is shown below
+#
+#
+
+# +
+import os
+import tempfile
+
+from ansys.pyaedt.examples.constants import EDB_VERSION
+import pyaedt
+
+# -
+
+# ## Set non-graphical mode
+#
+# Set non-graphical mode. The default is ``False``, which opens
+# the AEDT UI.
+
+non_graphical = False
+
+# ## Launch EDB.
+
+# +
+temp_dir = tempfile.TemporaryDirectory(suffix=".ansys")
+aedb_path = os.path.join(temp_dir.name, "pcb.aedb")
+
+# Select EDB version (change it manually if needed, e.g. "2023.2")
+edb_version = EDB_VERSION
+print(f"EDB version: {edb_version}")
+
+edb = pyaedt.Edb(edbpath=aedb_path, edbversion=edb_version)
+# -
+
+# Define the parameters.
+
+# +
+params = {
+ "$ms_width": "0.4mm",
+ "$sl_width": "0.2mm",
+ "$ms_spacing": "0.2mm",
+ "$sl_spacing": "0.1mm",
+ "$via_spacing": "0.5mm",
+ "$via_diam": "0.3mm",
+ "$pad_diam": "0.6mm",
+ "$anti_pad_diam": "0.7mm",
+ "$pcb_len": "15mm",
+ "$pcb_w": "5mm",
+ "$x_size": "1.2mm",
+ "$y_size": "1mm",
+ "$corner_rad": "0.5mm",
+}
+
+for par_name in params:
+ edb.add_project_variable(par_name, params[par_name])
+# -
+
+# Define the stackup layers from bottom to top.
+
+layers = [
+ {"name": "bottom", "layer_type": "signal", "thickness": "35um", "material": "copper"},
+ {"name": "diel_3", "layer_type": "dielectric", "thickness": "275um", "material": "FR4_epoxy"},
+ {"name": "sig_2", "layer_type": "signal", "thickness": "35um", "material": "copper"},
+ {"name": "diel_2", "layer_type": "dielectric", "thickness": "275um", "material": "FR4_epoxy"},
+ {"name": "sig_1", "layer_type": "signal", "thickness": "35um", "material": "copper"},
+ {"name": "diel_1", "layer_type": "dielectric", "thickness": "275um", "material": "FR4_epoxy"},
+ {"name": "top", "layer_type": "signal", "thickness": "35um", "material": "copper"},
+]
+
+# Create the EDB stackup.
+# Define the bottom layer
+
+prev = None
+for layer in layers:
+ edb.stackup.add_layer(
+ layer["name"],
+ base_layer=prev,
+ layer_type=layer["layer_type"],
+ thickness=layer["thickness"],
+ material=layer["material"],
+ )
+ prev = layer["name"]
+
+# Create a parametrized padstack for the signal via.
+
+signal_via_padstack = "automated_via"
+edb.padstacks.create(
+ padstackname=signal_via_padstack,
+ holediam="$via_diam",
+ paddiam="$pad_diam",
+ antipaddiam="",
+ antipad_shape="Bullet",
+ x_size="$x_size",
+ y_size="$y_size",
+ corner_radius="$corner_rad",
+ start_layer=layers[-1]["name"],
+ stop_layer=layers[-3]["name"],
+)
+
+# Assign net names. There are only two signal nets.
+
+net_p = "p"
+net_n = "n"
+
+# Place the signal vias.
+
+edb.padstacks.place(
+ position=["$pcb_len/3", "($ms_width+$ms_spacing+$via_spacing)/2"],
+ definition_name=signal_via_padstack,
+ net_name=net_p,
+ via_name="",
+ rotation=90.0,
+)
+
+edb.padstacks.place(
+ position=["2*$pcb_len/3", "($ms_width+$ms_spacing+$via_spacing)/2"],
+ definition_name=signal_via_padstack,
+ net_name=net_p,
+ via_name="",
+ rotation=90.0,
+)
+
+edb.padstacks.place(
+ position=["$pcb_len/3", "-($ms_width+$ms_spacing+$via_spacing)/2"],
+ definition_name=signal_via_padstack,
+ net_name=net_n,
+ via_name="",
+ rotation=-90.0,
+)
+
+edb.padstacks.place(
+ position=["2*$pcb_len/3", "-($ms_width+$ms_spacing+$via_spacing)/2"],
+ definition_name=signal_via_padstack,
+ net_name=net_n,
+ via_name="",
+ rotation=-90.0,
+)
+
+
+# ## Draw parametrized traces
+#
+# Trace width and the routing (Microstrip-Stripline-Microstrip).
+# Applies to both p and n nets.
+
+# Trace width, n and p
+width = ["$ms_width", "$sl_width", "$ms_width"]
+# Routing layer, n and p
+route_layer = [layers[-1]["name"], layers[4]["name"], layers[-1]["name"]]
+
+# Define points for three traces in the "p" net
+
+points_p = [
+ [
+ ["0.0", "($ms_width+$ms_spacing)/2"],
+ ["$pcb_len/3-2*$via_spacing", "($ms_width+$ms_spacing)/2"],
+ ["$pcb_len/3-$via_spacing", "($ms_width+$ms_spacing+$via_spacing)/2"],
+ ["$pcb_len/3", "($ms_width+$ms_spacing+$via_spacing)/2"],
+ ],
+ [
+ ["$pcb_len/3", "($ms_width+$sl_spacing+$via_spacing)/2"],
+ ["$pcb_len/3+$via_spacing", "($ms_width+$sl_spacing+$via_spacing)/2"],
+ ["$pcb_len/3+2*$via_spacing", "($sl_width+$sl_spacing)/2"],
+ ["2*$pcb_len/3-2*$via_spacing", "($sl_width+$sl_spacing)/2"],
+ ["2*$pcb_len/3-$via_spacing", "($ms_width+$sl_spacing+$via_spacing)/2"],
+ ["2*$pcb_len/3", "($ms_width+$sl_spacing+$via_spacing)/2"],
+ ],
+ [
+ ["2*$pcb_len/3", "($ms_width+$ms_spacing+$via_spacing)/2"],
+ ["2*$pcb_len/3+$via_spacing", "($ms_width+$ms_spacing+$via_spacing)/2"],
+ ["2*$pcb_len/3+2*$via_spacing", "($ms_width+$ms_spacing)/2"],
+ ["$pcb_len", "($ms_width+$ms_spacing)/2"],
+ ],
+]
+
+# Define points for three traces in the "n" net
+
+points_n = [
+ [
+ ["0.0", "-($ms_width+$ms_spacing)/2"],
+ ["$pcb_len/3-2*$via_spacing", "-($ms_width+$ms_spacing)/2"],
+ ["$pcb_len/3-$via_spacing", "-($ms_width+$ms_spacing+$via_spacing)/2"],
+ ["$pcb_len/3", "-($ms_width+$ms_spacing+$via_spacing)/2"],
+ ],
+ [
+ ["$pcb_len/3", "-($ms_width+$sl_spacing+$via_spacing)/2"],
+ ["$pcb_len/3+$via_spacing", "-($ms_width+$sl_spacing+$via_spacing)/2"],
+ ["$pcb_len/3+2*$via_spacing", "-($ms_width+$sl_spacing)/2"],
+ ["2*$pcb_len/3-2*$via_spacing", "-($ms_width+$sl_spacing)/2"],
+ ["2*$pcb_len/3-$via_spacing", "-($ms_width+$sl_spacing+$via_spacing)/2"],
+ ["2*$pcb_len/3", "-($ms_width+$sl_spacing+$via_spacing)/2"],
+ ],
+ [
+ ["2*$pcb_len/3", "-($ms_width+$ms_spacing+$via_spacing)/2"],
+ ["2*$pcb_len/3 + $via_spacing", "-($ms_width+$ms_spacing+$via_spacing)/2"],
+ ["2*$pcb_len/3 + 2*$via_spacing", "-($ms_width+$ms_spacing)/2"],
+ ["$pcb_len", "-($ms_width + $ms_spacing)/2"],
+ ],
+]
+
+# Add traces to the EDB.
+
+trace_p = []
+trace_n = []
+for n in range(len(points_p)):
+ trace_p.append(
+ edb.modeler.create_trace(points_p[n], route_layer[n], width[n], net_p, "Flat", "Flat")
+ )
+ trace_n.append(
+ edb.modeler.create_trace(points_n[n], route_layer[n], width[n], net_n, "Flat", "Flat")
+ )
+
+# Create the wave ports
+
+edb.hfss.create_differential_wave_port(
+ trace_p[0].id,
+ ["0.0", "($ms_width+$ms_spacing)/2"],
+ trace_n[0].id,
+ ["0.0", "-($ms_width+$ms_spacing)/2"],
+ "wave_port_1",
+)
+edb.hfss.create_differential_wave_port(
+ trace_p[2].id,
+ ["$pcb_len", "($ms_width+$ms_spacing)/2"],
+ trace_n[2].id,
+ ["$pcb_len", "-($ms_width + $ms_spacing)/2"],
+ "wave_port_2",
+)
+
+# Draw a conducting rectangle on the the ground layers.
+
+gnd_poly = [
+ [0.0, "-$pcb_w/2"],
+ ["$pcb_len", "-$pcb_w/2"],
+ ["$pcb_len", "$pcb_w/2"],
+ [0.0, "$pcb_w/2"],
+]
+gnd_shape = edb.modeler.Shape("polygon", points=gnd_poly)
+
+# Void in ground for traces on the signal routing layer
+
+# +
+void_poly = [
+ ["$pcb_len/3", "-($ms_width+$ms_spacing+$via_spacing+$anti_pad_diam)/2-$via_spacing/2"],
+ [
+ "$pcb_len/3 + $via_spacing",
+ "-($ms_width+$ms_spacing+$via_spacing+$anti_pad_diam)/2-$via_spacing/2",
+ ],
+ ["$pcb_len/3 + 2*$via_spacing", "-($ms_width+$ms_spacing+$via_spacing+$anti_pad_diam)/2"],
+ ["2*$pcb_len/3 - 2*$via_spacing", "-($ms_width+$ms_spacing+$via_spacing+$anti_pad_diam)/2"],
+ [
+ "2*$pcb_len/3 - $via_spacing",
+ "-($ms_width+$ms_spacing+$via_spacing+$anti_pad_diam)/2-$via_spacing/2",
+ ],
+ ["2*$pcb_len/3", "-($ms_width+$ms_spacing+$via_spacing+$anti_pad_diam)/2-$via_spacing/2"],
+ ["2*$pcb_len/3", "($ms_width+$ms_spacing+$via_spacing+$anti_pad_diam)/2+$via_spacing/2"],
+ [
+ "2*$pcb_len/3 - $via_spacing",
+ "($ms_width+$ms_spacing+$via_spacing+$anti_pad_diam)/2+$via_spacing/2",
+ ],
+ ["2*$pcb_len/3 - 2*$via_spacing", "($ms_width+$ms_spacing+$via_spacing+$anti_pad_diam)/2"],
+ ["$pcb_len/3 + 2*$via_spacing", "($ms_width+$ms_spacing+$via_spacing+$anti_pad_diam)/2"],
+ [
+ "$pcb_len/3 + $via_spacing",
+ "($ms_width+$ms_spacing+$via_spacing+$anti_pad_diam)/2+$via_spacing/2",
+ ],
+ ["$pcb_len/3", "($ms_width+$ms_spacing+$via_spacing+$anti_pad_diam)/2+$via_spacing/2"],
+ ["$pcb_len/3", "($ms_width+$ms_spacing+$via_spacing+$anti_pad_diam)/2"],
+]
+
+void_shape = edb.modeler.Shape("polygon", points=void_poly)
+# -
+
+# Add ground conductors.
+
+# +
+for layer in layers[:-1:2]:
+
+ # add void if the layer is the signal routing layer.
+ void = [void_shape] if layer["name"] == route_layer[1] else []
+
+ edb.modeler.create_polygon(
+ main_shape=gnd_shape, layer_name=layer["name"], voids=void, net_name="gnd"
+ )
+# -
+
+# Plot the layout.
+
+edb.nets.plot(None)
+
+# Save the EDB.
+
+edb.save_edb()
+edb.close_edb()
+
+# Open the project in HFSS 3D Layout.
+
+h3d = pyaedt.Hfss3dLayout(
+ projectname=aedb_path,
+ specified_version="2023.2",
+ non_graphical=non_graphical,
+ new_desktop_session=True,
+)
+
+# # Add HFSS simulation setup
+#
+# Add HFSS simulation setup.
+
+# +
+setup = h3d.create_setup()
+setup.props["AdaptiveSettings"]["SingleFrequencyDataList"]["AdaptiveFrequencyData"]["MaxPasses"] = 3
+
+h3d.create_linear_count_sweep(
+ setupname=setup.name,
+ unit="GHz",
+ freqstart=0,
+ freqstop=10,
+ num_of_freq_points=1001,
+ sweepname="sweep1",
+ sweep_type="Interpolating",
+ interpolation_tol_percent=1,
+ interpolation_max_solutions=255,
+ save_fields=False,
+ use_q3d_for_dc=False,
+)
+# -
+
+# Define the differential pairs to used to calculate differential and common mode
+# s-parameters.
+
+h3d.set_differential_pair(
+ diff_name="In", positive_terminal="wave_port_1:T1", negative_terminal="wave_port_1:T2"
+)
+h3d.set_differential_pair(
+ diff_name="Out", positive_terminal="wave_port_2:T1", negative_terminal="wave_port_2:T2"
+)
+
+# Solve the project.
+
+h3d.analyze()
+
+# Plot the results and shut down AEDT.
+
+solutions = h3d.post.get_solution_data(
+ ["dB(S(In,In))", "dB(S(In,Out))"], context="Differential Pairs"
+)
+solutions.plot()
+h3d.release_desktop()
+
+# Note that the ground nets are only connected to each other due
+# to the wave ports. The problem with poor grounding can be seen in the
+# S-parameters. This example can be downloaded as a Jupyter Notebook, so
+# you can modify it. Try changing parameters or adding ground vias to improve performance.
+#
+# The final cell cleans up the temporary directory, removing all files.
+
+temp_dir.cleanup()
diff --git a/examples/00-EDB/05_Plot_nets.py b/examples/00-EDB/05_Plot_nets.py
new file mode 100644
index 000000000..fac60c7da
--- /dev/null
+++ b/examples/00-EDB/05_Plot_nets.py
@@ -0,0 +1,65 @@
+# # EDB: plot nets with Matplotlib
+#
+# This example shows how to use the ``Edb`` class to view nets, layers and
+# via geometry directly in Python. The methods demonstrated in this example
+# rely on
+# [matplotlib](https://matplotlib.org/cheatsheets/_images/cheatsheets-1.png).
+
+# ## Perform required imports
+#
+# Perform required imports, which includes importing a section.
+
+# +
+import tempfile
+
+from ansys.pyaedt.examples.constants import EDB_VERSION
+import pyaedt
+
+# -
+
+# ## Download the EDB and copy it into the temporary folder.
+
+temp_dir = tempfile.TemporaryDirectory(suffix=".ansys")
+targetfolder = pyaedt.downloads.download_file("edb/ANSYS-HSD_V1.aedb", destination=temp_dir.name)
+
+# ## Create an instance of the Electronics Database using the `pyaedt.Edb` class.
+#
+# > Note that units are SI.
+
+# +
+# Select EDB version (change it manually if needed, e.g. "2023.2")
+edb_version = EDB_VERSION
+print(f"EDB version: {edb_version}")
+
+edb = pyaedt.Edb(edbpath=targetfolder, edbversion=edb_version)
+# -
+
+# Display the nets on a layer. You can display the net geometry directly in Python using
+# ``matplotlib`` from the ``pyaedt.Edb`` class.
+
+edb.nets.plot("AVCC_1V3")
+
+# You can view multiple nets by passing a list containing the net
+# names to the ``plot()`` method.
+
+edb.nets.plot(["GND", "GND_DP", "AVCC_1V3"], color_by_net=True)
+
+# You can display all copper on a single layer by passing ``None``
+# as the first argument. The second argument is a list
+# of layers to plot. In this case, only one
+# layer is to be displayed.
+
+edb.nets.plot(None, ["1_Top"], color_by_net=True, plot_components_on_top=True)
+
+# Display a side view of the layers and padstack geometry using the
+# ``Edb.stackup.plot()`` method.
+
+edb.stackup.plot(scale_elevation=False, plot_definitions=["c100hn140", "c35"])
+
+# Close the EDB.
+
+edb.close_edb()
+
+# Remove all files and the temporary directory.
+
+temp_dir.cleanup()
diff --git a/examples/00-EDB/06_Advanced_EDB.py b/examples/00-EDB/06_Advanced_EDB.py
new file mode 100644
index 000000000..982b7c367
--- /dev/null
+++ b/examples/00-EDB/06_Advanced_EDB.py
@@ -0,0 +1,175 @@
+# # EDB: parametric via creation
+#
+# This example shows how you can use EDB to create a layout.
+#
+# First import the required Python packages.
+
+
+import os
+import tempfile
+
+from ansys.pyaedt.examples.constants import EDB_VERSION
+import numpy as np
+import pyaedt
+
+# Create the EDB project.
+
+temp_dir = tempfile.TemporaryDirectory(suffix=".ansys")
+aedb_path = os.path.join(temp_dir.name, "parametric_via.aedb")
+
+# ## Create stackup
+#
+# The ``StackupSimple`` class creates a stackup based on few inputs. This stackup
+# is used later.
+#
+# Define a function to create the ground conductor.
+
+
+def create_ground_planes(edb, layers):
+ plane = edb.modeler.Shape("rectangle", pointA=["-3mm", "-3mm"], pointB=["3mm", "3mm"])
+ for i in layers:
+ edb.modeler.create_polygon(plane, i, net_name="GND")
+
+
+# ## Create the EDB
+#
+# Create the EDB instance.
+# If the path doesn't exist, PyAEDT automatically generates a new AEDB folder.
+
+# +
+# Select EDB version (change it manually if needed, e.g. "2023.2")
+edb_version = EDB_VERSION
+print(f"EDB version: {edb_version}")
+
+edb = pyaedt.Edb(edbpath=aedb_path, edbversion=edb_version)
+# -
+
+# Insert the stackup layers.
+
+layout_count = 12
+diel_material_name = "FR4_epoxy"
+diel_thickness = "0.15mm"
+cond_thickness_outer = "0.05mm"
+cond_thickness_inner = "0.017mm"
+soldermask_thickness = "0.05mm"
+trace_in_layer = "TOP"
+trace_out_layer = "L10"
+gvia_num = 10
+gvia_angle = 30
+edb.stackup.create_symmetric_stackup(
+ layer_count=layout_count,
+ inner_layer_thickness=cond_thickness_inner,
+ outer_layer_thickness=cond_thickness_outer,
+ soldermask_thickness=soldermask_thickness,
+ dielectric_thickness=diel_thickness,
+ dielectric_material=diel_material_name,
+)
+
+# ## Define parameters
+#
+# Define parameters to allow changes in the model dimesons. Parameters preceded by
+# the ``$`` character have project-wide scope.
+# Without the ``$`` prefix, the parameter scope is limited to the design.
+
+# +
+giva_angle_rad = gvia_angle / 180 * np.pi
+
+edb["$via_hole_size"] = "0.3mm"
+edb["$antipaddiam"] = "0.7mm"
+edb["$paddiam"] = "0.5mm"
+edb.add_design_variable("via_pitch", "1mm", is_parameter=True)
+edb.add_design_variable("trace_in_width", "0.2mm", is_parameter=True)
+edb.add_design_variable("trace_out_width", "0.1mm", is_parameter=True)
+# -
+
+# ## Define padstacks
+#
+# Create two padstck definitions, one for the ground via and one for the signal via.
+
+edb.padstacks.create(
+ padstackname="SVIA",
+ holediam="$via_hole_size",
+ antipaddiam="$antipaddiam",
+ paddiam="$paddiam",
+ start_layer=trace_in_layer,
+ stop_layer=trace_out_layer,
+)
+edb.padstacks.create(padstackname="GVIA", holediam="0.3mm", antipaddiam="0.7mm", paddiam="0.5mm")
+
+# Place the signal via.
+
+edb.padstacks.place([0, 0], "SVIA", net_name="RF")
+
+# Place the ground vias.
+
+# +
+gvia_num_side = gvia_num / 2
+
+if gvia_num_side % 2:
+
+ # Even number of ground vias on each side
+ edb.padstacks.place(["via_pitch", 0], "GVIA", net_name="GND")
+ edb.padstacks.place(["via_pitch*-1", 0], "GVIA", net_name="GND")
+ for i in np.arange(1, gvia_num_side / 2):
+ xloc = "{}*{}".format(np.cos(giva_angle_rad * i), "via_pitch")
+ yloc = "{}*{}".format(np.sin(giva_angle_rad * i), "via_pitch")
+ edb.padstacks.place([xloc, yloc], "GVIA", net_name="GND")
+ edb.padstacks.place([xloc, yloc + "*-1"], "GVIA", net_name="GND")
+
+ edb.padstacks.place([xloc + "*-1", yloc], "GVIA", net_name="GND")
+ edb.padstacks.place([xloc + "*-1", yloc + "*-1"], "GVIA", net_name="GND")
+else:
+
+ # Odd number of ground vias on each side
+ for i in np.arange(0, gvia_num_side / 2):
+ xloc = "{}*{}".format(np.cos(giva_angle_rad * (i + 0.5)), "via_pitch")
+ yloc = "{}*{}".format(np.sin(giva_angle_rad * (i + 0.5)), "via_pitch")
+ edb.padstacks.place([xloc, yloc], "GVIA", net_name="GND")
+ edb.padstacks.place([xloc, yloc + "*-1"], "GVIA", net_name="GND")
+
+ edb.padstacks.place([xloc + "*-1", yloc], "GVIA", net_name="GND")
+ edb.padstacks.place([xloc + "*-1", yloc + "*-1"], "GVIA", net_name="GND")
+# -
+
+# Draw the traces
+
+# +
+edb.modeler.create_trace(
+ [[0, 0], [0, "-3mm"]],
+ layer_name=trace_in_layer,
+ net_name="RF",
+ width="trace_in_width",
+ start_cap_style="Flat",
+ end_cap_style="Flat",
+)
+
+edb.modeler.create_trace(
+ [[0, 0], [0, "3mm"]],
+ layer_name=trace_out_layer,
+ net_name="RF",
+ width="trace_out_width",
+ start_cap_style="Flat",
+ end_cap_style="Flat",
+)
+# -
+
+# Draw ground conductors
+
+ground_layers = [i for i in edb.stackup.signal_layers.keys()]
+ground_layers.remove(trace_in_layer)
+ground_layers.remove(trace_out_layer)
+create_ground_planes(edb=edb, layers=ground_layers)
+
+# Display the layout
+
+edb.stackup.plot(plot_definitions=["GVIA", "SVIA"])
+
+# Save EDB and close the EDB.
+
+edb.save_edb()
+edb.close_edb()
+print("aedb Saved in {}".format(aedb_path))
+
+# Clean up the temporary directory.
+
+temp_dir.cleanup()
diff --git a/examples/00-EDB/08_CPWG.py b/examples/00-EDB/08_CPWG.py
new file mode 100644
index 000000000..7481b6eba
--- /dev/null
+++ b/examples/00-EDB/08_CPWG.py
@@ -0,0 +1,190 @@
+# # EDB: fully parametrized CPWG design
+
+# This example shows how you can use HFSS 3D Layout to create a parametric design
+# for a CPWG (coplanar waveguide with ground).
+
+
+# ## Perform required imports
+
+# Perform required imports. Importing the ``Hfss3dlayout`` object initializes it
+# on version 2023 R2.
+
+import os
+
+from ansys.pyaedt.examples.constants import AEDT_VERSION, EDB_VERSION
+import numpy as np
+import pyaedt
+
+# ## Set non-graphical mode
+
+# Set non-graphical mode. The default is ``False``.
+
+non_graphical = False
+
+# ## Launch EDB
+
+# +
+aedb_path = os.path.join(
+ pyaedt.generate_unique_folder_name(), pyaedt.generate_unique_name("pcb") + ".aedb"
+)
+print(aedb_path)
+
+# Select EDB version (change it manually if needed, e.g. "2023.2")
+edb_version = EDB_VERSION
+print(f"EDB version: {edb_version}")
+
+edbapp = pyaedt.Edb(edbpath=aedb_path, edbversion=edb_version)
+# -
+
+# ## Define parameters
+
+params = {
+ "$ms_width": "0.4mm",
+ "$ms_clearance": "0.3mm",
+ "$ms_length": "20mm",
+}
+for par_name in params:
+ edbapp.add_project_variable(par_name, params[par_name])
+
+
+# ## Create s symmetric stackup
+
+edbapp.stackup.create_symmetric_stackup(2)
+edbapp.stackup.plot()
+
+# ## Draw planes
+
+# +
+plane_lw_pt = ["0mm", "-3mm"]
+plane_up_pt = ["$ms_length", "3mm"]
+
+top_layer_obj = edbapp.modeler.create_rectangle(
+ "TOP", net_name="gnd", lower_left_point=plane_lw_pt, upper_right_point=plane_up_pt
+)
+bot_layer_obj = edbapp.modeler.create_rectangle(
+ "BOTTOM", net_name="gnd", lower_left_point=plane_lw_pt, upper_right_point=plane_up_pt
+)
+layer_dict = {"TOP": top_layer_obj, "BOTTOM": bot_layer_obj}
+# -
+
+# ## Draw a trace
+
+trace_path = [["0", "0"], ["$ms_length", "0"]]
+edbapp.modeler.create_trace(
+ trace_path,
+ layer_name="TOP",
+ width="$ms_width",
+ net_name="sig",
+ start_cap_style="Flat",
+ end_cap_style="Flat",
+)
+
+# ## Create a trace to plane clearance
+
+poly_void = edbapp.modeler.create_trace(
+ trace_path,
+ layer_name="TOP",
+ net_name="gnd",
+ width="{}+2*{}".format("$ms_width", "$ms_clearance"),
+ start_cap_style="Flat",
+ end_cap_style="Flat",
+)
+edbapp.modeler.add_void(layer_dict["TOP"], poly_void)
+
+# ## Create a ground via padstack and place ground stitching vias
+
+# +
+edbapp.padstacks.create(
+ padstackname="GVIA",
+ holediam="0.3mm",
+ paddiam="0.5mm",
+)
+
+yloc_u = "$ms_width/2+$ms_clearance+0.25mm"
+yloc_l = "-$ms_width/2-$ms_clearance-0.25mm"
+
+for i in np.arange(1, 20):
+ edbapp.padstacks.place([str(i) + "mm", yloc_u], "GVIA", net_name="GND")
+ edbapp.padstacks.place([str(i) + "mm", yloc_l], "GVIA", net_name="GND")
+# -
+
+# ## Save and close EDB
+
+edbapp.save_edb()
+edbapp.close_edb()
+
+# ## Open EDB in AEDT
+
+h3d = pyaedt.Hfss3dLayout(
+ projectname=aedb_path,
+ specified_version=AEDT_VERSION,
+ non_graphical=non_graphical,
+ new_desktop_session=True,
+)
+
+# ## Create wave ports
+
+h3d.create_edge_port(
+ "line_3", 0, iswave=True, wave_vertical_extension=10, wave_horizontal_extension=10
+)
+h3d.create_edge_port(
+ "line_3", 2, iswave=True, wave_vertical_extension=10, wave_horizontal_extension=10
+)
+
+# ## Edit airbox extents
+
+h3d.edit_hfss_extents(air_vertical_positive_padding="10mm", air_vertical_negative_padding="1mm")
+
+# ## Create setup
+
+setup = h3d.create_setup()
+setup["MaxPasses"] = 2
+setup["AdaptiveFrequency"] = "3GHz"
+setup["SaveAdaptiveCurrents"] = True
+h3d.create_linear_count_sweep(
+ setupname=setup.name,
+ unit="GHz",
+ freqstart=0,
+ freqstop=5,
+ num_of_freq_points=1001,
+ sweepname="sweep1",
+ sweep_type="Interpolating",
+ interpolation_tol_percent=1,
+ interpolation_max_solutions=255,
+ save_fields=False,
+ use_q3d_for_dc=False,
+)
+
+# ## Plot layout
+
+# +
+h3d.modeler.edb.nets.plot(None, None, color_by_net=True)
+
+cp_name = h3d.modeler.clip_plane()
+# -
+
+# ## Solve the active design
+
+# Uncomment the following code to start the HFSS solver and perform post processing.
+
+# +
+# h3d.analyze()
+
+# solutions = h3d.get_touchstone_data()[0]
+# solutions.log_x = False
+# solutions.plot()
+
+# h3d.post.create_fieldplot_cutplane(
+# cp_name, "Mag_E", h3d.nominal_adaptive, intrinsincDict={"Freq": "3GHz", "Phase": "0deg"}
+# )
+# -
+
+# ## Save AEDT
+
+aedt_path = aedb_path.replace(".aedb", ".aedt")
+h3d.logger.info("Your AEDT project is saved to {}".format(aedt_path))
+h3d.save_project()
+
+# ## Release AEDT
+
+h3d.release_desktop()
diff --git a/examples/00-EDB/09_Configuration.py b/examples/00-EDB/09_Configuration.py
new file mode 100644
index 000000000..286ebff0e
--- /dev/null
+++ b/examples/00-EDB/09_Configuration.py
@@ -0,0 +1,226 @@
+# # EDB: Pin to Pin project
+#
+# This example demonstrates the use of the Electronics
+# Database (EDB) interface to create a layout using the BOM and
+# a configuration file.
+
+# ## Perform required imports
+#
+# The ``Hfss3dlayout`` class provides an interface to
+# the 3D Layout editor in AEDT.
+# on version 2023 R2.
+
+# +
+import os
+import tempfile
+
+from ansys.pyaedt.examples.constants import EDB_VERSION
+import pyaedt
+
+# -
+
+# Download the AEDB file and copy it to a temporary folder.
+
+temp_dir = tempfile.TemporaryDirectory(suffix=".ansys")
+target_aedb = pyaedt.downloads.download_file("edb/ANSYS-HSD_V1.aedb", destination=temp_dir.name)
+print("Project folder is", target_aedb)
+
+# ## Launch EDB
+#
+# Launch the ``pyaedt.Edb`` class using EDB 2023 R2. Length units are SI.
+
+# +
+# Select EDB version (change it manually if needed, e.g. "2023.2")
+edb_version = EDB_VERSION
+print(f"EDB version: {edb_version}")
+
+edbapp = pyaedt.Edb(target_aedb, edbversion=edb_version)
+# -
+
+# ## Import definitions
+#
+# The definition file uses the [json](https://www.json.org/json-en.html) to
+# map layout part numbers to their corresponding models.
+#
+# The model may be an RLC, S-parameter, or
+# [SPICE](https://en.wikipedia.org/wiki/SPICE) model definition.
+# Once imported, the definition is applied to the components in the layout.
+# In this example, the JSON file is in the ``*.aedb`` folder and has the following format:
+# ``` json
+# {
+# "SParameterModel": {
+# "GRM32_DC0V_25degC_series": "./GRM32_DC0V_25degC_series.s2p"
+# },
+# "SPICEModel": {
+# "GRM32_DC0V_25degC": "./GRM32_DC0V_25degC.mod"
+# },
+# "Definitions": {
+# "CAPC1005X05N": {
+# "Component_type": "Capacitor",
+# "Model_type": "RLC",
+# "Res": 1,
+# "Ind": 2,
+# "Cap": 3,
+# "Is_parallel": false
+# },
+# "'CAPC3216X180X55ML20T25": {
+# "Component_type": "Capacitor",
+# "Model_type": "SParameterModel",
+# "Model_name": "GRM32_DC0V_25degC_series"
+# },
+# "'CAPC3216X180X20ML20": {
+# "Component_type": "Capacitor",
+# "Model_type": "SPICEModel",
+# "Model_name": "GRM32_DC0V_25degC"
+# }
+# }
+# }
+# ```
+#
+# The ``Edb.components.import_definitions()`` method imports the component definitions that map
+# electrical models to the components in the simulation model.
+
+edbapp.components.import_definition(os.path.join(target_aedb, "1_comp_definition.json"))
+
+# ## Import BOM
+#
+# The bill of materials (BOM) file provides the list of all components
+# by reference designator, part name, component type, and nominal value.
+#
+# Components that are not contained in the BOM are deactivated in the
+# simulation model.
+# This example saves the CSV file in the ``aedb`` folder.
+#
+# ```
+# +------------+-----------------------+-----------+------------+
+# | RefDes | Part name | Type | Value |
+# +============+=======================+===========+============+
+# | C380 | CAPC1005X55X25LL05T10 | Capacitor | 11nF |
+# +------------+-----------------------+-----------+------------+
+# ```
+#
+# Having red the information in the BOM and definitions file, electrical models can be
+# assigned to all of the components in the simulation model.
+
+edbapp.components.import_bom(
+ os.path.join(target_aedb, "0_bom.csv"),
+ refdes_col=0,
+ part_name_col=1,
+ comp_type_col=2,
+ value_col=3,
+)
+
+# ## Verify a Component
+#
+# Component property allows to access all components instances and their property with
+# getters and setters.
+
+comp = edbapp.components["C1"]
+comp.model_type, comp.value
+
+# ## Check component definition
+#
+# When an s-parameter model is associated to a component it will be available in
+# nport_comp_definition property.
+
+edbapp.components.nport_comp_definition
+edbapp.save_edb()
+
+# ## Configure the simulation setup
+#
+# This step enables the following:
+
+# - Definition of the nets to include in the cutout region
+# - Cutout details
+# - Components to create the ports on
+# - Simulation settings
+#
+# The ``Edb.new_simulaton_configuration()`` method returns an instance
+# of the ``SimulationConfiguration`` class.
+
+# +
+sim_setup = edbapp.new_simulation_configuration()
+sim_setup.solver_type = sim_setup.SOLVER_TYPE.SiwaveSYZ
+sim_setup.batch_solve_settings.cutout_subdesign_expansion = 0.003
+sim_setup.batch_solve_settings.do_cutout_subdesign = True
+sim_setup.batch_solve_settings.use_pyaedt_cutout = True
+sim_setup.ac_settings.max_arc_points = 6
+sim_setup.ac_settings.max_num_passes = 5
+
+sim_setup.batch_solve_settings.signal_nets = [
+ "PCIe_Gen4_TX2_CAP_P",
+ "PCIe_Gen4_TX2_CAP_N",
+ "PCIe_Gen4_TX2_P",
+ "PCIe_Gen4_TX2_N",
+]
+sim_setup.batch_solve_settings.components = ["U1", "X1"]
+sim_setup.batch_solve_settings.power_nets = ["GND", "GND_DP"]
+sim_setup.ac_settings.start_freq = "100Hz"
+sim_setup.ac_settings.stop_freq = "6GHz"
+sim_setup.ac_settings.step_freq = "10MHz"
+# -
+
+# ## Implement the setup
+#
+# The cutout and all other simulation settings are applied to the simulation model.
+
+sim_setup.export_json(os.path.join(temp_dir.name, "configuration.json"))
+edbapp.build_simulation_project(sim_setup)
+
+# ## Display the cutout
+#
+# Plot cutout once finished. The model is ready to simulate.
+
+edbapp.nets.plot(None, None)
+
+# ## Save and close EDB
+#
+# EDB is saved and re-opened in HFSS
+# 3D Layout, where the HFSS simulation can be run.
+
+edbapp.save_edb()
+edbapp.close_edb()
+
+# ## Open Electronics Desktop
+#
+# The EDB is opened in AEDT Hfss3DLayout.
+#
+# Set ``non_graphical=True`` to run the simulation in non-graphical mode.
+
+h3d = pyaedt.Hfss3dLayout(
+ specified_version="2023.2",
+ projectname=target_aedb,
+ non_graphical=False,
+ new_desktop_session=False,
+)
+
+# ## Analyze
+#
+# This project is ready to solve.
+# Executing the following cell runs the HFSS simulation on the layout.
+
+h3d.analyze()
+
+# ## View results
+#
+# S-parameter data is loaded at the end of simulation.
+
+solutions = h3d.post.get_solution_data()
+
+# ## Plot results
+#
+# Plot S-Parameter data.
+
+solutions.plot(solutions.expressions, "db20")
+
+# ## Save and close AEDT
+#
+# HFSS 3D Layout is saved and closed.
+
+h3d.save_project()
+h3d.release_desktop()
+
+# Clean up the temporary directory. All files and the temporary project
+# folder will be deleted in the next step.
+
+temp_dir.cleanup()
diff --git a/examples/00-EDB/10_GDS_workflow.py b/examples/00-EDB/10_GDS_workflow.py
new file mode 100644
index 000000000..894286a54
--- /dev/null
+++ b/examples/00-EDB/10_GDS_workflow.py
@@ -0,0 +1,121 @@
+# # EDB: Edit Control File and import gds
+#
+# This example demonstrates how to import a gds layout for subsequent
+# simulation with HFSS.
+
+# Perform imports.
+
+# +
+import os
+import shutil
+import tempfile
+
+from ansys.pyaedt.examples.constants import EDB_VERSION
+import pyaedt
+from pyaedt.edb_core.edb_data.control_file import ControlFile
+
+# -
+
+# ## Fetch Example Data
+#
+# Download the EDB folder and copy it to a temporary folder.
+# The following files are used in this example:
+# - _sky130_fictious_dtc_exmple_contol_no_map.xml_
+# defines physical information such
+# as material properties, stackup layers, and boundary conditions.
+# - _dummy_layermap.map_
+# maps properties to stackup layers.
+
+# +
+temp_dir = tempfile.TemporaryDirectory(suffix=".ansys")
+control_fn = "sky130_fictitious_dtc_example_control_no_map.xml"
+gds_fn = "sky130_fictitious_dtc_example.gds"
+layer_map = "dummy_layermap.map"
+
+local_path = pyaedt.downloads.download_file("gds", destination=temp_dir.name)
+c_file_in = os.path.join(local_path, control_fn)
+c_map = os.path.join(local_path, layer_map)
+gds_in = os.path.join(local_path, gds_fn)
+gds_out = os.path.join(temp_dir.name, "gds_out.gds")
+shutil.copy2(gds_in, gds_out)
+# -
+
+# ## Control file
+#
+# A Control file is an xml file which purpose if to provide additional information during
+# import phase. It can include, materials, stackup, setup, boundaries and settings.
+# In this example we will import an existing xml, integrate it with a layer mapping file of gds
+# and then adding setup and boundaries.
+
+c = ControlFile(c_file_in, layer_map=c_map)
+
+# ## Set up simulation
+#
+# This code sets up a simulation with HFSS and adds a frequency sweep.
+
+setup = c.setups.add_setup("Setup1", "1GHz")
+setup.add_sweep("Sweep1", "0.01GHz", "5GHz", "0.1GHz")
+
+# ## Provide additional stackup settings
+#
+# After import, you can change the stackup settings and add or remove layers or materials.
+
+c.stackup.units = "um"
+c.stackup.dielectrics_base_elevation = -100
+c.stackup.metal_layer_snapping_tolerance = "10nm"
+for via in c.stackup.vias:
+ via.create_via_group = True
+ via.snap_via_group = True
+
+# ## Define boundary settings
+#
+# Boundaries can include ports, components and boundary extent.
+
+c.boundaries.units = "um"
+c.boundaries.add_port("P1", x1=223.7, y1=222.6, layer1="Metal6", x2=223.7, y2=100, layer2="Metal6")
+c.boundaries.add_extent()
+comp = c.components.add_component("B1", "BGA", "IC", "Flip chip", "Cylinder")
+comp.solder_diameter = "65um"
+comp.add_pin("1", "81.28", "84.6", "met2")
+comp.add_pin("2", "211.28", "84.6", "met2")
+comp.add_pin("3", "211.28", "214.6", "met2")
+comp.add_pin("4", "81.28", "214.6", "met2")
+c.import_options.import_dummy_nets = True
+
+# ## Write XML file
+#
+# After all settings are ready, you can write an XML file.
+
+c.write_xml(os.path.join(temp_dir.name, "output.xml"))
+
+# ## Open EDB
+#
+# Import the gds and open the edb.
+
+# +
+from pyaedt import Edb
+
+# Select EDB version (change it manually if needed, e.g. "2023.2")
+edb_version = EDB_VERSION
+print(f"EDB version: {edb_version}")
+
+edb = Edb(
+ gds_out, edbversion=edb_version, technology_file=os.path.join(temp_dir.name, "output.xml")
+)
+# -
+
+# ## Plot stackup
+#
+# Plot the stackup.
+
+edb.stackup.plot(first_layer="met1")
+
+# ## Close EDB
+#
+# Close the project.
+
+edb.close_edb()
+
+# Clean up the temporary folder.
+
+temp_dir.cleanup()
diff --git a/examples/00-EDB/11_post_layout_parameterization.py b/examples/00-EDB/11_post_layout_parameterization.py
new file mode 100644
index 000000000..30a5d40ee
--- /dev/null
+++ b/examples/00-EDB/11_post_layout_parameterization.py
@@ -0,0 +1,93 @@
+# # EDB: post-layout parameterization
+#
+# This example shows you how to parameterize the signal net in post-layout.
+#
+# Define input parameters.
+
+signal_net_name = "DDR4_ALERT3"
+coplanar_plane_net_name = "1V0" # Specify name of coplanar plane net for adding clearance
+layers = ["16_Bottom"] # Specify layers to parameterize
+
+# Perform required imports.
+
+# +
+import os
+import tempfile
+
+from ansys.pyaedt.examples.constants import EDB_VERSION
+import pyaedt
+
+temp_dir = tempfile.TemporaryDirectory(suffix=".ansys")
+
+# Download and open example layout file in edb format.
+
+edb_path = pyaedt.downloads.download_file("edb/ANSYS-HSD_V1.aedb", destination=temp_dir.name)
+
+# Select EDB version (change it manually if needed, e.g. "2023.2")
+edb_version = EDB_VERSION
+print(f"EDB version: {edb_version}")
+
+edb = pyaedt.Edb(edb_path, edbversion=edb_version)
+# -
+
+# ## Create cutout
+#
+# The ``Edb.cutout()`` method takes a list of
+# signal nets as the first argument and a list of
+# reference nets as the second argument.
+
+edb.cutout([signal_net_name], [coplanar_plane_net_name, "GND"], remove_single_pin_components=True)
+
+# Retrieve the path segments from the signal net.
+
+net = edb.nets[signal_net_name]
+trace_segments = []
+for p in net.primitives:
+ if p.layer_name not in layers:
+ continue
+ if not p.type == "Path":
+ continue
+ trace_segments.append(p)
+
+# Create and assign delta w variable per layer.
+
+for p in trace_segments:
+ vname = f"{p.net_name}_{p.layer_name}_dw"
+ if vname not in edb.variables:
+ edb[vname] = "0mm"
+ new_w = f"{p.width}+{vname}"
+ p.width = new_w
+
+# Delete existing clearance.
+
+for p in trace_segments:
+ for g in edb.modeler.get_polygons_by_layer(p.layer_name, coplanar_plane_net_name):
+ for v in g.voids:
+ if p.is_intersecting(v):
+ v.delete()
+
+# Create and assign the clearance variable for each layer.
+
+for p in trace_segments:
+ clr = f"{p.net_name}_{p.layer_name}_clr"
+ if clr not in edb.variables:
+ edb[clr] = "0.5mm"
+ path = p.get_center_line()
+ for g in edb.modeler.get_polygons_by_layer(p.layer_name, coplanar_plane_net_name):
+ void = edb.modeler.create_trace(path, p.layer_name, f"{p.width}+{clr}*2")
+ g.add_void(void)
+
+# Visualize the layout.
+
+edb.nets.plot(layers=layers[0], size=2000)
+
+# Save the AEDB file and close EDB.
+
+save_edb_path = os.path.join(temp_dir.name, "post_layout_parameterization.aedb")
+edb.save_edb_as(save_edb_path)
+print("Edb is saved to ", save_edb_path)
+edb.close_edb()
+
+# Clean up the temporary folder.
+
+temp_dir.cleanup()
diff --git a/examples/00-EDB/12_edb_sma_connector_on_board.py b/examples/00-EDB/12_edb_sma_connector_on_board.py
new file mode 100644
index 000000000..ddfe361bc
--- /dev/null
+++ b/examples/00-EDB/12_edb_sma_connector_on_board.py
@@ -0,0 +1,220 @@
+# # EDB: geometry creation
+#
+# This example shows how to
+# 1. Create a parameterized PCB with an SMA connector footprint for a single-ended
+# SMA connector launch footprint..
+# 2. Place 3D component on PCB.
+# 3. Create HFSS setup and frequency sweep with a mesh operation.
+# 4. Create return loss plot
+
+# ## See the finished project
+#
+#
+
+# ## Create a parameterized PCB
+#
+# Import dependencies.
+
+import os
+import tempfile
+
+from ansys.pyaedt.examples.constants import EDB_VERSION
+import numpy as np
+import pyaedt
+
+# Create the EDB.
+
+# +
+temp_dir = tempfile.TemporaryDirectory(suffix=".ansys")
+working_folder = temp_dir.name
+
+# Select EDB version (change it manually if needed, e.g. "2023.2")
+edb_version = EDB_VERSION
+print(f"EDB version: {edb_version}")
+
+aedb_path = os.path.join(working_folder, "pcb.aedb")
+print("AEDB file is located in {}".format(aedb_path))
+
+edb = pyaedt.Edb(edbpath=aedb_path, edbversion=edb_version)
+# -
+
+# Add the FR4 dielectric for the PCB.
+
+edb.materials.add_dielectric_material("ANSYS_FR4", 3.5, 0.005)
+
+# ## Create Stackup
+#
+# While this code explicitly defines the stackup, you can import it
+# from a from a CSV or XML file using the
+# ``Edb.stackup.import_stackup()`` method.
+
+edb.add_design_variable("$DIEL_T", "0.15mm")
+edb.stackup.add_layer("BOT")
+edb.stackup.add_layer(
+ "D5", "GND", layer_type="dielectric", thickness="$DIEL_T", material="ANSYS_FR4"
+)
+edb.stackup.add_layer("L5", "Diel", thickness="0.05mm")
+edb.stackup.add_layer(
+ "D4", "GND", layer_type="dielectric", thickness="$DIEL_T", material="ANSYS_FR4"
+)
+edb.stackup.add_layer("L4", "Diel", thickness="0.05mm")
+edb.stackup.add_layer(
+ "D3", "GND", layer_type="dielectric", thickness="$DIEL_T", material="ANSYS_FR4"
+)
+edb.stackup.add_layer("L3", "Diel", thickness="0.05mm")
+edb.stackup.add_layer(
+ "D2", "GND", layer_type="dielectric", thickness="$DIEL_T", material="ANSYS_FR4"
+)
+edb.stackup.add_layer("L2", "Diel", thickness="0.05mm")
+edb.stackup.add_layer(
+ "D1", "GND", layer_type="dielectric", thickness="$DIEL_T", material="ANSYS_FR4"
+)
+edb.stackup.add_layer("TOP", "Diel", thickness="0.05mm")
+
+# Create ground conductors.
+
+# +
+edb.add_design_variable("PCB_W", "20mm")
+edb.add_design_variable("PCB_L", "20mm")
+
+gnd_dict = {}
+for layer_name in edb.stackup.signal_layers.keys():
+ gnd_dict[layer_name] = edb.modeler.create_rectangle(
+ layer_name, "GND", [0, "PCB_W/-2"], ["PCB_L", "PCB_W/2"]
+ )
+# -
+
+# ## Create signal net
+#
+# Create signal net on layer 3, and add clearance to the ground plane.
+
+# +
+edb.add_design_variable("SIG_L", "10mm")
+edb.add_design_variable("SIG_W", "0.1mm")
+edb.add_design_variable("SIG_C", "0.3mm")
+
+signal_path = (["5mm", 0], ["SIG_L+5mm", 0])
+signal_trace = edb.modeler.create_trace(signal_path, "L3", "SIG_W", "SIG", "Flat", "Flat")
+
+signal_path = (["5mm", 0], ["PCB_L", 0])
+clr = edb.modeler.create_trace(signal_path, "L3", "SIG_C*2+SIG_W", "SIG", "Flat", "Flat")
+gnd_dict["L3"].add_void(clr)
+# -
+
+# ## Place signal vias
+#
+# Create the via padstack definition and place the signal vias.
+
+edb.add_design_variable("SG_VIA_D", "1mm")
+edb.add_design_variable("$VIA_AP_D", "1.2mm")
+edb.padstacks.create("ANSYS_VIA", "0.3mm", "0.5mm", "$VIA_AP_D")
+edb.padstacks.place(["5mm", 0], "ANSYS_VIA", "SIG")
+
+# Create ground vias around the SMA
+# connector launch footprint. The vias
+# are placed around the circumference
+# of the launch from 35 degrees to 325
+# degrees.
+
+for i in np.arange(30, 326, 35):
+ px = np.cos(i / 180 * np.pi)
+ py = np.sin(i / 180 * np.pi)
+ edb.padstacks.place(
+ ["{}*{}+5mm".format("SG_VIA_D", px), "{}*{}".format("SG_VIA_D", py)], "ANSYS_VIA", "GND"
+ )
+
+# Create ground vias along the signal trace.
+
+for i in np.arange(2e-3, edb.variables["SIG_L"].value - 2e-3, 2e-3):
+ edb.padstacks.place(["{}+5mm".format(i), "1mm"], "ANSYS_VIA", "GND")
+ edb.padstacks.place(["{}+5mm".format(i), "-1mm"], "ANSYS_VIA", "GND")
+
+# Create a wave port at the end of the signal trace.
+
+signal_trace.create_edge_port("port_1", "End", "Wave", horizontal_extent_factor=10)
+
+# ## Set up HFSS simulation
+#
+# The ``max_num_passes`` argument sets an upper limit on the
+# number of adaptive passes for mesh refinement.
+#
+# For broadband applications when the simulation results may be used
+# to generate a SPICE model, the outer domain boundary can be
+# located roughly $$ d=\lambda/8 $$ from the internal structures
+# in the model.
+
+# +
+extend_domain = 3e11 / 5e9 / 8.0 # Quarter wavelength at 4 GHz.
+edb.design_options.antipads_always_on = True
+edb.hfss.hfss_extent_info.air_box_horizontal_extent = extend_domain
+edb.hfss.hfss_extent_info.air_box_positive_vertical_extent = extend_domain
+edb.hfss.hfss_extent_info.air_box_negative_vertical_extent = extend_domain
+
+setup = edb.create_hfss_setup("Setup1")
+setup.set_solution_single_frequency("5GHz", max_num_passes=8, max_delta_s="0.02")
+setup.hfss_solver_settings.order_basis = "first"
+# -
+
+# Add a mesh operation to the setup.
+
+edb.setups["Setup1"].add_length_mesh_operation({"SIG": ["L3"]}, "m1", max_length="0.1mm")
+
+# Add a frequency sweep to setup.
+#
+# When the simulation results are to
+# be used for transient SPICE analysis, you should
+# use the following strategy:
+#
+# - DC point
+# - Logarithmic sweep from 1 kHz to 100 MHz
+# - Linear scale for higher frequencies.
+
+setup.add_frequency_sweep(
+ "Sweep1",
+ frequency_sweep=[
+ ["linear count", "0", "1KHz", 1],
+ ["log scale", "1KHz", "100MHz", 10],
+ ["linear scale", "0.1GHz", "5GHz", "0.1GHz"],
+ ],
+)
+
+# Save and close EDB.
+
+edb.save_edb()
+edb.close_edb()
+
+# Launch HFSS 3D Layout.
+
+h3d = pyaedt.Hfss3dLayout(aedb_path, specified_version=edb_version, new_desktop_session=True)
+
+# Place a 3D component.
+
+full_comp_name = pyaedt.downloads.download_file(
+ "component_3d", filename="SMA_RF_SURFACE_MOUNT.a3dcomp", destination=working_folder
+)
+comp = h3d.modeler.place_3d_component(
+ component_path=full_comp_name,
+ number_of_terminals=1,
+ placement_layer="TOP",
+ component_name="my_connector",
+ pos_x="5mm",
+ pos_y=0.000,
+)
+
+# ## Run simulation
+
+h3d.analyze(num_cores=4)
+
+# ## Visualize the return loss.
+
+h3d.post.create_report("dB(S(port_1, port_1))")
+
+# ## Save and close the project.
+
+h3d.save_project()
+print("Project is saved to {}".format(h3d.project_path))
+h3d.release_desktop(True, True)
+
+# ## Clean up the temporary folder.
+
+temp_dir.cleanup()
diff --git a/examples/00-EDB/13_edb_create_component.py b/examples/00-EDB/13_edb_create_component.py
new file mode 100644
index 000000000..c5c590183
--- /dev/null
+++ b/examples/00-EDB/13_edb_create_component.py
@@ -0,0 +1,253 @@
+# # EDB: Layout Creation and Setup
+#
+# This example demonstrates how to to
+#
+# 1. Create a layout layer stackup.
+# 2. Define padstacks.
+# 3. Place padstack instances in the layout where the connectors are located.
+# 4. Create primitives such as polygons and traces.
+# 5. Create "components" from the padstack definitions using "pins".
+# >The "component" in EDB acts as a placeholder to enable automatic
+# >placement of electrical models, or
+# >as in this example to assign ports. In many
+# >cases the EDB is imported from a 3rd party layout, in which case the
+# >concept of a "component" as a placeholder is needed to map
+# >models to the components on the PCB for later use in the
+# >simulation.
+# 7. Create the HFSS simulation setup and assign ports where the connectors are located.
+
+# ## View PCB trace model
+#
+# Here is an image of the model that is created in this example.
+#
+#
+#
+# The rectangular sheets at each end of the PCB enable placement of ports where the connectors
+# are located.
+
+# Initialize the EDB layout object.
+
+# +
+import os
+import tempfile
+
+from ansys.pyaedt.examples.constants import EDB_VERSION
+import pyaedt
+from pyaedt import Edb
+
+temp_dir = tempfile.TemporaryDirectory(suffix=".ansys")
+aedb_path = os.path.join(temp_dir.name, "component_example.aedb")
+
+# Select EDB version (change it manually if needed, e.g. "2023.2")
+edb_version = EDB_VERSION
+print(f"EDB version: {edb_version}")
+
+edb = Edb(edbpath=aedb_path, edbversion=edb_version)
+print("EDB is located at {}".format(aedb_path))
+# -
+
+# Initialize variables
+
+layout_count = 12
+diel_material_name = "FR4_epoxy"
+diel_thickness = "0.15mm"
+cond_thickness_outer = "0.05mm"
+cond_thickness_inner = "0.017mm"
+soldermask_thickness = "0.05mm"
+trace_in_layer = "TOP"
+trace_out_layer = "L10"
+trace_width = "200um"
+connector_size = 2e-3
+conectors_position = [[0, 0], [10e-3, 0]]
+
+# Create the stackup
+
+edb.stackup.create_symmetric_stackup(
+ layer_count=layout_count,
+ inner_layer_thickness=cond_thickness_inner,
+ outer_layer_thickness=cond_thickness_outer,
+ soldermask_thickness=soldermask_thickness,
+ dielectric_thickness=diel_thickness,
+ dielectric_material=diel_material_name,
+)
+
+# Create ground planes
+
+ground_layers = [
+ layer_name
+ for layer_name in edb.stackup.signal_layers.keys()
+ if layer_name not in [trace_in_layer, trace_out_layer]
+]
+plane_shape = edb.modeler.Shape("rectangle", pointA=["-3mm", "-3mm"], pointB=["13mm", "3mm"])
+for i in ground_layers:
+ edb.modeler.create_polygon(plane_shape, i, net_name="VSS")
+
+# ### Add design parameters
+#
+# Parameters that are preceded by a _"$"_ character have project-wide scope.
+# Therefore, the padstack **definition** and hence all instances of that padstack
+# rely on the parameters.
+#
+# Parameters such as _"trace_in_width"_ and _"trace_out_width"_ have local scope and
+# are only used in in the design.
+
+edb.add_design_variable("$via_hole_size", "0.3mm")
+edb.add_design_variable("$antipaddiam", "0.7mm")
+edb.add_design_variable("$paddiam", "0.5mm")
+edb.add_design_variable("trace_in_width", "0.2mm", is_parameter=True)
+edb.add_design_variable("trace_out_width", "0.1mm", is_parameter=True)
+
+# ### Create the connector component
+#
+# The component definition is used to place the connector on the PCB. First define the padstacks.
+
+edb.padstacks.create_padstack(
+ padstackname="Via", holediam="$via_hole_size", antipaddiam="$antipaddiam", paddiam="$paddiam"
+)
+
+# Create the first connector
+
+component1_pins = [
+ edb.padstacks.place_padstack(
+ conectors_position[0],
+ "Via",
+ net_name="VDD",
+ fromlayer=trace_in_layer,
+ tolayer=trace_out_layer,
+ ),
+ edb.padstacks.place_padstack(
+ [
+ conectors_position[0][0] - connector_size / 2,
+ conectors_position[0][1] - connector_size / 2,
+ ],
+ "Via",
+ net_name="VSS",
+ ),
+ edb.padstacks.place_padstack(
+ [
+ conectors_position[0][0] + connector_size / 2,
+ conectors_position[0][1] - connector_size / 2,
+ ],
+ "Via",
+ net_name="VSS",
+ ),
+ edb.padstacks.place_padstack(
+ [
+ conectors_position[0][0] + connector_size / 2,
+ conectors_position[0][1] + connector_size / 2,
+ ],
+ "Via",
+ net_name="VSS",
+ ),
+ edb.padstacks.place_padstack(
+ [
+ conectors_position[0][0] - connector_size / 2,
+ conectors_position[0][1] + connector_size / 2,
+ ],
+ "Via",
+ net_name="VSS",
+ ),
+]
+
+# Create the second connector
+
+component2_pins = [
+ edb.padstacks.place_padstack(
+ conectors_position[-1],
+ "Via",
+ net_name="VDD",
+ fromlayer=trace_in_layer,
+ tolayer=trace_out_layer,
+ ),
+ edb.padstacks.place_padstack(
+ [
+ conectors_position[1][0] - connector_size / 2,
+ conectors_position[1][1] - connector_size / 2,
+ ],
+ "Via",
+ net_name="VSS",
+ ),
+ edb.padstacks.place_padstack(
+ [
+ conectors_position[1][0] + connector_size / 2,
+ conectors_position[1][1] - connector_size / 2,
+ ],
+ "Via",
+ net_name="VSS",
+ ),
+ edb.padstacks.place_padstack(
+ [
+ conectors_position[1][0] + connector_size / 2,
+ conectors_position[1][1] + connector_size / 2,
+ ],
+ "Via",
+ net_name="VSS",
+ ),
+ edb.padstacks.place_padstack(
+ [
+ conectors_position[1][0] - connector_size / 2,
+ conectors_position[1][1] + connector_size / 2,
+ ],
+ "Via",
+ net_name="VSS",
+ ),
+]
+
+# ### Define pins
+#
+# Pins are fist defined to allow a component to subsequently connect to the remainder
+# of the model. In this case, ports are assigned at the connector instances using the pins.
+
+for padstack_instance in list(edb.padstacks.instances.values()):
+ padstack_instance.is_pin = True
+
+# Create components from the pins
+
+edb.components.create(component1_pins, "connector_1")
+edb.components.create(component2_pins, "connector_2")
+
+# Create ports on the pins and insert a simulation setup using the
+# ``SimulationConfiguration`` class.
+
+sim_setup = edb.new_simulation_configuration()
+sim_setup.solver_type = sim_setup.SOLVER_TYPE.Hfss3dLayout
+sim_setup.batch_solve_settings.cutout_subdesign_expansion = 0.01
+sim_setup.batch_solve_settings.do_cutout_subdesign = False
+sim_setup.batch_solve_settings.signal_nets = ["VDD"]
+sim_setup.batch_solve_settings.components = ["connector_1", "connector_2"]
+sim_setup.batch_solve_settings.power_nets = ["VSS"]
+sim_setup.ac_settings.start_freq = "0GHz"
+sim_setup.ac_settings.stop_freq = "5GHz"
+sim_setup.ac_settings.step_freq = "1GHz"
+edb.build_simulation_project(sim_setup)
+
+# Save the EDB and open it in the 3D Layout editor. If ``non_graphical==False``,
+# there may be a delay while AEDT starts.
+
+edb.save_edb()
+edb.close_edb()
+h3d = pyaedt.Hfss3dLayout(
+ specified_version="2023.2",
+ projectname=aedb_path,
+ non_graphical=False, # Set non_graphical = False to launch AEDT in graphical mode.
+ new_desktop_session=True,
+)
+
+# ### Release the application from the Python kernel
+#
+# It is important to release the application from the Python kernel after
+# execution of the script. The default behavior of the ``release_desktop()`` method closes all open
+# projects and closes the application.
+#
+# If you want to conintue working on the project in graphical mode
+# after script execution, call the following method with both arguments set to ``False``.
+
+h3d.release_desktop(close_projects=True, close_desktop=True)
+
+# ### Clean up the temporary directory
+#
+# The following command cleans up the temporary directory, thereby removing all
+# project files. If you'd like to save this project, save it to a folder of your choice
+# prior to running the following cell.
+
+temp_dir.cleanup()
diff --git a/examples/00-EDB/14_edb_create_parametrized_design.py b/examples/00-EDB/14_edb_create_parametrized_design.py
new file mode 100644
index 000000000..802c2b425
--- /dev/null
+++ b/examples/00-EDB/14_edb_create_parametrized_design.py
@@ -0,0 +1,113 @@
+# # EDB: parameterized design
+#
+# This example shows how to
+# 1. Set up an HFSS project using SimulationConfiguration class.
+# 2. Create automatically parametrized design.
+#
+# This image shows the layout created in this example:
+#
+#
+#
+
+# ## Import dependencies.
+
+import tempfile
+
+from ansys.pyaedt.examples.constants import EDB_VERSION
+import pyaedt
+
+# ## Create an instance of a pyaedt.Edb object.
+
+# +
+temp_dir = tempfile.TemporaryDirectory(suffix=".ansys")
+target_aedb = pyaedt.downloads.download_file("edb/ANSYS-HSD_V1.aedb", destination=temp_dir.name)
+print("Project is located in ", target_aedb)
+
+# Select EDB version (change it manually if needed, e.g. "2023.2")
+edb_version = EDB_VERSION
+print(f"EDB version: {edb_version}")
+
+edb = pyaedt.Edb(edbpath=target_aedb, edbversion=edb_version)
+print("AEDB file is located in {}".format(target_aedb))
+# -
+
+# ## Prepare the layout for the simulation
+#
+# The ``new_simulation_configuration()`` method creates an instance of
+# the ``SimulationConfiguration`` class. This class helps define all preprocessing steps
+# required to set up the PCB for simulation. After the simulation configuration has been defined,
+# they are applied to the EDB using the ``Edb.build_simulation()`` method.
+
+simulation_configuration = edb.new_simulation_configuration()
+simulation_configuration.signal_nets = [
+ "PCIe_Gen4_RX0_P",
+ "PCIe_Gen4_RX0_N",
+ "PCIe_Gen4_RX1_P",
+ "PCIe_Gen4_RX1_N",
+]
+simulation_configuration.power_nets = ["GND"]
+simulation_configuration.components = ["X1", "U1"]
+simulation_configuration.do_cutout_subdesign = True
+simulation_configuration.start_freq = "OGHz"
+simulation_configuration.stop_freq = "20GHz"
+simulation_configuration.step_freq = "10MHz"
+
+# Now apply the simulation setup to the EDB.
+
+edb.build_simulation_project(simulation_configuration)
+
+# ## Parameterize
+#
+# The layout can automatically be set up to enable parametric studies. For example, the
+# impact of antipad diameter or trace width on signal integrity performance may be invested
+# parametrically.
+
+edb.auto_parametrize_design(
+ layers=True, materials=True, via_holes=True, pads=True, antipads=True, traces=True
+)
+edb.save_edb()
+edb.close_edb()
+
+# ## Open project in AEDT
+#
+# All manipulations thus far have been executed using the EDB API, which provides fast,
+# streamlined processing of layout data in non-graphical mode. The layout and simulation
+# setup can be visualized by opening it using the 3D Layout editor in AEDT.
+#
+# Note that there may be some delay while AEDT is being launched.
+
+hfss = pyaedt.Hfss3dLayout(
+ projectname=target_aedb,
+ specified_version=edb_version,
+ non_graphical=False,
+ new_desktop_session=True,
+)
+
+# The following cell can be used to ensure that the design is valid for simulation.
+
+validation_info = hfss.validate_full_design()
+is_ready_to_simulate = True
+
+# +
+for s in validation_info[0]:
+ if "error" in s:
+ print(s)
+ is_ready_to_simulate = False
+
+if is_ready_to_simulate:
+ print("The model is ready for simulation.")
+else:
+ print("There are errors in the model that must be fixed.")
+# -
+
+# ## Release the application from the Python kernel
+#
+# It is important to release the application from the Python kernel after
+# execution of the script. The default behavior of the ``release_desktop()`` method closes all open
+# projects and closes the application.
+#
+# If you want to continue working on the project in graphical mode
+# after script execution, call the following method with both arguments set to ``False``.
+
+hfss.release_desktop(close_projects=True, close_desktop=True)
+temp_dir.cleanup() # Remove the temporary folder and files. All data will be removd!
diff --git a/examples/00-EDB/15_ac_analysis.py b/examples/00-EDB/15_ac_analysis.py
new file mode 100644
index 000000000..d9b48248a
--- /dev/null
+++ b/examples/00-EDB/15_ac_analysis.py
@@ -0,0 +1,179 @@
+# # EDB: Network Analysis in SIwave
+#
+# This example shows how to use PyAEDT to set up SYZ analysis on a
+# [serdes](https://en.wikipedia.org/wiki/SerDes) channel.
+# The signal input is applied differetially. The positive net is _"PCIe_Gen4_TX3_CAP_P"_.
+# The negative net is _"PCIe_Gen4_TX3_CAP_N"_. In this example, ports are placed on the
+# driver and
+# receiver components.
+
+# ### Perform required imports
+#
+# Perform required imports, which includes importing a section.
+
+import tempfile
+import time
+
+from ansys.pyaedt.examples.constants import EDB_VERSION
+import pyaedt
+
+# ### Download file
+#
+# Download the AEDB file and copy it in the temporary folder.
+
+# +
+temp_dir = tempfile.TemporaryDirectory(suffix=".ansys")
+edb_full_path = pyaedt.downloads.download_file("edb/ANSYS-HSD_V1.aedb", destination=temp_dir.name)
+time.sleep(5)
+
+print(edb_full_path)
+# -
+
+# ### Configure EDB
+#
+# Create an instance of the ``pyaedt.Edb`` class.
+
+# +
+# Select EDB version (change it manually if needed, e.g. "2023.2")
+edb_version = EDB_VERSION
+print(f"EDB version: {edb_version}")
+
+edbapp = pyaedt.Edb(edbpath=edb_full_path, edbversion=edb_version)
+# -
+
+# ### Generate extended nets
+#
+# An extended net consists of two nets that are connected
+# through a passive component such as a resistor or capacitor.
+
+all_nets = edbapp.extended_nets.auto_identify_signal(
+ resistor_below=10, inductor_below=1, capacitor_above=1e-9
+)
+
+# Review the properties of extended nets.
+
+# +
+diff_p = edbapp.nets["PCIe_Gen4_TX3_CAP_P"]
+diff_n = edbapp.nets["PCIe_Gen4_TX3_CAP_N"]
+
+nets_p = list(diff_p.extended_net.nets.keys())
+nets_n = list(diff_n.extended_net.nets.keys())
+
+comp_p = list(diff_p.extended_net.components.keys())
+comp_n = list(diff_n.extended_net.components.keys())
+
+rlc_p = list(diff_p.extended_net.rlc.keys())
+rlc_n = list(diff_n.extended_net.rlc.keys())
+
+print(comp_p, rlc_p, comp_n, rlc_n, sep="\n")
+# -
+
+# Prepare input data for port creation.
+
+# +
+ports = []
+for net_name, net_obj in diff_p.extended_net.nets.items():
+ for comp_name, comp_obj in net_obj.components.items():
+ if comp_obj.type not in ["Resistor", "Capacitor", "Inductor"]:
+ ports.append(
+ {
+ "port_name": "{}_{}".format(comp_name, net_name),
+ "comp_name": comp_name,
+ "net_name": net_name,
+ }
+ )
+
+for net_name, net_obj in diff_n.extended_net.nets.items():
+ for comp_name, comp_obj in net_obj.components.items():
+ if comp_obj.type not in ["Resistor", "Capacitor", "Inductor"]:
+ ports.append(
+ {
+ "port_name": "{}_{}".format(comp_name, net_name),
+ "comp_name": comp_name,
+ "net_name": net_name,
+ }
+ )
+
+print(*ports, sep="\n")
+# -
+
+# ### Create ports
+#
+# Solder balls are generated automatically. The default port type is coax port.
+
+for d in ports:
+ port_name = d["port_name"]
+ comp_name = d["comp_name"]
+ net_name = d["net_name"]
+ edbapp.components.create_port_on_component(
+ component=comp_name, net_list=net_name, port_name=port_name
+ )
+
+# ### Cutout
+#
+# Retain only relevant parts of the layout.
+
+nets = []
+nets.extend(nets_p)
+nets.extend(nets_n)
+edbapp.cutout(signal_list=nets, reference_list=["GND"], extent_type="Bounding")
+
+# Set up the model for network analysis in SIwave.
+
+setup = edbapp.create_siwave_syz_setup("setup1")
+setup.add_frequency_sweep(
+ frequency_sweep=[
+ ["linear count", "0", "1kHz", 1],
+ ["log scale", "1kHz", "0.1GHz", 10],
+ ["linear scale", "0.1GHz", "10GHz", "0.1GHz"],
+ ]
+)
+
+# Save and close the EDB.
+
+edbapp.save()
+edbapp.close_edb()
+
+# ### Launch Hfss3dLayout
+#
+# The HFSS 3D Layout user interface in AEDT is used to import the EDB and
+# run the analysis. AEDT 3D Layout can be used to view the model
+# if it is launched in graphical mode.
+
+h3d = pyaedt.Hfss3dLayout(
+ edb_full_path,
+ specified_version="2023.2",
+ non_graphical=False, # Set to true for non-graphical mode.
+ new_desktop_session=True,
+)
+
+# Define the differential pair.
+
+h3d.set_differential_pair(
+ positive_terminal="U1_PCIe_Gen4_TX3_CAP_P",
+ negative_terminal="U1_PCIe_Gen4_TX3_CAP_N",
+ diff_name="PAIR_U1",
+)
+h3d.set_differential_pair(
+ positive_terminal="X1_PCIe_Gen4_TX3_P",
+ negative_terminal="X1_PCIe_Gen4_TX3_N",
+ diff_name="PAIR_X1",
+)
+
+# Solve and plot the results.
+
+h3d.analyze(num_cores=4)
+
+# Visualze the results.
+
+h3d.post.create_report("dB(S(PAIR_U1,PAIR_U1))", context="Differential Pairs")
+
+# Close AEDT.
+
+h3d.save_project()
+print("Project is saved to {}".format(h3d.project_path))
+h3d.release_desktop(True, True)
+
+# The following cell cleans up the temporary directory and removes all project data.
+
+temp_dir.cleanup()