diff --git a/_unittest/test_21_Circuit.py b/_unittest/test_21_Circuit.py index c84adc5032b..495ed61a1f8 100644 --- a/_unittest/test_21_Circuit.py +++ b/_unittest/test_21_Circuit.py @@ -64,42 +64,42 @@ def teardown_class(self): gc.collect() def test_01_create_inductor(self): - myind = self.aedtapp.modeler.components.create_inductor(value=1e-9, location=[0.2, 0.2]) + myind = self.aedtapp.modeler.schematic.create_inductor(value=1e-9, location=[0.2, 0.2]) assert type(myind.id) is int assert myind.parameters["L"] == '1e-09' def test_02_create_resistor(self): - myres = self.aedtapp.modeler.components.create_resistor(value=50, location=[0.4, 0.2]) + myres = self.aedtapp.modeler.schematic.create_resistor(value=50, location=[0.4, 0.2]) assert type(myres.id) is int assert myres.parameters["R"] == '50' def test_03_create_capacitor(self): - mycap = self.aedtapp.modeler.components.create_capacitor(value=1e-12, location=[0.6, 0.2]) + mycap = self.aedtapp.modeler.schematic.create_capacitor(value=1e-12, location=[0.6, 0.2]) assert type(mycap.id) is int assert mycap.parameters["C"] == '1e-12' def test_04_getpin_names(self): - mycap2 = self.aedtapp.modeler.components.create_capacitor(value=1e-12) - pinnames = self.aedtapp.modeler.components.get_pins(mycap2) - pinnames2 = self.aedtapp.modeler.components.get_pins(mycap2.id) - pinnames3 = self.aedtapp.modeler.components.get_pins(mycap2.composed_name) + mycap2 = self.aedtapp.modeler.schematic.create_capacitor(value=1e-12) + pinnames = self.aedtapp.modeler.schematic.get_pins(mycap2) + pinnames2 = self.aedtapp.modeler.schematic.get_pins(mycap2.id) + pinnames3 = self.aedtapp.modeler.schematic.get_pins(mycap2.composed_name) assert pinnames2 == pinnames3 assert type(pinnames) is list assert len(pinnames) == 2 def test_05_getpin_location(self): - for el in self.aedtapp.modeler.components.components: - pinnames = self.aedtapp.modeler.components.get_pins(el) + for el in self.aedtapp.modeler.schematic.components: + pinnames = self.aedtapp.modeler.schematic.get_pins(el) for pinname in pinnames: - pinlocation = self.aedtapp.modeler.components.get_pin_location(el, pinname) + pinlocation = self.aedtapp.modeler.schematic.get_pin_location(el, pinname) assert len(pinlocation) == 2 def test_06_add_3dlayout_component(self): - myedb = self.aedtapp.modeler.components.add_subcircuit_3dlayout("Galileo_G87173_204") + myedb = self.aedtapp.modeler.schematic.add_subcircuit_3dlayout("Galileo_G87173_204") assert type(myedb.id) is int def test_07_add_hfss_component(self): - my_model, myname = self.aedtapp.modeler.components.create_field_model( + my_model, myname = self.aedtapp.modeler.schematic.create_field_model( "uUSB", "Setup1 : Sweep", ["usb_N_conn", "usb_N_pcb", "usb_P_conn", "usb_P_pcb"] ) assert type(my_model) is int @@ -142,10 +142,10 @@ def test_11_export_fullwave(self): def test_12_connect_components(self): - myind = self.aedtapp.modeler.components.create_inductor("L100", 1e-9) - myres = self.aedtapp.modeler.components.create_resistor("R100", 50) - mycap = self.aedtapp.modeler.components.create_capacitor("C100", 1e-12) - portname = self.aedtapp.modeler.components.create_interface_port("Port1") + myind = self.aedtapp.modeler.schematic.create_inductor("L100", 1e-9) + myres = self.aedtapp.modeler.schematic.create_resistor("R100", 50) + mycap = self.aedtapp.modeler.schematic.create_capacitor("C100", 1e-12) + portname = self.aedtapp.modeler.schematic.create_interface_port("Port1") assert "Port1" in portname.name assert self.aedtapp.modeler.connect_schematic_components(myind.id, myind.id, pinnum_second=2) @@ -162,21 +162,21 @@ def test_12_connect_components(self): for pin in C1_pins: C1_pin2location[pin.name] = pin.location - portname = self.aedtapp.modeler.components.create_interface_port( + portname = self.aedtapp.modeler.schematic.create_interface_port( "P1_1", [L1_pin2location["n1"][0], L1_pin2location["n1"][1]] ) assert "P1_1" in portname.name - portname = self.aedtapp.modeler.components.create_interface_port( + portname = self.aedtapp.modeler.schematic.create_interface_port( "P2_2", [C1_pin2location["negative"][0], C1_pin2location["negative"][1]] ) assert "P2_2" in portname.name # create_page_port - portname = self.aedtapp.modeler.components.create_page_port( + portname = self.aedtapp.modeler.schematic.create_page_port( "Link_1", [L1_pin2location["n2"][0], L1_pin2location["n2"][1]] ) assert "Link_1" in portname.name - portname = self.aedtapp.modeler.components.create_page_port( + portname = self.aedtapp.modeler.schematic.create_page_port( "Link_2", [C1_pin2location["positive"][0], C1_pin2location["positive"][1]], 180 ) assert "Link_2" in portname.name @@ -297,3 +297,22 @@ def test_23_assign_power_sinusoidal_excitation_to_ports(self): settings = ["", "", "", "", "20W", "14GHz", "0s", "0", "0deg", "0Hz"] ports_list = ["P2_2"] assert self.aedtapp.assign_power_sinusoidal_excitation_to_ports(ports_list, settings) + + def test_24_new_connect_components(self): + self.aedtapp.insert_design("Components") + myind = self.aedtapp.modeler.schematic.create_inductor("L100", 1e-9) + myres = self.aedtapp.modeler.components.create_resistor("R100", 50) + mycap = self.aedtapp.modeler.components.create_capacitor("C100", 1e-12) + myind2 = self.aedtapp.modeler.components.create_inductor("L101", 1e-9) + port = self.aedtapp.modeler.components.create_interface_port("Port1") + assert self.aedtapp.modeler.schematic.connect_components_in_series([myind, myres.composed_name]) + assert self.aedtapp.modeler.schematic.connect_components_in_parallel([mycap, port, myind2.id]) + + def test_25_import_model(self): + self.aedtapp.insert_design("Touch_import") + touch = os.path.join(local_path, "example_models", "SSN_ssn.s6p") + t1 = self.aedtapp.modeler.schematic.create_touchsthone_component(touch) + assert t1 + assert len(t1.pins) == 6 + t2 = self.aedtapp.modeler.schematic.create_touchsthone_component(touch) + assert t2 diff --git a/_unittest/test_22_Circuit_DynamicLink.py b/_unittest/test_22_Circuit_DynamicLink.py index ee52062ee09..d3346c68645 100644 --- a/_unittest/test_22_Circuit_DynamicLink.py +++ b/_unittest/test_22_Circuit_DynamicLink.py @@ -74,7 +74,7 @@ def test_01_save(self): @pytest.mark.skipif(config.get("skip_circuits", False), reason="Skipped because Desktop is crashing") def test_02_add_subcircuits_3dlayout(self): layout_design = "Galileo_G87173_205_cutout3" - hfss3Dlayout_comp = self.aedtapp.modeler.components.add_subcircuit_3dlayout(layout_design) + hfss3Dlayout_comp = self.aedtapp.modeler.schematic.add_subcircuit_3dlayout(layout_design) assert hfss3Dlayout_comp.id == 86 assert hfss3Dlayout_comp @@ -86,7 +86,7 @@ def test_03_add_subcircuits_hfss_link(self): assert len(pin_names) == 4 assert "usb_P_pcb" in pin_names - hfss_comp = self.aedtapp.modeler.components.add_subcircuit_hfss_link( + hfss_comp = self.aedtapp.modeler.schematic.add_subcircuit_hfss_link( "uUSB", pin_names, source_project_path, src_design_name ) assert hfss_comp.id == 87 @@ -94,46 +94,46 @@ def test_03_add_subcircuits_hfss_link(self): @pytest.mark.skipif(config.get("skip_circuits", False), reason="Skipped because Desktop is crashing") def test_04_refresh_dynamic_link(self): - assert self.aedtapp.modeler.components.refresh_dynamic_link("uUSB") + assert self.aedtapp.modeler.schematic.refresh_dynamic_link("uUSB") @pytest.mark.skipif(config.get("skip_circuits", False), reason="Skipped because Desktop is crashing") def test_05_set_sim_option_on_hfss_subcircuit(self): hfss_comp = "CompInst@uUSB;87;3" - assert self.aedtapp.modeler.components.set_sim_option_on_hfss_subcircuit(hfss_comp) - assert self.aedtapp.modeler.components.set_sim_option_on_hfss_subcircuit(hfss_comp, option="interpolate") - assert not self.aedtapp.modeler.components.set_sim_option_on_hfss_subcircuit(hfss_comp, option="not_good") + assert self.aedtapp.modeler.schematic.set_sim_option_on_hfss_subcircuit(hfss_comp) + assert self.aedtapp.modeler.schematic.set_sim_option_on_hfss_subcircuit(hfss_comp, option="interpolate") + assert not self.aedtapp.modeler.schematic.set_sim_option_on_hfss_subcircuit(hfss_comp, option="not_good") @pytest.mark.skipif(config.get("skip_circuits", False), reason="Skipped because Desktop is crashing") def test_06_set_sim_solution_on_hfss_subcircuit(self): hfss_comp = "CompInst@uUSB;87;3" - assert self.aedtapp.modeler.components.set_sim_solution_on_hfss_subcircuit(hfss_comp) + assert self.aedtapp.modeler.schematic.set_sim_solution_on_hfss_subcircuit(hfss_comp) @pytest.mark.skipif(config.get("skip_circuits", False), reason="Skipped because Desktop is crashing") def test_07_create_page_port_and_interface_port(self): hfss_comp_id = 87 hfss3Dlayout_comp_id = 86 - hfssComp_pins = self.aedtapp.modeler.components.get_pins(hfss_comp_id) + hfssComp_pins = self.aedtapp.modeler.schematic.get_pins(hfss_comp_id) assert type(hfssComp_pins) is list assert len(hfssComp_pins) == 4 hfss_pin2location = {} for pin in hfssComp_pins: - hfss_pin2location[pin] = self.aedtapp.modeler.components.get_pin_location(hfss_comp_id, pin) + hfss_pin2location[pin] = self.aedtapp.modeler.schematic.get_pin_location(hfss_comp_id, pin) assert len(hfss_pin2location[pin]) == 2 - hfss3DlayoutComp_pins = self.aedtapp.modeler.components.get_pins(hfss3Dlayout_comp_id) + hfss3DlayoutComp_pins = self.aedtapp.modeler.schematic.get_pins(hfss3Dlayout_comp_id) assert type(hfssComp_pins) is list assert len(hfssComp_pins) == 4 hfss3Dlayout_pin2location = {} for pin in hfss3DlayoutComp_pins: - hfss3Dlayout_pin2location[pin] = self.aedtapp.modeler.components.get_pin_location(hfss3Dlayout_comp_id, pin) + hfss3Dlayout_pin2location[pin] = self.aedtapp.modeler.schematic.get_pin_location(hfss3Dlayout_comp_id, pin) assert len(hfss3Dlayout_pin2location[pin]) == 2 # Link 1 Creation - portname = self.aedtapp.modeler.components.create_page_port( + portname = self.aedtapp.modeler.schematic.create_page_port( "Link1", [hfss_pin2location["usb_N_conn"][0], hfss_pin2location["usb_N_conn"][1]], 180 ) assert "Link1" in portname.composed_name - portname = self.aedtapp.modeler.components.create_page_port( + portname = self.aedtapp.modeler.schematic.create_page_port( "Link1", [hfss3Dlayout_pin2location["J3B2.3.USBH2_DP_CH"][0], hfss3Dlayout_pin2location["J3B2.3.USBH2_DP_CH"][1]], 180, @@ -141,11 +141,11 @@ def test_07_create_page_port_and_interface_port(self): assert "Link1" in portname.composed_name # Link 2 Creation - portname = self.aedtapp.modeler.components.create_page_port( + portname = self.aedtapp.modeler.schematic.create_page_port( "Link2", [hfss_pin2location["usb_N_pcb"][0], hfss_pin2location["usb_N_pcb"][1]], 180 ) assert "Link2" in portname.composed_name - portname = self.aedtapp.modeler.components.create_page_port( + portname = self.aedtapp.modeler.schematic.create_page_port( "Link2", [hfss3Dlayout_pin2location["L3M1.3.USBH2_DN_CH"][0], hfss3Dlayout_pin2location["L3M1.3.USBH2_DN_CH"][1]], 180, @@ -153,20 +153,20 @@ def test_07_create_page_port_and_interface_port(self): assert "Link2" in portname.composed_name # Ports Creation - portname = self.aedtapp.modeler.components.create_interface_port( + portname = self.aedtapp.modeler.schematic.create_interface_port( "Excitation_1", [hfss_pin2location["USB_VCC_T1"][0], hfss_pin2location["USB_VCC_T1"][1]] ) assert "Excitation_1" in portname.composed_name - portname = self.aedtapp.modeler.components.create_interface_port( + portname = self.aedtapp.modeler.schematic.create_interface_port( "Excitation_2", [hfss_pin2location["usb_P_pcb"][0], hfss_pin2location["usb_P_pcb"][1]] ) assert "Excitation_2" in portname.composed_name - portname = self.aedtapp.modeler.components.create_interface_port( + portname = self.aedtapp.modeler.schematic.create_interface_port( "Port_1", [hfss3Dlayout_pin2location["L3M1.2.USBH2_DP_CH"][0], hfss3Dlayout_pin2location["L3M1.2.USBH2_DP_CH"][1]] ) assert "Port_1" in portname.composed_name - portname = self.aedtapp.modeler.components.create_interface_port( + portname = self.aedtapp.modeler.schematic.create_interface_port( "Port_2", [hfss3Dlayout_pin2location["J3B2.2.USBH2_DN_CH"][0], hfss3Dlayout_pin2location["J3B2.2.USBH2_DN_CH"][1]] ) diff --git a/_unittest/test_26_emit.py b/_unittest/test_26_emit.py index 04e5dec297f..d6896ec8c91 100644 --- a/_unittest/test_26_emit.py +++ b/_unittest/test_26_emit.py @@ -65,7 +65,7 @@ def test_connect_components(self): @pytest.mark.skipif(config["build_machine"], reason="Not functional in non-graphical mode") def test_radio_component(self): - radio = self.aedtapp.modeler.components.create_component("New Radio") + radio = self.aedtapp.modeler.schematic.create_component("New Radio") # default radio has 1 Tx channel and 1 Rx channel assert radio.has_rx_channels() assert radio.has_tx_channels() diff --git a/_unittest/test_34_Simplorer.py b/_unittest/test_34_Simplorer.py index 3ba87826167..bf7030b88f2 100644 --- a/_unittest/test_34_Simplorer.py +++ b/_unittest/test_34_Simplorer.py @@ -27,28 +27,28 @@ def teardown_class(self): gc.collect() def test_01_create_resistor(self): - id = self.aedtapp.modeler.components.create_resistor("Resistor1", 10, [0, 0]) + id = self.aedtapp.modeler.schematic.create_resistor("Resistor1", 10, [0, 0]) assert id.parameters["R"] == "10" def test_02_create_inductor(self): - id = self.aedtapp.modeler.components.create_inductor("Inductor1", 1.5, [0.25, 0]) + id = self.aedtapp.modeler.schematic.create_inductor("Inductor1", 1.5, [0.25, 0]) assert id.parameters["L"] == "1.5" def test_03_create_capacitor(self): - id = self.aedtapp.modeler.components.create_capacitor("Capacitor1", 7.5, [0.5, 0]) + id = self.aedtapp.modeler.schematic.create_capacitor("Capacitor1", 7.5, [0.5, 0]) assert id.parameters["C"] == "7.5" def test_04_create_diode(self): - id = self.aedtapp.modeler.components.create_diode("Diode1") + id = self.aedtapp.modeler.schematic.create_diode("Diode1") assert id.parameters["VF"] == "0.8V" def test_05_create_npn(self): - name = self.aedtapp.modeler.components.create_npn("NPN") + name = self.aedtapp.modeler.schematic.create_npn("NPN") # Get component info by part name assert name.parameters["VF"] == "0.8V" def test_06_create_pnp(self): - id = self.aedtapp.modeler.components.create_pnp("PNP") + id = self.aedtapp.modeler.schematic.create_pnp("PNP") assert id.parameters["VF"] == "0.8V" def test_07_import_netlist(self): diff --git a/examples/06-Multiphysics/Hfss_Mechanical.py b/examples/06-Multiphysics/Hfss_Mechanical.py index 56d8ea8269b..a01e1a9bc2b 100644 --- a/examples/06-Multiphysics/Hfss_Mechanical.py +++ b/examples/06-Multiphysics/Hfss_Mechanical.py @@ -46,7 +46,7 @@ # Starts Circuit and add Hfss dynamic link component to it. circuit = Circuit() -hfss_comp = circuit.modeler.components.add_subcircuit_hfss_link("MyHfss", pin_names, hfss.project_file, +hfss_comp = circuit.modeler.schematic.add_subcircuit_hfss_link("MyHfss", pin_names, hfss.project_file, hfss.design_name) ############################################################################### @@ -56,10 +56,10 @@ # argument of set_sim_option_on_hfss_subcircuit can be the component name, the component id or # the component object. -circuit.modeler.components.refresh_dynamic_link("MyHfss") -circuit.modeler.components.set_sim_option_on_hfss_subcircuit(hfss_comp) +circuit.modeler.schematic.refresh_dynamic_link("MyHfss") +circuit.modeler.schematic.set_sim_option_on_hfss_subcircuit(hfss_comp) hfss_setup_name = hfss.setups[0].name + " : " + hfss.setups[0].sweeps[0].name -circuit.modeler.components.set_sim_solution_on_hfss_subcircuit(hfss_comp.composed_name, hfss_setup_name) +circuit.modeler.schematic.set_sim_solution_on_hfss_subcircuit(hfss_comp.composed_name, hfss_setup_name) ############################################################################### # Create Ports and Excitations @@ -68,13 +68,13 @@ # Voltage source on input port. -circuit.modeler.components.create_interface_port("Excitation_1", +circuit.modeler.schematic.create_interface_port("Excitation_1", [hfss_comp.pins[0].location[0], hfss_comp.pins[0].location[1]]) -circuit.modeler.components.create_interface_port("Excitation_2", +circuit.modeler.schematic.create_interface_port("Excitation_2", [hfss_comp.pins[1].location[0], hfss_comp.pins[1].location[1]]) -circuit.modeler.components.create_interface_port("Port_1", +circuit.modeler.schematic.create_interface_port("Port_1", [hfss_comp.pins[2].location[0], hfss_comp.pins[2].location[1]]) -circuit.modeler.components.create_interface_port("Port_2", +circuit.modeler.schematic.create_interface_port("Port_2", [hfss_comp.pins[3].location[0], hfss_comp.pins[3].location[1]]) voltage = 1 diff --git a/pyaedt/modeler/Object3d.py b/pyaedt/modeler/Object3d.py index 3e10d7ccae1..90bcf49cdaa 100644 --- a/pyaedt/modeler/Object3d.py +++ b/pyaedt/modeler/Object3d.py @@ -1883,6 +1883,19 @@ def location(self): _retry_ntimes(30, self.m_Editor.GetComponentPinLocation, self._circuit_comp.composed_name, self.name, False)] + @property + def net(self): + """Get pin net.""" + if "PagePort@" in self.name: + return self._circuit_comp.name.split("@")[1] + for net in self._circuit_comp._circuit_components.nets: + conns = self.m_Editor.GetNetConnections(net) + for conn in conns: + if conn.endswith(self.name) and ( + ";{};".format(self._circuit_comp.id) in conn or ";{} ".format(self._circuit_comp.id) in conn): + return net + return "" + @aedt_exception_handler def connect_to_component(self, component_pin): """Connect schematic components. @@ -1898,27 +1911,27 @@ def connect_to_component(self, component_pin): ``True`` when successful, ``False`` when failed. """ + if not isinstance(component_pin, list): + component_pin = [component_pin] comp_angle = self._circuit_comp.angle * math.pi / 180 - comp_pin_angle = component_pin._circuit_comp.angle * math.pi / 180 if len(self._circuit_comp.pins) == 2: comp_angle += math.pi/2 - if len(component_pin._circuit_comp.pins) == 2: - comp_pin_angle += math.pi / 2 + page_name = "{}_{}".format(self._circuit_comp.composed_name.replace("CompInst@", "").replace(";", "_"), + self.name) + if "Port" in self._circuit_comp.composed_name: try: page_name = self._circuit_comp.name.split("@")[1].replace(";", "_") except: - page_name = "{}_{}".format(self._circuit_comp.composed_name.replace("CompInst@", "").replace(";", "_"), - self.name) - elif "Port" in component_pin._circuit_comp.composed_name: - try: - page_name = self._circuit_comp.name.split("@")[1].replace(";", "_") - except: - page_name = "{}_{}".format(self._circuit_comp.composed_name.replace("CompInst@", "").replace(";", "_"), - self.name) + pass else: - page_name = "{}_{}".format(self._circuit_comp.composed_name.replace("CompInst@", "").replace(";", "_"), - self.name) + for cmp in component_pin: + if "Port" in cmp._circuit_comp.composed_name: + try: + page_name = cmp._circuit_comp.name.split("@")[1].replace(";", "_") + break + except: + continue try: x_loc = AEDT_UNITS["Length"][decompose_variable_value(self._circuit_comp.location[0])[1]] * float( decompose_variable_value(self._circuit_comp.location[1])[0]) @@ -1928,25 +1941,27 @@ def connect_to_component(self, component_pin): angle = comp_angle else: angle = math.pi + comp_angle - ret1 = self._circuit_comp._circuit_components.create_page_port(page_name, self.location, angle=angle) - try: - x_loc = AEDT_UNITS["Length"][decompose_variable_value(component_pin._circuit_comp.location[0])[1]] * float( - decompose_variable_value(component_pin._circuit_comp.location[0])[0]) - except: - x_loc = float(self._circuit_comp.location[0]) - if component_pin.location[0] < x_loc: - angle = comp_pin_angle - else: - angle = math.pi + comp_pin_angle - ret2 = self._circuit_comp._circuit_components.create_page_port(page_name, location=component_pin.location, - angle=angle) + for cmp in component_pin: + try: + x_loc = AEDT_UNITS["Length"][decompose_variable_value(cmp._circuit_comp.location[0])[1]] * float( + decompose_variable_value(cmp._circuit_comp.location[0])[0]) + except: + x_loc = float(self._circuit_comp.location[0]) + comp_pin_angle = cmp._circuit_comp.angle * math.pi / 180 + if len(cmp._circuit_comp.pins) == 2: + comp_pin_angle += math.pi / 2 + if cmp.location[0] < x_loc: + angle = comp_pin_angle + else: + angle = math.pi + comp_pin_angle + ret2 = self._circuit_comp._circuit_components.create_page_port(page_name, location=cmp.location, + angle=angle) if ret1 and ret2: return True else: return False - class ComponentParameters(object): def __getitem__(self, key): @@ -2035,10 +2050,14 @@ def pins(self): self._pins.append(CircuitPins(self, self.composed_name)) else: pins = _retry_ntimes(10, self.m_Editor.GetComponentPins, self.composed_name) + if not pins: return [] for pin in pins: - self._pins.append(CircuitPins(self, pin)) + if self._circuit_components._app.design_type != "Twin Builder": + self._pins.append(CircuitPins(self, pin)) + elif pin not in list(self.parameters.parameters.keys()): + self._pins.append(CircuitPins(self, pin)) return self._pins @property diff --git a/pyaedt/modeler/PrimitivesCircuit.py b/pyaedt/modeler/PrimitivesCircuit.py index da248885a90..a952b4da514 100644 --- a/pyaedt/modeler/PrimitivesCircuit.py +++ b/pyaedt/modeler/PrimitivesCircuit.py @@ -3,9 +3,10 @@ import os import math -from pyaedt.generic.general_methods import aedt_exception_handler, _retry_ntimes +from pyaedt.generic.general_methods import aedt_exception_handler, _retry_ntimes, generate_unique_name from pyaedt.modeler.Object3d import CircuitComponent from pyaedt.generic.constants import AEDT_UNITS +from pyaedt.generic.TouchstoneParser import _parse_ports_name class CircuitComponents(object): """CircutComponents class. @@ -17,7 +18,7 @@ class CircuitComponents(object): >>> from pyaedt import Circuit >>> aedtapp = Circuit() - >>> prim = aedtapp.modeler.components + >>> prim = aedtapp.modeler.schematic """ @aedt_exception_handler @@ -80,6 +81,17 @@ def design_type(self): """Design type.""" return self._app.design_type + @property + def nets(self): + """List of all schematic nets.""" + nets_comp = self._oeditor.GetAllNets() + nets = [] + for net in nets_comp: + v = net.split(";") + if v[0].replace("Wire@", "") not in nets: + nets.append(v[0].replace("Wire@", "")) + return nets + @aedt_exception_handler def _get_location(self, location=None): if not location: @@ -138,7 +150,7 @@ def create_iport(self, name, posx=0.1, posy=0.1, angle=0): """Create an interface port. .. deprecated:: 0.4.0 - Use :func:`Circuit.modeler.components.create_interface_port` instead. + Use :func:`Circuit.modeler.schematic.create_interface_port` instead. """ warnings.warn("`create_iport` is deprecated. Use `create_interface_port` instead.", DeprecationWarning) return self.create_interface_port(name, posx, posy, angle) @@ -249,14 +261,21 @@ def create_model_from_touchstone(self, touchstone_full_path, model_name=None): Returns ------- - bool - ``True`` when successful, ``False`` when failed. + str + Model name when successfully created. ``False`` if something went wrong. """ if not model_name: model_name = os.path.splitext(os.path.basename(touchstone_full_path))[0] - + if model_name in list(self.o_model_manager.GetNames()): + model_name = generate_unique_name(model_name, n=2) num_terminal = int(touchstone_full_path[-2:-1]) + with open(touchstone_full_path, 'r') as f: + port_names = _parse_ports_name(f) + image_subcircuit_path = os.path.normpath(os.path.join(self._modeler._app.desktop_install_dir, "syslib", + "Bitmaps", "nport.bmp")) + if not port_names: + port_names = ["Port" + str(i + 1) for i in range(num_terminal)] arg = [ "NAME:" + model_name, "Name:=", @@ -272,7 +291,7 @@ def create_model_from_touchstone(self, touchstone_full_path, model_name=None): "Description:=", "", "ImageFile:=", - "", + image_subcircuit_path, "SymbolPinConfiguration:=", 0, ["NAME:PortInfoBlk"], @@ -286,7 +305,7 @@ def create_model_from_touchstone(self, touchstone_full_path, model_name=None): "sssmodel:=", False, "PortNames:=", - ["Port" + str(i + 1) for i in range(num_terminal)], + port_names, "domain:=", "frequency", "datamode:=", @@ -420,9 +439,9 @@ def create_model_from_touchstone(self, touchstone_full_path, model_name=None): ] for i in range(num_terminal): arg.append("Terminal:=") - arg.append(["Port" + str(i + 1), "Port" + str(i + 1), "A", False, i + 6, 1, "", "Electrical", "0"]) + arg.append([port_names[i], port_names[i], "A", False, i, 1, "", "Electrical", "0"]) arg.append("CompExtID:=") - arg.append(num_terminal) + arg.append(5) arg.append( [ "NAME:Parameters", @@ -458,11 +477,42 @@ def create_model_from_touchstone(self, touchstone_full_path, model_name=None): ) self.o_component_manager.Add(arg) + return model_name @aedt_exception_handler def create_component_from_touchstonmodel( self, - modelname, + model_name, + location=[], + angle=0, + ): + """Create a component from a Touchstone model. + + .. deprecated:: 0.4.14 + Use :func:`create_touchsthone_component` instead. + + Parameters + ---------- + model_name : str + Name of the Touchstone model or full path to touchstone file. + If full touchstone is provided then, new model will be created. + location : list of float, optional + Position on the X and Y axis. + angle : float, optional + Angle rotation in degrees. The default is ``0``. + + Returns + ------- + :class:`pyaedt.modeler.Object3d.CircuitComponent` + Circuit Component Object. + + """ + return self.create_touchsthone_component(model_name, location, angle) + + @aedt_exception_handler + def create_touchsthone_component( + self, + model_name, location=[], angle=0, ): @@ -470,8 +520,9 @@ def create_component_from_touchstonmodel( Parameters ---------- - modelname : str - Name of the Touchstone model. + model_name : str + Name of the Touchstone model or full path to touchstone file. + If full touchstone is provided then, new model will be created. location : list of float, optional Position on the X and Y axis. angle : float, optional @@ -485,7 +536,9 @@ def create_component_from_touchstonmodel( """ xpos, ypos = self._get_location(location) id = self.create_unique_id() - arg1 = ["NAME:ComponentProps", "Name:=", modelname, "Id:=", str(id)] + if os.path.exists(model_name): + model_name = self.create_model_from_touchstone(model_name) + arg1 = ["NAME:ComponentProps", "Name:=", model_name, "Id:=", str(id)] arg2 = ["NAME:Attributes", "Page:=", 1, "X:=", xpos, "Y:=", ypos, "Angle:=", angle, "Flip:=", False] id = _retry_ntimes(10, self._oeditor.CreateComponent, arg1, arg2) id = int(id.split(";")[1]) diff --git a/pyaedt/modeler/PrimitivesNexxim.py b/pyaedt/modeler/PrimitivesNexxim.py index eae914bd341..d2a8192436b 100644 --- a/pyaedt/modeler/PrimitivesNexxim.py +++ b/pyaedt/modeler/PrimitivesNexxim.py @@ -18,7 +18,7 @@ class NexximComponents(CircuitComponents): >>> from pyaedt import Circuit >>> aedtapp = Circuit() - >>> prim = aedtapp.modeler.components + >>> prim = aedtapp.modeler.schematic """ @property @@ -59,12 +59,88 @@ def __init__(self, modeler): self._currentId = 0 pass + @aedt_exception_handler + def connect_components_in_series(self, components_to_connect): + """Connect schematic components in series. + + Parameters + ---------- + components_to_connect : list of :class:`pyaedt.modeler.Object3d.CircuitComponent` + List of Components to connect. It can be a list of objects or component names. + + Returns + ------- + bool + ``True`` when successful, ``False`` when failed. + + Examples + -------- + >>> from pyaedt import Circuit + >>> circuit = Circuit() + >>> myind = circuit.modeler.schematic.create_inductor(compname="L100", value=1e-9, location=[0,0]) + >>> myres = circuit.modeler.schematic.create_resistor(compname="R100", value=50, location=[0.002, 0.05]) + >>> circuit.modeler.schematic.connect_components_in_series([myind, myres]) + """ + comps = [] + for component in components_to_connect: + if isinstance(component, CircuitComponent): + comps.append(component) + else: + for id, cmp in self.components.items(): + if component in [cmp.id, cmp.name, cmp.composed_name]: + comps.append(cmp) + break + i = 0 + assert len(comps) > 1, "At least two components have to be passed." + while i < (len(comps)-1): + comps[i].pins[-1].connect_to_component(comps[i+1].pins[0]) + i += 1 + return True + + @aedt_exception_handler + def connect_components_in_parallel(self, components_to_connect): + """Connect schematic components in parallel. + + Parameters + ---------- + components_to_connect : list of :class:`pyaedt.modeler.Object3d.CircuitComponent` + List of Components to connect. It can be a list of objects or component names. + + Returns + ------- + bool + ``True`` when successful, ``False`` when failed. + + Examples + -------- + >>> from pyaedt import Circuit + >>> circuit = Circuit() + >>> myind = circuit.modeler.schematic.create_inductor("L100", 1e-9) + >>> myres = circuit.modeler.schematic.create_resistor("R100", 50) + >>> circuit.modeler.schematic.connect_components_in_parallel([myind, myres.composed_name]) + """ + comps = [] + for component in components_to_connect: + if isinstance(component, CircuitComponent): + comps.append(component) + else: + for id, cmp in self.components.items(): + if component in [cmp.id, cmp.name, cmp.composed_name]: + comps.append(cmp) + break + assert len(comps) > 1, "At least two components have to be passed." + comps[0].pins[0].connect_to_component([i.pins[0] for i in comps[1:]]) + terminal_to_connect = [cmp for cmp in comps if len(cmp.pins) >= 2] + if len(terminal_to_connect) > 1: + terminal_to_connect[0].pins[1].connect_to_component([i.pins[1] for i in terminal_to_connect[1:]]) + return True + @aedt_exception_handler def create_3dlayout_subcircuit(self, sourcename): """Add a subcircuit from a HFSS 3DLayout. .. deprecated:: 0.4.0 - Use :func:`Circuit.modeler.components.add_subcircuit_3dlayout` instead. + Use :func:`Circuit.modeler.schematic.add_subcircuit_3dlayout` instead. """ warnings.warn( "`create_3dlayout_subcircuit` is deprecated. Use `add_subcircuit_3dlayout` instead.", DeprecationWarning @@ -1315,7 +1391,7 @@ def push_excitations(self, instance_name, thevenin_calculation=False, setup_name Use :func:`Circuit.push_excitations` instead. """ warnings.warn( - "`circuit.modeler.components.push_excitation` is deprecated. " "Use `circuit.push_excitation` instead.", + "`circuit.modeler.schematic.push_excitation` is deprecated. " "Use `circuit.push_excitation` instead.", DeprecationWarning, ) return self._app.push_excitations(instance_name, thevenin_calculation, setup_name) @@ -1325,7 +1401,7 @@ def assign_sin_excitation2ports(self, ports, settings): """Assign a voltage sinusoidal excitation to circuit ports. .. deprecated:: 0.4.0 - Use :func:`Circuit.modeler.components.assign_voltage_sinusoidal_excitation_to_ports` instead. + Use :func:`Circuit.modeler.schematic.assign_voltage_sinusoidal_excitation_to_ports` instead. """ warnings.warn( "`assign_sin_excitation2ports` is deprecated. " diff --git a/pyaedt/modeler/PrimitivesSimplorer.py b/pyaedt/modeler/PrimitivesSimplorer.py index 7d6a9b88f55..808116c186e 100644 --- a/pyaedt/modeler/PrimitivesSimplorer.py +++ b/pyaedt/modeler/PrimitivesSimplorer.py @@ -20,7 +20,7 @@ class SimplorerComponents(CircuitComponents): >>> from pyaedt import Simplorer >>> aedtapp = Simplorer() - >>> prim = aedtapp.modeler.components + >>> prim = aedtapp.modeler.schematic """ @property @@ -61,7 +61,6 @@ def __init__(self, modeler): self._app = modeler._app self._modeler = modeler self._currentId = 0 - self.components = {} pass @aedt_exception_handler diff --git a/pyaedt/simplorer.py b/pyaedt/simplorer.py index 666e8c9743d..f90e11d82b9 100644 --- a/pyaedt/simplorer.py +++ b/pyaedt/simplorer.py @@ -133,29 +133,29 @@ def create_schematic_from_netlist(self, file_to_import): name = fields[0] if fields[0][0] == "R": value = fields[3][fields[3].find("=") + 1 :].strip() - mycomp = self.modeler.components.create_resistor( + mycomp = self.modeler.schematic.create_resistor( name, value, [xpos, ypos], use_instance_id_netlist=use_instance ) elif fields[0][0] == "L": value = fields[3][fields[3].find("=") + 1 :].strip() - mycomp = self.modeler.components.create_inductor( + mycomp = self.modeler.schematic.create_inductor( name, value, [xpos, ypos], use_instance_id_netlist=use_instance ) elif fields[0][0] == "C": value = fields[3][fields[3].find("=") + 1 :].strip() - mycomp = self.modeler.components.create_capacitor( + mycomp = self.modeler.schematic.create_capacitor( name, value, [xpos, ypos], use_instance_id_netlist=use_instance ) elif fields[0][0] == "Q": if len(fields) == 4 and fields[0][0] == "Q": value = fields[3].strip() - mycomp = self.modeler.components.create_npn( + mycomp = self.modeler.schematic.create_npn( fields[0], value, [xpos, ypos], use_instance_id_netlist=use_instance ) value = None elif fields[0][0] == "D": value = fields[3][fields[3].find("=") + 1 :].strip() - mycomp = self.modeler.components.create_diode( + mycomp = self.modeler.schematic.create_diode( name, value, [xpos, ypos], use_instance_id_netlist=use_instance ) if mycomp: @@ -168,7 +168,7 @@ def create_schematic_from_netlist(self, file_to_import): angle = 0.0 else: angle = math.pi - self.modeler.components.create_page_port(fields[id], [pos[0], pos[1]], angle) + self.modeler.schematic.create_page_port(fields[id], [pos[0], pos[1]], angle) id += 1 ypos += delta if ypos > 0.254: