Skip to content

FEAT: EDB Config - export component properties #810

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

Merged
merged 9 commits into from
Sep 24, 2024
118 changes: 44 additions & 74 deletions src/pyedb/configuration/cfg_boundaries.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,97 +20,50 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

from enum import Enum
from pyedb.configuration.cfg_common import CfgBase


class CfgBoundaries:
def __init__(self, pdata, boundaries_dict):
self._pedb = pdata._pedb
self._boundaries_dict = boundaries_dict
self.open_region = self._boundaries_dict.get("open_region", None)
self._map_open_region_type()
self.pml_visible = self._boundaries_dict.get("pml_visible", None)
self.pml_operation_frequency = self._boundaries_dict.get("pml_operation_frequency", None)
self.pml_radiation_factor = self._boundaries_dict.get("pml_radiation_factor", None)
self._map_dielectric_extend_type()
self.dielectric_base_polygon = self._boundaries_dict.get("dielectric_base_polygon", None)
self.horizontal_padding = self._boundaries_dict.get("horizontal_padding", None)
self.honor_primitives_on_dielectric_layers = self._boundaries_dict.get(
"honor_primitives_on_dielectric_layers", False
)
self._map_air_box_extend_type()
self.air_box_base_polygon = self._boundaries_dict.get("air_box_base_polygon", None)
self.air_box_truncate_model_ground_layers = self._boundaries_dict.get(
"air_box_truncate_model_ground_layers", None
)
self.air_box_horizontal_padding = self._boundaries_dict.get("air_box_horizontal_padding", None)
self.air_box_positive_vertical_padding = self._boundaries_dict.get("air_box_positive_vertical_padding", None)
self.air_box_negative_vertical_padding = self._boundaries_dict.get("air_box_negative_vertical_padding", None)

def _map_air_box_extend_type(self):
air_box_type = self._boundaries_dict.get("air_box_extents_type", None)
if air_box_type == "bounding_box":
self.air_box_extents_type = self.ExtentType.BOUNDING_BOX
elif air_box_type == "conformal":
self.air_box_extents_type = self.ExtentType.CONFORMAL
elif air_box_type == "convex_hull":
self.air_box_extents_type = self.ExtentType.CONVEX_HULL
elif air_box_type == "polygon":
self.air_box_extents_type = self.ExtentType.POLYGON
else:
self.air_box_extents_type = self.ExtentType.BOUNDING_BOX

def _map_open_region_type(self):
open_region = self._boundaries_dict.get("open_region_type", None)
if open_region == "radiation":
self.open_region_type = self.OpenRegionType.RADIATION
elif open_region == "pec":
self.open_region_type = self.OpenRegionType.PEC
else:
self.open_region_type = self.OpenRegionType.RADIATION

def _map_dielectric_extend_type(self):
extend_type = self._boundaries_dict.get("dielectric_extents_type", None)
if extend_type == "bounding_box":
self.dielectric_extents_type = self.ExtentType.BOUNDING_BOX
elif extend_type == "conformal":
self.dielectric_extents_type = self.ExtentType.CONFORMAL
elif extend_type == "convex_hull":
self.dielectric_extents_type = self.ExtentType.CONVEX_HULL
elif extend_type == "polygon":
self.dielectric_extents_type = self.ExtentType.POLYGON
else:
self.dielectric_extents_type = self.ExtentType.BOUNDING_BOX

class OpenRegionType(Enum):
RADIATION = 0
PEC = 1

class ExtentType(Enum):
BOUNDING_BOX = 0
CONFORMAL = 1
CONVEX_HULL = 2
POLYGON = 3
class CfgBoundaries(CfgBase):
def __init__(self, pedb, boundary_data):
self._pedb = pedb
self.open_region = boundary_data.get("open_region", None)
self.open_region_type = boundary_data.get("map_open_region_type", None)
self.pml_visible = boundary_data.get("pml_visible", None)
self.pml_operation_frequency = boundary_data.get("pml_operation_frequency", None)
self.pml_radiation_factor = boundary_data.get("pml_radiation_factor", None)
self.dielectric_extent_type = boundary_data.get("dielectric_extent_type", None)
# self.dielectric_base_polygon = self.**kwargs.get("dielectric_base_polygon", None)
self.horizontal_padding = boundary_data.get("horizontal_padding", None)
self.honor_primitives_on_dielectric_layers = boundary_data.get("honor_primitives_on_dielectric_layers", False)
self.air_box_extent_type = boundary_data.get("air_box_extent_type", None)
self.air_box_base_polygon = boundary_data.get("air_box_base_polygon", None)
self.air_box_truncate_model_ground_layers = boundary_data.get("air_box_truncate_model_ground_layers", None)
self.air_box_horizontal_padding = boundary_data.get("air_box_horizontal_padding", None)
self.air_box_positive_vertical_padding = boundary_data.get("air_box_positive_vertical_padding", None)
self.air_box_negative_vertical_padding = boundary_data.get("air_box_negative_vertical_padding", None)

def apply(self):
"""Imports boundary information from JSON."""
if self.open_region is not None:
self._pedb.hfss.hfss_extent_info.use_open_region = self.open_region
self._pedb.hfss.hfss_extent_info.open_region_type = self.open_region_type.name.lower()
if self.open_region_type:
self._pedb.hfss.hfss_extent_info.open_region_type = self.open_region_type.lower()
if self.pml_visible is not None:
self._pedb.hfss.hfss_extent_info.is_pml_visible = self.pml_visible
if self.pml_operation_frequency:
self._pedb.hfss.hfss_extent_info.operating_freq = self.pml_operation_frequency
if self.pml_radiation_factor:
self._pedb.hfss.hfss_extent_info.radiation_level = self.pml_radiation_factor
self._pedb.hfss.hfss_extent_info.extent_type = self.dielectric_extents_type.name.lower()
if self.dielectric_base_polygon:
self._pedb.hfss.hfss_extent_info.dielectric_base_polygon = self.dielectric_base_polygon
if self.dielectric_extent_type:
self._pedb.hfss.hfss_extent_info.extent_type = self.dielectric_extent_type.lower()
# if self.dielectric_base_polygon:
# self._pedb.hfss.hfss_extent_info.dielectric_base_polygon = self.dielectric_base_polygon
if self.horizontal_padding:
self._pedb.hfss.hfss_extent_info.dielectric_extent_size = float(self.horizontal_padding)
if self.honor_primitives_on_dielectric_layers is not None:
self._pedb.hfss.hfss_extent_info.honor_user_dielectric = self.honor_primitives_on_dielectric_layers
self._pedb.hfss.hfss_extent_info.extent_type = self.air_box_extents_type.name.lower()
if self.air_box_extent_type:
self._pedb.hfss.hfss_extent_info.extent_type = self.air_box_extent_type.lower()
if self.air_box_truncate_model_ground_layers is not None:
self._pedb.hfss.hfss_extent_info.truncate_air_box_at_ground = self.air_box_truncate_model_ground_layers
if self.air_box_horizontal_padding:
Expand All @@ -123,3 +76,20 @@ def apply(self):
self._pedb.hfss.hfss_extent_info.air_box_negative_vertical_extent = float(
self.air_box_negative_vertical_padding
)

def get_data_from_db(self):
self.open_region = self._pedb.hfss.hfss_extent_info.use_open_region
self.open_region_type = self._pedb.hfss.hfss_extent_info.open_region_type
self.pml_visible = self._pedb.hfss.hfss_extent_info.is_pml_visible
self.pml_operation_frequency = self._pedb.hfss.hfss_extent_info.operating_freq.tostring
self.pml_radiation_factor = self._pedb.hfss.hfss_extent_info.radiation_level.tostring
self.dielectric_extent_type = self._pedb.hfss.hfss_extent_info.extent_type
# self.dielectric_base_polygon = self._pedb.hfss.hfss_extent_info.dielectric_base_polygon
self.horizontal_padding = self._pedb.hfss.hfss_extent_info.dielectric_extent_size
self.honor_primitives_on_dielectric_layers = self._pedb.hfss.hfss_extent_info.honor_user_dielectric
self.air_box_extent_type = self._pedb.hfss.hfss_extent_info.extent_type
self.air_box_truncate_model_ground_layers = self._pedb.hfss.hfss_extent_info.truncate_air_box_at_ground
self.air_box_horizontal_padding = self._pedb.hfss.hfss_extent_info.air_box_horizontal_extent
self.air_box_positive_vertical_padding = self._pedb.hfss.hfss_extent_info.air_box_positive_vertical_extent
self.air_box_negative_vertical_padding = self._pedb.hfss.hfss_extent_info.air_box_negative_vertical_extent
return self.get_attributes()
2 changes: 1 addition & 1 deletion src/pyedb/configuration/cfg_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def get_attributes(self, exclude=None):
exclude = exclude if isinstance(exclude, list) else [exclude]
attrs = {i: j for i, j in attrs.items() if i not in exclude}
attrs = {i: j for i, j in attrs.items() if not i.startswith("_")}
attrs = {i: j for i, j in attrs.items() if j is not None}
attrs = {i: j for i, j in attrs.items() if j not in [None, [], {}]}
return attrs

def set_attributes(self, pedb_object):
Expand Down
104 changes: 29 additions & 75 deletions src/pyedb/configuration/cfg_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,6 @@
from pyedb.configuration.cfg_common import CfgBase


class CfgPortProperties(CfgBase):
def __init__(self, **kwargs):
self.reference_offset = kwargs.pop("reference_offset", 0)
self.reference_size_auto = kwargs.pop("reference_size_auto", 0)
self.reference_size_x = kwargs.pop("reference_size_x", 0)
self.reference_size_y = kwargs.pop("reference_size_y", 0)


class CfgSolderBallsProperties(CfgBase):
def __init__(self, **kwargs):
self.shape = kwargs.pop("shape", None)
self.diameter = kwargs.pop("diameter", None)
self.mid_diameter = kwargs.pop("mid_diameter", None)
self.height = kwargs.pop("height", None)
self.enabled = kwargs.pop("enabled", None)


class CfgRlcModel(CfgBase):
def __init__(self, **kwargs):
self.resistance = kwargs.get("resistance", None)
Expand All @@ -51,42 +34,17 @@ def __init__(self, **kwargs):


class CfgComponent(CfgBase):
protected_attributes = ["reference_designator", "definition", "location", "angle", "placement_layer"]

def __init__(self, **kwargs):
self.enabled = kwargs.get("enabled", None)

self.reference_designator = kwargs.get("reference_designator", None)
self.definition = kwargs.get("definition", None)
self.type = kwargs.get("part_type", None)
self.port_properties = CfgPortProperties(**kwargs["port_properties"]) if "port_properties" in kwargs else None
self.solder_ball_properties = (
CfgSolderBallsProperties(**kwargs["solder_ball_properties"]) if "solder_ball_properties" in kwargs else None
)
self.type = kwargs["part_type"].lower() if kwargs.get("part_type") else None
self.port_properties = kwargs.get("port_properties", {})
self.solder_ball_properties = kwargs.get("solder_ball_properties", {})
self.ic_die_properties = kwargs.get("ic_die_properties", {})
self.pin_pair_model = kwargs.get("pin_pair_model", None)

self.x_location, self.y_location = kwargs.get("location", [None, None])
self.angle = kwargs.get("angle", None)
self.placement_layer = kwargs.get("placement_layer", None)

def export_properties(self):
"""Export component properties.

Returns
-------
Dict
"""
data_comp = {}
data_comp["enabled"] = self.enabled
data_comp["reference_designator"] = self.reference_designator
data_comp["definition"] = self.definition
data_comp["type"] = self.type
data_comp["pin_pair_model"] = self.pin_pair_model
data_comp["x_location"] = self.x_location
data_comp["y_location"] = self.y_location
# data_comp["angle"] = self.angle
data_comp["placement_layer"] = self.placement_layer
return data_comp
self.spice_model = kwargs.get("spice_model", None)
self.s_parameter_model = kwargs.get("s_parameter_model", None)


class CfgComponents:
Expand All @@ -98,31 +56,22 @@ def apply(self):
comps_in_db = self._pedb.components
for comp in self.components:
c_db = comps_in_db[comp.reference_designator]

for attr, value in comp.get_attributes().items(): # All component properties
if attr == "solder_ball_properties":
solder_ball_properties = value
port_properties = comp.port_properties
self._pedb.components.set_solder_ball(
component=comp.reference_designator,
sball_diam=solder_ball_properties.diameter,
sball_mid_diam=solder_ball_properties.mid_diameter,
sball_height=solder_ball_properties.height,
shape=solder_ball_properties.shape,
auto_reference_size=port_properties.reference_size_auto,
reference_height=port_properties.reference_offset,
reference_size_x=port_properties.reference_size_x,
reference_size_y=port_properties.reference_size_y,
)
elif attr == "port_properties":
pass
elif attr == "pin_pair_model":
c_db.set_model_properties(pin_pair_model=comp.pin_pair_model)
else:
if attr in dir(c_db):
setattr(c_db, attr, value)
else:
raise AttributeError(f"'{attr}' is not valid component attribute.")
if comp.definition:
c_db.definition = comp.definition
if comp.type:
c_db.type = comp.type
if comp.solder_ball_properties:
c_db.solder_ball_properties = comp.solder_ball_properties
if comp.port_properties:
c_db.port_properties = comp.port_properties
if comp.ic_die_properties:
c_db.set_ic_die_properties = comp.ic_die_properties
if comp.pin_pair_model:
c_db.model_properties = {"pin_pair_model": comp.pin_pair_model}
if comp.spice_model:
c_db.model_properties = {"spice_model": comp.spice_model}
if comp.s_parameter_model:
c_db.model_properties = {"s_parameter_model": comp.s_parameter_model}

def _load_data_from_db(self):
self.components = []
Expand All @@ -132,16 +81,21 @@ def _load_data_from_db(self):
enabled=comp.enabled,
reference_designator=comp.name,
part_type=comp.type,
pin_pair_model=comp.get_model_properties().get("pin_pair_model"),
pin_pair_model=comp.model_properties.get("pin_pair_model"),
spice_model=comp.model_properties.get("spice_model"),
s_parameter_model=comp.model_properties.get("s_parameter_model"),
definition=comp.component_def,
location=comp.location,
placement_layer=comp.placement_layer,
solder_ball_properties=comp.solder_ball_properties,
ic_die_properties=comp.ic_die_properties,
port_properties=comp.port_properties,
)
self.components.append(cfg_comp)

def get_data_from_db(self):
self._load_data_from_db()
data = []
for comp in self.components:
data.append(comp.export_properties())
data.append(comp.get_attributes())
return data
4 changes: 1 addition & 3 deletions src/pyedb/configuration/cfg_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,7 @@ def __init__(self, pedb, **kwargs):
self._pedb = pedb
self.general = CfgGeneral(self, kwargs.get("general", None))

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

self.nets = CfgNets(
self, kwargs.get("nets", {}).get("signal_nets", []), kwargs.get("nets", {}).get("power_ground_nets", [])
Expand Down
24 changes: 14 additions & 10 deletions src/pyedb/configuration/cfg_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,20 @@ def __init__(self, pedb, **kwargs):

def get_data_from_db(self):
if "pyedb_cutout" in self._pedb.stackup.all_layers:
poly = self._pedb.layout.find_primitive(layer_name="pyedb_cutout")[0]
self.custom_extent = poly.polygon_data.points
polygons = self._pedb.layout.find_primitive(layer_name="pyedb_cutout")
if polygons:
poly = polygons[0]
self.custom_extent = poly.polygon_data.points

net_names = []
for name, obj in self._pedb.nets.nets.items():
if obj.primitives[0].layer.name == "pyedb_cutout":
continue
if len(obj.primitives) > 0:
net_names.append(name)
net_names = []
for name, obj in self._pedb.nets.nets.items():
if obj.primitives[0].layer.name == "pyedb_cutout":
continue
if len(obj.primitives) > 0:
net_names.append(name)

self.reference_list = []
self.signal_list = net_names
self.reference_list = []
self.signal_list = net_names
return self.export_properties()

def export_properties(self):
Expand Down Expand Up @@ -95,3 +97,5 @@ def get_data_from_db(self):
data_from_db = self.op_cutout.get_data_from_db()
if data_from_db:
return {"cutout": data_from_db}
else:
return {}
6 changes: 4 additions & 2 deletions src/pyedb/configuration/cfg_ports_sources.py
Original file line number Diff line number Diff line change
Expand Up @@ -337,13 +337,15 @@ def create(self):
return circuit_elements

def export_properties(self):
return {
data = {
"name": self.name,
"type": self.type,
"reference_designator": self.reference_designator,
"positive_terminal": self.positive_terminal_info.export_properties(),
"negative_terminal": self.negative_terminal_info.export_properties(),
}
if self.negative_terminal_info:
data.update({"negative_terminal": self.negative_terminal_info.export_properties()})
return data


class CfgSource(CfgCircuitElement):
Expand Down
Loading
Loading