Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FIX: stackup load #527

Merged
merged 8 commits into from
May 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions src/pyedb/configuration/cfg_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,30 +39,42 @@ def __init__(self, pedb, **kwargs):
self.pedb = pedb
self.edb_comps = self.pedb.components.components
self.general = CfgGeneral(self, kwargs.get("general", None))

self.boundaries = {}
if kwargs.get("boundaries", None):
self.boundaries = CfgBoundaries(self, kwargs.get("boundaries", None))
self.nets = CfgNets(self)

self.nets = None
if kwargs.get("nets"):
self.nets = CfgNets(
self, kwargs.get("nets", {}).get("signal_nets", []), kwargs.get("nets", {}).get("power_ground_nets", [])
)

self.components = [CfgComponent(self, **component) for component in kwargs.get("components", [])]

self.padstacks = CfgPadstacks(self, kwargs.get("padstacks", None))

self.pin_groups = [CfgPinGroup(self, pin_group) for pin_group in kwargs.get("pin_groups", [])]

self.ports = [CfgPort(self, **port) for port in kwargs.get("ports", [])]

self.sources = [CfgSources(self, **source) for source in kwargs.get("sources", [])]
self.setups = [CfgSetup(self)]

self.setups = []
if kwargs.get("setups", None):
self.setups = [CfgSetup(self, setup) for setup in kwargs.get("setups", [])]

self.stackup = None

self.s_parameters = [
CfgSParameterModel(self, self.general.s_parameter_library, sparam_model)
for sparam_model in kwargs.get("s_parameters", [])
]

self.spice_models = [
CfgSpiceModel(self, self.general.spice_model_library, spice_model)
for spice_model in kwargs.get("spice_models", [])
]

self.package_definition = None
self.operations = None
59 changes: 23 additions & 36 deletions src/pyedb/configuration/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@

from pyedb.configuration.cfg_data import CfgData
from pyedb.dotnet.edb_core.definition.package_def import PackageDef
from pyedb.dotnet.edb_core.stackup import LayerCollection
from pyedb.generic.general_methods import pyedb_function_handler


Expand Down Expand Up @@ -182,56 +181,44 @@ def _load_stackup(self):
layers = data.get("layers")

if layers:
lc = self._pedb.stackup
input_signal_layers = [i for i in layers if i["type"].lower() == "signal"]
if not len(input_signal_layers) == len(lc.signal_layers):
if not len(input_signal_layers) == len(self._pedb.stackup.signal_layers):
self._pedb.logger.error("Input signal layer count do not match.")
return False

layer_clones = []
doc_layer_clones = []
for name, obj in lc.layers.items():
if obj.is_stackup_layer:
if obj.type == "signal": # keep signal layers
layer_clones.append(obj)
else:
doc_layer_clones.append(obj)

lc_new = LayerCollection(self._pedb)
lc_new.auto_refresh = False
signal_layer_ids = {}
top_layer_clone = None

# add all signal layers
removal_list = []
lc_signal_layers = []
for name, obj in self._pedb.stackup.all_layers.items():
if obj.type == "dielectric":
removal_list.append(name)
elif obj.type == "signal":
lc_signal_layers.append(obj.id)
for l in removal_list:
self._pedb.stackup.remove_layer(l)

# update all signal layers
id_name = {i[0]: i[1] for i in self._pedb.stackup.layers_by_id}
signal_idx = 0
for l in layers:
if l["type"] == "signal":
clone = layer_clones.pop(0)
clone.update(**l)
lc_new.add_layer_bottom(name=clone.name, layer_clone=clone)
signal_layer_ids[clone.name] = clone.id

# add all document layers at bottom
for l in doc_layer_clones:
doc_layer = lc_new.add_document_layer(name=l.name, layer_clone=l)
first_doc_layer_name = doc_layer.name
layer_id = lc_signal_layers[signal_idx]
layer_name = id_name[layer_id]
self._pedb.stackup.layers[layer_name].update(**l)
signal_idx = signal_idx + 1

# add all dielectric layers. Dielectric layers must be added last. Otherwise,
# dielectric layer will occupy signal and document layer id.
prev_layer_clone = None
l = layers.pop(0)
if l["type"] == "signal":
prev_layer_clone = lc_new.layers[l["name"]]
prev_layer_clone = self._pedb.stackup.layers[l["name"]]
else:
prev_layer_clone = lc_new.add_layer_top(**l)
prev_layer_clone = self._pedb.stackup.add_layer_top(**l)
for idx, l in enumerate(layers):
if l["type"] == "dielectric":
prev_layer_clone = lc_new.add_layer_below(base_layer_name=prev_layer_clone.name, **l)
else:
prev_layer_clone = lc_new.layers[l["name"]]

lc._edb_object = lc_new._edb_object
lc_new.auto_refresh = True
lc.update_layout()
prev_layer_clone = self._pedb.stackup.add_layer_below(base_layer_name=prev_layer_clone.name, **l)
elif l["type"] == "signal":
prev_layer_clone = self._pedb.stackup.layers[l["name"]]

@pyedb_function_handler
def _load_operations(self):
Expand Down
4 changes: 1 addition & 3 deletions src/pyedb/dotnet/edb.py
Original file line number Diff line number Diff line change
Expand Up @@ -846,9 +846,7 @@ def stackup(self):
>>> edbapp.stackup.layers["TOP"].thickness == 4e-05
>>> edbapp.stackup.add_layer("Diel", "GND", layer_type="dielectric", thickness="0.1mm", material="FR4_epoxy")
"""
if not self._stackup2 and self.active_db:
self._stackup2 = Stackup(self, self.layout.layer_collection)
return self._stackup2
return Stackup(self, self.layout.layer_collection)

@property
def materials(self):
Expand Down
4 changes: 2 additions & 2 deletions src/pyedb/dotnet/edb_core/edb_data/layer_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,8 +257,8 @@ def __init__(self, pedb, edb_object=None, name="", layer_type="signal", **kwargs
self._lower_elevation = 0.0

def _create(self, layer_type):
layer_type = self._layer_name_mapping[layer_type]
layer_type = self._layer_type_mapping[layer_type]
layer_type_edb_name = self._layer_name_mapping[layer_type]
layer_type = self._layer_type_mapping[layer_type_edb_name]
self._edb_object = self._pedb.edb_api.cell._cell.StackupLayer(
self._name,
layer_type,
Expand Down
101 changes: 40 additions & 61 deletions src/pyedb/dotnet/edb_core/stackup.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,6 @@


class LayerCollection(object):
auto_refresh = True

def __init__(self, pedb, edb_object=None):
self._pedb = pedb

Expand All @@ -91,17 +89,21 @@ def __init__(self, pedb, edb_object=None):
"multizone": self._pedb.edb_api.cell._cell.LayerCollectionMode.MultiZone,
}

def update_layout(self, stackup=None):
def update_layout(self):
"""Set layer collection into edb.

Parameters
----------
stackup
"""
if stackup:
self._edb_object = stackup._edb_object
self._pedb.layout.layer_collection = self._edb_object

@pyedb_function_handler()
def refresh_layer_collection(self):
"""Refresh layer collection from Edb. This method is run on demand after all edit operations on stackup."""
self._edb_object = self._pedb.edb_api.cell._cell.LayerCollection(self._pedb.layout.layer_collection)
self._lc = self._edb_object

@pyedb_function_handler
def _add_layer(self, add_method, base_layer_name="", **kwargs):
"""Add a layer to edb.
Expand All @@ -115,7 +117,13 @@ def _add_layer(self, add_method, base_layer_name="", **kwargs):
if layer_clone:
obj = layer_clone
else:
obj = StackupLayerEdbClass(self._pedb, edb_object=None, **kwargs)
layer_type = kwargs.get("layer_type", None)
if not layer_type:
layer_type = kwargs["type"]
if layer_type in ["signal", "dielectric"]:
obj = StackupLayerEdbClass(self._pedb, edb_object=None, **kwargs)
else:
obj = LayerEdbClass(self._pedb, edb_object=None, **kwargs)
method_top_bottom = None
method_above_below = None
if add_method == "add_layer_top":
Expand All @@ -134,8 +142,7 @@ def _add_layer(self, add_method, base_layer_name="", **kwargs):
obj = obj if method_top_bottom(obj._edb_object) else False
elif method_above_below:
obj = obj if method_above_below(obj._edb_object, base_layer_name) else False
if self.auto_refresh:
self.update_layout()
self.update_layout()
return obj

@pyedb_function_handler
Expand Down Expand Up @@ -268,8 +275,7 @@ def set_layer_clone(self, layer_clone):
lc.AddLayerBottom(i._edb_object)

self._edb_object = lc
if self.auto_refresh:
self.update_layout()
self.update_layout()

if not obj:
logger.info("Layer clone was not found in stackup or non stackup layers.")
Expand All @@ -278,33 +284,32 @@ def set_layer_clone(self, layer_clone):
@property
def stackup_layers(self):
"""Retrieve the dictionary of signal and dielectric layers."""
temp = list(self._edb_object.Layers((self._pedb.edb_api.cell.layer_type_set.StackupLayerSet)))
layers = OrderedDict()
for i in temp:
name = i.GetName()
layers[name] = StackupLayerEdbClass(self._pedb, i.Clone(), name=name)
return layers
warnings.warn("Use new property :func:`layers` instead.", DeprecationWarning)
return self.layers

@property
def non_stackup_layers(self):
"""Retrieve the dictionary of signal layers."""
temp = list(self._edb_object.Layers(self._layer_type_set_mapping["non_stackup_layer_set"]))
layers = OrderedDict()
for i in temp:
name = i.GetName()
layers[name] = LayerEdbClass(self._pedb, i, name=name)
return layers
return {name: obj for name, obj in self.all_layers.items() if not obj.is_stackup_layer}

@property
def layers_by_id(self):
"""Retrieve the list of layers with their ids."""
layer_list = list(self._layer_collection.Layers(self._pedb.edb_api.cell.layer_type_set.AllLayerSet))
temp = []
def all_layers(self):
self.refresh_layer_collection()
layer_list = list(self._edb_object.Layers(self._pedb.edb_api.cell.layer_type_set.AllLayerSet))
temp = dict()
for i in layer_list:
obj = StackupLayerEdbClass(self._pedb, i.Clone(), name=i.GetName)
temp.append([obj.id, obj.name])
if i.IsStackupLayer():
obj = StackupLayerEdbClass(self._pedb, i.Clone(), name=i.GetName())
else:
obj = LayerEdbClass(self._pedb, i.Clone(), name=i.GetName())
temp[obj.name] = obj
return temp

@property
def layers_by_id(self):
"""Retrieve the list of layers with their ids."""
return [[obj.id, name] for name, obj in self.all_layers.items()]

@property
def layers(self):
"""Retrieve the dictionary of layers.
Expand All @@ -313,22 +318,14 @@ def layers(self):
-------
Dict[str, :class:`pyedb.dotnet.edb_core.edb_data.layer_data.LayerEdbClass`]
"""
_lays = OrderedDict()
layer_list = list(self._edb_object.Layers(self._pedb.edb_api.cell.layer_type_set.AllLayerSet))
for l in layer_list:
name = l.GetName()
if not l.IsStackupLayer():
_lays[name] = LayerEdbClass(self._pedb, l, name=name)
else:
_lays[name] = StackupLayerEdbClass(self._pedb, l, name=name)
return _lays
return {name: obj for name, obj in self.all_layers.items() if obj.is_stackup_layer}


class Stackup(LayerCollection):
"""Manages EDB methods for stackup accessible from `Edb.stackup` property."""

def __getitem__(self, item):
return self.layers[item]
return self.all_layers[item]

def __init__(self, pedb, edb_object=None):
super().__init__(pedb, edb_object)
Expand Down Expand Up @@ -576,12 +573,6 @@ def create_symmetric_stackup(
)
return True

@pyedb_function_handler()
def refresh_layer_collection(self):
"""Refresh layer collection from Edb. This method is run on demand after all edit operations on stackup."""
self._lc = self._pedb.edb_api.cell._cell.LayerCollection(self._pedb.layout.layer_collection)
self._edb_object = self._lc

@property
def _layer_collection(self):
"""Copy of EDB layer collection.
Expand All @@ -591,8 +582,7 @@ def _layer_collection(self):
:class:`Ansys.Ansoft.Edb.Cell.LayerCollection`
Collection of layers.
"""
if not self._lc:
self.refresh_layer_collection()
self.refresh_layer_collection()
return self._lc

@property
Expand Down Expand Up @@ -620,7 +610,7 @@ def mode(self, value):
self._layer_collection.SetMode(mode.Overlapping)
elif value == 2 or value == mode.MultiZone or value == "MultiZone":
self._layer_collection.SetMode(mode.MultiZone)
self._pedb.layout.layer_collection = self._layer_collection
self.update_layout()

@property
def stackup_mode(self):
Expand Down Expand Up @@ -744,9 +734,8 @@ def _set_layout_stackup(self, layer_clone, operation, base_layer=None, method=1)
_lc.AddStackupLayerAtElevation(layer_clone)
elif operation == "non_stackup":
_lc.AddLayerBottom(layer_clone)
if self.auto_refresh:
self._pedb.layout.layer_collection = _lc
self.refresh_layer_collection()
self._pedb.layout.layer_collection = _lc
self.refresh_layer_collection()
return True

@pyedb_function_handler()
Expand Down Expand Up @@ -814,17 +803,7 @@ def add_outline_layer(self, outline_name="Outline"):
bool
"True" if successful, ``False`` if failed.
"""
outlineLayer = self._pedb.edb_api.cell.layer.FindByName(self._pedb.layout.layer_collection, outline_name)
if outlineLayer.IsNull():
return self.add_layer(
outline_name,
layer_type="outline",
material="",
fillMaterial="",
thickness="",
)
else:
return False
return self.add_document_layer(name="Outline", layer_type="outline")

# TODO: Update optional argument material into material_name and fillMaterial into fill_material_name
@pyedb_function_handler()
Expand Down
Loading
Loading