From dcdcb64c23496352a05da9556ab08eb100bcc08f Mon Sep 17 00:00:00 2001 From: svandenb-dev <74993647+svandenb-dev@users.noreply.github.com> Date: Wed, 22 May 2024 16:48:27 +0200 Subject: [PATCH] component configfile tested added + refactoring (#501) --- src/pyedb/configuration/cfg_data.py | 6 +- .../configuration/cfg_s_parameter_models.py | 60 ++++++++++++ src/pyedb/configuration/configuration.py | 91 +------------------ tests/legacy/system/test_edb_config_json.py | 4 + 4 files changed, 71 insertions(+), 90 deletions(-) create mode 100644 src/pyedb/configuration/cfg_s_parameter_models.py diff --git a/src/pyedb/configuration/cfg_data.py b/src/pyedb/configuration/cfg_data.py index e540eda2e2..babcbaa011 100644 --- a/src/pyedb/configuration/cfg_data.py +++ b/src/pyedb/configuration/cfg_data.py @@ -27,6 +27,7 @@ from pyedb.configuration.cfg_padstacks import CfgPadstacks from pyedb.configuration.cfg_pin_groups import CfgPinGroup from pyedb.configuration.cfg_ports_sources import CfgPort, CfgSources +from pyedb.configuration.cfg_s_parameter_models import CfgSParameterModel from pyedb.configuration.cfg_setup import CfgSetup from pyedb.configuration.cfg_spice_models import CfgSpiceModel @@ -55,7 +56,10 @@ def __init__(self, pedb, **kwargs): if kwargs.get("setups", None): self.setups = [CfgSetup(self, setup) for setup in kwargs.get("setups", [])] self.stackup = None - self.s_parameters = 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", []) diff --git a/src/pyedb/configuration/cfg_s_parameter_models.py b/src/pyedb/configuration/cfg_s_parameter_models.py new file mode 100644 index 0000000000..c508a68490 --- /dev/null +++ b/src/pyedb/configuration/cfg_s_parameter_models.py @@ -0,0 +1,60 @@ +# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates. +# SPDX-License-Identifier: MIT +# +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from pathlib import Path + + +class CfgSParameterModel: + def __init__(self, pdata, path_lib, sparam_dict): + self._pedb = pdata.pedb + self.path_libraries = path_lib + self._sparam_dict = sparam_dict + self.name = self._sparam_dict.get("name", "") + self.component_definition = self._sparam_dict.get("component_definition", "") + self.file_path = self._sparam_dict.get("file_path", "") + self.apply_to_all = self._sparam_dict.get("apply_to_all", False) + self.components = self._sparam_dict.get("components", []) + self.reference_net = self._sparam_dict.get("reference_net", "") + self.reference_net_per_component = self._sparam_dict.get("reference_net_per_component", {}) + + def apply(self): + fpath = self.file_path + if not Path(fpath).anchor: + fpath = str(Path(self.path_libraries) / fpath) + comp_def = self._pedb.definitions.component[self.component_definition] + comp_def.add_n_port_model(fpath, self.name) + comp_list = dict() + if self.apply_to_all: + comp_list.update( + {refdes: comp for refdes, comp in comp_def.components.items() if refdes not in self.components} + ) + else: + comp_list.update( + {refdes: comp for refdes, comp in comp_def.components.items() if refdes in self.components} + ) + + for refdes, comp in comp_list.items(): + if refdes in self.reference_net_per_component: + ref_net = self.reference_net_per_component[refdes] + else: + ref_net = self.reference_net + comp.use_s_parameter_model(self.name, reference_net=ref_net) diff --git a/src/pyedb/configuration/configuration.py b/src/pyedb/configuration/configuration.py index 4404af9975..84a4484977 100644 --- a/src/pyedb/configuration/configuration.py +++ b/src/pyedb/configuration/configuration.py @@ -22,7 +22,6 @@ import json import os -from pathlib import Path import toml @@ -148,8 +147,8 @@ def run(self): self._load_stackup() # Configure S-parameter - if "s_parameters" in self.data: - self._load_s_parameter() + for s_parameter_model in self.cfg_data.s_parameters: + s_parameter_model.apply() # Configure SPICE models for spice_model in self.cfg_data.spice_models: @@ -165,62 +164,6 @@ def run(self): return True - @pyedb_function_handler - def _load_sources(self): - """Imports source information from json.""" - - for src in self.data["sources"]: - src_type = src["type"] - name = src["name"] - - positive_terminal_json = src["positive_terminal"] - if "pin_group" in positive_terminal_json: - pin_group = self._pedb.siwave.pin_groups[positive_terminal_json["pin_group"]] - pos_terminal = pin_group.get_terminal(pin_group.name, True) - else: - ref_designator = src["reference_designator"] - comp_layout = self._components[ref_designator] - - if "pin" in positive_terminal_json: - pin_name = positive_terminal_json["pin"] - src_name = name - pos_terminal = comp_layout.pins[pin_name].get_terminal(src_name, True) - elif "net" in positive_terminal_json: # Net - net_name = positive_terminal_json["net"] - src_name = "{}_{}".format(ref_designator, net_name) - pg_name = "pg_{}".format(src_name) - _, pg = self._pedb.siwave.create_pin_group_on_net(ref_designator, net_name, pg_name) - pos_terminal = pg.get_terminal(src_name, True) - - negative_terminal_json = src["negative_terminal"] - if "pin_group" in negative_terminal_json: - pin_group = self._pedb.siwave.pin_groups[negative_terminal_json["pin_group"]] - neg_terminal = pin_group.get_terminal(pin_group.name + "_ref", True) - else: - ref_designator = src["reference_designator"] - comp_layout = self._components[ref_designator] - if "pin" in negative_terminal_json: - pin_name = negative_terminal_json["pin"] - src_name = name + "_ref" - neg_terminal = comp_layout.pins[pin_name].get_terminal(src_name, True) - elif "net" in negative_terminal_json: - net_name = negative_terminal_json["net"] - src_name = name + "_ref" - pg_name = "pg_{}".format(src_name) - if pg_name not in self._pedb.siwave.pin_groups: - _, pg = self._pedb.siwave.create_pin_group_on_net(ref_designator, net_name, pg_name) - else: # pragma no cover - pg = self._pedb.siwave.pin_groups[pg_name] - neg_terminal = pg.get_terminal(src_name, True) - - if src_type == "voltage": - src_obj = self._pedb.create_voltage_source(pos_terminal, neg_terminal) - src_obj.magnitude = src["magnitude"] - elif src_type == "current": - src_obj = self._pedb.create_current_source(pos_terminal, neg_terminal) - src_obj.magnitude = src["magnitude"] - src_obj.name = name - @pyedb_function_handler def _load_stackup(self): """Imports stackup information from json.""" @@ -290,36 +233,6 @@ def _load_stackup(self): lc_new.auto_refresh = True lc.update_layout() - @pyedb_function_handler - def _load_s_parameter(self): - """Imports s-parameter information from json.""" - - for sp in self.data["s_parameters"]: - fpath = sp["file_path"] - if not Path(fpath).anchor: - fpath = str(Path(self._s_parameter_library) / fpath) - sp_name = sp["name"] - comp_def_name = sp["component_definition"] - comp_def = self._pedb.definitions.component[comp_def_name] - comp_def.add_n_port_model(fpath, sp_name) - comp_list = dict() - if sp["apply_to_all"]: - comp_list.update( - {refdes: comp for refdes, comp in comp_def.components.items() if refdes not in sp["components"]} - ) - else: - comp_list.update( - {refdes: comp for refdes, comp in comp_def.components.items() if refdes in sp["components"]} - ) - - for refdes, comp in comp_list.items(): - if "reference_net_per_component" in sp: - ref_net_per_comp = sp["reference_net_per_component"] - ref_net = ref_net_per_comp[refdes] if refdes in ref_net_per_comp else sp["reference_net"] - else: - ref_net = sp["reference_net"] - comp.use_s_parameter_model(sp_name, reference_net=ref_net) - @pyedb_function_handler def _load_operations(self): """Imports operation information from JSON.""" diff --git a/tests/legacy/system/test_edb_config_json.py b/tests/legacy/system/test_edb_config_json.py index afffef3aa1..aafa36dff3 100644 --- a/tests/legacy/system/test_edb_config_json.py +++ b/tests/legacy/system/test_edb_config_json.py @@ -196,6 +196,10 @@ def test_06_s_parameters(self): edbapp = Edb(str(self.local_edb), desktop_version) assert edbapp.configuration.load(data, apply_file=True) + assert len(edbapp.components.nport_comp_definition) == 2 + assert edbapp.components.nport_comp_definition["CAPC3216X180X55ML20T25"].reference_file + assert len(edbapp.components.nport_comp_definition["CAPC3216X180X55ML20T25"].components) == 9 + assert len(edbapp.components.nport_comp_definition["CAPC3216X190X55ML30T25"].components) == 12 edbapp.close() def test_07_boundaries(self):