diff --git a/_unittest/test_00_EDB.py b/_unittest/test_00_EDB.py index 717b7d2b97d..b50a3c43315 100644 --- a/_unittest/test_00_EDB.py +++ b/_unittest/test_00_EDB.py @@ -278,7 +278,7 @@ def test_010_nets_query(self): diff_pair = self.edbapp.differential_pairs.create("new_pair1", "PCIe_Gen4_RX1_P", "PCIe_Gen4_RX1_N") assert diff_pair.positive_net.name == "PCIe_Gen4_RX1_P" assert diff_pair.negative_net.name == "PCIe_Gen4_RX1_N" - assert self.edbapp.differential_pairs.items + assert self.edbapp.differential_pairs["new_pair1"] assert self.edbapp.net_classes.items assert self.edbapp.net_classes.create("DDR4_ADD", ["DDR4_A0", "DDR4_A1"]) @@ -448,12 +448,12 @@ def test_042_create_current_source(self): ) self.edbapp.siwave.create_pin_group( - reference_designator="U1", pin_numbers=["A14", "A15"], group_name="sink_pos" + reference_designator="U1", pin_numbers=["R23", "P23"], group_name="sink_pos" ) assert self.edbapp.siwave.create_voltage_source_on_pin_group("sink_pos", "gnd", name="vrm_voltage_source") self.edbapp.siwave.create_pin_group(reference_designator="U1", pin_numbers=["A27", "A28"], group_name="vp_pos") - self.edbapp.siwave.create_pin_group(reference_designator="U1", pin_numbers=["A14", "A15"], group_name="vp_neg") + self.edbapp.siwave.create_pin_group(reference_designator="U1", pin_numbers=["R23", "P23"], group_name="vp_neg") assert self.edbapp.siwave.create_voltage_probe_on_pin_group("vprobe", "vp_pos", "vp_neg") assert self.edbapp.probes["vprobe"] self.edbapp.siwave.place_voltage_probe( @@ -2402,6 +2402,14 @@ def test_134_create_port_between_pin_and_layer(self): edbapp.siwave.create_port_between_pin_and_layer( component_name="U1", pins_name="A27", layer_name="16_Bottom", reference_net="GND" ) + U7 = edbapp.components["U7"] + U7.pins["G7"].create_port() + port = U7.pins["F7"].create_port(reference=U7.pins["E7"]) + port.is_circuit_port = True + _, pin_group = edbapp.siwave.create_pin_group_on_net( + reference_designator="U7", net_name="GND", group_name="U7_GND" + ) + U7.pins["F7"].create_port(reference=pin_group) edbapp.close() def test_134_siwave_source_setter(self): diff --git a/pyaedt/edb.py b/pyaedt/edb.py index 3eee3c44133..3613c80450e 100644 --- a/pyaedt/edb.py +++ b/pyaedt/edb.py @@ -23,6 +23,7 @@ from pyaedt.edb_core.edb_data.edbvalue import EdbValue from pyaedt.edb_core.edb_data.hfss_simulation_setup_data import HfssSimulationSetup from pyaedt.edb_core.edb_data.ports import BundleWavePort +from pyaedt.edb_core.edb_data.ports import CircuitPort from pyaedt.edb_core.edb_data.ports import CoaxPort from pyaedt.edb_core.edb_data.ports import ExcitationSources from pyaedt.edb_core.edb_data.ports import GapPort @@ -400,9 +401,12 @@ def ports(self): ports = {} for t in temp: t2 = Terminal(self, t) - if t2.terminal_type == TerminalType.BundleTerminal.name: - bundle_ter = BundleWavePort(self, t) - ports[bundle_ter.name] = bundle_ter + if t2.is_circuit_port: + port = CircuitPort(self, t) + ports[port.name] = port + elif t2.terminal_type == TerminalType.BundleTerminal.name: + 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: @@ -3639,3 +3643,38 @@ def _get_connected_ports_from_multizone_cutout(self, terminal_info_dict): ): connected_ports_list.append((port1_connexion, port2_connexion)) return connected_ports_list + + @pyaedt_function_handler + def create_port(self, terminal, ref_terminal=None, is_circuit_port=False): + """Create a port between two terminals. + + 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`, + optional + Negative terminal of the port. + is_circuit_port : bool, optional + Whether it is a circuit port. The default is ``False``. + + Returns + ------- + + """ + 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 diff --git a/pyaedt/edb_core/edb_data/padstacks_data.py b/pyaedt/edb_core/edb_data/padstacks_data.py index a37d2b2987a..ed25ff69b08 100644 --- a/pyaedt/edb_core/edb_data/padstacks_data.py +++ b/pyaedt/edb_core/edb_data/padstacks_data.py @@ -1018,12 +1018,39 @@ def _create_terminal(self, name=None): @pyaedt_function_handler def create_coax_port(self, name=None, radial_extent_factor=0): """Create a coax port.""" - from pyaedt.edb_core.edb_data.ports import CoaxPort - term = self._create_terminal(name) - coax = CoaxPort(self._pedb, term._edb_object) - coax.radial_extent_factor = radial_extent_factor - return coax + port = self.create_port(name) + port.radial_extent_factor = radial_extent_factor + return port + + @pyaedt_function_handler + def create_port(self, name=None, reference=None, is_circuit_port=False): + """Create a port on the padstack. + + Parameters + ---------- + name : str, optional + Name of the port. The default is ``None``, in which case a name is automatically assigned. + reference : class:`pyaedt.edb_core.edb_data.nets_data.EDBNetsData`, + class:`pyaedt.edb_core.edb_data.padstacks_data.EDBPadstackInstance`, + class:`pyaedt.edb_core.edb_data.sources.PinGroup`, optional + Negative terminal of the port. + is_circuit_port : bool, optional + Whether it is a circuit port. + + Returns + ------- + + """ + terminal = self._create_terminal(name) + if reference: + ref_terminal = reference._create_terminal(terminal.name + "_ref") + if reference._edb_object.ToString() == "PinGroup": + is_circuit_port = True + else: + ref_terminal = None + + return self._pedb.create_port(terminal, ref_terminal, is_circuit_port) @property def _em_properties(self): @@ -1163,7 +1190,8 @@ def in_polygon(self, polygon_data, include_partial=True, simple_check=False): @property def pin(self): - """Return Edb padstack object.""" + """EDB padstack object.""" + warnings.warn("`pin` is deprecated.", DeprecationWarning) return self._edb_padstackinstance @property diff --git a/pyaedt/edb_core/edb_data/ports.py b/pyaedt/edb_core/edb_data/ports.py index a26d240be6f..b68539286ba 100644 --- a/pyaedt/edb_core/edb_data/ports.py +++ b/pyaedt/edb_core/edb_data/ports.py @@ -54,6 +54,25 @@ def renormalize_z0(self): ) +class CircuitPort(GapPort): + """Manages gap port properties. + + Parameters + ---------- + pedb : pyaedt.edb.Edb + EDB object from the ``Edblib`` library. + edb_object : Ansys.Ansoft.Edb.Cell.Terminal.EdgeTerminal + Edge terminal instance from EDB. + + Examples + -------- + This example shows how to access the ``GapPort`` class. + """ + + def __init__(self, pedb, edb_object): + super().__init__(pedb, edb_object) + + class WavePort(EdgeTerminal): """Manages wave port properties. diff --git a/pyaedt/edb_core/edb_data/sources.py b/pyaedt/edb_core/edb_data/sources.py index f7a3bc6c0a0..5adcb6e259b 100644 --- a/pyaedt/edb_core/edb_data/sources.py +++ b/pyaedt/edb_core/edb_data/sources.py @@ -229,6 +229,7 @@ def __init__(self, name="", edb_pin_group=None, pedb=None): self._component = "" self._node_pins = [] self._net = "" + self._edb_object = self._edb_pin_group @property def _active_layout(self): @@ -274,26 +275,45 @@ def net(self, value): def net_name(self): return self._edb_pin_group.GetNet().GetName() + @property + def terminal(self): + """Terminal.""" + 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() - def _create_pin_group_terminal(self, is_reference=False): - pg_term = self._edb_pin_group.GetPinGroupTerminal() - pin_group_net = self._edb_pin_group.GetNet() - if pin_group_net.IsNull(): # pragma: no cover - pin_group_net = list(self._edb_pin_group.GetPins())[0].GetNet() - if pg_term.IsNull(): - return self._pedb.edb_api.cell.terminal.PinGroupTerminal.Create( - self._active_layout, - pin_group_net, - self.name, - self._edb_pin_group, - is_reference, - ) - else: + def _create_terminal(self, name=None): + """Create a terminal on the pin group. + + Parameters + ---------- + name : str, optional + Name of the terminal. The default is ``None``, in which case a name is + automatically assigned. + + Returns + ------- + :class:`pyaedt.edb_core.edb_data.terminals.PinGroupTerminal` + """ + pg_term = self.terminal + if not name: + name = self.name + + if pg_term: return pg_term + else: + from pyaedt.edb_core.edb_data.terminals import PinGroupTerminal + + term = PinGroupTerminal(self._pedb) + + term = term.create(name, self.net_name, self.name) + return term @pyaedt_function_handler() def create_current_source_terminal(self, magnitude=1, phase=0): - terminal = self._create_pin_group_terminal() + terminal = self._create_terminal()._edb_object terminal.SetBoundaryType(self._pedb.edb_api.cell.terminal.BoundaryType.kCurrentSource) terminal.SetSourceAmplitude(self._pedb.edb_value(magnitude)) terminal.SetSourcePhase(self._pedb.edb_api.utility.value(phase)) @@ -301,7 +321,7 @@ def create_current_source_terminal(self, magnitude=1, phase=0): @pyaedt_function_handler() def create_voltage_source_terminal(self, magnitude=1, phase=0, impedance=0.001): - terminal = self._create_pin_group_terminal() + terminal = self._create_terminal()._edb_object terminal.SetBoundaryType(self._pedb.edb_api.cell.terminal.BoundaryType.kVoltageSource) terminal.SetSourceAmplitude(self._pedb.edb_value(magnitude)) terminal.SetSourcePhase(self._pedb.edb_api.utility.value(phase)) @@ -310,14 +330,14 @@ def create_voltage_source_terminal(self, magnitude=1, phase=0, impedance=0.001): @pyaedt_function_handler() def create_voltage_probe_terminal(self, impedance=1000000): - terminal = self._create_pin_group_terminal() + terminal = self._create_terminal()._edb_object terminal.SetBoundaryType(self._pedb.edb_api.cell.terminal.BoundaryType.kVoltageProbe) terminal.SetImpedance(self._pedb.edb_value(impedance)) return terminal @pyaedt_function_handler() def create_port_terminal(self, impedance=50): - terminal = self._create_pin_group_terminal() + terminal = self._create_terminal()._edb_object terminal.SetBoundaryType(self._pedb.edb_api.cell.terminal.BoundaryType.PortBoundary) terminal.SetImpedance(self._pedb.edb_value(impedance)) terminal.SetIsCircuitPort(True) diff --git a/pyaedt/edb_core/edb_data/terminals.py b/pyaedt/edb_core/edb_data/terminals.py index 39245883611..61de92cbba8 100644 --- a/pyaedt/edb_core/edb_data/terminals.py +++ b/pyaedt/edb_core/edb_data/terminals.py @@ -516,7 +516,7 @@ def create(self, name, net, location, layer, is_ref=False): Returns ------- - + :class:`pyaedt.edb_core.edb_data.terminals.PointTerminal` """ terminal = self._pedb.edb_api.cell.terminal.PointTerminal.Create( self._pedb.active_layout, @@ -562,3 +562,32 @@ class PinGroupTerminal(Terminal): def __init__(self, pedb, edb_object=None): super().__init__(pedb, edb_object) + + @pyaedt_function_handler + def create(self, name, net_name, pin_group_name, is_ref=False): + """Create a pin group terminal. + + Parameters + ---------- + name : str + Name of the terminal. + net_name : str + Name of the net. + pin_group_name : str, + Name of the pin group. + is_ref : bool, optional + Whether it is a reference terminal. The default is ``False``. + + Returns + ------- + :class:`pyaedt.edb_core.edb_data.terminals.PinGroupTerminal` + """ + term = self._pedb.edb_api.cell.terminal.PinGroupTerminal.Create( + self._pedb.active_layout, + self._pedb.nets[net_name].net_object, + name, + self._pedb.siwave.pin_groups[pin_group_name]._edb_object, + is_ref, + ) + term = PinGroupTerminal(self._pedb, term) + return term if not term.is_null else False