diff --git a/_unittest/test_00_EDB.py b/_unittest/test_00_EDB.py index b3df33be11d..e1ea1b7ee2b 100644 --- a/_unittest/test_00_EDB.py +++ b/_unittest/test_00_EDB.py @@ -173,7 +173,7 @@ def test_003_create_coax_port_on_component(self): coax_port.radial_extent_factor = 3 assert coax_port.radial_extent_factor == 3 assert coax_port.component - assert self.edbapp.components["U6"].pins["R3"].terminal + assert self.edbapp.components["U6"].pins["R3"].get_terminal() assert self.edbapp.components["U6"].pins["R3"].id assert self.edbapp.terminals assert self.edbapp.ports @@ -494,6 +494,10 @@ def test_041_create_voltage_source(self): assert list(self.edbapp.sources.values())[0].magnitude == 3.3 list(self.edbapp.sources.values())[0].phase = 1 assert list(self.edbapp.sources.values())[0].phase == 1 + u6 = self.edbapp.components["U6"] + self.edbapp.create_voltage_source( + u6.pins["F2"].get_terminal(create_new_terminal=True), u6.pins["F1"].get_terminal(create_new_terminal=True) + ) def test_042_create_current_source(self): assert self.edbapp.siwave.create_current_source_on_net("U1", "USB3_D_N", "U1", "GND", 0.1, 0) != "" @@ -524,6 +528,10 @@ def test_042_create_current_source(self): ref_term.location = [0, 0] assert ref_term.layer ref_term.layer = "1_Top" + u6 = self.edbapp.components["U6"] + self.edbapp.create_current_source( + u6.pins["H8"].get_terminal(create_new_terminal=True), u6.pins["G9"].get_terminal(create_new_terminal=True) + ) def test_043_create_dc_terminal(self): assert self.edbapp.siwave.create_dc_terminal("U1", "DDR4_DQ40", "dc_terminal1") == "dc_terminal1" diff --git a/pyaedt/edb.py b/pyaedt/edb.py index 8e8f33f380b..7dc1d8b4e67 100644 --- a/pyaedt/edb.py +++ b/pyaedt/edb.py @@ -32,16 +32,10 @@ from pyaedt.edb_core.edb_data.siwave_simulation_setup_data import SiwaveDCSimulationSetup from pyaedt.edb_core.edb_data.siwave_simulation_setup_data import SiwaveSYZSimulationSetup from pyaedt.edb_core.edb_data.sources import SourceType -from pyaedt.edb_core.edb_data.terminals import BundleTerminal -from pyaedt.edb_core.edb_data.terminals import EdgeTerminal -from pyaedt.edb_core.edb_data.terminals import PadstackInstanceTerminal -from pyaedt.edb_core.edb_data.terminals import PinGroupTerminal from pyaedt.edb_core.edb_data.terminals import Terminal from pyaedt.edb_core.edb_data.variables import Variable -from pyaedt.edb_core.general import BoundaryType from pyaedt.edb_core.general import LayoutObjType from pyaedt.edb_core.general import Primitives -from pyaedt.edb_core.general import TerminalType from pyaedt.edb_core.general import convert_py_list_to_net_list from pyaedt.edb_core.hfss import EdbHfss from pyaedt.edb_core.ipc2581.ipc2581 import Ipc2581 @@ -357,18 +351,10 @@ def variables(self): def terminals(self): """Get terminals belonging to active layout.""" temp = {} + terminal_mapping = Terminal(self)._terminal_mapping for i in self.layout.terminals: terminal_type = i.ToString().split(".")[-1] - if terminal_type == TerminalType.EdgeTerminal.name: - ter = EdgeTerminal(self, i) - elif terminal_type == TerminalType.BundleTerminal.name: - ter = BundleTerminal(self, i) - elif terminal_type == TerminalType.PadstackInstanceTerminal.name: - ter = PadstackInstanceTerminal(self, i) - elif terminal_type == TerminalType.PinGroupTerminal.name: - ter = PinGroupTerminal(self, i) - else: - ter = Terminal(self, i) + ter = terminal_mapping[terminal_type](self, i) temp[ter.name] = ter return temp @@ -400,15 +386,18 @@ def ports(self): ports = {} for t in temp: t2 = Terminal(self, t) + if not t2.boundary_type == "PortBoundary": + continue + if t2.is_circuit_port: port = CircuitPort(self, t) ports[port.name] = port - elif t2.terminal_type == TerminalType.BundleTerminal.name: + elif t2.terminal_type == "BundleTerminal": port = BundleWavePort(self, t) ports[port.name] = port elif t2.hfss_type == "Wave": ports[t2.name] = WavePort(self, t) - elif t2.terminal_type == TerminalType.PadstackInstanceTerminal.name: + elif t2.terminal_type == "PadstackInstanceTerminal": ports[t2.name] = CoaxPort(self, t) else: ports[t2.name] = GapPort(self, t) @@ -432,7 +421,7 @@ def probes(self): """Get all layout sources.""" temp = {} for name, val in self.terminals.items(): - if val.boundary_type == BoundaryType.kVoltageProbe.name: + if val.boundary_type == "kVoltageProbe": if not val.is_reference_terminal: temp[name] = val return temp @@ -3640,7 +3629,7 @@ def _get_connected_ports_from_multizone_cutout(self, terminal_info_dict): @pyaedt_function_handler def create_port(self, terminal, ref_terminal=None, is_circuit_port=False): - """Create a port between two terminals. + """Create a port. Parameters ---------- @@ -3662,13 +3651,126 @@ def create_port(self, terminal, ref_terminal=None, is_circuit_port=False): ------- """ - if not ref_terminal: - port = CoaxPort(self, terminal._edb_object) - else: - if is_circuit_port: - port = CircuitPort(self, terminal._edb_object) - else: - port = GapPort(self, terminal._edb_object) - port.ref_terminal = ref_terminal - port.is_circuit_port = is_circuit_port - return port + + terminal.boundary_type = "PortBoundary" + terminal.is_circuit_port = is_circuit_port + + if ref_terminal: + ref_terminal.boundary_type = "PortBoundary" + terminal.ref_terminal = ref_terminal + + return self.ports[terminal.name] + + @pyaedt_function_handler + def create_voltage_probe(self, terminal, ref_terminal): + """Create a voltage probe. + + Parameters + ---------- + terminal : :class:`pyaedt.edb_core.edb_data.terminals.EdgeTerminal`, + :class:`pyaedt.edb_core.edb_data.terminals.PadstackInstanceTerminal`, + :class:`pyaedt.edb_core.edb_data.terminals.PointTerminal`, + :class:`pyaedt.edb_core.edb_data.terminals.PinGroupTerminal`, + Positive terminal of the port. + ref_terminal : :class:`pyaedt.edb_core.edb_data.terminals.EdgeTerminal`, + :class:`pyaedt.edb_core.edb_data.terminals.PadstackInstanceTerminal`, + :class:`pyaedt.edb_core.edb_data.terminals.PointTerminal`, + :class:`pyaedt.edb_core.edb_data.terminals.PinGroupTerminal`, + Negative terminal of the probe. + + Returns + ------- + + """ + term = Terminal(self, terminal._edb_object) + term.boundary_type = "kVoltageProbe" + + ref_term = Terminal(self, ref_terminal._edb_object) + ref_term.boundary_type = "kVoltageProbe" + + term.ref_terminal = ref_terminal + return self.probes[term.name] + + @pyaedt_function_handler + def create_voltage_source(self, terminal, ref_terminal): + """Create a voltage source. + + Parameters + ---------- + terminal : :class:`pyaedt.edb_core.edb_data.terminals.EdgeTerminal`, + :class:`pyaedt.edb_core.edb_data.terminals.PadstackInstanceTerminal`, + :class:`pyaedt.edb_core.edb_data.terminals.PointTerminal`, + :class:`pyaedt.edb_core.edb_data.terminals.PinGroupTerminal`, + Positive terminal of the port. + ref_terminal : class:`pyaedt.edb_core.edb_data.terminals.EdgeTerminal`, + :class:`pyaedt.edb_core.edb_data.terminals.PadstackInstanceTerminal`, + :class:`pyaedt.edb_core.edb_data.terminals.PointTerminal`, + :class:`pyaedt.edb_core.edb_data.terminals.PinGroupTerminal`, + Negative terminal of the source. + + Returns + ------- + class:`pyaedt.edb_core.edb_data.ports.ExcitationSources` + """ + term = Terminal(self, terminal._edb_object) + term.boundary_type = "kVoltageSource" + + ref_term = Terminal(self, ref_terminal._edb_object) + ref_term.boundary_type = "kVoltageProbe" + + term.ref_terminal = ref_terminal + return self.sources[term.name] + + @pyaedt_function_handler + def create_current_source(self, terminal, ref_terminal): + """Create a current source. + + Parameters + ---------- + terminal : :class:`pyaedt.edb_core.edb_data.terminals.EdgeTerminal`, + :class:`pyaedt.edb_core.edb_data.terminals.PadstackInstanceTerminal`, + :class:`pyaedt.edb_core.edb_data.terminals.PointTerminal`, + :class:`pyaedt.edb_core.edb_data.terminals.PinGroupTerminal`, + Positive terminal of the port. + ref_terminal : class:`pyaedt.edb_core.edb_data.terminals.EdgeTerminal`, + :class:`pyaedt.edb_core.edb_data.terminals.PadstackInstanceTerminal`, + :class:`pyaedt.edb_core.edb_data.terminals.PointTerminal`, + :class:`pyaedt.edb_core.edb_data.terminals.PinGroupTerminal`, + Negative terminal of the source. + + Returns + ------- + :class:`pyaedt.edb_core.edb_data.ports.ExcitationSources` + """ + term = Terminal(self, terminal._edb_object) + term.boundary_type = "kCurrentSource" + + ref_term = Terminal(self, ref_terminal._edb_object) + ref_term.boundary_type = "kCurrentSource" + + term.ref_terminal = ref_terminal + return self.sources[term.name] + + @pyaedt_function_handler + def get_point_terminal(self, name, net_name, location, layer): + """Place a voltage probe between two points. + + Parameters + ---------- + name : str, + Name of the terminal. + net_name : str + Name of the net. + location : list + Location of the terminal. + layer : str, + Layer of the terminal. + + Returns + ------- + :class:`pyaedt.edb_core.edb_data.terminals.PointTerminal` + """ + from pyaedt.edb_core.edb_data.terminals import PointTerminal + + point_terminal = PointTerminal(self) + return point_terminal.create(name, net_name, location, layer) diff --git a/pyaedt/edb_core/edb_data/padstacks_data.py b/pyaedt/edb_core/edb_data/padstacks_data.py index 4c654868c4d..4abd7768f42 100644 --- a/pyaedt/edb_core/edb_data/padstacks_data.py +++ b/pyaedt/edb_core/edb_data/padstacks_data.py @@ -998,12 +998,29 @@ def __init__(self, edb_padstackinstance, _pedb): self._position = [] self._pdef = None - @property - def terminal(self): - """Return PadstackInstanceTerminal object.""" - from pyaedt.edb_core.edb_data.terminals import PadstackInstanceTerminal + @pyaedt_function_handler + def get_terminal(self, name=None, create_new_terminal=False): + """Return PadstackInstanceTerminal object. - term = PadstackInstanceTerminal(self._pedb, self._edb_object.GetPadstackInstanceTerminal()) + Parameters + ---------- + name : str, optional + Name of the terminal. Only applicable when create_new_terminal is True. + create_new_terminal : bool, optional + Whether to create a new terminal. + + Returns + ------- + :class:`pyaedt.edb_core.edb_data.terminals` + + """ + + if create_new_terminal: + term = self._create_terminal(name) + else: + from pyaedt.edb_core.edb_data.terminals import PadstackInstanceTerminal + + term = PadstackInstanceTerminal(self._pedb, self._edb_object.GetPadstackInstanceTerminal()) if not term.is_null: return term diff --git a/pyaedt/edb_core/edb_data/sources.py b/pyaedt/edb_core/edb_data/sources.py index 5adcb6e259b..ad17de61947 100644 --- a/pyaedt/edb_core/edb_data/sources.py +++ b/pyaedt/edb_core/edb_data/sources.py @@ -1,3 +1,4 @@ +import pyaedt from pyaedt import pyaedt_function_handler from pyaedt.generic.constants import NodeType from pyaedt.generic.constants import SourceType @@ -275,12 +276,16 @@ def net(self, value): def net_name(self): return self._edb_pin_group.GetNet().GetName() - @property - def terminal(self): + @pyaedt_function_handler + def get_terminal(self, name=None, create_new_terminal=False): """Terminal.""" - from pyaedt.edb_core.edb_data.terminals import PinGroupTerminal - term = PinGroupTerminal(self._pedb, self._edb_pin_group.GetPinGroupTerminal()) + if create_new_terminal: + term = self._create_terminal(name) + else: + from pyaedt.edb_core.edb_data.terminals import PinGroupTerminal + + term = PinGroupTerminal(self._pedb, self._edb_pin_group.GetPinGroupTerminal()) return term if not term.is_null else None @pyaedt_function_handler() @@ -297,19 +302,19 @@ def _create_terminal(self, name=None): ------- :class:`pyaedt.edb_core.edb_data.terminals.PinGroupTerminal` """ - pg_term = self.terminal + terminal = self.get_terminal() + if terminal: + return terminal + if not name: - name = self.name + name = pyaedt.generate_unique_name(self.name) - if pg_term: - return pg_term - else: - from pyaedt.edb_core.edb_data.terminals import PinGroupTerminal + from pyaedt.edb_core.edb_data.terminals import PinGroupTerminal - term = PinGroupTerminal(self._pedb) + term = PinGroupTerminal(self._pedb) - term = term.create(name, self.net_name, self.name) - return term + term = term.create(name, self.net_name, self.name) + return term @pyaedt_function_handler() def create_current_source_terminal(self, magnitude=1, phase=0): diff --git a/pyaedt/edb_core/edb_data/terminals.py b/pyaedt/edb_core/edb_data/terminals.py index 61de92cbba8..c178821eb70 100644 --- a/pyaedt/edb_core/edb_data/terminals.py +++ b/pyaedt/edb_core/edb_data/terminals.py @@ -4,19 +4,49 @@ from pyaedt.edb_core.edb_data.connectable import Connectable from pyaedt.edb_core.edb_data.padstacks_data import EDBPadstackInstance from pyaedt.edb_core.edb_data.primitives_data import cast -from pyaedt.edb_core.general import BoundaryType -from pyaedt.edb_core.general import TerminalType from pyaedt.edb_core.general import convert_py_list_to_net_list from pyaedt.generic.general_methods import generate_unique_name class Terminal(Connectable): - def __init__(self, pedb, edb_object): + def __init__(self, pedb, edb_object=None): super().__init__(pedb, edb_object) self._reference_object = None + self._boundary_type_mapping = { + "InvalidBoundary": self._pedb.edb_api.cell.terminal.BoundaryType.InvalidBoundary, + "PortBoundary": self._pedb.edb_api.cell.terminal.BoundaryType.PortBoundary, + "PecBoundary": self._pedb.edb_api.cell.terminal.BoundaryType.PecBoundary, + "RlcBoundary": self._pedb.edb_api.cell.terminal.BoundaryType.RlcBoundary, + "kCurrentSource": self._pedb.edb_api.cell.terminal.BoundaryType.kCurrentSource, + "kVoltageSource": self._pedb.edb_api.cell.terminal.BoundaryType.kVoltageSource, + "kNexximGround": self._pedb.edb_api.cell.terminal.BoundaryType.kNexximGround, + "kNexximPort": self._pedb.edb_api.cell.terminal.BoundaryType.kNexximPort, + "kDcTerminal": self._pedb.edb_api.cell.terminal.BoundaryType.kDcTerminal, + "kVoltageProbe": self._pedb.edb_api.cell.terminal.BoundaryType.kVoltageProbe, + } + + self._terminal_type_mapping = { + "InvalidTerminal": self._pedb.edb_api.cell.terminal.TerminalType.InvalidTerminal, + "EdgeTerminal": self._pedb.edb_api.cell.terminal.TerminalType.EdgeTerminal, + "PointTerminal": self._pedb.edb_api.cell.terminal.TerminalType.PointTerminal, + "TerminalInstanceTerminal": self._pedb.edb_api.cell.terminal.TerminalType.TerminalInstanceTerminal, + "PadstackInstanceTerminal": self._pedb.edb_api.cell.terminal.TerminalType.PadstackInstanceTerminal, + "BundleTerminal": self._pedb.edb_api.cell.terminal.TerminalType.BundleTerminal, + "PinGroupTerminal": self._pedb.edb_api.cell.terminal.TerminalType.PinGroupTerminal, + } + + self._terminal_mapping = { + "EdgeTerminal": EdgeTerminal, + "PointTerminal": PointTerminal, + "PadstackInstanceTerminal": PadstackInstanceTerminal, + "BundleTerminal": BundleTerminal, + "PinGroupTerminal": PinGroupTerminal, + } + @property def _hfss_port_property(self): + """HFSS port property.""" hfss_prop = re.search(r"HFSS\(.*?\)", self._edb_properties) p = {} if hfss_prop: @@ -128,25 +158,26 @@ def terminal_type(self): """ return self._edb_object.GetTerminalType().ToString() + @terminal_type.setter + def terminal_type(self, value): + self._edb_object.GetTerminalType(self._terminal_type_mapping[value]) + @property def boundary_type(self): - """Boundary Type. + """Boundary type. + Returns ------- - int + str + InvalidBoundary, PortBoundary, PecBoundary, RlcBoundary, kCurrentSource, kVoltageSource, kNexximGround, + kNexximPort, kDcTerminal, kVoltageProbe """ return self._edb_object.GetBoundaryType().ToString() @boundary_type.setter def boundary_type(self, value): - if not value in [i.name for i in BoundaryType]: # pragma : no cover - self._pedb.logger.warning("Invalid Boundary Type={}".format(value)) - if value == self._pedb.edb_api.cell.terminal.BoundaryType.kVoltageProbe.ToString(): - temp = self._pedb.edb_api.cell.terminal.BoundaryType.kVoltageProbe - else: # pragma : no cover - temp = self._pedb.edb_api.cell.terminal.BoundaryType.InvalidBoundary - self._edb_object.SetBoundaryType(temp) + self._edb_object.SetBoundaryType(self._boundary_type_mapping[value]) @property def impedance(self): @@ -168,12 +199,7 @@ def ref_terminal(self): terminal = Terminal(self._pedb, self._edb_object.GetReferenceTerminal()) if not terminal.is_null: - if terminal.terminal_type == TerminalType.PointTerminal.name: - return PointTerminal(self._pedb, terminal._edb_object) - elif terminal.terminal_type == TerminalType.EdgeTerminal.name: - return EdgeTerminal(self._pedb, terminal._edb_object) - elif terminal.terminal_type == TerminalType.InvalidTerminal.name: # pragma : no cover - return None + return self._terminal_mapping[terminal.terminal_type](self._pedb, terminal._edb_object) @ref_terminal.setter def ref_terminal(self, value): @@ -199,11 +225,11 @@ def reference_object(self): # pragma : no cover self._reference_object = self.get_pad_edge_terminal_reference_pin() else: self._reference_object = self.get_edge_terminal_reference_primitive() - elif self.terminal_type == TerminalType.PinGroupTerminal.name: + elif self.terminal_type == "PinGroupTerminal": self._reference_object = self.get_pin_group_terminal_reference_pin() - elif self.terminal_type == TerminalType.PointTerminal.name: + elif self.terminal_type == "PointTerminal": self._reference_object = self.get_point_terminal_reference_primitive() - elif self.terminal_type == TerminalType.PadstackInstanceTerminal.name: + elif self.terminal_type == "PadstackInstanceTerminal": self._reference_object = self.get_padstack_terminal_reference_pin() else: self._pedb.logger.warning("Invalid Terminal Type={}".format(term.GetTerminalType())) @@ -471,7 +497,10 @@ def create(self, padstack_instance, name=None, layer=None, is_ref=False): Edb.Cell.Terminal.EdgeTerminal """ if not name: - name = generate_unique_name("Terminal") + pin_name = padstack_instance._edb_object.GetName() + refdes = padstack_instance.component.refdes + name = "{}_{}".format(refdes, pin_name) + name = generate_unique_name(name) if not layer: layer = padstack_instance.start_layer @@ -531,11 +560,10 @@ def create(self, name, net, location, layer, is_ref=False): @property def location(self): - """Get location of the terminal.""" - point_data = self._pedb.point_data(0, 0) + """Location of the terminal.""" layer = list(self._pedb.stackup.layers.values())[0]._edb_layer - if self._edb_object.GetParameters(point_data, layer): - return [point_data.X.ToDouble(), point_data.Y.ToDouble()] + _, point_data, _ = self._edb_object.GetParameters(None, layer) + return [point_data.X.ToDouble(), point_data.Y.ToDouble()] @location.setter def location(self, value): diff --git a/pyaedt/edb_core/general.py b/pyaedt/edb_core/general.py index 6be4a4b417d..a3cfcb63883 100644 --- a/pyaedt/edb_core/general.py +++ b/pyaedt/edb_core/general.py @@ -151,29 +151,6 @@ class DielectricExtentType(Enum): Polygon = 3 -class BoundaryType(Enum): - InvalidBoundary = -1 - PortBoundary = 0 - PecBoundary = 1 - RlcBoundary = 2 - kCurrentSource = 3 - kVoltageSource = 4 - kNexximGround = 5 - kNexximPort = 6 - kDcTerminal = 7 - kVoltageProbe = 8 - - -class TerminalType(Enum): - InvalidTerminal = -1 - EdgeTerminal = 0 - PointTerminal = 1 - TerminalInstanceTerminal = 2 - PadstackInstanceTerminal = 3 - BundleTerminal = 4 - PinGroupTerminal = 5 - - class Primitives(Enum): Rectangle = 0 Circle = 1 diff --git a/pyaedt/edb_core/siwave.py b/pyaedt/edb_core/siwave.py index 708a905a6d2..35ed2eb60b6 100644 --- a/pyaedt/edb_core/siwave.py +++ b/pyaedt/edb_core/siwave.py @@ -13,7 +13,6 @@ from pyaedt.edb_core.edb_data.sources import PinGroup from pyaedt.edb_core.edb_data.sources import ResistorSource from pyaedt.edb_core.edb_data.sources import VoltageSource -from pyaedt.edb_core.general import BoundaryType from pyaedt.edb_core.general import convert_py_list_to_net_list from pyaedt.generic.constants import SolverType from pyaedt.generic.constants import SweepType @@ -1418,13 +1417,7 @@ def place_voltage_probe( negative_layer : str Layer of the negative terminal. """ - from pyaedt.edb_core.edb_data.terminals import PointTerminal - point_terminal = PointTerminal(self._pedb) - p_terminal = point_terminal.create(name, positive_net_name, positive_location, positive_layer) - p_terminal.boundary_type = BoundaryType.kVoltageProbe.name - - n_terminal = point_terminal.create(name + "_ref", negative_net_name, negative_location, negative_layer) - n_terminal.boundary_type = BoundaryType.kVoltageProbe.name - p_terminal.ref_terminal = n_terminal - return self._pedb.probes[name] + p_terminal = self._pedb.get_point_terminal(name, positive_net_name, positive_location, positive_layer) + n_terminal = self._pedb.get_point_terminal(name + "_ref", negative_net_name, negative_location, negative_layer) + return self._pedb.create_voltage_probe(p_terminal, n_terminal)