Skip to content

Commit

Permalink
Merge branch 'main' into dependabot/pip/pytest-cov-gte-4.0.0-and-lt-6.1
Browse files Browse the repository at this point in the history
  • Loading branch information
SMoraisAnsys authored Nov 16, 2024
2 parents 37b9524 + fc9a6f4 commit 0992e4f
Show file tree
Hide file tree
Showing 14 changed files with 430 additions and 38 deletions.
3 changes: 2 additions & 1 deletion doc/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,8 @@ def setup(app):

# Sphinx gallery customization
nbsphinx_thumbnails = {
"examples/use_configuration/set_up_edb_for_signal_integrity_analysis": "_static/thumbnails/101_getting_started.png",
"examples/use_configuration/pdn_analysis": "_static/thumbnails/101_getting_started.png",
"examples/use_configuration/serdes": "_static/thumbnails/101_getting_started.png",
"examples/use_configuration/import_stackup": "_static/thumbnails/101_getting_started.png",
"examples/use_configuration/import_material": "_static/thumbnails/101_getting_started.png",
"examples/use_configuration/import_ports": "_static/thumbnails/101_getting_started.png",
Expand Down
3 changes: 2 additions & 1 deletion examples/use_configuration/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ End-to-end workflow

.. nbgallery::

set_up_edb_for_signal_integrity_analysis.py
pdn_analysis.py
serdes.py

Step explanation
-------------------------
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# # Set up EDB for Power Integrity Analysis
# # Set up EDB for Power Distribution Network Analysis
# This example shows how to set up the electronics database (EDB) for power integrity analysis from a single
# configuration file.

Expand Down
277 changes: 277 additions & 0 deletions examples/use_configuration/serdes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
# # Set up EDB for Serdes channel S-parameter extraction

# ## Import the required packages

import json

# +
import os
import tempfile

from ansys.aedt.core import Hfss3dLayout
from ansys.aedt.core.downloads import download_file

from pyedb import Edb

AEDT_VERSION = "2024.2"
NG_MODE = False

# -

# Download the example PCB data.

temp_folder = tempfile.TemporaryDirectory(suffix=".ansys")
file_edb = download_file(source="edb/ANSYS-HSD_V1.aedb", destination=temp_folder.name)
download_file(source="touchstone", name="GRM32_DC0V_25degC_series.s2p", destination=os.path.split(file_edb)[0])

# ## Load example layout

edbapp = Edb(file_edb, edbversion=AEDT_VERSION)

# ## Create config file

cfg_general = {"anti_pads_always_on": True, "suppress_pads": True}

# Define dielectric materials, stackup and surface roughness model.

cfg_stackup = {
"materials": [
{"name": "copper", "permittivity": 1, "conductivity": 58000000.0},
{"name": "megtron4", "permittivity": 3.77, "dielectric_loss_tangent": 0.005},
{"name": "solder_resist", "permittivity": 3.0, "dielectric_loss_tangent": 0.035},
],
"layers": [
{
"name": "Top",
"type": "signal",
"material": "copper",
"fill_material": "solder_resist",
"thickness": "0.035mm",
"roughness": {
"top": {"model": "huray", "nodule_radius": "0.5um", "surface_ratio": "5"},
"bottom": {"model": "huray", "nodule_radius": "0.5um", "surface_ratio": "5"},
"side": {"model": "huray", "nodule_radius": "0.5um", "surface_ratio": "5"},
"enabled": True,
},
},
{"name": "DE1", "type": "dielectric", "material": "megtron4", "fill_material": "", "thickness": "0.1mm"},
{"name": "Inner1", "type": "signal", "material": "copper", "fill_material": "megtron4", "thickness": "0.017mm"},
{"name": "DE2", "type": "dielectric", "material": "megtron4", "fill_material": "", "thickness": "0.088mm"},
{"name": "Inner2", "type": "signal", "material": "copper", "fill_material": "megtron4", "thickness": "0.017mm"},
{"name": "DE3", "type": "dielectric", "material": "megtron4", "fill_material": "", "thickness": "0.1mm"},
{"name": "Inner3", "type": "signal", "material": "copper", "fill_material": "megtron4", "thickness": "0.017mm"},
{"name": "Megtron4-1mm", "type": "dielectric", "material": "megtron4", "fill_material": "", "thickness": 0.001},
{"name": "Inner4", "type": "signal", "material": "copper", "fill_material": "megtron4", "thickness": "0.017mm"},
{"name": "DE5", "type": "dielectric", "material": "megtron4", "fill_material": "", "thickness": "0.1mm"},
{"name": "Inner5", "type": "signal", "material": "copper", "fill_material": "megtron4", "thickness": "0.017mm"},
{"name": "DE6", "type": "dielectric", "material": "megtron4", "fill_material": "", "thickness": "0.088mm"},
{"name": "Inner6", "type": "signal", "material": "copper", "fill_material": "megtron4", "thickness": "0.017mm"},
{"name": "DE7", "type": "dielectric", "material": "megtron4", "fill_material": "", "thickness": "0.1mm"},
{
"name": "Bottom",
"type": "signal",
"material": "copper",
"fill_material": "solder_resist",
"thickness": "0.035mm",
},
],
}

# Define Component with solderballs.

cfg_components = [
{
"reference_designator": "U1",
"part_type": "io",
"solder_ball_properties": {"shape": "cylinder", "diameter": "300um", "height": "300um"},
"port_properties": {
"reference_offset": "0",
"reference_size_auto": True,
"reference_size_x": 0,
"reference_size_y": 0,
},
}
]

# Edit via padstack definition. Add backdrilling.

cfg_padstacks = {
"definitions": [
{
"name": "v40h15-2",
"material": "copper",
"hole_range": "upper_pad_to_lower_pad",
"hole_parameters": {"shape": "circle", "diameter": "0.2mm"},
},
{
"name": "v35h15-1",
"material": "copper",
"hole_range": "upper_pad_to_lower_pad",
"hole_parameters": {"shape": "circle", "diameter": "0.25mm"},
},
],
"instances": [
{
"name": "Via313",
"backdrill_parameters": {
"from_bottom": {"drill_to_layer": "Inner3", "diameter": "1mm", "stub_length": "0.2mm"}
},
},
{
"name": "Via314",
"backdrill_parameters": {
"from_bottom": {"drill_to_layer": "Inner3", "diameter": "1mm", "stub_length": "0.2mm"}
},
},
],
}

# Define ports.

cfg_ports = [
{
"name": "port_1",
"reference_designator": "U1",
"type": "coax",
"positive_terminal": {"net": "PCIe_Gen4_TX2_CAP_P"},
},
{
"name": "port_2",
"reference_designator": "U1",
"type": "coax",
"positive_terminal": {"net": "PCIe_Gen4_TX2_CAP_N"},
},
{
"name": "port_3",
"reference_designator": "X1",
"type": "circuit",
"positive_terminal": {"pin": "B8"},
"negative_terminal": {"pin": "B7"},
},
{
"name": "port_4",
"reference_designator": "X1",
"type": "circuit",
"positive_terminal": {"pin": "B9"},
"negative_terminal": {"pin": "B10"},
},
]

# Define S-parameter assignment

cfg_s_parameters = [
{
"name": "cap_10nf",
"file_path": "$PROJECTDIR\\touchstone\\GRM32_DC0V_25degC_series.s2p",
"component_definition": "CAPC1005X55X25LL05T10",
"components": ["C375", "C376"],
"reference_net": "GND",
}
]

# Define SIwave setup.

cfg_setups = [
{
"name": "siwave_setup",
"type": "siwave_ac",
"si_slider_position": 1,
"freq_sweep": [
{
"name": "Sweep1",
"type": "interpolation",
"frequencies": [
{"distribution": "linear_scale", "start": "50MHz", "stop": "20GHz", "increment": "50MHz"}
],
}
],
}
]

# Define cutout.

cfg_operations = {
"cutout": {
"signal_list": ["PCIe_Gen4_TX2_CAP_P", "PCIe_Gen4_TX2_CAP_N", "PCIe_Gen4_TX2_P", "PCIe_Gen4_TX2_N"],
"reference_list": ["GND"],
"custom_extent": [
[0.014, 0.055],
[0.03674271504652968, 0.05493094625752912],
[0.07, 0.039],
[0.07, 0.034],
[0.05609890516829415, 0.03395233061637539],
[0.014, 0.044],
],
}
}

# Create final configuration.

cfg = {
"general": cfg_general,
"stackup": cfg_stackup,
"components": cfg_components,
"padstacks": cfg_padstacks,
"ports": cfg_ports,
"s_parameters": cfg_s_parameters,
"setups": cfg_setups,
"operations": cfg_operations,
}

# Create the config file.

file_json = os.path.join(temp_folder.name, "edb_configuration.json")
with open(file_json, "w") as f:
json.dump(cfg, f, indent=4, ensure_ascii=False)

# ## Apply Config file

# Apply configuration to the example layout

edbapp.configuration.load(config_file=file_json)
edbapp.configuration.run()

edbapp.nets.plot(nets=[])

# Save and close EDB.

edbapp.save()
edbapp.close()

# The configured EDB file is saved in a temp folder.

print(temp_folder.name)

# ## Load edb into HFSS 3D Layout.

h3d = Hfss3dLayout(edbapp.edbpath, version=AEDT_VERSION, non_graphical=NG_MODE, new_desktop=True)

# Create differential pair definition.

h3d.set_differential_pair(
differential_mode="DIFF_BGA",
assignment="port_1",
reference="port_2",
)

h3d.set_differential_pair(
differential_mode="DIFF_CONN",
assignment="port_3",
reference="port_4",
)

# Solve.

h3d.analyze(setup="siwave_setup")

# Plot insertion loss.

solutions = h3d.post.get_solution_data(expressions="mag(S(DIFF_CONN,DIFF_BGA))", context="Differential Pairs")
solutions.plot(formula="db20")

# Shut Down Electronics Desktop

h3d.close_desktop()

# All project files are saved in the folder ``temp_file.dir``. If you've run this example as a Jupyter notebook you
# can retrieve those project files.
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ dependencies = [
"pywin32 >= 303;platform_system=='Windows'",
"ansys-pythonnet >= 3.1.0rc3",
"dotnetcore2 ==3.1.23;platform_system=='Linux'",
"numpy>=1.20.0,<2",
"numpy>=1.20.0,<3",
"pandas>=1.1.0,<2.3",
"pydantic>=2.6.4,<2.10",
"Rtree >= 1.2.0",
Expand All @@ -50,7 +50,7 @@ doc = [
"ansys-sphinx-theme>=0.10.0,<1.1",
"imageio>=2.30.0,<2.37",
"ipython>=8.13.0,<8.30",
"jupyterlab>=4.0.0,<4.3",
"jupyterlab>=4.0.0,<4.4",
"jupytext>=1.16.0,<1.17",
"matplotlib>=3.5.0,<3.10",
"nbsphinx>=0.9.0,<0.10",
Expand Down
4 changes: 3 additions & 1 deletion src/pyedb/configuration/cfg_padstacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ def apply(self):

def retrieve_parameters_from_edb(self):
self.clean()
for _, obj in self._pedb.padstacks.definitions.items():
for name, obj in self._pedb.padstacks.definitions.items():
if name.lower() == "symbol":
continue
pdef = CfgPadstackDefinition(self._pedb, obj)
pdef.retrieve_parameters_from_edb()
self.definitions.append(pdef)
Expand Down
2 changes: 1 addition & 1 deletion src/pyedb/configuration/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ def export(
self,
file_path,
stackup=True,
package_definitions=True,
package_definitions=False,
setups=True,
sources=True,
ports=True,
Expand Down
44 changes: 43 additions & 1 deletion src/pyedb/dotnet/edb.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@
SiwaveDCSimulationSetup,
SiwaveSimulationSetup,
)
from pyedb.generic.constants import AEDT_UNITS, SolverType
from pyedb.generic.constants import AEDT_UNITS, SolverType, unit_converter
from pyedb.generic.general_methods import (
generate_unique_name,
get_string_version,
Expand Down Expand Up @@ -4598,3 +4598,45 @@ def definitions(self):
def workflow(self):
"""Workflow class."""
return Workflow(self)

def export_gds_comp_xml(self, comps_to_export, gds_comps_unit="mm", control_path=None):
"""Exports an XML file with selected components information for use in a GDS import.
Parameters
----------
comps_to_export : list
List of components whose information will be exported to xml file.
gds_comps_unit : str, optional
GDS_COMPONENTS section units. Default is ``"mm"``.
control_path : str, optional
Path for outputting the XML file.
Returns
-------
bool
``True`` when successful, ``False`` when failed.
"""
from pyedb.generic.general_methods import ET

components = ET.Element("GDS_COMPONENTS")
components.set("LengthUnit", gds_comps_unit)
if not comps_to_export:
comps_to_export = self.components.components
for comp in comps_to_export:
ocomp = self.components.components[comp]
gds_component = ET.SubElement(components, "GDS_COMPONENT")
for pin_name, pin in ocomp.pins.items():
pins_position_unit = unit_converter(pin.position, output_units=gds_comps_unit)
gds_pin = ET.SubElement(gds_component, "GDS_PIN")
gds_pin.set("Name", pin_name)
gds_pin.set("x", str(pins_position_unit[0]))
gds_pin.set("y", str(pins_position_unit[1]))
gds_pin.set("Layer", pin.placement_layer)
component = ET.SubElement(gds_component, "Component")
component.set("RefDes", ocomp.refdes)
component.set("PartName", ocomp.partname)
component.set("PartType", ocomp.type)
tree = ET.ElementTree(components)
ET.indent(tree, space="\t", level=0)
tree.write(control_path)
return True if os.path.exists(control_path) else False
Loading

0 comments on commit 0992e4f

Please sign in to comment.