diff --git a/.gitignore b/.gitignore index 24c53893698..0f8b3b54b26 100644 --- a/.gitignore +++ b/.gitignore @@ -383,6 +383,7 @@ scratch_notebooks/ # Visual studio code local settings .vscode/ +*.code-workspace # EDB temp and backup files *.aedb.bak/ diff --git a/README.md b/README.md index fbefa97cc5a..831b0a6632f 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ *** PyAEDT README --> -[![PyAEDT logo](https://github.com/ansys/pyaedt/blob/main/doc/source/_static/logo.png)](https://aedt.docs.pyansys.com) +[![PyAEDT logo](https://raw.githubusercontent.com/ansys/pyaedt/blob/main/doc/source/_static/logo.png)](https://aedt.docs.pyansys.com)


English | 中文 diff --git a/_unittest/conftest.py b/_unittest/conftest.py index 183590b6378..cf6e0f24400 100644 --- a/_unittest/conftest.py +++ b/_unittest/conftest.py @@ -166,8 +166,9 @@ def desktop(): d = Desktop(desktop_version, NONGRAPHICAL, new_thread) d.odesktop.SetTempDirectory(tempfile.gettempdir()) d.disable_autosave() - d.odesktop.SetDesktopConfiguration("All") - d.odesktop.SetSchematicEnvironment(0) + if desktop_version > "2022.2": + d.odesktop.SetDesktopConfiguration("All") + d.odesktop.SetSchematicEnvironment(0) yield d d.release_desktop(True, True) time.sleep(1) diff --git a/_unittest/example_models/T98/transient_fs.aedtz b/_unittest/example_models/T98/transient_fs.aedtz index e73de4a0dc7..1c35dfb9aeb 100644 Binary files a/_unittest/example_models/T98/transient_fs.aedtz and b/_unittest/example_models/T98/transient_fs.aedtz differ diff --git a/_unittest/test_01_3dlayout_edb.py b/_unittest/test_01_3dlayout_edb.py index b01d11d8faf..c4de3284c8a 100644 --- a/_unittest/test_01_3dlayout_edb.py +++ b/_unittest/test_01_3dlayout_edb.py @@ -415,5 +415,6 @@ def test_23_dissolve_element(self): assert self.aedtapp.create_ports_on_component_by_nets(comp.name, nets) assert self.aedtapp.create_pec_on_component_by_nets(comp.name, "GND") + @pytest.mark.skipif(config["desktopVersion"] <= "2024.1", reason="Introduced in 2024R1") def test_24_open_ic_mode_design(self): assert self.ic_mode_design.ic_mode diff --git a/_unittest/test_01_Design.py b/_unittest/test_01_Design.py index 47816c8f985..d26f86f05e0 100644 --- a/_unittest/test_01_Design.py +++ b/_unittest/test_01_Design.py @@ -385,7 +385,7 @@ def test_33_aedt_object(self): def test_34_force_project_path_disable(self): settings.force_error_on_missing_project = True - assert settings.force_error_on_missing_project == True + assert settings.force_error_on_missing_project e = None exception_raised = False try: diff --git a/_unittest/test_02_2D_modeler.py b/_unittest/test_02_2D_modeler.py index 2fa6543f471..e6165321e55 100644 --- a/_unittest/test_02_2D_modeler.py +++ b/_unittest/test_02_2D_modeler.py @@ -61,7 +61,7 @@ def test_03_objects(self): assert self.aedtapp.modeler._odefinition_manager assert self.aedtapp.modeler._omaterial_manager - def test_04_create_rectangle(self): + def test_04a_create_rectangle(self): test_color = (220, 90, 0) rect1 = self.aedtapp.modeler.create_rectangle([0, -2, -2], [3, 8]) rect2 = self.aedtapp.modeler.create_rectangle( @@ -88,6 +88,29 @@ def test_04_create_rectangle(self): list_of_pos = [ver.position for ver in rect2.vertices] assert sorted(list_of_pos) == [[10.0, -2.0, -2.0], [10.0, 8.0, -2.0], [13.0, -2.0, -2.0], [13.0, 8.0, -2.0]] + def test_04b_create_rectangle(self): + materials = ["copper", "steel_1008"] + material_array = [] + for m in materials: + material_array.append('"' + m + '"') + s = ", ".join(material_array) + self.aedtapp["Materials"] = "[{}]".format(s) + material_index = 1 + rect1 = self.aedtapp.modeler.create_rectangle( + origin=[0, 0, 0], sizes=[6, 12], name="rect1", material=f"Materials[{material_index}]" + ) + assert rect1.material_name == materials[material_index] + rect2 = self.aedtapp.modeler.create_rectangle(origin=[0, 0, 0], sizes=[6, 12], name="rect2", material="test[0]") + assert rect2.material_name == "vacuum" + self.aedtapp["disp"] = 0 + rect3 = self.aedtapp.modeler.create_rectangle( + origin=[0, 0, 0], + sizes=[6, 12], + name="rect3", + material="Materials[if(disp<={} && {}<=disp+{}-1,0,1)]".format(2, 2, 10), + ) + assert rect3.material_name == materials[0] + def test_05_create_rectangle_rz(self): self.aedtapp.solution_type = "MagnetostaticZ" rect1 = self.aedtapp.modeler.create_rectangle([1, 0, -2], [8, 3]) diff --git a/_unittest/test_02_3D_modeler.py b/_unittest/test_02_3D_modeler.py index fab1d449857..9a3c48c6ae4 100644 --- a/_unittest/test_02_3D_modeler.py +++ b/_unittest/test_02_3D_modeler.py @@ -248,7 +248,10 @@ def test_18_chamfer(self): o1 = self.aedtapp.modeler["box_to_split"] assert abs(o1.volume - 4000.0) / 4000.0 < small_number assert o1.top_edge_x.chamfer(1) - assert abs(o1.volume - 3990.0) / 3990.0 < small_number # Volume decreased + if config["desktopVersion"] == "2022.2": + assert abs(o1.volume - 3995.0) / 3995.0 < small_number # Volume decreased + else: + assert abs(o1.volume - 3990.0) / 3990.0 < small_number # Volume decreased def test_19_clone(self): self.restore_model() @@ -521,7 +524,10 @@ def test_40b_create_object_coordinate_system(self): assert cs assert cs.name == "obj_cs" assert cs.entity_id == box.id - assert cs.ref_cs == "Global" + if config["desktopVersion"] == "2022.2": + assert not cs.ref_cs + else: + assert cs.ref_cs == "Global" cs.props["MoveToEnd"] = False assert not cs.props["MoveToEnd"] cs.props["yAxis"]["xDirection"] = 1 @@ -535,7 +541,10 @@ def test_40b_create_object_coordinate_system(self): assert cs assert cs.name == "obj_cs" assert cs.entity_id == box.id - assert cs.ref_cs == "Global" + if config["desktopVersion"] == "2022.2": + assert not cs.ref_cs + else: + assert cs.ref_cs == "Global" cs.props["MoveToEnd"] = False assert not cs.props["MoveToEnd"] cs.props["xAxis"]["xDirection"] = 1 diff --git a/_unittest/test_04_SBR.py b/_unittest/test_04_SBR.py index c2ab4e117b9..532ac7a01fd 100644 --- a/_unittest/test_04_SBR.py +++ b/_unittest/test_04_SBR.py @@ -251,6 +251,28 @@ def test_12_import_map(self): for part in parts_dict["parts"]: assert os.path.exists(parts_dict["parts"][part]["file_name"]) + def test_13_create_custom_array(self, aedtapp, local_scratch): + output_file1 = aedtapp.create_sbr_custom_array() + assert os.path.isfile(output_file1) + + output_file2 = aedtapp.create_sbr_custom_array( + frequencies=[1.0, 2.0, 5.0], + element_number=4, + state_number=2, + position=[[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 1.0, 1.0]], + x_axis=[[1.0, 0.0, 0.0]] * 4, + y_axis=[[0.0, 1.0, 0.0]] * 4, + weight=[ + [complex(1.0, 0.0), complex(1.0, 0.0), complex(1.1, 0.0), complex(1.0, 0.0)], + [complex(1.0, 0.0), complex(1.0, 0.0), complex(1.0, 0.0), complex(1.0, 0.0)], + [complex(1.0, 0.0), complex(1.0, 0.0), complex(1.0, 1.0), complex(1.0, 0.0)], + [complex(1.0, 0.0), complex(1.0, 0.0), complex(1.0, 0.0), complex(1.0, 0.0)], + [complex(1.0, 0.0), complex(1.0, 0.0), complex(1.0, 0.0), complex(1.0, 0.0)], + [complex(1.0, 0.0), complex(1.0, 0.0), complex(1.0, 0.0), complex(1.0, 0.0)], + ], + ) + assert os.path.isfile(output_file2) + @pytest.mark.skipif(is_linux, reason="feature supported in Cpython") def test_16_read_hdm(self): self.aedtapp.insert_design("hdm") diff --git a/_unittest/test_08_Primitives3D.py b/_unittest/test_08_Primitives3D.py index 2bad83982bf..78e22e4b138 100644 --- a/_unittest/test_08_Primitives3D.py +++ b/_unittest/test_08_Primitives3D.py @@ -498,7 +498,6 @@ def test_24_create_cone(self): assert o.object_type == "Solid" assert o.is3d is True assert not self.aedtapp.modeler.create_cone(axis, [1, 1], 20, 10, 5, name="MyCone", material="Copper") - assert not self.aedtapp.modeler.create_cone(axis, udp, 20, 20, 5, name="MyCone", material="Copper") assert not self.aedtapp.modeler.create_cone(axis, udp, -20, 20, 5, name="MyCone", material="Copper") assert not self.aedtapp.modeler.create_cone(axis, udp, 20, -20, 5, name="MyCone", material="Copper") assert not self.aedtapp.modeler.create_cone(axis, udp, 20, 20, -5, name="MyCone", material="Copper") diff --git a/_unittest/test_11_Setup.py b/_unittest/test_11_Setup.py index 5124417a691..7da351b0c71 100644 --- a/_unittest/test_11_Setup.py +++ b/_unittest/test_11_Setup.py @@ -68,6 +68,40 @@ def test_01_create_hfss_setup(self): setup1.disable() setup1.enable() + assert setup1.use_matrix_convergence( + entry_selection=0, + ignore_phase_when_mag_is_less_than=0.015, + all_diagonal_entries=True, + max_delta=0.03, + max_delta_phase=8, + custom_entries=None, + ) + assert setup1.use_matrix_convergence( + entry_selection=1, + ignore_phase_when_mag_is_less_than=0.025, + all_diagonal_entries=True, + max_delta=0.023, + max_delta_phase=18, + custom_entries=None, + all_offdiagonal_entries=False, + ) + assert setup1.use_matrix_convergence( + entry_selection=1, + ignore_phase_when_mag_is_less_than=0.025, + all_diagonal_entries=True, + max_delta=0.023, + max_delta_phase=18, + custom_entries=None, + ) + assert setup1.use_matrix_convergence( + entry_selection=2, + ignore_phase_when_mag_is_less_than=0.01, + all_diagonal_entries=True, + max_delta=0.01, + max_delta_phase=8, + custom_entries=[["1", "2", 0.03, 4]], + ) + def test_01b_create_hfss_sweep(self): self.aedtapp.save_project() setup1 = self.aedtapp.get_setup("My_HFSS_Setup") diff --git a/_unittest/test_12_1_PostProcessing.py b/_unittest/test_12_1_PostProcessing.py index 978a87500b8..c17da79e79e 100644 --- a/_unittest/test_12_1_PostProcessing.py +++ b/_unittest/test_12_1_PostProcessing.py @@ -596,6 +596,95 @@ def test_14B_Field_Ploton_Vector(self): image_format="jpg", ) assert os.path.exists(plot_obj.image_file) + assert plot_obj.range_min is None + assert plot_obj.range_max is None + plot_obj_1 = self.aedtapp.post.plot_field( + "Vector_E", + cutlist, + "CutPlane", + setup=setup_name, + intrinsics=intrinsic, + mesh_on_fields=False, + view="isometric", + show=False, + export_path=self.local_scratch.path, + image_format="jpg", + log_scale=False, + ) + assert os.path.exists(plot_obj_1.image_file) + assert plot_obj_1.range_min is None + assert plot_obj_1.range_max is None + plot_obj_2 = self.aedtapp.post.plot_field( + "Vector_E", + cutlist, + "CutPlane", + setup=setup_name, + intrinsics=intrinsic, + mesh_on_fields=False, + view="isometric", + show=False, + export_path=self.local_scratch.path, + image_format="jpg", + log_scale=False, + scale_min=0, + scale_max=10e6, + ) + assert os.path.exists(plot_obj_2.image_file) + assert plot_obj_2.range_min == 0 + assert plot_obj_2.range_max == 10e6 + plot_obj_3 = self.aedtapp.post.plot_field( + "Vector_E", + cutlist, + "CutPlane", + setup=setup_name, + intrinsics=intrinsic, + mesh_on_fields=False, + view="isometric", + show=False, + export_path=self.local_scratch.path, + image_format="jpg", + log_scale=True, + scale_min=0, + scale_max=10e6, + ) + assert os.path.exists(plot_obj_3.image_file) + assert plot_obj_3.range_min is None + assert plot_obj_3.range_max is None + plot_obj_4 = self.aedtapp.post.plot_field( + "Vector_E", + cutlist, + "CutPlane", + setup=setup_name, + intrinsics=intrinsic, + mesh_on_fields=False, + view="isometric", + show=False, + export_path=self.local_scratch.path, + image_format="jpg", + log_scale=True, + scale_min=10e6, + scale_max=0, + ) + assert os.path.exists(plot_obj_4.image_file) + assert plot_obj_4.range_min is None + assert plot_obj_4.range_max is None + plot_obj_5 = self.aedtapp.post.plot_field( + "Vector_E", + cutlist, + "CutPlane", + setup=setup_name, + intrinsics=intrinsic, + mesh_on_fields=False, + view="isometric", + show=False, + export_path=self.local_scratch.path, + image_format="jpg", + log_scale=False, + scale_min=0, + ) + assert os.path.exists(plot_obj_5.image_file) + assert plot_obj_5.range_min is None + assert plot_obj_5.range_max is None @pytest.mark.skipif(is_linux or sys.version_info < (3, 8), reason="Not running in ironpython") def test_15_export_plot(self): diff --git a/_unittest/test_27_Maxwell2D.py b/_unittest/test_27_Maxwell2D.py index 74b1741de59..95b4bf7e77a 100644 --- a/_unittest/test_27_Maxwell2D.py +++ b/_unittest/test_27_Maxwell2D.py @@ -24,7 +24,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -from collections import OrderedDict import os import shutil @@ -286,7 +285,7 @@ def test_19_matrix(self): group_sources=group_sources, ) assert L.props["MatrixGroup"]["MatrixGroup"] - group_sources = OrderedDict() + group_sources = {} group_sources["Group1_Test"] = ["Current1", "Current3"] group_sources["Group2_Test"] = ["Current2", "Current4"] L = self.aedtapp.assign_matrix( diff --git a/_unittest/test_29_Mechanical.py b/_unittest/test_29_Mechanical.py index 3a1002177ee..a0a6082ebff 100644 --- a/_unittest/test_29_Mechanical.py +++ b/_unittest/test_29_Mechanical.py @@ -79,10 +79,14 @@ def test_05_assign_load(self, add_app): assert self.aedtapp.assign_em_losses(hfss.design_name, hfss.setups[0].name, "LastAdaptive", freq) def test_06a_create_setup(self): + assert not self.aedtapp.assign_2way_coupling() mysetup = self.aedtapp.create_setup() mysetup.props["Solver"] = "Direct" assert mysetup.update() + def test_06b_two_way(self): + assert self.aedtapp.assign_2way_coupling() + @pytest.mark.skipif(config["desktopVersion"] < "2021.2", reason="Skipped on versions lower than 2021.2") def test_07_assign_thermal_loss(self, add_app): ipk = add_app(application=Icepak, solution_type=self.aedtapp.SOLUTIONS.Icepak.SteadyTemperatureAndFlow) diff --git a/_unittest/test_41_3dlayout_modeler.py b/_unittest/test_41_3dlayout_modeler.py index df072e9f2be..58a66560aaa 100644 --- a/_unittest/test_41_3dlayout_modeler.py +++ b/_unittest/test_41_3dlayout_modeler.py @@ -369,6 +369,39 @@ def test_15_edit_setup(self): setup2.props["AdvancedSettings"]["OrderBasis"] = 2 setup2.props["PercentRefinementPerPass"] = 17 assert setup2.update() + assert setup2.use_matrix_convergence( + entry_selection=0, + ignore_phase_when_mag_is_less_than=0.015, + all_diagonal_entries=True, + max_delta=0.03, + max_delta_phase=8, + custom_entries=None, + ) + assert setup2.use_matrix_convergence( + entry_selection=1, + ignore_phase_when_mag_is_less_than=0.025, + all_diagonal_entries=True, + max_delta=0.023, + max_delta_phase=18, + custom_entries=None, + all_offdiagonal_entries=False, + ) + assert setup2.use_matrix_convergence( + entry_selection=1, + ignore_phase_when_mag_is_less_than=0.025, + all_diagonal_entries=True, + max_delta=0.023, + max_delta_phase=18, + custom_entries=None, + ) + assert setup2.use_matrix_convergence( + entry_selection=2, + ignore_phase_when_mag_is_less_than=0.01, + all_diagonal_entries=True, + max_delta=0.01, + max_delta_phase=8, + custom_entries=[["1", "2", 0.03, 4]], + ) def test_16_disable_enable_setup(self): setup_name = "RFBoardSetup3" diff --git a/_unittest/test_45_FilterSolutions/resources/__init__.py b/_unittest/test_45_FilterSolutions/resources/__init__.py index d2b2bdb76b9..f744b86ba71 100644 --- a/_unittest/test_45_FilterSolutions/resources/__init__.py +++ b/_unittest/test_45_FilterSolutions/resources/__init__.py @@ -23,3 +23,4 @@ # SOFTWARE. from .resources import read_resource_file +from .resources import resource_path diff --git a/_unittest/test_45_FilterSolutions/resources/import_tuned_variables.ckt b/_unittest/test_45_FilterSolutions/resources/import_tuned_variables.ckt new file mode 100644 index 00000000000..dd8016e153c --- /dev/null +++ b/_unittest/test_45_FilterSolutions/resources/import_tuned_variables.ckt @@ -0,0 +1,17 @@ +* +V1 1 0 AC 1 PULSE 0 1 0 1.592E-13 0 +R0 1 2 50 +C1 2 0 2.296E-12 +L2 2 3 1.688E-08 +C3 3 0 4.517E-12 +L4 3 4 1.688E-08 +C5 4 0 2.296E-12 +R6 4 0 50 +* +.AC DEC 200 2E+08 5E+09 +.PLOT AC VDB(4) -90 0 +.PLOT AC VP(4) -200 200 +.PLOT AC VG(4) 0 1.2E-09 +.TRAN 5E-11 1E-08 0 +.PLOT TRAN V(4) 0 0.6 +.END diff --git a/_unittest/test_45_FilterSolutions/resources/imported_netlist.ckt b/_unittest/test_45_FilterSolutions/resources/imported_netlist.ckt new file mode 100644 index 00000000000..dd8016e153c --- /dev/null +++ b/_unittest/test_45_FilterSolutions/resources/imported_netlist.ckt @@ -0,0 +1,17 @@ +* +V1 1 0 AC 1 PULSE 0 1 0 1.592E-13 0 +R0 1 2 50 +C1 2 0 2.296E-12 +L2 2 3 1.688E-08 +C3 3 0 4.517E-12 +L4 3 4 1.688E-08 +C5 4 0 2.296E-12 +R6 4 0 50 +* +.AC DEC 200 2E+08 5E+09 +.PLOT AC VDB(4) -90 0 +.PLOT AC VP(4) -200 200 +.PLOT AC VG(4) 0 1.2E-09 +.TRAN 5E-11 1E-08 0 +.PLOT TRAN V(4) 0 0.6 +.END diff --git a/_unittest/test_45_FilterSolutions/resources/library_parts.cfg b/_unittest/test_45_FilterSolutions/resources/library_parts.cfg new file mode 100644 index 00000000000..d53e30325bd --- /dev/null +++ b/_unittest/test_45_FilterSolutions/resources/library_parts.cfg @@ -0,0 +1,45 @@ +modsubType=2 +modsubEr=4.5 +modsubRho=5.8E+07 +modsubTand=0.035 +modsubH=0.002 +modsubT=5E-07 +modsubS=0.00127 +modsubC=0.00635 +modsubErsel=-1 +modsubRhosel=-1 +modsubTandsel=-1 +modsubTanddef=0 +modsubiSubSel=0 +modsubName=User Defined Substrate +modsubBrow= +modsubNameVal=4.5 +modAnsSubIndex=0 +modAWRSubIndex=0 +webAWRSubIndex=0 +locAWRSubIndex=0 +ModelData=2 +ModelDataV=1 +ModelInd=0 +ModelCap=3 +ModelRes=0 +ModelIndV=1 +ModelCapV=1 +ModelResV=1 +modRatLen=2 +modRatZ=1 +Interc=1 +modActLen=0.00254 +modActWid=0.00127 +modRatZMin=0.5 +modRatZMax=2 +modRatLenMin=0.5 +modRatLenMax=2 +modActLenMin=0.00127 +modActWidMin=0.000635 +modActLenMax=0.00508 +modActWidMax=0.00254 +useGeo=0 +OptGeo=1 +indTol=1 +capTol=1 diff --git a/_unittest/test_45_FilterSolutions/resources/library_parts_test.cfg b/_unittest/test_45_FilterSolutions/resources/library_parts_test.cfg new file mode 100644 index 00000000000..e69de29bb2d diff --git a/_unittest/test_45_FilterSolutions/test_filter/test_attributes.py b/_unittest/test_45_FilterSolutions/test_filter/test_attributes.py index 90c0e1e1528..122843ce2c5 100644 --- a/_unittest/test_45_FilterSolutions/test_filter/test_attributes.py +++ b/_unittest/test_45_FilterSolutions/test_filter/test_attributes.py @@ -46,7 +46,7 @@ def test_filter_type(self): design = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) assert design.attributes.filter_type == FilterType.BUTTERWORTH - assert len(FilterType) == 9 + assert len(FilterType) == 10 for fimp in [FilterImplementation.LUMPED]: design.attributes.filter_implementation = fimp diff --git a/_unittest/test_45_FilterSolutions/test_filter/test_dll_interface.py b/_unittest/test_45_FilterSolutions/test_filter/test_dll_interface.py index 19a313c4c03..f92472ac971 100644 --- a/_unittest/test_45_FilterSolutions/test_filter/test_dll_interface.py +++ b/_unittest/test_45_FilterSolutions/test_filter/test_dll_interface.py @@ -35,7 +35,7 @@ @pytest.mark.skipif(config["desktopVersion"] < "2025.1", reason="Skipped on versions earlier than 2025.1") class TestClass: def test_version(self): - assert ansys.aedt.core.filtersolutions_core.api_version() == "FilterSolutions API Version 2025 R1" + assert ansys.aedt.core.filtersolutions_core.api_version() == "FilterSolutions API Version 2025 R1 (Beta)" def test_string_to_enum(self): assert ( diff --git a/_unittest/test_45_FilterSolutions/test_filter/test_graph_setup.py b/_unittest/test_45_FilterSolutions/test_filter/test_graph_setup.py index 148f0a54435..16f3bb13a50 100644 --- a/_unittest/test_45_FilterSolutions/test_filter/test_graph_setup.py +++ b/_unittest/test_45_FilterSolutions/test_filter/test_graph_setup.py @@ -53,6 +53,6 @@ def test_minimum_time(self): def test_maximum_time(self): design = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) - assert design.graph_setup.maximum_time == "10n" + assert design.graph_setup.maximum_time == "10 ns" design.graph_setup.maximum_time = "8 ns" assert design.graph_setup.maximum_time == "8 ns" diff --git a/_unittest/test_45_FilterSolutions/test_lumped_export/__init__.py b/_unittest/test_45_FilterSolutions/test_lumped_export/__init__.py new file mode 100644 index 00000000000..9c4476773da --- /dev/null +++ b/_unittest/test_45_FilterSolutions/test_lumped_export/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2021 - 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. diff --git a/_unittest/test_45_FilterSolutions/test_lumped_export/test_export_to_aedt.py b/_unittest/test_45_FilterSolutions/test_lumped_export/test_export_to_aedt.py new file mode 100644 index 00000000000..9ca433a806f --- /dev/null +++ b/_unittest/test_45_FilterSolutions/test_lumped_export/test_export_to_aedt.py @@ -0,0 +1,616 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2021 - 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 _unittest.conftest import config +import ansys.aedt.core +from ansys.aedt.core.filtersolutions_core.attributes import FilterImplementation +from ansys.aedt.core.filtersolutions_core.export_to_aedt import PartLibraries +from ansys.aedt.core.filtersolutions_core.export_to_aedt import SubstrateEr +from ansys.aedt.core.filtersolutions_core.export_to_aedt import SubstrateResistivity +from ansys.aedt.core.filtersolutions_core.export_to_aedt import SubstrateType +from ansys.aedt.core.generic.general_methods import is_linux +import pytest + +from ..resources import read_resource_file +from ..resources import resource_path + +first_modelithics_inductor = "AVX -> IND_AVX_0201_101 Accu-L" +second_modelithics_inductor = "AVX -> IND_AVX_0402_101 AccuL" +third_modelithics_inductor = "Wurth -> IND_WTH_0603_003 WE-KI" +first_modelithics_capacitor = "Amotech -> CAP_AMH_0201_001 A60Z" +second_modelithics_capacitor = "Murata -> CAP_MUR_0805_004 GRM219" +first_modelithics_resistor = "AVX -> RES_AVX_0402_001 UBR0402" +second_modelithics_resistor = "Vishay -> RES_VIS_0603_001 D11" + + +@pytest.mark.skipif(is_linux, reason="FilterSolutions API is not supported on Linux.") +@pytest.mark.skipif(config["desktopVersion"] < "2025.1", reason="Skipped on versions earlier than 2025.1") +class TestClass: + def test_modelithics_inductor_list_count(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.modelithics_inductor_list_count == 116 + + def test_modelithics_inductor_list(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + with pytest.raises(RuntimeError) as info: + lumpdesign.export_to_aedt.modelithics_inductor_list(-1) + assert info.value.args[0] == "The Modelithics inductor at the given index is not available" + lumpdesign.export_to_aedt.modelithics_inductor_selection = first_modelithics_inductor + assert lumpdesign.export_to_aedt.modelithics_inductor_list(0) == first_modelithics_inductor + + def test_modelithics_inductor_selection(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + with pytest.raises(RuntimeError) as info: + lumpdesign.export_to_aedt.modelithics_inductor_selection + assert info.value.args[0] == "No Modelithics inductor is selected" + lumpdesign.export_to_aedt.modelithics_inductor_selection = first_modelithics_inductor + assert lumpdesign.export_to_aedt.modelithics_inductor_selection == first_modelithics_inductor + + def test_modelithics_inductor_family_list_count(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.modelithics_inductor_family_list_count == 0 + lumpdesign.export_to_aedt.modelithics_inductor_add_family(second_modelithics_inductor) + assert lumpdesign.export_to_aedt.modelithics_inductor_family_list_count == 1 + lumpdesign.export_to_aedt.modelithics_inductor_add_family(third_modelithics_inductor) + assert lumpdesign.export_to_aedt.modelithics_inductor_family_list_count == 2 + + def test_modelithics_inductor_family_list(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + with pytest.raises(RuntimeError) as info: + lumpdesign.export_to_aedt.modelithics_inductor_family_list(0) + assert info.value.args[0] == "The Modelithics inductor family at the given index is not available" + lumpdesign.export_to_aedt.modelithics_inductor_add_family(second_modelithics_inductor) + lumpdesign.export_to_aedt.modelithics_inductor_add_family(third_modelithics_inductor) + assert lumpdesign.export_to_aedt.modelithics_inductor_family_list(0) == second_modelithics_inductor + assert lumpdesign.export_to_aedt.modelithics_inductor_family_list(1) == third_modelithics_inductor + + def test_modelithics_inductor_family_list_add_family(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + with pytest.raises(RuntimeError) as info: + lumpdesign.export_to_aedt.modelithics_inductor_family_list(0) + assert info.value.args[0] == "The Modelithics inductor family at the given index is not available" + lumpdesign.export_to_aedt.modelithics_inductor_add_family(second_modelithics_inductor) + lumpdesign.export_to_aedt.modelithics_inductor_add_family(third_modelithics_inductor) + assert lumpdesign.export_to_aedt.modelithics_inductor_family_list(0) == second_modelithics_inductor + assert lumpdesign.export_to_aedt.modelithics_inductor_family_list(1) == third_modelithics_inductor + + def test_modelithics_inductor_family_list_remove_family(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + with pytest.raises(RuntimeError) as info: + lumpdesign.export_to_aedt.modelithics_inductor_family_list(0) + assert info.value.args[0] == "The Modelithics inductor family at the given index is not available" + lumpdesign.export_to_aedt.modelithics_inductor_add_family(second_modelithics_inductor) + lumpdesign.export_to_aedt.modelithics_inductor_add_family(third_modelithics_inductor) + assert lumpdesign.export_to_aedt.modelithics_inductor_family_list_count == 2 + lumpdesign.export_to_aedt.modelithics_inductor_remove_family(third_modelithics_inductor) + assert lumpdesign.export_to_aedt.modelithics_inductor_family_list_count == 1 + + def test_modelithics_capacitor_list_count(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.modelithics_capacitor_list_count == 140 + + def test_modelithics_capacitor_list(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + with pytest.raises(RuntimeError) as info: + lumpdesign.export_to_aedt.modelithics_capacitor_list(-1) + assert info.value.args[0] == "The Modelithics capacitor at the given index is not available" + lumpdesign.export_to_aedt.modelithics_capacitor_selection = first_modelithics_capacitor + assert lumpdesign.export_to_aedt.modelithics_capacitor_list(0) == first_modelithics_capacitor + + def test_modelithics_capacitor_selection(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + with pytest.raises(RuntimeError) as info: + lumpdesign.export_to_aedt.modelithics_capacitor_selection + assert info.value.args[0] == "No Modelithics capacitor is selected" + lumpdesign.export_to_aedt.modelithics_capacitor_selection = first_modelithics_capacitor + assert lumpdesign.export_to_aedt.modelithics_capacitor_selection == first_modelithics_capacitor + + def test_modelithics_capacitor_family_list_count(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.modelithics_capacitor_family_list_count == 0 + lumpdesign.export_to_aedt.modelithics_capacitor_add_family(first_modelithics_capacitor) + assert lumpdesign.export_to_aedt.modelithics_capacitor_family_list_count == 1 + lumpdesign.export_to_aedt.modelithics_capacitor_add_family(second_modelithics_capacitor) + assert lumpdesign.export_to_aedt.modelithics_capacitor_family_list_count == 2 + + def test_modelithics_capacitor_family_list(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + with pytest.raises(RuntimeError) as info: + lumpdesign.export_to_aedt.modelithics_capacitor_family_list(0) + assert info.value.args[0] == "The Modelithics capacitor family at the given index is not available" + lumpdesign.export_to_aedt.modelithics_capacitor_add_family(first_modelithics_capacitor) + lumpdesign.export_to_aedt.modelithics_capacitor_add_family(second_modelithics_capacitor) + assert lumpdesign.export_to_aedt.modelithics_capacitor_family_list(0) == first_modelithics_capacitor + assert lumpdesign.export_to_aedt.modelithics_capacitor_family_list(1) == second_modelithics_capacitor + + def test_modelithics_capacitor_family_list_add_family(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + with pytest.raises(RuntimeError) as info: + lumpdesign.export_to_aedt.modelithics_capacitor_family_list(0) + assert info.value.args[0] == "The Modelithics capacitor family at the given index is not available" + lumpdesign.export_to_aedt.modelithics_capacitor_add_family(first_modelithics_capacitor) + lumpdesign.export_to_aedt.modelithics_capacitor_add_family(second_modelithics_capacitor) + assert lumpdesign.export_to_aedt.modelithics_capacitor_family_list(0) == first_modelithics_capacitor + assert lumpdesign.export_to_aedt.modelithics_capacitor_family_list(1) == second_modelithics_capacitor + + def test_modelithics_capacitor_family_list_remove_family(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + with pytest.raises(RuntimeError) as info: + lumpdesign.export_to_aedt.modelithics_capacitor_family_list(0) + assert info.value.args[0] == "The Modelithics capacitor family at the given index is not available" + lumpdesign.export_to_aedt.modelithics_capacitor_add_family(first_modelithics_capacitor) + lumpdesign.export_to_aedt.modelithics_capacitor_add_family(second_modelithics_capacitor) + assert lumpdesign.export_to_aedt.modelithics_capacitor_family_list_count == 2 + lumpdesign.export_to_aedt.modelithics_capacitor_remove_family(second_modelithics_capacitor) + assert lumpdesign.export_to_aedt.modelithics_capacitor_family_list_count == 1 + + def test_modelithics_resistor_list_count(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.modelithics_resistor_list_count == 39 + + def test_modelithics_resistor_list(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + with pytest.raises(RuntimeError) as info: + lumpdesign.export_to_aedt.modelithics_resistor_list(-1) + assert info.value.args[0] == "The Modelithics resistor at the given index is not available" + lumpdesign.export_to_aedt.modelithics_resistor_selection = first_modelithics_resistor + assert lumpdesign.export_to_aedt.modelithics_resistor_list(0) == first_modelithics_resistor + + def test_modelithics_resistor_selection(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + with pytest.raises(RuntimeError) as info: + lumpdesign.export_to_aedt.modelithics_resistor_selection + assert info.value.args[0] == "No Modelithics resistor is selected" + lumpdesign.export_to_aedt.modelithics_resistor_selection = first_modelithics_resistor + assert lumpdesign.export_to_aedt.modelithics_resistor_selection == first_modelithics_resistor + + def test_modelithics_resistor_family_list_count(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.modelithics_resistor_family_list_count == 0 + lumpdesign.export_to_aedt.modelithics_resistor_add_family(first_modelithics_resistor) + assert lumpdesign.export_to_aedt.modelithics_resistor_family_list_count == 1 + lumpdesign.export_to_aedt.modelithics_resistor_add_family(second_modelithics_resistor) + assert lumpdesign.export_to_aedt.modelithics_resistor_family_list_count == 2 + + def test_modelithics_resistor_family_list(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + with pytest.raises(RuntimeError) as info: + lumpdesign.export_to_aedt.modelithics_resistor_family_list(0) + assert info.value.args[0] == "The Modelithics resistor family at the given index is not available" + lumpdesign.export_to_aedt.modelithics_resistor_add_family(first_modelithics_resistor) + lumpdesign.export_to_aedt.modelithics_resistor_add_family(second_modelithics_resistor) + assert lumpdesign.export_to_aedt.modelithics_resistor_family_list(0) == first_modelithics_resistor + assert lumpdesign.export_to_aedt.modelithics_resistor_family_list(1) == second_modelithics_resistor + + def test_modelithics_resistor_family_list_add_family(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + with pytest.raises(RuntimeError) as info: + lumpdesign.export_to_aedt.modelithics_resistor_family_list(0) + assert info.value.args[0] == "The Modelithics resistor family at the given index is not available" + lumpdesign.export_to_aedt.modelithics_resistor_add_family(first_modelithics_resistor) + lumpdesign.export_to_aedt.modelithics_resistor_add_family(second_modelithics_resistor) + assert lumpdesign.export_to_aedt.modelithics_resistor_family_list(0) == first_modelithics_resistor + assert lumpdesign.export_to_aedt.modelithics_resistor_family_list(1) == second_modelithics_resistor + + def test_modelithics_resistor_family_list_remove_family(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + with pytest.raises(RuntimeError) as info: + lumpdesign.export_to_aedt.modelithics_resistor_family_list(0) + assert info.value.args[0] == "The Modelithics resistor family at the given index is not available" + lumpdesign.export_to_aedt.modelithics_resistor_add_family(first_modelithics_resistor) + lumpdesign.export_to_aedt.modelithics_resistor_add_family(second_modelithics_resistor) + assert lumpdesign.export_to_aedt.modelithics_resistor_family_list_count == 2 + lumpdesign.export_to_aedt.modelithics_resistor_remove_family(second_modelithics_resistor) + assert lumpdesign.export_to_aedt.modelithics_resistor_family_list_count == 1 + + def test_schematic_name(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + lumpdesign.export_to_aedt.schematic_name = "my_schematic" + assert lumpdesign.export_to_aedt.schematic_name == "my_schematic" + + def test_simulate_after_export_enabled(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.simulate_after_export_enabled == False + lumpdesign.export_to_aedt.simulate_after_export_enabled = True + assert lumpdesign.export_to_aedt.simulate_after_export_enabled == True + + def test_include_group_delay_enabled(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.include_group_delay_enabled == False + lumpdesign.export_to_aedt.include_group_delay_enabled = True + assert lumpdesign.export_to_aedt.include_group_delay_enabled == True + + def test_include_gt_gain_enabled(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.include_gt_gain_enabled == False + lumpdesign.export_to_aedt.include_gt_gain_enabled = True + assert lumpdesign.export_to_aedt.include_gt_gain_enabled == True + + def test_include_vgsl_enabled(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.include_vgsl_enabled == False + lumpdesign.export_to_aedt.include_vgsl_enabled = True + assert lumpdesign.export_to_aedt.include_vgsl_enabled == True + + def test_include_vgin_enabled(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.include_vgin_enabled == False + lumpdesign.export_to_aedt.include_vgin_enabled = True + assert lumpdesign.export_to_aedt.include_vgin_enabled == True + + def test_include_input_return_loss_s11_enabled(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.include_input_return_loss_s11_enabled == True + lumpdesign.export_to_aedt.include_input_return_loss_s11_enabled = False + assert lumpdesign.export_to_aedt.include_input_return_loss_s11_enabled == False + + def test_include_forward_transfer_s21_enabled(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.include_forward_transfer_s21_enabled == True + lumpdesign.export_to_aedt.include_forward_transfer_s21_enabled = False + assert lumpdesign.export_to_aedt.include_forward_transfer_s21_enabled == False + + def test_include_reverse_transfer_s12_enabled(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.include_reverse_transfer_s12_enabled == False + lumpdesign.export_to_aedt.include_reverse_transfer_s12_enabled = True + assert lumpdesign.export_to_aedt.include_reverse_transfer_s12_enabled == True + + def test_include_output_return_loss_s22_enabled(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.include_output_return_loss_s22_enabled == False + lumpdesign.export_to_aedt.include_output_return_loss_s22_enabled = True + assert lumpdesign.export_to_aedt.include_output_return_loss_s22_enabled == True + + def test_db_format_enabled(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.db_format_enabled == True + lumpdesign.export_to_aedt.db_format_enabled = False + assert lumpdesign.export_to_aedt.db_format_enabled == False + + def test_rectangular_plot_enabled(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.rectangular_plot_enabled == True + lumpdesign.export_to_aedt.rectangular_plot_enabled = False + assert lumpdesign.export_to_aedt.rectangular_plot_enabled == False + + def test_smith_plot_enabled(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.smith_plot_enabled == False + lumpdesign.export_to_aedt.smith_plot_enabled = True + assert lumpdesign.export_to_aedt.smith_plot_enabled == True + + def test_polar_plot_enabled(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.polar_plot_enabled == False + lumpdesign.export_to_aedt.polar_plot_enabled = True + assert lumpdesign.export_to_aedt.polar_plot_enabled == True + + def test_table_data_enabled(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.table_data_enabled == False + lumpdesign.export_to_aedt.table_data_enabled = True + assert lumpdesign.export_to_aedt.table_data_enabled == True + + def test_optimitrics_enabled(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.optimitrics_enabled == True + lumpdesign.export_to_aedt.optimitrics_enabled = False + assert lumpdesign.export_to_aedt.optimitrics_enabled == False + + def test_optimize_after_export_enabled(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.optimize_after_export_enabled == False + lumpdesign.export_to_aedt.optimize_after_export_enabled = True + assert lumpdesign.export_to_aedt.optimize_after_export_enabled == True + + def test_load_library_parts_config(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + lumpdesign.export_to_aedt.load_library_parts_config(resource_path("library_parts.cfg")) + assert lumpdesign.export_to_aedt.part_libraries == PartLibraries.MODELITHICS + assert lumpdesign.export_to_aedt.substrate_er == "4.5" + assert lumpdesign.export_to_aedt.substrate_resistivity == "5.8E+07 " + assert lumpdesign.export_to_aedt.substrate_conductor_thickness == "500 nm" + assert lumpdesign.export_to_aedt.substrate_dielectric_height == "2 mm" + assert lumpdesign.export_to_aedt.substrate_loss_tangent == "0.035 " + + def test_save_library_parts_config(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + lumpdesign.export_to_aedt.part_libraries = PartLibraries.MODELITHICS + lumpdesign.export_to_aedt.substrate_er = "2.25" + lumpdesign.export_to_aedt.substrate_resistivity = "4.2E+07 " + lumpdesign.export_to_aedt.substrate_conductor_thickness = "350 nm" + lumpdesign.export_to_aedt.substrate_dielectric_height = "3 mm" + lumpdesign.export_to_aedt.substrate_loss_tangent = "0.065 " + lumpdesign.export_to_aedt.save_library_parts_config(resource_path("library_parts_test.cfg")) + lumpdesign.export_to_aedt.load_library_parts_config(resource_path("library_parts_test.cfg")) + assert lumpdesign.export_to_aedt.part_libraries == PartLibraries.MODELITHICS + assert lumpdesign.export_to_aedt.substrate_er == "2.25" + assert lumpdesign.export_to_aedt.substrate_resistivity == "4.2E+07 " + assert lumpdesign.export_to_aedt.substrate_conductor_thickness == "350 nm" + assert lumpdesign.export_to_aedt.substrate_dielectric_height == "3 mm" + assert lumpdesign.export_to_aedt.substrate_loss_tangent == "0.065 " + + def test_import_tuned_variables(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + lumpdesign.export_to_aedt.simulate_after_export_enabled = True + lumpdesign.export_to_aedt.optimize_after_export_enabled = True + lumpdesign.export_to_aedt.export_design() + assert lumpdesign.export_to_aedt.import_tuned_variables().splitlines() == read_resource_file( + "imported_netlist.ckt" + ) + + def test_part_libraries(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + lumpdesign.export_to_aedt._open_aedt_export() + + assert lumpdesign.export_to_aedt.part_libraries == PartLibraries.LUMPED + assert len(PartLibraries) == 3 + lumpdesign.export_to_aedt.part_libraries = PartLibraries.MODELITHICS + assert lumpdesign.export_to_aedt.part_libraries == PartLibraries.MODELITHICS + + def test_interconnect_length_to_width_ratio(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.interconnect_length_to_width_ratio == "2" + lumpdesign.export_to_aedt.interconnect_length_to_width_ratio = "3" + assert lumpdesign.export_to_aedt.interconnect_length_to_width_ratio == "3" + + def test_interconnect_minimum_length_to_width_ratio(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.interconnect_minimum_length_to_width_ratio == "0.5" + lumpdesign.export_to_aedt.interconnect_minimum_length_to_width_ratio = "0.6" + assert lumpdesign.export_to_aedt.interconnect_minimum_length_to_width_ratio == "0.6" + + def test_interconnect_maximum_length_to_width_ratio(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.interconnect_maximum_length_to_width_ratio == "2" + lumpdesign.export_to_aedt.interconnect_maximum_length_to_width_ratio = "3" + assert lumpdesign.export_to_aedt.interconnect_maximum_length_to_width_ratio == "3" + + def test_interconnect_line_to_termination_width_ratio(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.interconnect_line_to_termination_width_ratio == "1" + lumpdesign.export_to_aedt.interconnect_line_to_termination_width_ratio = "2" + assert lumpdesign.export_to_aedt.interconnect_line_to_termination_width_ratio == "2" + + def test_interconnect_minimum_line_to_termination_width_ratio(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.interconnect_minimum_line_to_termination_width_ratio == "0.5" + lumpdesign.export_to_aedt.interconnect_minimum_line_to_termination_width_ratio = "0.6" + assert lumpdesign.export_to_aedt.interconnect_minimum_line_to_termination_width_ratio == "0.6" + + def test_interconnect_maximum_line_to_termination_width_ratio(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.interconnect_maximum_line_to_termination_width_ratio == "2" + lumpdesign.export_to_aedt.interconnect_maximum_line_to_termination_width_ratio = "3" + assert lumpdesign.export_to_aedt.interconnect_maximum_line_to_termination_width_ratio == "3" + + def test_interconnect_length_value(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.interconnect_length_value == "2.54 mm" + lumpdesign.export_to_aedt.interconnect_length_value = "3 mm" + assert lumpdesign.export_to_aedt.interconnect_length_value == "3 mm" + + def test_interconnect_minimum_length_value(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.interconnect_minimum_length_value == "1.27 mm" + lumpdesign.export_to_aedt.interconnect_minimum_length_value = "0.6 mm" + assert lumpdesign.export_to_aedt.interconnect_minimum_length_value == "0.6 mm" + + def test_interconnect_maximum_length_value(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.interconnect_maximum_length_value == "5.08 mm" + lumpdesign.export_to_aedt.interconnect_maximum_length_value = "6 mm" + assert lumpdesign.export_to_aedt.interconnect_maximum_length_value == "6 mm" + + def test_interconnect_line_width_value(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.interconnect_line_width_value == "1.27 mm" + lumpdesign.export_to_aedt.interconnect_line_width_value = "2 mm" + assert lumpdesign.export_to_aedt.interconnect_line_width_value == "2 mm" + + def test_interconnect_minimum_width_value(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.interconnect_minimum_width_value == "635 um" + lumpdesign.export_to_aedt.interconnect_minimum_width_value = "725 um" + assert lumpdesign.export_to_aedt.interconnect_minimum_width_value == "725 um" + + def test_interconnect_maximum_width_value(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.interconnect_maximum_width_value == "2.54 mm" + lumpdesign.export_to_aedt.interconnect_maximum_width_value = "3 mm" + assert lumpdesign.export_to_aedt.interconnect_maximum_width_value == "3 mm" + + def test_interconnect_inductor_tolerance_value(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + lumpdesign.export_to_aedt.part_libraries = PartLibraries.MODELITHICS + assert lumpdesign.export_to_aedt.interconnect_inductor_tolerance_value == "1" + lumpdesign.export_to_aedt.interconnect_inductor_tolerance_value = "10" + assert lumpdesign.export_to_aedt.interconnect_inductor_tolerance_value == "10" + + def test_interconnect_capacitor_tolerance_value(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + lumpdesign.export_to_aedt.part_libraries = PartLibraries.MODELITHICS + assert lumpdesign.export_to_aedt.interconnect_capacitor_tolerance_value == "1" + lumpdesign.export_to_aedt.interconnect_capacitor_tolerance_value = "10" + assert lumpdesign.export_to_aedt.interconnect_capacitor_tolerance_value == "10" + + def test_interconnect_geometry_optimization_enabled(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.interconnect_geometry_optimization_enabled == True + lumpdesign.export_to_aedt.interconnect_geometry_optimization_enabled = False + assert lumpdesign.export_to_aedt.interconnect_geometry_optimization_enabled == False + + def test_substrate_type(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.substrate_type == SubstrateType.MICROSTRIP + assert len(SubstrateType) == 5 + for substrate in SubstrateType: + lumpdesign.export_to_aedt.substrate_type = substrate + assert lumpdesign.export_to_aedt.substrate_type == substrate + + def test_substrate_er(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.substrate_er == SubstrateEr.ALUMINA + assert len(SubstrateEr) == 17 + for er in SubstrateEr: + lumpdesign.export_to_aedt.substrate_er = er + assert lumpdesign.export_to_aedt.substrate_er == er + lumpdesign.export_to_aedt.substrate_er = "3.2" + assert lumpdesign.export_to_aedt.substrate_er == "3.2" + + def test_substrate_resistivity(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.substrate_resistivity == SubstrateResistivity.GOLD + assert len(SubstrateResistivity) == 11 + for resistivity in SubstrateResistivity: + lumpdesign.export_to_aedt.substrate_resistivity = resistivity + assert lumpdesign.export_to_aedt.substrate_resistivity == resistivity + lumpdesign.export_to_aedt.substrate_resistivity = "0.02" + assert lumpdesign.export_to_aedt.substrate_resistivity == "0.02" + + def test_substrate_loss_tangent(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.substrate_loss_tangent == SubstrateEr.ALUMINA + assert len(SubstrateEr) == 17 + for loss in SubstrateEr: + lumpdesign.export_to_aedt.substrate_loss_tangent = loss + assert lumpdesign.export_to_aedt.substrate_loss_tangent == loss + lumpdesign.export_to_aedt.substrate_loss_tangent = "0.0002" + assert lumpdesign.export_to_aedt.substrate_loss_tangent == "0.0002" + + def test_substrate_conductor_thickness(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.substrate_conductor_thickness == "2.54 um" + lumpdesign.export_to_aedt.substrate_conductor_thickness = "1.25 um" + assert lumpdesign.export_to_aedt.substrate_conductor_thickness == "1.25 um" + + def test_substrate_dielectric_height(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.substrate_dielectric_height == "1.27 mm" + lumpdesign.export_to_aedt.substrate_dielectric_height = "1.22 mm" + assert lumpdesign.export_to_aedt.substrate_dielectric_height == "1.22 mm" + + def test_substrate_unbalanced_lower_dielectric_height(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + lumpdesign.export_to_aedt.substrate_type = SubstrateType.STRIPLINE + lumpdesign.export_to_aedt.substrate_unbalanced_stripline_enabled = True + assert lumpdesign.export_to_aedt.substrate_unbalanced_lower_dielectric_height == "6.35 mm" + lumpdesign.export_to_aedt.substrate_unbalanced_lower_dielectric_height = "5.2 mm" + assert lumpdesign.export_to_aedt.substrate_unbalanced_lower_dielectric_height == "5.2 mm" + + def test_substrate_suspend_dielectric_height(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + lumpdesign.export_to_aedt.substrate_type = SubstrateType.SUSPEND + assert lumpdesign.export_to_aedt.substrate_suspend_dielectric_height == "1.27 mm" + lumpdesign.export_to_aedt.substrate_suspend_dielectric_height = "3.2 mm" + assert lumpdesign.export_to_aedt.substrate_suspend_dielectric_height == "3.2 mm" + + def test_substrate_cover_height(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + lumpdesign.export_to_aedt.substrate_cover_height_enabled = True + assert lumpdesign.export_to_aedt.substrate_cover_height == "6.35 mm" + lumpdesign.export_to_aedt.substrate_cover_height = "2.5 mm" + assert lumpdesign.export_to_aedt.substrate_cover_height == "2.5 mm" + + def test_substrate_unbalanced_stripline_enabled(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + lumpdesign.export_to_aedt.substrate_type = SubstrateType.STRIPLINE + assert lumpdesign.export_to_aedt.substrate_unbalanced_stripline_enabled == False + lumpdesign.export_to_aedt.substrate_unbalanced_stripline_enabled = True + assert lumpdesign.export_to_aedt.substrate_unbalanced_stripline_enabled == True + + def test_substrate_cover_height_enabled(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + assert lumpdesign.export_to_aedt.substrate_cover_height_enabled == False + lumpdesign.export_to_aedt.substrate_cover_height_enabled = True + assert lumpdesign.export_to_aedt.substrate_cover_height_enabled == True diff --git a/_unittest/test_45_FilterSolutions/test_lumped_export/test_optimization_goals_table.py b/_unittest/test_45_FilterSolutions/test_lumped_export/test_optimization_goals_table.py new file mode 100644 index 00000000000..09d87471f80 --- /dev/null +++ b/_unittest/test_45_FilterSolutions/test_lumped_export/test_optimization_goals_table.py @@ -0,0 +1,148 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2021 - 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 _unittest.conftest import config +import ansys.aedt.core +from ansys.aedt.core.filtersolutions_core.attributes import FilterImplementation +from ansys.aedt.core.filtersolutions_core.optimization_goals_table import OptimizationGoalParameter +from ansys.aedt.core.generic.general_methods import is_linux +import pytest + + +@pytest.mark.skipif(is_linux, reason="FilterSolutions API is not supported on Linux.") +@pytest.mark.skipif(config["desktopVersion"] < "2025.1", reason="Skipped on versions earlier than 2025.1") +class TestClass: + + def test_row_count(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + lumpdesign.optimization_goals_table.restore_design_goals() + assert lumpdesign.optimization_goals_table.row_count == 2 + + def test_row(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + lumpdesign.optimization_goals_table.restore_design_goals() + assert lumpdesign.optimization_goals_table.row(0) == [ + "200 MHz", + "1 GHz", + "-3.0103", + "<=", + "dB(S(Port1,Port1))", + "1", + "Y", + ] + assert lumpdesign.optimization_goals_table.row(1) == [ + "1.5849 GHz", + "1.9019 GHz", + "-23.01", + "<=", + "dB(S(Port2,Port1))", + "0.5", + "Y", + ] + assert ( + lumpdesign.optimization_goals_table.row(0)[OptimizationGoalParameter.PARAMETER_NAME.value] + == "dB(S(Port1,Port1))" + ) + assert lumpdesign.optimization_goals_table.row(1)[OptimizationGoalParameter.WEIGHT.value] == "0.5" + + def test_update_row(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + lumpdesign.optimization_goals_table.restore_design_goals() + lumpdesign.optimization_goals_table.update_row( + 0, lower_frequency="100 MHz", upper_frequency="2 GHz", condition=">", weight="0.7" + ) + assert lumpdesign.optimization_goals_table.row(0) == [ + "100 MHz", + "2 GHz", + "-3.0103", + ">", + "dB(S(Port1,Port1))", + "0.7", + "Y", + ] + + def test_append_row(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + lumpdesign.optimization_goals_table.restore_design_goals() + lumpdesign.optimization_goals_table.append_row("100 MHz", "2 GHz", "-3", ">", "dB(S(Port2,Port2))", "0.3", "Y") + assert lumpdesign.optimization_goals_table.row(2) == [ + "100 MHz", + "2 GHz", + "-3", + ">", + "dB(S(Port2,Port2))", + "0.3", + "Y", + ] + + def test_insert_row(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + lumpdesign.optimization_goals_table.restore_design_goals() + lumpdesign.optimization_goals_table.insert_row( + 1, "100 MHz", "2 GHz", "-3", ">", "dB(S(Port2,Port2))", "0.3", "Y" + ) + assert lumpdesign.optimization_goals_table.row(1) == [ + "100 MHz", + "2 GHz", + "-3", + ">", + "dB(S(Port2,Port2))", + "0.3", + "Y", + ] + + def test_remove_row(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + lumpdesign.optimization_goals_table.restore_design_goals() + lumpdesign.optimization_goals_table.remove_row(1) + assert lumpdesign.optimization_goals_table.row_count == 1 + assert lumpdesign.optimization_goals_table.row(0) == [ + "200 MHz", + "1 GHz", + "-3.0103", + "<=", + "dB(S(Port1,Port1))", + "1", + "Y", + ] + + def test_adjust_goal_frequency(self): + lumpdesign = ansys.aedt.core.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + lumpdesign.export_to_aedt._open_aedt_export() + lumpdesign.optimization_goals_table.restore_design_goals() + lumpdesign.optimization_goals_table.adjust_goal_frequency("150 MHz") + assert lumpdesign.optimization_goals_table.row(0)[OptimizationGoalParameter.LOWER_FREQUENCY.value] == "350 MHz" + assert lumpdesign.optimization_goals_table.row(0)[OptimizationGoalParameter.UPPER_FREQUENCY.value] == "1.15 GHz" + assert ( + lumpdesign.optimization_goals_table.row(1)[OptimizationGoalParameter.LOWER_FREQUENCY.value] == "1.7349 GHz" + ) + assert ( + lumpdesign.optimization_goals_table.row(1)[OptimizationGoalParameter.UPPER_FREQUENCY.value] == "2.0519 GHz" + ) diff --git a/_unittest/test_45_FilterSolutions/test_lumped_filter/test_lumped_nodes_and_leads.py b/_unittest/test_45_FilterSolutions/test_lumped_filter/test_lumped_nodes_and_leads.py index 853aff15297..c4b1acd09c8 100644 --- a/_unittest/test_45_FilterSolutions/test_lumped_filter/test_lumped_nodes_and_leads.py +++ b/_unittest/test_45_FilterSolutions/test_lumped_filter/test_lumped_nodes_and_leads.py @@ -26,8 +26,6 @@ import ansys.aedt.core from ansys.aedt.core.filtersolutions_core.attributes import FilterImplementation from ansys.aedt.core.generic.general_methods import is_linux - -# from ..filtersolutions_resources import resource_path import pytest from ..resources import read_resource_file diff --git a/_unittest/test_45_FilterSolutions/test_lumped_filter/test_lumped_termination_impedance.py b/_unittest/test_45_FilterSolutions/test_lumped_filter/test_lumped_termination_impedance_table.py similarity index 99% rename from _unittest/test_45_FilterSolutions/test_lumped_filter/test_lumped_termination_impedance.py rename to _unittest/test_45_FilterSolutions/test_lumped_filter/test_lumped_termination_impedance_table.py index 1f4a5513af5..ad2344fa3d9 100644 --- a/_unittest/test_45_FilterSolutions/test_lumped_filter/test_lumped_termination_impedance.py +++ b/_unittest/test_45_FilterSolutions/test_lumped_filter/test_lumped_termination_impedance_table.py @@ -25,8 +25,8 @@ from _unittest.conftest import config import ansys.aedt.core from ansys.aedt.core.filtersolutions_core.attributes import FilterImplementation -from ansys.aedt.core.filtersolutions_core.lumped_termination_impedance import ComplexReactanceType -from ansys.aedt.core.filtersolutions_core.lumped_termination_impedance import ComplexTerminationDefinition +from ansys.aedt.core.filtersolutions_core.lumped_termination_impedance_table import ComplexReactanceType +from ansys.aedt.core.filtersolutions_core.lumped_termination_impedance_table import ComplexTerminationDefinition from ansys.aedt.core.generic.general_methods import is_linux import pytest diff --git a/_unittest/test_98_Icepak.py b/_unittest/test_98_Icepak.py index cdfd42ae05a..8b295c05876 100644 --- a/_unittest/test_98_Icepak.py +++ b/_unittest/test_98_Icepak.py @@ -34,6 +34,8 @@ from ansys.aedt.core.modules.boundary import PCBSettingsPackageParts from ansys.aedt.core.modules.mesh_icepak import MeshRegion from ansys.aedt.core.modules.setup_templates import SetupKeys +from ansys.aedt.core.modules.solutions import FolderPlotSettings +from ansys.aedt.core.modules.solutions import SpecifiedScale import pytest test_subfolder = "T98" @@ -1868,9 +1870,112 @@ def test_80_global_mesh_region(self): assert g_m_r.global_region.object.material_name == "Carbon Monoxide" def test_81_transient_fs(self, add_app): - app = add_app(application=Icepak, project_name=transient_fs, subfolder=test_subfolder) + app = add_app( + application=Icepak, project_name=transient_fs, subfolder=test_subfolder, design_name="IcepakDesign1" + ) fs = app.post.create_field_summary() for t in ["0s", "1s", "2s", "3s", "4s", "5s"]: fs.add_calculation("Object", "Surface", "Box1", "Temperature", time=t) df = fs.get_field_summary_data(pandas_output=True) assert not df["Mean"].empty + app.close_project() + + def test_82_folder_settings(self, add_app): + app = add_app( + application=Icepak, project_name=transient_fs, subfolder=test_subfolder, design_name="IcepakDesign2" + ) + plot_object = app.post.create_fieldplot_surface( + assignment=app.modeler["Box1"].faces[0].id, quantity="Temperature" + ) + assert plot_object.folder_settings is None + assert ( + app.logger.error_messages[-1] == "[error] Could not find settings data in the design properties." + " Define the `FolderPlotSettings` class from scratch or save the project file and try again." + ) + app.save_project() + fs = plot_object.folder_settings + assert isinstance(fs, FolderPlotSettings) + assert str(fs.color_map_settings) == "ColorMapSettings(map_type='Spectrum', color=Rainbow)" + assert ( + str(fs.marker_settings) + == "MarkerSettings(marker_type='Arrow', map_size=False, map_color=False, marker_size=0.25)" + ) + assert ( + str(fs.scale_settings) == "Scale3DSettings(scale_type='Auto', scale_settings=AutoScale(n_levels=10," + " limit_precision_digits=False, precision_digits=4, use_current_scale_for_animation=False)," + " log=False, db=False)" + ) + assert ( + str(fs.arrow_settings) + == "Arrow3DSettings(arrow_type='Cylinder', arrow_size=1, map_size=False, map_color=True," + " show_arrow_tail=True, magnitude_filtering=False, magnitude_threshold=0," + " min_magnitude=1, max_magnitude=0)" + ) + with pytest.raises(ValueError): + fs.arrow_settings.arrow_type = "Arrow" + assert fs.arrow_settings.arrow_type == "Cylinder" + + fs.arrow_settings.arrow_type = "Line" + assert fs.arrow_settings.arrow_type == "Line" + assert isinstance(fs.arrow_settings.to_dict(), dict) + + with pytest.raises(KeyError): + fs.marker_settings.marker_type = "Line" + assert fs.marker_settings.marker_type == "Arrow" + + fs.marker_settings.marker_type = "Tetrahedron" + assert fs.marker_settings.marker_type == "Tetrahedron" + assert isinstance(fs.marker_settings.to_dict(), dict) + + with pytest.raises(ValueError): + fs.scale_settings.scale_type = "Personalized" + assert fs.scale_settings.scale_type == "Auto" + assert isinstance(fs.scale_settings.to_dict(), dict) + assert ( + str(fs.scale_settings.scale_settings) == "AutoScale(n_levels=10, limit_precision_digits=False, " + "precision_digits=4, use_current_scale_for_animation=False)" + ) + fs.scale_settings.scale_type = "Specified" + assert str(fs.scale_settings.scale_settings) == "SpecifiedScale(scale_values=[])" + assert isinstance(fs.scale_settings.to_dict(), dict) + with pytest.raises(ValueError): + SpecifiedScale(1) + fs.scale_settings.scale_type = "MinMax" + assert str(fs.scale_settings.scale_settings) == "MinMaxScale(n_levels=10, min_value=1, max_value=100)" + assert isinstance(fs.scale_settings.to_dict(), dict) + + assert str(fs.scale_settings.number_format) == "NumberFormat(format_type=Automatic, width=12, precision=4)" + with pytest.raises(ValueError): + fs.scale_settings.number_format.format_type = "Science" + assert fs.scale_settings.number_format.format_type == "Automatic" + fs.scale_settings.number_format.format_type = "Scientific" + assert fs.scale_settings.number_format.format_type == "Scientific" + assert isinstance(fs.scale_settings.number_format.to_dict(), dict) + assert str(fs.color_map_settings) == "ColorMapSettings(map_type='Spectrum', color=Rainbow)" + with pytest.raises(ValueError): + fs.color_map_settings.map_type = "Personalized" + fs.color_map_settings.map_type = "Ramp" + assert fs.color_map_settings.map_type == "Ramp" + with pytest.raises(ValueError): + fs.color_map_settings.color = 1 + assert fs.color_map_settings.color == [255, 127, 127] + fs.color_map_settings.color = [1, 1, 1] + fs.color_map_settings.map_type = "Uniform" + assert fs.color_map_settings.color != [1, 1, 1] + fs.color_map_settings.color = [1, 1, 1] + fs.color_map_settings.map_type = "Spectrum" + with pytest.raises(ValueError): + fs.color_map_settings.color = "Hot" + assert fs.color_map_settings.color == "Rainbow" + fs.color_map_settings.color = "Temperature" + assert isinstance(fs.color_map_settings.to_dict(), dict) + assert isinstance(fs.to_dict(), dict) + fs.update() + with pytest.raises(ValueError): + plot_object.folder_settings = 1 + plot_object.folder_settings = fs + with pytest.raises(KeyError): + fs.scale_settings.unit = "AEDT" + fs.scale_settings.unit = "kel" + assert fs.scale_settings.unit == "kel" + app.close_project() diff --git a/_unittest_solvers/example_models/T45/waveport.aedb/edb.def b/_unittest_solvers/example_models/T45/waveport.aedb/edb.def new file mode 100644 index 00000000000..50886518f67 Binary files /dev/null and b/_unittest_solvers/example_models/T45/waveport.aedb/edb.def differ diff --git a/_unittest_solvers/test_45_workflows.py b/_unittest_solvers/test_45_workflows.py index e6c5bf61f10..535e51b5ead 100644 --- a/_unittest_solvers/test_45_workflows.py +++ b/_unittest_solvers/test_45_workflows.py @@ -162,7 +162,33 @@ def test_08_configure_a3d(self, local_scratch): local_scratch.copyfolder(os.path.join(solver_local_path, "example_models", "T45", "ANSYS-HSD_V1.aedb"), file_path) - assert main({"is_test": True, "aedb_path": file_path, "configuration_path": configuration_path}) + main(is_test=True, execute={ + "aedt_load": [ + {"project_file": file_path, + "file_cfg_path": configuration_path, + "file_save_path": file_path.replace(".aedb", "_1.aedt")} + ], + "aedt_export": [ + {"project_file": file_path, + "file_path_save": configuration_path.replace(".json", "_1.json")} + ], + "active_load": [], + "active_export": [], + "siwave_load": [], + "siwave_export": [], + }) + + main(is_test=True, execute={ + "aedt_load": [], + "aedt_export": [], + "active_load": [{"project_file": file_path, + "file_cfg_path": configuration_path, + "file_save_path": file_path.replace(".aedb", "_1.aedt")}], + "active_export": [{"project_file": file_path, + "file_path_save": configuration_path.replace(".json", "_1.json")}], + "siwave_load": [], + "siwave_export": [], + }) def test_08_advanced_fields_calculator_non_general(self, add_app): aedtapp = add_app(application=ansys.aedt.core.Hfss, @@ -179,13 +205,13 @@ def test_08_advanced_fields_calculator_non_general(self, add_app): "assignment": "", "assignment_type": ["Line"], "operations": ["Fundamental_Quantity('E')", - "Operation('Real')", - "Operation('Tangent')", - "Operation('Dot')", - "EnterLine('assignment')", - "Operation('LineValue')", - "Operation('Integrate')", - "Operation('CmplxR')"], + "Operation('Real')", + "Operation('Tangent')", + "Operation('Dot')", + "EnterLine('assignment')", + "Operation('LineValue')", + "Operation('Integrate')", + "Operation('CmplxR')"], "report": ["Data Table", "Rectangular Plot"], } @@ -384,3 +410,25 @@ def test_15_import_asc(self, local_scratch, add_app): assert main({"is_test": True, "asc_file": file_path}) aedtapp.close_project() + @pytest.mark.skipif(is_linux, reason="Not supported in Linux.") + def test_16_arbitrary_waveport(self, local_scratch): + from ansys.aedt.core.workflows.hfss3dlayout.generate_arbitrary_wave_ports import main + import tempfile + + file_path = os.path.join(local_scratch.path, "waveport.aedb") + + temp_dir = tempfile.TemporaryDirectory(suffix=".arbitrary_waveport_test") + + local_scratch.copyfolder(os.path.join(solver_local_path, "example_models", + "T45", + "waveport.aedb"), file_path) + + assert main({"is_test": True, + "working_path": temp_dir.name, + "source_path": file_path, + "mounting_side": "top" + }) + + assert os.path.isfile(os.path.join(temp_dir.name, "wave_port.a3dcomp")) + + temp_dir.cleanup() diff --git a/doc/source/API/Post.rst b/doc/source/API/Post.rst index 62f63dfc78f..a4ac06f7adb 100644 --- a/doc/source/API/Post.rst +++ b/doc/source/API/Post.rst @@ -1,7 +1,8 @@ -Postprocessing -============== +Post-processing +=============== This section lists modules for creating and editing -plots in AEDT. They are accessible through the ``post`` property. +plots in AEDT and shows how to interact with AEDT fields calculator. +They are accessible through the ``post`` property. .. note:: Some capabilities of the ``advanced_post_processing`` module require Python 3 and @@ -13,6 +14,8 @@ plots in AEDT. They are accessible through the ``post`` property. Some functionalities are available only when AEDT is running in graphical mode. +Advanced post-processing +~~~~~~~~~~~~~~~~~~~~~~~~ .. currentmodule:: ansys.aedt.core.modules @@ -73,9 +76,11 @@ PyAEDT has classes for manipulating any report property. report_templates.Emission report_templates.Spectral - Icepak monitors ~~~~~~~~~~~~~~~ +The ``monitor_icepak`` module includes the classes listed below to add, modify, and manage monitors during simulations. +Retrieve monitor values for post-processing and analysis to gain insights into key simulation metrics. +Methods and properties are accessible through the ``monitor`` property of the ``Icepak`` class. .. currentmodule:: ansys.aedt.core.modules.monitor_icepak @@ -87,3 +92,17 @@ Icepak monitors FaceMonitor PointMonitor Monitor + +Advanced fields calculator +~~~~~~~~~~~~~~~~~~~~~~~~~~ +The ``fields_calculator`` module includes the ``FieldsCalculator`` class. +It provides methods to interact with AEDT Fields Calculator by adding, loading and deleting custom expressions. + +.. currentmodule:: ansys.aedt.core.modules.fields_calculator + +.. autosummary:: + :toctree: _autosummary + :nosignatures: + + + FieldsCalculator diff --git a/doc/source/Getting_started/Installation.rst b/doc/source/Getting_started/Installation.rst index f1480f7873e..3d3ebf5cb73 100644 --- a/doc/source/Getting_started/Installation.rst +++ b/doc/source/Getting_started/Installation.rst @@ -49,11 +49,13 @@ Extension manager The user can install or uninstall automated workflows using the extension manager. There are three options: -- Custom PyAEDT scripts. +- **Pre-installed extensions** already available in the PyAEDT library. -- Existing workflows in the PyAEDT library. +- **Open source PyAEDT toolkits** described in the `PyAEDT Common Toolkit documentation `_. -- Open source PyAEDT toolkits described in the `PyAEDT Common Toolkit documentation `_. +- **Custom PyAEDT extensions**. + +See `Extension Manager `_ for more information. .. image:: ../Resources/toolkit_manager_1.png :width: 800 diff --git a/doc/source/Resources/my_custom_extension.png b/doc/source/Resources/my_custom_extension.png new file mode 100644 index 00000000000..90ece84f848 Binary files /dev/null and b/doc/source/Resources/my_custom_extension.png differ diff --git a/doc/source/Resources/my_custom_extension_1.png b/doc/source/Resources/my_custom_extension_1.png new file mode 100644 index 00000000000..47684e58a85 Binary files /dev/null and b/doc/source/Resources/my_custom_extension_1.png differ diff --git a/doc/source/Resources/pyaedt_installer_from_aedt.py b/doc/source/Resources/pyaedt_installer_from_aedt.py index 0222384e54d..7ef2a81dce4 100644 --- a/doc/source/Resources/pyaedt_installer_from_aedt.py +++ b/doc/source/Resources/pyaedt_installer_from_aedt.py @@ -84,10 +84,16 @@ def run_pyinstaller_from_c_python(oDesktop): # enable in debug mode # f.write("import sys\n") # f.write('sys.path.insert(0, r"c:\\ansysdev\\git\\repos\\pyaedt")\n') - f.write("from ansys.aedt.core.workflows.installer.pyaedt_installer import add_pyaedt_to_aedt\n") - f.write( - 'add_pyaedt_to_aedt(aedt_version="{}", personal_lib=r"{}")\n'.format( - oDesktop.GetVersion()[:6], oDesktop.GetPersonalLibDirectory())) + if version <= "231": + f.write("from pyaedt.workflows.installer.pyaedt_installer import add_pyaedt_to_aedt\n") + f.write( + 'add_pyaedt_to_aedt(aedt_version="{}", personallib=r"{}")\n'.format( + oDesktop.GetVersion()[:6], oDesktop.GetPersonalLibDirectory())) + else: + f.write("from ansys.aedt.core.workflows.installer.pyaedt_installer import add_pyaedt_to_aedt\n") + f.write( + 'add_pyaedt_to_aedt(aedt_version="{}", personal_lib=r"{}")\n'.format( + oDesktop.GetVersion()[:6], oDesktop.GetPersonalLibDirectory())) command = r'"{}" "{}"'.format(python_exe, python_script) oDesktop.AddMessage("", "", 0, "Configuring PyAEDT panels in automation tab.") @@ -198,7 +204,7 @@ def install_pyaedt(): # run_command( # '"{}" --default-timeout=1000 install git+https://github.com/ansys/pyaedt.git@main'.format(pip_exe)) if args.version <= "231": - run_command('"{}" --default-timeout=1000 install pyaedt[all]=="0.9.3"'.format(pip_exe)) + run_command('"{}" --default-timeout=1000 install pyaedt[all]=="0.9.0"'.format(pip_exe)) run_command('"{}" --default-timeout=1000 install jupyterlab'.format(pip_exe)) run_command('"{}" --default-timeout=1000 install ipython -U'.format(pip_exe)) run_command('"{}" --default-timeout=1000 install ipyvtklink'.format(pip_exe)) @@ -222,14 +228,14 @@ def install_pyaedt(): # Extract all contents to a directory. (You can specify a different extraction path if needed.) zip_ref.extractall(unzipped_path) if args.version <= "231": - run_command('"{}" install --no-cache-dir --no-index --find-links={} pyaedt[all]=="0.9.3"'.format(pip_exe, + run_command('"{}" install --no-cache-dir --no-index --find-links={} pyaedt[all]=="0.9.0"'.format(pip_exe, unzipped_path)) else: run_command('"{}" install --no-cache-dir --no-index --find-links={} pyaedt[installer]'.format(pip_exe, unzipped_path)) else: if args.version <= "231": - run_command('"{}" --default-timeout=1000 install pyaedt[all]=="0.9.3"'.format(pip_exe)) + run_command('"{}" --default-timeout=1000 install pyaedt[all]=="0.9.0"'.format(pip_exe)) run_command('"{}" --default-timeout=1000 install jupyterlab'.format(pip_exe)) run_command('"{}" --default-timeout=1000 install ipython -U'.format(pip_exe)) run_command('"{}" --default-timeout=1000 install ipyvtklink'.format(pip_exe)) diff --git a/doc/source/Resources/toolkit_manager_1.png b/doc/source/Resources/toolkit_manager_1.png index 5e093f2f703..f9733ac953c 100644 Binary files a/doc/source/Resources/toolkit_manager_1.png and b/doc/source/Resources/toolkit_manager_1.png differ diff --git a/doc/source/User_guide/extensions.rst b/doc/source/User_guide/extensions.rst index 5c8ebf63794..0976d6c6e19 100644 --- a/doc/source/User_guide/extensions.rst +++ b/doc/source/User_guide/extensions.rst @@ -1,18 +1,23 @@ -Extensions -========== +Extension manager +================= -Extensions provide a simplified interface to perform automated workflows in AEDT. -In AEDT, you can use the Extension Manager to add or remove extensions. -For more information, see `Extension Manager `_. +Extensions provide a simplified interface to perform automated workflows in AEDT, they are generally tool-specific and are therefore only accessible given the appropriate context. +In AEDT, you can use the `Extension manager `_ to add or remove extensions. +The Extension manager allows the user to install three different types of extensions: -Extensions are generally tool-specific and are therefore only accessible given the appropriate context. The following sections provide further clarification. +- **Pre-installed extensions** available at project level. +- **Open source PyAEDT toolkits** available at application level. +- **Custom extensions** installable both at project and application level. + +The following sections provide further clarification. You can launch extensions in standalone mode from the console or a Python script. -Project extensions -================== +Pre-installed extensions +~~~~~~~~~~~~~~~~~~~~~~~~ -Project extension apply to all extensions that are applicable for all AEDT applications. +Pre-installed extensions are available at project level so they are available for all AEDT applications. +They are small automated workflow with a simple UI. .. grid:: 2 @@ -40,21 +45,92 @@ Project extension apply to all extensions that are applicable for all AEDT appli Lear how to convert projects from 2022R2 to newer versions. + +.. toctree:: + :hidden: + :maxdepth: 2 + + pyaedt_extensions_doc/project + pyaedt_extensions_doc/hfss3dlayout + +HFSS 3D Layout extensions +------------------------- + .. grid-item-card:: Parametrize Layout :link: pyaedt_extensions_doc/hfss3dlayout/parametrize_edb :link-type: doc Learn how to parametrize a full aedb. -.. toctree:: - :hidden: - :maxdepth: 2 + .. grid-item-card:: Generate arbitrary wave ports + :link: pyaedt_extensions_doc/project/arbitrary_wave_port + :link-type: doc - pyaedt_extensions_doc/project + Generate arbitrary wave ports in HFSS -HFSS extensions -=============== +Open source toolkits +~~~~~~~~~~~~~~~~~~~~ -HFSS 3D Layout extensions -========================= +Open source toolkits are available at application level. +They are complex workflows where backend and frontend are split. +They are also fully documented and tested. + +Here are some links to existing toolkits: +- Hfss: `Antenna Wizard `_. +- Maxwell 3D: `Magnet Segmentation Wizard `_. + + +Custom extensions +~~~~~~~~~~~~~~~~~ + +Custom extensions are custom workflows (Python script) that can be installed both at project and application level. +From the Extension manager select the target destination: + +.. image:: ../Resources/toolkit_manager_1.png + :width: 500 + :alt: PyAEDT toolkit manager 1 + +Select `Custom` as the extension type. +Provide the path of the Python script containing the workflow. +Enter the extension name. This is the name that appears beneath the button in the Automation tab after a successful installation. + +.. image:: ../Resources/my_custom_extension.png + :width: 500 + :alt: Custom Extension + +After the normal completion of the installation a new button appears: + +.. image:: ../Resources/my_custom_extension_1.png + :width: 500 + :alt: Custom Extension 1 + +The example below is a simple example of custom extension. +The Python script requires a common initial part to define the port and the version of the AEDT session to connect to. + +.. code:: python + + import ansys.aedt.core + import os + + # common part + if "PYAEDT_SCRIPT_PORT" in os.environ and "PYAEDT_SCRIPT_VERSION" in os.environ: + port = os.environ["PYAEDT_SCRIPT_PORT"] + version = os.environ["PYAEDT_SCRIPT_VERSION"] + else: + port = 0 + version = "2024.2" + + # your pyaedt script + app = ansys.aedt.core.Desktop(new_desktop_session=False, specified_version=version, port=port) + + active_project = app.active_project() + active_design = app.active_design(active_project) + + # no need to hardcode you application but get_pyaedt_app will detect it for you + aedtapp = ansys.aedt.core.get_pyaedt_app(design_name=active_design.GetName(), desktop=app) + + # your workflow + aedtapp.modeler.create_sphere([0, 0, 0], 20) + + app.release_desktop(False, False) diff --git a/doc/source/User_guide/pyaedt_extensions_doc/hfss3dlayout/arbitrary_wave_port.rst b/doc/source/User_guide/pyaedt_extensions_doc/hfss3dlayout/arbitrary_wave_port.rst new file mode 100644 index 00000000000..367cbcf796a --- /dev/null +++ b/doc/source/User_guide/pyaedt_extensions_doc/hfss3dlayout/arbitrary_wave_port.rst @@ -0,0 +1,33 @@ +Parametrize Layout +================== + +This extension is used to generate arbitrary wave ports. + +It assumes that oblong voids are explicit and some pad-stack instances are inside to define terminal. +After defining the working directory and the source file used for creating wave ports, the combobox for defining +the mounting side is important. You can choose between `top` and `bottom`. +For the selected design, `top` searches for the top metal layer and `bottom` for the bottom signal layer. +If not void are found the tool shows an error message, you might have to change the mounting side. + +Note: The selected working directory content is deleted once you press `Generate` button. +If this folder already exists and is not empty, user gets a warning window asking to continue or not. +The check box `Import EDB` is checked by default, when user browse for source file, +only folders are displayed since EDB is an AEDB folder. + +The tool also supports other format, when the user does not check `Import EDB` box, the following file formats are available: +odb++, brd, mcm, or zip are allowed. + +The extension is accessible through the icon created by the Extension Manager in the **Automation** tab. + +The available arguments are: ``working_path``, ``source_path``, ``mounting_side``. + +``working_path`` and ``source_path`` define the working path and ECAD project path. +``mounting_side`` defines the port orientation in the layout. + +The extension user interface can also be launched from the terminal. An example can be found here: + + +.. toctree:: + :maxdepth: 2 + + ../commandline diff --git a/doc/source/User_guide/pyaedt_extensions_doc/project/configure_edb.rst b/doc/source/User_guide/pyaedt_extensions_doc/project/configure_edb.rst index 0874b239676..d8317179049 100644 --- a/doc/source/User_guide/pyaedt_extensions_doc/project/configure_edb.rst +++ b/doc/source/User_guide/pyaedt_extensions_doc/project/configure_edb.rst @@ -1,28 +1,31 @@ Configure layout EDB ==================== -Single configuration file to set up layout for any kind of PCB & package analysis. +------------ +Introduction +------------ +This extension provides the capability of -The following image shows the extension user interface: - -.. image:: ../../../_static/extensions/configure_edb.png - :width: 800 - :alt: Configure Layout UI - - -The available arguments are: ``aedb_path``, ``configuration_path``. -User can pass as an argument a configuration file (a json formatted file or a toml file), or a folder containing more -than N configuration files. In such case the script creates N new aedb projects, each one with corresponding -setting file applied. +- Apply simulation configuration to HFSS 3D Layout design or SIwave project. +- Export simulation configuration as a text file from HFSS 3D Layout design or SIwave project. +The simulation configuration file is a text file in json or toml format. It contains information like layer stackup, +materials, components, HFSS/SIwave setups, etc. This configure file can be used to set up PCB for DCIR, signal +integrity as well as power integrity analysis. .. image:: ../../../_static/extensions/configure_edb_way_of_work.png :width: 800 :alt: Principle of working of Layout UI +Please refer to EDB Configuration `User Guide`_ for details + +.. _User Guide: https://edb.docs.pyansys.com/version/stable/examples/use_configuration/index.html + +-------------------------------------------------------------------------- +A brief description of which options are defined in the configuration file +-------------------------------------------------------------------------- -A brief description of which options are defined in the configuration file: .. image:: ../../../_static/extensions/edb_config_setup.png :width: 800 @@ -38,3 +41,46 @@ configuration setup and re-use it with or without modifications as many times as The value of this format and toolkit, lies in the fact that it is totally reusable, it is really user-friendly, even with users that are not familiar with scripting. It supports most of the options that the UI also supports (not only the ones explained above, but many additional), and it has the advantage of obtaining the initial configuration file from the design, by using its export property. + +---------- +How to use +---------- + +.. image:: ../../../_static/extensions/configure_edb.png + :width: 800 + :alt: Configure Layout UI + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Configure HFSS 3D Layout design in active AEDT project +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +1, Select ``Active Design`` in GUI. + +2, Make sure the HFSS 3D Layout design is open and active in AEDT. + +3, Click ``Select and Apply Configuration`` and browse to your configuration files. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Configure HFSS 3D Layout design in a AEDT project +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +1, Select ``HFSS 3D Layout`` in GUI. + +2, Click ``Select Project File`` and browse to .aedt file. + +3, Click ``Select and Apply Configuration`` and browse to your configuration files. + +4, In the second pop-up window. Specify where to save the new project. + + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Configure design in siwave project +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +1, Select ``SIwave`` in GUI. + +2, Click ``Select Project File`` and browse to .siw file. + +3, Click ``Select and Apply Configuration`` and browse to your configuration files. + +4, In the second pop-up window. Specify where to save the new project. \ No newline at end of file diff --git a/doc/source/User_guide/pyaedt_extensions_doc/project/kernel_convert.rst b/doc/source/User_guide/pyaedt_extensions_doc/project/kernel_convert.rst index 79dfb3d1209..9c2e0f7e986 100644 --- a/doc/source/User_guide/pyaedt_extensions_doc/project/kernel_convert.rst +++ b/doc/source/User_guide/pyaedt_extensions_doc/project/kernel_convert.rst @@ -25,7 +25,7 @@ all the 3DComponents to be converted, they must have the same Application and So given as an input in the last two entries of the UI, as well as same password, in order for the conversion to be successful for all files. -Last but least, for every file in the folder, a new file is generated in the path provided, that contains the +Last but not least, for every file in the folder, a new file is generated in the path provided, that contains the design converted to the latest version, and its name indicating the initial file version (i.e.test_aedt_2025.1) Furthermore, for every conversion, a .csv file is created, with a name pointing to the converted design name, containing any violations that occurred during the conversion, and that need **manual** fixing by the user. diff --git a/doc/source/User_guide/settings.rst b/doc/source/User_guide/settings.rst index 7bf7bf4d82f..9b0f86c46d2 100644 --- a/doc/source/User_guide/settings.rst +++ b/doc/source/User_guide/settings.rst @@ -62,6 +62,8 @@ Below is the content that can be updated through the YAML file. logger_file_path: null # Message format of the log entries logger_formatter: '%(asctime)s:%(destination)s:%(extra)s%(levelname)-8s:%(message)s' + # Path to the AEDT log file + aedt_log_file: null # Settings related to Linux systems running LSF scheduler lsf: diff --git a/doc/source/_static/extensions/configure_edb.png b/doc/source/_static/extensions/configure_edb.png index c233b528409..8dfdf2d83e9 100644 Binary files a/doc/source/_static/extensions/configure_edb.png and b/doc/source/_static/extensions/configure_edb.png differ diff --git a/doc/source/conf.py b/doc/source/conf.py index 91697a923be..67397d9d91f 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -200,7 +200,7 @@ def setup(app): numpydoc_validation_exclude = { # set of regex r"\.AEDTMessageManager.add_message$", # bad SS05 r"\.Modeler3D\.create_choke$", # bad RT05 - r"HistoryProps.", # bad RT05 because of the base class named OrderedDict + r"HistoryProps.", # bad RT05 because of the base class named dict } # Favicon diff --git a/doc/source/release_1_0.rst b/doc/source/release_1_0.rst index 0563eabe3c7..7a86d76fe32 100644 --- a/doc/source/release_1_0.rst +++ b/doc/source/release_1_0.rst @@ -29,10 +29,10 @@ Restructuring of the codebase ----------------------------- To facilitate the maintenance of PyAEDT and to adhere to PyAnsys' guidelines, the codebase -is being restructured. The sources are to be moved from ``pyaedt`` to ``src.ansys.aedt`` +is being restructured. The sources are to be moved from ``pyaedt`` to ``ansys.aedt.core`` to improve the organization and maintainability of the codebase. -The changes to the structure follow: +The changes follow the structure below: .. code-block:: text @@ -49,8 +49,9 @@ The changes to the structure follow: src/ └── ansys/ └── aedt/ - ├── application/ - ├── ... + └── core/ + ├── application/ + ├── ... When migrating to major release `1.0`, please update any references or imports in your project accordingly. An example of migration is shown below: @@ -175,8 +176,8 @@ Other changes in release 1.0 In addition to the major changes described earlier, modifications are continuously performed to improve the quality of the project, its maintainability, its documentation, and -to ensure users' need are met as efficiently as possible. This includes ensuring -consistent argument names, improving data encapsulation, strengthening CI/CD, and extracting -examples to a dedicated project. +to ensure users' needs are met as efficiently as possible. This includes ensuring +consistent argument names, improving data encapsulation, strengthening CI/CD, and migrate +examples to a different repository. For more information on the status of the 1.0 release, see `PyAEDT Milestone `_ . diff --git a/doc/styles/config/vocabularies/ANSYS/accept.txt b/doc/styles/config/vocabularies/ANSYS/accept.txt index f9d92aaea61..0ae1c2e5c92 100644 --- a/doc/styles/config/vocabularies/ANSYS/accept.txt +++ b/doc/styles/config/vocabularies/ANSYS/accept.txt @@ -8,6 +8,7 @@ airgap (?i)Ansys API autosave +brd busbar busbars Bz @@ -44,6 +45,7 @@ matplotlib Maxwell 2D Maxwell 3D Maxwell Circuit +mcm [Mm]echanical multiphysics multiplot diff --git a/examples/04-Icepak/Icepak_CSV_Import.py b/examples/04-Icepak/Icepak_CSV_Import.py index c6796835432..5b4bd223e10 100644 --- a/examples/04-Icepak/Icepak_CSV_Import.py +++ b/examples/04-Icepak/Icepak_CSV_Import.py @@ -13,7 +13,6 @@ import os import re import csv -from collections import OrderedDict import ansys.aedt.core from ansys.aedt.core.modules.boundary import BoundaryObject diff --git a/examples/04-Icepak/Icepak_ECAD_Import.py b/examples/04-Icepak/Icepak_ECAD_Import.py index a05900f4295..1bdbc73dc74 100644 --- a/examples/04-Icepak/Icepak_ECAD_Import.py +++ b/examples/04-Icepak/Icepak_ECAD_Import.py @@ -56,16 +56,8 @@ # ~~~~~~~~~~~~~~~~~~~~ # Sample *.bdf and *.ldf files are presented here. # -# -# .. image:: ../../_static/bdf.png -# :width: 400 -# :alt: BDF image. -# -# -# .. image:: ../../_static/ldf.png -# :width: 400 -# :alt: LDF image. -# +# +# # # Imports the idf files with several filtering options including caps, resistors, inductors, power, size, ... # There are also options for the PCB creation (number o flayers, copper percentages, layer sizes). diff --git a/examples/07-Circuit/Reports.py b/examples/07-Circuit/Reports.py index f9dc6556001..15fbe039666 100644 --- a/examples/07-Circuit/Reports.py +++ b/examples/07-Circuit/Reports.py @@ -32,7 +32,7 @@ # The Boolean parameter ``new_thread`` defines whether to create a new instance # of AEDT or try to connect to an existing instance of it. -non_graphical = True +non_graphical = False NewThread = True ############################################################################### diff --git a/examples/08-FilterSolutions/Lumped_Element_Response.py b/examples/08-FilterSolutions/Lumped_Element_Response.py index acb4a07e124..971463f3195 100644 --- a/examples/08-FilterSolutions/Lumped_Element_Response.py +++ b/examples/08-FilterSolutions/Lumped_Element_Response.py @@ -14,19 +14,19 @@ import ansys.aedt.core.filtersolutions_core.attributes from ansys.aedt.core.filtersolutions_core.attributes import FilterType, FilterClass, FilterImplementation from ansys.aedt.core.filtersolutions_core.ideal_response import FrequencyResponseColumn +from ansys.aedt.core.filtersolutions_core.export_to_aedt import PartLibraries, ExportFormat import matplotlib.pyplot as plt ############################################################################### # Create the lumped design # ~~~~~~~~~~~~~~~~~~~~~~~~ # Create a lumped element filter design and assign the class, type, frequency, and order. -design = ansys.aedt.core.FilterSolutions(version="2025.1", implementation_type= FilterImplementation.LUMPED) +design = ansys.aedt.core.FilterSolutions(version="2025.1", implementation_type= FilterImplementation.LUMPED) design.attributes.filter_class = FilterClass.BAND_PASS design.attributes.filter_type = FilterType.BUTTERWORTH design.attributes.pass_band_center_frequency = "1G" design.attributes.pass_band_width_frequency = "500M" design.attributes.filter_order = 5 - ############################################################################## # Plot the frequency response of the filter # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/pyproject.toml b/pyproject.toml index 300d7f76f59..0ab078c63fa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,7 +45,7 @@ dependencies = [ [project.optional-dependencies] tests = [ - "ipython>=7.30.0,<8.27", + "ipython>=7.30.0,<8.28", "joblib>=1.0.0,<1.5", "matplotlib>=3.5.0,<3.10", "mock>=5.1.0,<5.2", @@ -59,20 +59,20 @@ tests = [ "pyvista[io]>=0.38.0,<0.45", # Never directly imported but required when loading ML related file see #4713 "scikit-learn>=1.0.0,<1.6", - "scikit-rf>=0.30.0,<1.3", + "scikit-rf>=0.30.0,<1.4", "SRTM.py", "utm", ] dotnet = [ "ansys-pythonnet>=3.1.0rc3", - "cffi==1.17.0; platform_system=='Linux' and python_version == '3.7'", + "cffi==1.17.1; platform_system=='Linux' and python_version == '3.7'", "cffi>=1.16.0,<1.18; platform_system=='Linux' and python_version > '3.7'", "dotnetcore2==3.1.23; platform_system=='Linux'", "pywin32>=303; platform_system=='Windows'", ] doc = [ "ansys-sphinx-theme>=0.10.0,<1.1", - "ipython>=8.13.0,<8.27", + "ipython>=8.13.0,<8.28", "joblib>=1.3.0,<1.5", "jupyterlab>=4.0.0,<4.3", "matplotlib>=3.5.0,<3.10", @@ -84,10 +84,10 @@ doc = [ #"pytest-sphinx", "pyvista[io]>=0.38.0,<0.45", "recommonmark", - "scikit-rf>=0.30.0,<1.3", + "scikit-rf>=0.30.0,<1.4", "Sphinx>=7.1.0,<8.1", - "sphinx-autobuild==2021.3.14; python_version == '3.8'", - "sphinx-autobuild==2024.4.16; python_version > '3.8'", + "sphinx-autobuild==2024.9.3; python_version == '3.8'", + "sphinx-autobuild==2024.9.3; python_version > '3.8'", #"sphinx-autodoc-typehints", "sphinx-copybutton>=0.5.0,<0.6", "sphinx-gallery>=0.14.0,<0.18", @@ -102,8 +102,8 @@ doc-no-examples = [ "numpydoc>=1.5.0,<1.9", "recommonmark", "Sphinx>=7.1.0,<8.1", - "sphinx-autobuild==2021.3.14; python_version == '3.8'", - "sphinx-autobuild==2024.4.16; python_version > '3.8'", + "sphinx-autobuild==2024.9.3; python_version == '3.8'", + "sphinx-autobuild==2024.9.3; python_version > '3.8'", #"sphinx-autodoc-typehints", "sphinx-copybutton>=0.5.0,<0.6", "sphinx-gallery>=0.14.0,<0.18", @@ -111,7 +111,7 @@ doc-no-examples = [ #"sphinxcontrib-websupport", "sphinx_design>=0.4.0,<0.7", "matplotlib>=3.5.0,<3.10", - "scikit-rf>=0.30.0,<1.3", + "scikit-rf>=0.30.0,<1.4", "pyvista[io]>=0.38.0,<0.45", ] all = [ @@ -124,7 +124,7 @@ all = [ "fast-simplification>=0.1.7", # Never directly imported but required when loading ML related file see #4713 "scikit-learn>=1.0.0,<1.6", - "scikit-rf>=0.30.0,<1.3", + "scikit-rf>=0.30.0,<1.4", "SRTM.py", "utm", ] @@ -137,11 +137,11 @@ installer = [ "pyvista[io]>=0.38.0,<0.45", # Never directly imported but required when loading ML related file see #4713 "scikit-learn>=1.0.0,<1.6", - "scikit-rf>=0.30.0,<1.3", + "scikit-rf>=0.30.0,<1.4", "SRTM.py", "utm", "jupyterlab>=3.6.0,<4.3", - "ipython>=7.30.0,<8.27", + "ipython>=7.30.0,<8.28", "ipyvtklink>=0.2.0,<0.2.4", ] diff --git a/src/ansys/aedt/core/application/analysis.py b/src/ansys/aedt/core/application/analysis.py index ddafff07312..463b85af59c 100644 --- a/src/ansys/aedt/core/application/analysis.py +++ b/src/ansys/aedt/core/application/analysis.py @@ -31,7 +31,6 @@ from __future__ import absolute_import # noreorder -from collections import OrderedDict import os import re import shutil @@ -1037,12 +1036,12 @@ def _get_native_data(self): data_vals = self.design_properties["ModelSetup"]["GeometryCore"]["GeometryOperations"][ "SubModelDefinitions" ]["NativeComponentDefinition"] - if not isinstance(data_vals, list) and isinstance(data_vals, (OrderedDict, dict)): + if not isinstance(data_vals, list) and isinstance(data_vals, dict): data_vals = [data_vals] for ds in data_vals: try: component_name = "undefined" - if isinstance(ds, (OrderedDict, dict)): + if isinstance(ds, dict): component_type = ds["NativeComponentDefinitionProvider"]["Type"] component_name = ds["BasicComponentInfo"]["ComponentName"] if component_type == "PCB": @@ -1388,7 +1387,7 @@ def _create_setup(self, name="MySetupAuto", setup_type=None, props=None): # Handle the situation when ports have not been defined. if not self.excitations and "MaxDeltaS" in setup.props: - new_dict = OrderedDict() + new_dict = {} setup.auto_update = False for k, v in setup.props.items(): if k == "MaxDeltaS": diff --git a/src/ansys/aedt/core/application/design.py b/src/ansys/aedt/core/application/design.py index d3897399eeb..f4f9b846ba0 100644 --- a/src/ansys/aedt/core/application/design.py +++ b/src/ansys/aedt/core/application/design.py @@ -33,7 +33,6 @@ from __future__ import absolute_import # noreorder from abc import abstractmethod -from collections import OrderedDict import gc import json import os @@ -254,7 +253,7 @@ def __init__( self.last_run_job = "" self._design_dictionary = None # Get Desktop from global Desktop Environment - self._project_dictionary = OrderedDict() + self._project_dictionary = {} self._boundaries = {} self._project_datasets = {} self._design_datasets = {} @@ -609,7 +608,7 @@ def design_properties(self): if designs["Name"] == self.design_name: return designs except Exception: - return OrderedDict() + return {} @property def aedt_version_id(self): @@ -2357,7 +2356,7 @@ def _get_boundaries_data(self): if self.design_properties and "BoundarySetup" in self.design_properties: for ds in self.design_properties["BoundarySetup"]["Boundaries"]: try: - if isinstance(self.design_properties["BoundarySetup"]["Boundaries"][ds], (OrderedDict, dict)): + if isinstance(self.design_properties["BoundarySetup"]["Boundaries"][ds], dict): if ( self.design_properties["BoundarySetup"]["Boundaries"][ds]["BoundType"] == "Network" and self.design_type == "Icepak" @@ -2381,7 +2380,7 @@ def _get_boundaries_data(self): try: param = "MaxwellParameters" setup = "MaxwellParameterSetup" - if isinstance(self.design_properties[setup][param][ds], (OrderedDict, dict)): + if isinstance(self.design_properties[setup][param][ds], dict): boundaries.append( MaxwellParameters( self, @@ -2401,7 +2400,7 @@ def _get_boundaries_data(self): motion_list = "MotionSetupList" setup = "ModelSetup" # check moving part - if isinstance(self.design_properties[setup][motion_list][ds], (OrderedDict, dict)): + if isinstance(self.design_properties[setup][motion_list][ds], dict): boundaries.append( BoundaryObject( self, diff --git a/src/ansys/aedt/core/filtersolutions.py b/src/ansys/aedt/core/filtersolutions.py index 538de904614..0c6e6132aaa 100644 --- a/src/ansys/aedt/core/filtersolutions.py +++ b/src/ansys/aedt/core/filtersolutions.py @@ -25,14 +25,16 @@ import ansys.aedt.core from ansys.aedt.core.filtersolutions_core.attributes import Attributes from ansys.aedt.core.filtersolutions_core.attributes import FilterImplementation +from ansys.aedt.core.filtersolutions_core.export_to_aedt import ExportToAedt from ansys.aedt.core.filtersolutions_core.graph_setup import GraphSetup from ansys.aedt.core.filtersolutions_core.ideal_response import IdealResponse from ansys.aedt.core.filtersolutions_core.lumped_nodes_and_leads import LumpedNodesandLeads from ansys.aedt.core.filtersolutions_core.lumped_parasitics import LumpedParasitics -from ansys.aedt.core.filtersolutions_core.lumped_termination_impedance import LumpedTerminationImpedance -from ansys.aedt.core.filtersolutions_core.lumped_termination_impedance import TerminationType +from ansys.aedt.core.filtersolutions_core.lumped_termination_impedance_table import LumpedTerminationImpedance +from ansys.aedt.core.filtersolutions_core.lumped_termination_impedance_table import TerminationType from ansys.aedt.core.filtersolutions_core.lumped_topology import LumpedTopology from ansys.aedt.core.filtersolutions_core.multiple_bands_table import MultipleBandsTable +from ansys.aedt.core.filtersolutions_core.optimization_goals_table import OptimizationGoalsTable from ansys.aedt.core.filtersolutions_core.transmission_zeros import TableFormat from ansys.aedt.core.filtersolutions_core.transmission_zeros import TransmissionZeros @@ -87,3 +89,5 @@ def _init_lumped_design(self): self.multiple_bands_table = MultipleBandsTable() self.transmission_zeros_ratio = TransmissionZeros(TableFormat.RATIO) self.transmission_zeros_bandwidth = TransmissionZeros(TableFormat.BANDWIDTH) + self.export_to_aedt = ExportToAedt() + self.optimization_goals_table = OptimizationGoalsTable() diff --git a/src/ansys/aedt/core/filtersolutions_core/attributes.py b/src/ansys/aedt/core/filtersolutions_core/attributes.py index 3e6f524e550..78be0ec9ec1 100644 --- a/src/ansys/aedt/core/filtersolutions_core/attributes.py +++ b/src/ansys/aedt/core/filtersolutions_core/attributes.py @@ -45,8 +45,10 @@ class FilterType(Enum): - CHEBYSHEV_II: Represents a Chevyshev type II filter. - HOURGLASS: Represents an hourglass filter. - ELLIPTIC: Represents an elliptic filter. + - DELAY: Represents a delay filter. + - RAISED_COS: Represents a raised cosine filter. - Custom, raised-cos, and matched filter types are not available in this release. + Custom and matched filter types are not available in this release. """ GAUSSIAN = 0 @@ -58,10 +60,10 @@ class FilterType(Enum): HOURGLASS = 6 ELLIPTIC = 7 DELAY = 8 + RAISED_COS = 9 # CUSTOM = 8 -# RAISED_COS = 9 # MATCHED = 10 # DELAY = 11 @@ -135,6 +137,35 @@ class DiplexerType(Enum): TRIPLEXER_2 = 5 +class RaisedCosineAlphaPercentage(Enum): + """Provides an enum of alpha percentage for raised, root raised, or data transmission filters. + + **Attributes:** + + - FIFTEEN: 15% + - TWENTY: 20% + - TWENTY_FIVE: 25% + - THIRTY: 30% + - THIRTY_FIVE: 35% + - FORTY: 40% + - FORTY_FIVE: 45% + - FIFTY: 50% + - SEVENTY_FIVE: 75% + - HUNDRED: 100% + """ + + FIFTEEN = 0 + TWENTY = 1 + TWENTY_FIVE = 2 + THIRTY = 3 + THIRTY_FIVE = 4 + FORTY = 5 + FORTY_FIVE = 6 + FIFTY = 7 + SEVENTY_FIVE = 8 + HUNDRED = 9 + + class BesselRipplePercentage(Enum): """Provides an enum of peak-to-peak group delay ripple magnitudes as percents of averages for Bessel filters. @@ -251,7 +282,7 @@ class StopbandDefinition(Enum): class Attributes: """Defines attributes and parameters of filters. - This class allows you to construct all the necessary attributes for the ``FilterDesign`` class. + This class lets you construct all the necessary attributes for the ``FilterDesign`` class. """ def __init__(self): @@ -297,10 +328,35 @@ def _define_attributes_dll_functions(self): self._dll.getDiplexerType.argtypes = [c_char_p, c_int] self._dll.getDiplexerType.restype = c_int - self._dll.setDiplexerType.argtype = c_char_p - self._dll.setDiplexerType.restype = c_int - self._dll.getDiplexerType.argtypes = [c_char_p, c_int] - self._dll.getDiplexerType.restype = c_int + self._dll.setDiplexerInnerPassbandWidth.argtype = c_char_p + self._dll.setDiplexerInnerPassbandWidth.restype = c_int + self._dll.getDiplexerInnerPassbandWidth.argtypes = [c_char_p, c_int] + self._dll.getDiplexerInnerPassbandWidth.restype = c_int + + self._dll.setDiplexerOuterPassbandWidth.argtype = c_char_p + self._dll.setDiplexerOuterPassbandWidth.restype = c_int + self._dll.getDiplexerOuterPassbandWidth.argtypes = [c_char_p, c_int] + self._dll.getDiplexerOuterPassbandWidth.restype = c_int + + self._dll.setDiplexerLowerCenterFrequency.argtype = c_char_p + self._dll.setDiplexerLowerCenterFrequency.restype = c_int + self._dll.getDiplexerLowerCenterFrequency.argtypes = [c_char_p, c_int] + self._dll.getDiplexerLowerCenterFrequency.restype = c_int + + self._dll.setDiplexerUpperCenterFrequency.argtype = c_char_p + self._dll.setDiplexerUpperCenterFrequency.restype = c_int + self._dll.getDiplexerUpperCenterFrequency.argtypes = [c_char_p, c_int] + self._dll.getDiplexerUpperCenterFrequency.restype = c_int + + self._dll.setDiplexerLowerBandwidth.argtype = c_char_p + self._dll.setDiplexerLowerBandwidth.restype = c_int + self._dll.getDiplexerLowerBandwidth.argtypes = [c_char_p, c_int] + self._dll.getDiplexerLowerBandwidth.restype = c_int + + self._dll.setDiplexerUpperBandwidth.argtype = c_char_p + self._dll.setDiplexerUpperBandwidth.restype = c_int + self._dll.getDiplexerUpperBandwidth.argtypes = [c_char_p, c_int] + self._dll.getDiplexerUpperBandwidth.restype = c_int self._dll.setOrder.argtype = c_int self._dll.setOrder.restype = c_int @@ -393,15 +449,30 @@ def _define_attributes_dll_functions(self): self._dll.getEquirippleDelayEnabled.argtype = POINTER(c_bool) self._dll.getEquirippleDelayEnabled.restype = c_int + self._dll.setRootRaisedCosineEnabled.argtype = c_bool + self._dll.setRootRaisedCosineEnabled.restype = c_int + self._dll.getRootRaisedCosineEnabled.argtype = POINTER(c_bool) + self._dll.getRootRaisedCosineEnabled.restype = c_int + + self._dll.setDataTransmissionEnabled.argtype = c_bool + self._dll.setDataTransmissionEnabled.restype = c_int + self._dll.getDataTransmissionEnabled.argtype = POINTER(c_bool) + self._dll.getDataTransmissionEnabled.restype = c_int + + self._dll.setRaisedCosineAlphaPercentage.argtype = c_int + self._dll.setRaisedCosineAlphaPercentage.restype = c_int + self._dll.getRaisedCosineAlphaPercentage.argtype = POINTER(c_int) + self._dll.getRaisedCosineAlphaPercentage.restype = c_int + self._dll.setDelayRipplePeriod.argtype = c_char_p self._dll.setDelayRipplePeriod.restype = c_int self._dll.getDelayRipplePeriod.argtypes = [c_char_p, c_int] self._dll.getDelayRipplePeriod.restype = c_int - self._dll.setGroupDealyRipplePercentage.argtype = c_int - self._dll.setGroupDealyRipplePercentage.restype = c_int - self._dll.setGroupDealyRipplePercentage.argtype = POINTER(c_int) - self._dll.setGroupDealyRipplePercentage.restype = c_int + self._dll.setGroupDelayRipplePercentage.argtype = c_int + self._dll.setGroupDelayRipplePercentage.restype = c_int + self._dll.getGroupDelayRipplePercentage.argtype = POINTER(c_int) + self._dll.getGroupDelayRipplePercentage.restype = c_int self._dll.setCutoffAttenuationdB.argtype = c_char_p self._dll.setCutoffAttenuationdB.restype = c_int @@ -893,6 +964,110 @@ def upper_frequency(self) -> str: def upper_frequency(self, upper_freq_string): self._dll_interface.set_string(self._dll.setUpperFrequency, upper_freq_string) + @property + def diplexer_inner_band_width(self) -> str: + """Diplexer inner band width for ``BP1`` and ``Triplexer1`` diplexer types. + The default is ``200 MHz``. + + Returns + ------- + str + """ + diplexer_inner_band_width_string = self._dll_interface.get_string(self._dll.getDiplexerInnerPassbandWidth) + return diplexer_inner_band_width_string + + @diplexer_inner_band_width.setter + def diplexer_inner_band_width(self, diplexer_inner_band_width_string): + self._dll_interface.set_string(self._dll.setDiplexerInnerPassbandWidth, diplexer_inner_band_width_string) + + @property + def diplexer_outer_band_width(self) -> str: + """Diplexer outer band width for ``BP1`` and ``Triplexer1`` diplexer types. + The default is ``2 GHz``. + + Returns + ------- + str + """ + diplexer_outer_band_width_string = self._dll_interface.get_string(self._dll.getDiplexerOuterPassbandWidth) + return diplexer_outer_band_width_string + + @diplexer_outer_band_width.setter + def diplexer_outer_band_width(self, diplexer_outer_band_width_string): + self._dll_interface.set_string(self._dll.setDiplexerOuterPassbandWidth, diplexer_outer_band_width_string) + + @property + def diplexer_lower_center_frequency(self) -> str: + """Diplexer lower center frequency for ``BP2`` and ``Triplexer2`` diplexer types. + The default is ``500 MHz``. + + Returns + ------- + str + """ + diplexer_lower_center_frequency_string = self._dll_interface.get_string( + self._dll.getDiplexerLowerCenterFrequency + ) + return diplexer_lower_center_frequency_string + + @diplexer_lower_center_frequency.setter + def diplexer_lower_center_frequency(self, diplexer_lower_center_frequency_string): + self._dll_interface.set_string( + self._dll.setDiplexerLowerCenterFrequency, diplexer_lower_center_frequency_string + ) + + @property + def diplexer_upper_center_frequency(self) -> str: + """Diplexer upper center frequency for ``BP2`` and ``Triplexer2`` diplexer types. + The default is ``2 GHz``. + + Returns + ------- + str + """ + diplexer_upper_center_frequency_string = self._dll_interface.get_string( + self._dll.getDiplexerUpperCenterFrequency + ) + return diplexer_upper_center_frequency_string + + @diplexer_upper_center_frequency.setter + def diplexer_upper_center_frequency(self, diplexer_upper_center_frequency_string): + self._dll_interface.set_string( + self._dll.setDiplexerUpperCenterFrequency, diplexer_upper_center_frequency_string + ) + + @property + def diplexer_lower_band_width(self) -> str: + """Diplexer lower band width for ``BP2`` and ``Triplexer2`` diplexer types. + The default is ``500 MHz``. + + Returns + ------- + str + """ + diplexer_lower_band_width_string = self._dll_interface.get_string(self._dll.getDiplexerLowerBandwidth) + return diplexer_lower_band_width_string + + @diplexer_lower_band_width.setter + def diplexer_lower_band_width(self, diplexer_lower_band_width_string): + self._dll_interface.set_string(self._dll.setDiplexerLowerBandwidth, diplexer_lower_band_width_string) + + @property + def diplexer_upper_band_width(self) -> str: + """Diplexer upper band width for ``BP2`` and ``Triplexer2`` diplexer types. + The default is ``2 GHz``. + + Returns + ------- + str + """ + diplexer_upper_band_width_string = self._dll_interface.get_string(self._dll.getDiplexerUpperBandwidth) + return diplexer_upper_band_width_string + + @diplexer_upper_band_width.setter + def diplexer_upper_band_width(self, diplexer_upper_band_width_string): + self._dll_interface.set_string(self._dll.setDiplexerUpperBandwidth, diplexer_upper_band_width_string) + @property def stop_band_definition(self) -> StopbandDefinition: """Stop band parameter entry option. @@ -980,6 +1155,63 @@ def standard_pass_band_attenuation(self, standard_pass_band_attenuation: bool): status = self._dll.setStandardCutoffEnabled(standard_pass_band_attenuation) ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + @property + def root_raised_cosine(self) -> bool: + """Flag indicating if the root raised cosine is enabled. + + Returns + ------- + bool + """ + root_raised_cosine = c_bool() + status = self._dll.getRootRaisedCosineEnabled(byref(root_raised_cosine)) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + return bool(root_raised_cosine.value) + + @root_raised_cosine.setter + def root_raised_cosine(self, root_raised_cosine: bool): + status = self._dll.setRootRaisedCosineEnabled(root_raised_cosine) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + @property + def data_transmission_filter(self) -> bool: + """Flag indicating if the data transmission filter is enabled. + + Returns + ------- + bool + """ + data_transmission_filter = c_bool() + status = self._dll.getDataTransmissionEnabled(byref(data_transmission_filter)) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + return bool(data_transmission_filter.value) + + @data_transmission_filter.setter + def data_transmission_filter(self, data_transmission_filter: bool): + status = self._dll.setDataTransmissionEnabled(data_transmission_filter) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + @property + def raised_cosine_alpha_percentage(self) -> RaisedCosineAlphaPercentage: + """Raised cosine alpha percentage. + The default is ''FORTY''. + + Returns + ------- + :enum:`RaisedCosineAlphaPercentage` + """ + index = c_int() + raised_cosine_alpha_percentage = list(RaisedCosineAlphaPercentage) + status = self._dll.getRaisedCosineAlphaPercentage(byref(index)) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + raised_cosine_alpha_percentage = raised_cosine_alpha_percentage[index.value] + return raised_cosine_alpha_percentage + + @raised_cosine_alpha_percentage.setter + def raised_cosine_alpha_percentage(self, column: RaisedCosineAlphaPercentage): + status = self._dll.setRaisedCosineAlphaPercentage(column.value) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + @property def equiripple_delay(self) -> bool: """Flag indicating if the equiripple delay is enabled. @@ -1019,7 +1251,7 @@ def group_delay_ripple_period(self, group_delay_ripple_period_string): @property def normalized_group_delay_percentage(self) -> int: - """Bessel filter ripple percentage. + """Normalized group delay percentage. The default is ''0''. Returns @@ -1028,14 +1260,14 @@ def normalized_group_delay_percentage(self) -> int: """ index = c_int() normalized_group_delay_percentage = list(BesselRipplePercentage) - status = self._dll.getGroupDealyRipplePercentage(byref(index)) + status = self._dll.getGroupDelayRipplePercentage(byref(index)) ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) normalized_group_delay_percentage_string = normalized_group_delay_percentage[index.value] return normalized_group_delay_percentage_string @normalized_group_delay_percentage.setter def normalized_group_delay_percentage(self, column: BesselRipplePercentage): - status = self._dll.setGroupDealyRipplePercentage(column.value) + status = self._dll.setGroupDelayRipplePercentage(column.value) ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) @property @@ -1530,10 +1762,10 @@ def standard_delay_equ_pass_band_attenuation(self) -> bool: ------- bool """ - standard_dealy_equ_cut = c_bool() - status = self._dll.getStandardDelayEquCut(byref(standard_dealy_equ_cut)) + standard_delay_equ_cut = c_bool() + status = self._dll.getStandardDelayEquCut(byref(standard_delay_equ_cut)) ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) - return bool(standard_dealy_equ_cut.value) + return bool(standard_delay_equ_cut.value) @standard_delay_equ_pass_band_attenuation.setter def standard_delay_equ_pass_band_attenuation(self, standard_delay_equ_pass_band_attenuation: bool): diff --git a/src/ansys/aedt/core/filtersolutions_core/export_to_aedt.py b/src/ansys/aedt/core/filtersolutions_core/export_to_aedt.py new file mode 100644 index 00000000000..31241b1a7dc --- /dev/null +++ b/src/ansys/aedt/core/filtersolutions_core/export_to_aedt.py @@ -0,0 +1,1759 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2021 - 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 ctypes import POINTER +from ctypes import byref +from ctypes import c_bool +from ctypes import c_char_p +from ctypes import c_int +from ctypes import create_string_buffer +from enum import Enum +import os +from typing import Union + +import ansys.aedt.core + + +class ExportFormat(Enum): + """Provides an enum of export format types. + + **Attributes:** + + - DIRECT_TO_AEDT: Represents a direct export to ``AEDT``. + - PYTHON: Represents a Python scripted export. + """ + + DIRECT_TO_AEDT = 0 + PYTHON_SCRIPT = 1 + + +class ExportCreationMode(Enum): + """Provides an enum of export creation modes. + + **Attributes:** + + - OVERWRITE: Represents export to ``AEDT`` and overwrite to existing design. + - APPEND: Represents export to ``AEDT`` and append to existing design. + """ + + OVERWRITE = 0 + APPEND = 1 + + +class PartLibraries(Enum): + """Provides an enum of export format types. + + **Attributes:** + + - LUMPED = Represents a lumped part library. + - INTERCONNECT_ONLY = Represents an interconnect only part library. + - MODELITHICS = Represents a ``Modelithics`` part library. + """ + + LUMPED = 0 + INTERCONNECT = 1 + MODELITHICS = 2 + + +class SubstrateType(Enum): + """Provides an enum of substrate types for various materials. + + **Attributes:** + + - RGLC = Represents a RGLC substrate type. + - STRIPLINE = Represents a stripline substrate type. + - MICROSTRIP = Represents a microstrip substrate type. + - SUSPEND = Represents a suspended substrate type. + - INVERTED = Represents an inverted substrate type. + """ + + RGLC = 0 + STRIPLINE = 1 + MICROSTRIP = 2 + SUSPEND = 3 + INVERTED = 4 + + +class SubstrateEr(Enum): + """Provides an enum of substrate relative permitivity (``Er``) for various materials.. + The enum values represent common materials used in substrates and their associated ``Er`` value. + + **Attributes:** + + - AIR = Represents air substrate with an ``Er`` of ``1.00``. + - ALUMINA = Represents alumina substrate with an ``Er`` of ``9.8``. + - GA_AS = Represents Gallium Arsenide substrate with an ``Er`` of ``12.9``. + - GERMANIUM = Represents Germanium substrate with an ``Er`` of ``16.0``. + - INDIUM_PHOSPHATE = Represents Indium Phosphate substrate with an ``Er`` of ``12.4``. + - SILICON = Represents Silicon substrate with an ``Er`` of ``11.7``. + - QUARTZ = Represents Quartz substrate with an ``Er`` of ``3.78``. + - RT_DUROID_5880 = Represents RT Duroid 5880 substrate with an ``Er`` of ``2.2``. + - RT_DUROID_5870 = Represents RT Duroid 5870 substrate with an ``Er`` of ``2.33``. + - RT_DUROID_6006 = Represents RT Duroid 6006 substrate with an ``Er`` of ``6.15``. + - G_10_LOW_RESIN = Represents G-10 Low Resin substrate with an ``Er`` of ``4.8``. + - G_10_HIGH_RESIN = Represents G-10 High Resin substrate with an ``Er`` of ``3.5``. + - PAPER_PHONELIC = Represents Paper Phenolic substrate with an ``Er`` of ``4.5``. + - POLYTHYLENE = Represents Polyethylene substrate with an ``Er`` of ``2.25``. + - POLYSTYRENE = Represents Polystyrene substrate with an ``Er`` of ``2.56``. + - CORNING_GLASS_7059 = Represents Corning Glass 7059 substrate with an ``Er`` of ``7.9``. + - BERYLIUM_OXIDE = Represents Beryllium Oxide substrate with an ``Er`` of ``6.7``. + """ + + AIR = 0 + ALUMINA = 1 + GA_AS = 2 + GERMANIUM = 3 + INDIUM_PHOSPHATE = 4 + SILICON = 5 + QUARTZ = 6 + RT_DUROID_5880 = 7 + RT_DUROID_5870 = 8 + RT_DUROID_6006 = 9 + G_10_LOW_RESIN = 10 + G_10_HIGH_RESIN = 11 + PAPER_PHONELIC = 12 + POLYTHYLENE = 13 + POLYSTYRENE = 14 + CORNING_GLASS_7059 = 15 + BERYLIUM_OXIDE = 16 + + +class SubstrateResistivity(Enum): + """Provides an enum of substrate resistivity types for various materials. + The enum values represent common materials used in substrates and their associated resistivity index. + + **Attributes:** + + - IDEAL: Represents an ideal, perfect conductor, ``0`` with respect to copper resistivity. + - SILVER: Represents Silver resitivity, ``0.95`` with respect to copper resistivity. + - COPPER: Represents Copper, ``1.00`` as referernce resistivity. + - GOLD: Represents Gold, ``1.43`` with respect to copper resistivity. + - ALUMINUM: Represents Aluminum, ``1.67`` with respect to copper resistivity. + - MAGNESIUM: Represents Magnesium, ``2.67`` with respect to copper resistivity. + - TUNGSTEN: Represents Tungsten, ``3.23`` with respect to copper resistivity. + - ZINC: Represents Zinc, ``3.56`` with respect to copper resistivity. + - NICKEL: Represents Nickel, ``4.00`` with respect to copper resistivity. + - IRON: Represents Iron, ``5.80`` with respect to copper resistivity. + - PLATINUM: Represents Platinum, ``6.34`` with respect to copper resistivity. + """ + + IDEAL = 0 + SILVER = 1 + COPPER = 2 + GOLD = 3 + ALUMINUM = 4 + MAGNESIUM = 5 + TUNGSTEN = 6 + ZINC = 7 + NICKEL = 8 + IRON = 9 + PLATINUM = 10 + + +class ExportToAedt: + """Defines attributes and parameters for exporting filter . + + This class lets you construct all the necessary attributes for the ``ExportToAedt`` class. + """ + + def __init__(self): + self._dll = ansys.aedt.core.filtersolutions_core._dll_interface()._dll + self._dll_interface = ansys.aedt.core.filtersolutions_core._dll_interface() + self._define_export_to_desktop_dll_functions() + self._substrate_er = SubstrateEr.AIR.value # Default to AIR's Er value + + def _define_export_to_desktop_dll_functions(self): + """Define C++ API DLL functions.""" + + self._dll.setSchematicName.argtype = c_char_p + self._dll.setSchematicName.restype = c_int + self._dll.getSchematicName.argtypes = [c_char_p, c_int] + self._dll.getSchematicName.restype = c_int + + self._dll.setSimulateAfterExport.argtype = c_bool + self._dll.setSimulateAfterExport.restype = c_int + self._dll.getSimulateAfterExport.argtype = POINTER(c_bool) + self._dll.getSimulateAfterExport.restype = c_int + + self._dll.setGroupDelay.argtype = c_bool + self._dll.setGroupDelay.restype = c_int + self._dll.getGroupDelay.argtype = POINTER(c_bool) + self._dll.getGroupDelay.restype = c_int + + self._dll.setGTGain.argtype = c_bool + self._dll.setGTGain.restype = c_int + self._dll.getGTGain.argtype = POINTER(c_bool) + self._dll.getGTGain.restype = c_int + + self._dll.setVGSL.argtype = c_bool + self._dll.setVGSL.restype = c_int + self._dll.getVGSL.argtype = POINTER(c_bool) + self._dll.getVGSL.restype = c_int + + self._dll.setVGIN.argtype = c_bool + self._dll.setVGIN.restype = c_int + self._dll.getVGIN.argtype = POINTER(c_bool) + self._dll.getVGIN.restype = c_int + + self._dll.setS11.argtype = c_bool + self._dll.setS11.restype = c_int + self._dll.getS11.argtype = POINTER(c_bool) + self._dll.getS11.restype = c_int + + self._dll.setS21.argtype = c_bool + self._dll.setS21.restype = c_int + self._dll.getS21.argtype = POINTER(c_bool) + self._dll.getS21.restype = c_int + + self._dll.setS12.argtype = c_bool + self._dll.setS12.restype = c_int + self._dll.getS12.argtype = POINTER(c_bool) + self._dll.getS12.restype = c_int + + self._dll.setS22.argtype = c_bool + self._dll.setS22.restype = c_int + self._dll.getS22.argtype = POINTER(c_bool) + self._dll.getS22.restype = c_int + + self._dll.setDbFormat.argtype = c_bool + self._dll.setDbFormat.restype = c_int + self._dll.getDbFormat.argtype = POINTER(c_bool) + self._dll.getDbFormat.restype = c_int + + self._dll.setRectPlot.argtype = c_bool + self._dll.setRectPlot.restype = c_int + self._dll.getRectPlot.argtype = POINTER(c_bool) + self._dll.getRectPlot.restype = c_int + + self._dll.setSmithPlot.argtype = c_bool + self._dll.setSmithPlot.restype = c_int + self._dll.getSmithPlot.argtype = POINTER(c_bool) + self._dll.getSmithPlot.restype = c_int + + self._dll.setPolarPlot.argtype = c_bool + self._dll.setPolarPlot.restype = c_int + self._dll.getPolarPlot.argtype = POINTER(c_bool) + self._dll.getPolarPlot.restype = c_int + + self._dll.setTableData.argtype = c_bool + self._dll.setTableData.restype = c_int + self._dll.getTableData.argtype = POINTER(c_bool) + self._dll.getTableData.restype = c_int + + self._dll.setOptimetrics.argtype = c_bool + self._dll.setOptimetrics.restype = c_int + self._dll.getOptimetrics.argtype = POINTER(c_bool) + self._dll.getOptimetrics.restype = c_int + + self._dll.setOptimizeAfterExport.argtype = c_bool + self._dll.setOptimizeAfterExport.restype = c_int + self._dll.getOptimizeAfterExport.argtype = POINTER(c_bool) + self._dll.getOptimizeAfterExport.restype = c_int + + self._dll.loadLibraryPartsConf.argtype = c_char_p + self._dll.loadLibraryPartsConf.restype = c_int + + self._dll.saveLibraryPartsConf.argtype = c_char_p + self._dll.saveLibraryPartsConf.restype = c_int + + self._dll.importTunedVariablesSize.argtype = POINTER(c_int) + self._dll.importTunedVariablesSize.restype = c_int + self._dll.importTunedVariables.argtypes = [c_char_p, c_int] + self._dll.importTunedVariables.restype = c_int + + def _open_aedt_export(self): + """Open export page to accept manipulate export parameters""" + status = self._dll.openLumpedExportPage() + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + self._dll.setPartLibraries.argtype = c_int + self._dll.setPartLibraries.restype = c_int + self._dll.getPartLibraries.argtype = POINTER(c_int) + self._dll.getPartLibraries.restype = c_int + + self._dll.setLengthToWidthRatio.argtype = c_char_p + self._dll.setLengthToWidthRatio.restype = c_int + self._dll.getLengthToWidthRatio.argtypes = [c_char_p, c_int] + self._dll.getLengthToWidthRatio.restype = c_int + + self._dll.setLowerLengthGeometricLimitRatio.argtype = c_char_p + self._dll.setLowerLengthGeometricLimitRatio.restype = c_int + self._dll.getLowerLengthGeometricLimitRatio.argtypes = [c_char_p, c_int] + self._dll.getLowerLengthGeometricLimitRatio.restype = c_int + + self._dll.setUpperLengthGeometricLimitRatio.argtype = c_char_p + self._dll.setUpperLengthGeometricLimitRatio.restype = c_int + self._dll.getUpperLengthGeometricLimitRatio.argtypes = [c_char_p, c_int] + self._dll.getUpperLengthGeometricLimitRatio.restype = c_int + + self._dll.setLineWidthToTerminationWidthRatio.argtype = c_char_p + self._dll.setLineWidthToTerminationWidthRatio.restype = c_int + self._dll.getLineWidthToTerminationWidthRatio.argtypes = [c_char_p, c_int] + self._dll.getLineWidthToTerminationWidthRatio.restype = c_int + + self._dll.setLowerWidthGeometricLimitRatio.argtype = c_char_p + self._dll.setLowerWidthGeometricLimitRatio.restype = c_int + self._dll.getLowerWidthGeometricLimitRatio.argtypes = [c_char_p, c_int] + self._dll.getLowerWidthGeometricLimitRatio.restype = c_int + + self._dll.setUpperWidthGeometricLimitRatio.argtype = c_char_p + self._dll.setUpperWidthGeometricLimitRatio.restype = c_int + self._dll.getUpperWidthGeometricLimitRatio.argtypes = [c_char_p, c_int] + self._dll.getUpperWidthGeometricLimitRatio.restype = c_int + + self._dll.setLengthToWidthValue.argtype = c_char_p + self._dll.setLengthToWidthValue.restype = c_int + self._dll.getLengthToWidthValue.argtypes = [c_char_p, c_int] + self._dll.getLengthToWidthValue.restype = c_int + + self._dll.setLowerLengthGeometricLimitValue.argtype = c_char_p + self._dll.setLowerLengthGeometricLimitValue.restype = c_int + self._dll.getLowerLengthGeometricLimitValue.argtypes = [c_char_p, c_int] + self._dll.getLowerLengthGeometricLimitValue.restype = c_int + + self._dll.setUpperLengthGeometricLimitValue.argtype = c_char_p + self._dll.setUpperLengthGeometricLimitValue.restype = c_int + self._dll.getUpperLengthGeometricLimitValue.argtypes = [c_char_p, c_int] + self._dll.getUpperLengthGeometricLimitValue.restype = c_int + + self._dll.setLineWidthToTerminationWidthValue.argtype = c_char_p + self._dll.setLineWidthToTerminationWidthValue.restype = c_int + self._dll.getLineWidthToTerminationWidthValue.argtypes = [c_char_p, c_int] + self._dll.getLineWidthToTerminationWidthValue.restype = c_int + + self._dll.setLowerWidthGeometricLimitValue.argtype = c_char_p + self._dll.setLowerWidthGeometricLimitValue.restype = c_int + self._dll.getLowerWidthGeometricLimitValue.argtypes = [c_char_p, c_int] + self._dll.getLowerWidthGeometricLimitValue.restype = c_int + + self._dll.setUpperWidthGeometricLimitValue.argtype = c_char_p + self._dll.setUpperWidthGeometricLimitValue.restype = c_int + self._dll.getUpperWidthGeometricLimitValue.argtypes = [c_char_p, c_int] + self._dll.getUpperWidthGeometricLimitValue.restype = c_int + + self._dll.setInterConnectInductorTolerance.argtype = c_char_p + self._dll.setInterConnectInductorTolerance.restype = c_int + self._dll.getInterConnectInductorTolerance.argtypes = [c_char_p, c_int] + self._dll.getInterConnectInductorTolerance.restype = c_int + + self._dll.setInterConnectCapacitorTolerance.argtype = c_char_p + self._dll.setInterConnectCapacitorTolerance.restype = c_int + self._dll.getInterConnectCapacitorTolerance.argtypes = [c_char_p, c_int] + self._dll.getInterConnectCapacitorTolerance.restype = c_int + + self._dll.setInterconnectGeometryOptimization.argtype = c_bool + self._dll.setInterconnectGeometryOptimization.restype = c_int + self._dll.getInterconnectGeometryOptimization.argtype = POINTER(c_bool) + self._dll.getInterconnectGeometryOptimization.restype = c_int + + self._dll.setSubstrateType.argtype = c_char_p + self._dll.setSubstrateType.restype = int + self._dll.getSubstrateType.argtypes = [c_char_p, c_int] + self._dll.getSubstrateType.restype = int + + self._dll.setEr.argtype = [c_char_p, c_int] + self._dll.setEr.restype = c_int + self._dll.getEr.argtype = [c_char_p, POINTER(c_int), c_int] + self._dll.getEr.restype = c_int + + self._dll.setResistivity.argtype = [c_char_p, c_int] + self._dll.setResistivity.restype = c_int + self._dll.getResistivity.argtype = [c_char_p, POINTER(c_int), c_int] + self._dll.getResistivity.restype = c_int + + self._dll.setLossTangent.argtype = [c_char_p, c_int] + self._dll.setLossTangent.restype = c_int + self._dll.getLossTangent.argtype = [c_char_p, POINTER(c_int), c_int] + self._dll.getLossTangent.restype = c_int + + self._dll.setConductorThickness.argtype = c_char_p + self._dll.setConductorThickness.restype = c_int + self._dll.getConductorThickness.argtypes = [c_char_p, c_int] + self._dll.getConductorThickness.restype = c_int + + self._dll.setDielectricHeight.argtype = c_char_p + self._dll.setDielectricHeight.restype = c_int + self._dll.getDielectricHeight.argtypes = [c_char_p, c_int] + self._dll.getDielectricHeight.restype = c_int + + self._dll.setLowerDielectricHeight.argtype = c_char_p + self._dll.setLowerDielectricHeight.restype = c_int + self._dll.getLowerDielectricHeight.argtypes = [c_char_p, c_int] + self._dll.getLowerDielectricHeight.restype = c_int + + self._dll.setSuspendDielectricHeight.argtype = c_char_p + self._dll.setSuspendDielectricHeight.restype = c_int + self._dll.getSuspendDielectricHeight.argtypes = [c_char_p, c_int] + self._dll.getSuspendDielectricHeight.restype = c_int + + self._dll.setCoverHeight.argtype = c_char_p + self._dll.setCoverHeight.restype = c_int + self._dll.getCoverHeight.argtypes = [c_char_p, c_int] + self._dll.getCoverHeight.restype = c_int + + self._dll.setUnbalancedStripLine.argtype = c_bool + self._dll.setUnbalancedStripLine.restype = c_int + self._dll.getUnbalancedStripLine.argtype = POINTER(c_bool) + self._dll.getUnbalancedStripLine.restype = c_int + + self._dll.setGroundedCoverAboveLine.argtype = c_bool + self._dll.setGroundedCoverAboveLine.restype = c_int + self._dll.getGroundedCoverAboveLine.argtype = POINTER(c_bool) + self._dll.getGroundedCoverAboveLine.restype = c_int + + self._dll.setModelithicsIncludeInterconnect.argtype = c_bool + self._dll.setModelithicsIncludeInterconnect.restype = c_int + self._dll.getModelithicsIncludeInterconnect.argtype = POINTER(c_bool) + self._dll.getModelithicsIncludeInterconnect.restype = c_int + + self._dll.getModelithicsInductorsListCount.argtype = POINTER(c_int) + self._dll.getModelithicsInductorsListCount.restype = c_int + + self._dll.getModelithicsInductorsList.argtype = [c_int, c_char_p, c_int] + self._dll.getModelithicsInductorsList.restype = c_int + + self._dll.setModelithicsInductors.argtype = c_char_p + self._dll.setModelithicsInductors.restype = c_int + self._dll.getModelithicsInductors.argtypes = [c_char_p, c_int] + self._dll.getModelithicsInductors.restype = c_int + + self._dll.getModelithicsInductorsFamilyListCount.argtype = POINTER(c_int) + self._dll.getModelithicsInductorsFamilyListCount.restype = c_int + + self._dll.getModelithicsInductorsFamilyList.argtype = [c_int, c_char_p, c_int] + self._dll.getModelithicsInductorsFamilyList.restype = c_int + + self._dll.addModelithicsInductorsFamily.argtype = c_char_p + self._dll.addModelithicsInductorsFamily.restype = c_int + + self._dll.removeModelithicsInductorsFamily.argtype = c_char_p + self._dll.removeModelithicsInductorsFamily.restype = c_int + + self._dll.getModelithicsCapacitorsListCount.argtype = POINTER(c_int) + self._dll.getModelithicsCapacitorsListCount.restype = c_int + + self._dll.getModelithicsCapacitorsList.argtype = [c_int, c_char_p, c_int] + self._dll.getModelithicsCapacitorsList.restype = c_int + + self._dll.setModelithicsCapacitors.argtype = c_char_p + self._dll.setModelithicsCapacitors.restype = c_int + self._dll.getModelithicsCapacitors.argtypes = [c_char_p, c_int] + self._dll.getModelithicsCapacitors.restype = c_int + + self._dll.getModelithicsCapacitorsFamilyListCount.argtype = POINTER(c_int) + self._dll.getModelithicsCapacitorsFamilyListCount.restype = c_int + + self._dll.getModelithicsCapacitorsFamilyList.argtype = [c_int, c_char_p, c_int] + self._dll.getModelithicsCapacitorsFamilyList.restype = c_int + + self._dll.addModelithicsCapacitorsFamily.argtype = c_char_p + self._dll.addModelithicsCapacitorsFamily.restype = c_int + + self._dll.removeModelithicsCapacitorsFamily.argtype = c_char_p + self._dll.removeModelithicsCapacitorsFamily.restype = c_int + + self._dll.getModelithicsResistorsListCount.argtype = POINTER(c_int) + self._dll.getModelithicsResistorsListCount.restype = c_int + + self._dll.getModelithicsResistorsList.argtype = [c_int, c_char_p, c_int] + self._dll.getModelithicsResistorsList.restype = c_int + + self._dll.setModelithicsResistors.argtype = c_char_p + self._dll.setModelithicsResistors.restype = c_int + self._dll.getModelithicsResistors.argtypes = [c_char_p, c_int] + self._dll.getModelithicsResistors.restype = c_int + + self._dll.getModelithicsResistorsFamilyListCount.argtype = POINTER(c_int) + self._dll.getModelithicsResistorsFamilyListCount.restype = c_int + + self._dll.getModelithicsResistorsFamilyList.argtype = [c_int, c_char_p, c_int] + self._dll.getModelithicsResistorsFamilyList.restype = c_int + + self._dll.addModelithicsResistorsFamily.argtype = c_char_p + self._dll.addModelithicsResistorsFamily.restype = c_int + self._dll.removeModelithicsResistorsFamily.argtype = c_char_p + self._dll.removeModelithicsResistorsFamily.restype = c_int + + @property + def schematic_name(self) -> str: + """Name of the exported schematic in ``AEDT``, displayed as the project and design names. + The default name is ``FilterSolutions`` if not specified. + + + Returns + ------- + str + """ + schematic_name_string = self._dll_interface.get_string(self._dll.getSchematicName) + return schematic_name_string + + @schematic_name.setter + def schematic_name(self, schematic_name_string): + self._dll_interface.set_string(self._dll.setSchematicName, schematic_name_string) + + @property + def simulate_after_export_enabled(self) -> bool: + """Flag indicating if the simulation will be initiated upon export to ``AEDT``. + + Returns + ------- + bool + """ + simulate_after_export_enabled = c_bool() + status = self._dll.getSimulateAfterExport(byref(simulate_after_export_enabled)) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + return bool(simulate_after_export_enabled.value) + + @simulate_after_export_enabled.setter + def simulate_after_export_enabled(self, simulate_after_export_enabled: bool): + status = self._dll.setSimulateAfterExport(simulate_after_export_enabled) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + @property + def include_group_delay_enabled(self) -> bool: + """Flag indicating if the group delay report will be created upon export to ``AEDT``. + + Returns + ------- + bool + """ + include_group_delay_enabled = c_bool() + status = self._dll.getGroupDelay(byref(include_group_delay_enabled)) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + return bool(include_group_delay_enabled.value) + + @include_group_delay_enabled.setter + def include_group_delay_enabled(self, include_group_delay_enabled: bool): + status = self._dll.setGroupDelay(include_group_delay_enabled) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + @property + def include_gt_gain_enabled(self) -> bool: + """Flag indicating if the total voltage gain report will be created upon + export to ``AEDT``. + + Returns + ------- + bool + """ + include_gt_gain_enabled = c_bool() + status = self._dll.getGTGain(byref(include_gt_gain_enabled)) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + return bool(include_gt_gain_enabled.value) + + @include_gt_gain_enabled.setter + def include_gt_gain_enabled(self, include_gt_gain_enabled: bool): + status = self._dll.setGTGain(include_gt_gain_enabled) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + @property + def include_vgsl_enabled(self) -> bool: + """Flag indicating if the voltage gain source load report will be created upon + export to ``AEDT``. + + Returns + ------- + bool + """ + include_vgsl_enabled = c_bool() + status = self._dll.getVGSL(byref(include_vgsl_enabled)) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + return bool(include_vgsl_enabled.value) + + @include_vgsl_enabled.setter + def include_vgsl_enabled(self, include_vgsl_enabled: bool): + status = self._dll.setVGSL(include_vgsl_enabled) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + @property + def include_vgin_enabled(self) -> bool: + """Flag indicating if the voltage gain insertion report will be created upon + export to ``AEDT``. + + Returns + ------- + bool + """ + include_vgin_enabled = c_bool() + status = self._dll.getVGIN(byref(include_vgin_enabled)) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + return bool(include_vgin_enabled.value) + + @include_vgin_enabled.setter + def include_vgin_enabled(self, include_vgin_enabled: bool): + status = self._dll.setVGIN(include_vgin_enabled) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + @property + def include_input_return_loss_s11_enabled(self) -> bool: + """Flag indicating if the input return loss report will be created upon + export to ``AEDT``. + + Returns + ------- + bool + """ + include_input_return_loss_s11_enabled = c_bool() + status = self._dll.getS11(byref(include_input_return_loss_s11_enabled)) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + return bool(include_input_return_loss_s11_enabled.value) + + @include_input_return_loss_s11_enabled.setter + def include_input_return_loss_s11_enabled(self, include_input_return_loss_s11_enabled: bool): + status = self._dll.setS11(include_input_return_loss_s11_enabled) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + @property + def include_forward_transfer_s21_enabled(self) -> bool: + """Flag indicating if the forward transfer gain report will be created upon + export to ``AEDT``. + + Returns + ------- + bool + """ + include_forward_transfer_s21_enabled = c_bool() + status = self._dll.getS21(byref(include_forward_transfer_s21_enabled)) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + return bool(include_forward_transfer_s21_enabled.value) + + @include_forward_transfer_s21_enabled.setter + def include_forward_transfer_s21_enabled(self, include_forward_transfer_s21_enabled: bool): + status = self._dll.setS21(include_forward_transfer_s21_enabled) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + @property + def include_reverse_transfer_s12_enabled(self) -> bool: + """Flag indicating if the reverse transfer gain report will be created upon + export to ``AEDT``. + + Returns + ------- + bool + """ + include_reverse_transfer_s12_enabled = c_bool() + status = self._dll.getS12(byref(include_reverse_transfer_s12_enabled)) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + return bool(include_reverse_transfer_s12_enabled.value) + + @include_reverse_transfer_s12_enabled.setter + def include_reverse_transfer_s12_enabled(self, include_reverse_transfer_s12_enabled: bool): + status = self._dll.setS12(include_reverse_transfer_s12_enabled) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + @property + def include_output_return_loss_s22_enabled(self) -> bool: + """Flag indicating if the output return loss report will be created upon + export to ``AEDT``. + + Returns + ------- + bool + """ + include_output_return_loss_s22_enabled = c_bool() + status = self._dll.getS22(byref(include_output_return_loss_s22_enabled)) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + return bool(include_output_return_loss_s22_enabled.value) + + @include_output_return_loss_s22_enabled.setter + def include_output_return_loss_s22_enabled(self, include_output_return_loss_s22_enabled: bool): + status = self._dll.setS22(include_output_return_loss_s22_enabled) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + @property + def db_format_enabled(self) -> bool: + """Flag indicating if the report format in dB in the + exported filter to ``AEDT`` is enabled. + + Returns + ------- + bool + """ + db_format_enabled = c_bool() + status = self._dll.getDbFormat(byref(db_format_enabled)) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + return bool(db_format_enabled.value) + + @db_format_enabled.setter + def db_format_enabled(self, db_format_enabled: bool): + status = self._dll.setDbFormat(db_format_enabled) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + @property + def rectangular_plot_enabled(self) -> bool: + """Flag indicating if the rectangular report format in the + exported filter to ``AEDT`` is enabled. + + Returns + ------- + bool + """ + rectangular_plot_enabled = c_bool() + status = self._dll.getRectPlot(byref(rectangular_plot_enabled)) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + return bool(rectangular_plot_enabled.value) + + @rectangular_plot_enabled.setter + def rectangular_plot_enabled(self, rectangular_plot_enabled: bool): + status = self._dll.setRectPlot(rectangular_plot_enabled) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + @property + def smith_plot_enabled(self) -> bool: + """Flag indicating if the ``Smith Chart`` report format in the + exported filter to ``AEDT`` is enabled. + + Returns + ------- + bool + """ + smith_plot_enabled = c_bool() + status = self._dll.getSmithPlot(byref(smith_plot_enabled)) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + return bool(smith_plot_enabled.value) + + @smith_plot_enabled.setter + def smith_plot_enabled(self, smith_plot_enabled: bool): + status = self._dll.setSmithPlot(smith_plot_enabled) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + @property + def polar_plot_enabled(self) -> bool: + """Flag indicating if the polar report format in the + exported filter to ``AEDT`` is enabled. + + Returns + ------- + bool + """ + polar_plot_enabled = c_bool() + status = self._dll.getPolarPlot(byref(polar_plot_enabled)) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + return bool(polar_plot_enabled.value) + + @polar_plot_enabled.setter + def polar_plot_enabled(self, polar_plot_enabled: bool): + status = self._dll.setPolarPlot(polar_plot_enabled) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + @property + def table_data_enabled(self) -> bool: + """Flag indicating if the table data format in the + exported filter to ``AEDT`` is enabled. + + Returns + ------- + bool + """ + table_data_enabled = c_bool() + status = self._dll.getTableData(byref(table_data_enabled)) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + return bool(table_data_enabled.value) + + @table_data_enabled.setter + def table_data_enabled(self, table_data_enabled: bool): + status = self._dll.setTableData(table_data_enabled) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + @property + def optimitrics_enabled(self) -> bool: + """Flag indicating if the optimitric parameters in the + exported filter to ``AEDT`` is enabled. + + Returns + ------- + bool + """ + optimitrics_enabled = c_bool() + status = self._dll.getOptimetrics(byref(optimitrics_enabled)) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + return bool(optimitrics_enabled.value) + + @optimitrics_enabled.setter + def optimitrics_enabled(self, optimitrics_enabled: bool): + status = self._dll.setOptimetrics(optimitrics_enabled) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + @property + def optimize_after_export_enabled(self) -> bool: + """Flag indicating if the optimization after exporting to ``AEDT`` is enabled. + + Returns + ------- + bool + """ + optimize_after_export_enabled = c_bool() + status = self._dll.getOptimizeAfterExport(byref(optimize_after_export_enabled)) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + return bool(optimize_after_export_enabled.value) + + @optimize_after_export_enabled.setter + def optimize_after_export_enabled(self, optimize_after_export_enabled: bool): + status = self._dll.setOptimizeAfterExport(optimize_after_export_enabled) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + def export_design(self, export_format=None, export_creation_mode=None, export_path=None): + """Export the design directly to ``AEDT` or generate a ``Python`` script for exporting. + When exporting to ``AEDT``, the design can either be appended to an existing project or overwrite it. + When generating a Python script, the script is created and saved to the specified file location. + + Parameters + ---------- + export_format : `ExportFormat` + The export format type. + The default is ``None``. + design_creation_mode : `ExportCreationMode` + The design creation mode. + The default is ``None``. + export_path : str + The export path for Python script. + The default is ``None``. + """ + if export_format is None: + export_format = ExportFormat.DIRECT_TO_AEDT + if export_creation_mode is None: + export_creation_mode = ExportCreationMode.OVERWRITE + if export_path is None: + export_path = "" + else: + directory_path = os.path.dirname(export_path) + if not os.path.exists(directory_path): + os.makedirs(directory_path) + export_path_bytes = bytes(export_path, "ascii") + status = self._dll.exportDesign(export_format.value, export_creation_mode.value, export_path_bytes) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + def load_library_parts_config(self, load_library_parts_config_string): + self._dll_interface.set_string(self._dll.loadLibraryPartsConf, load_library_parts_config_string) + + def save_library_parts_config(self, save_library_parts_config_string): + self._dll_interface.set_string(self._dll.saveLibraryPartsConf, save_library_parts_config_string) + + def import_tuned_variables(self): + """Imported ``AEDT`` tuned parameter variables back into the ``FilterSolutions`` project.""" + size = c_int() + status = self._dll.importTunedVariablesSize(byref(size)) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + circuit_response_string = self._dll_interface.get_string(self._dll.importTunedVariables, max_size=size.value) + return circuit_response_string + + @property + def part_libraries(self) -> PartLibraries: + """Part libraries selection. The default is ``LUMPED``. + The ``PartLibraries`` enum provides a list of all options. + + Returns + ------- + :enum:`PartLibraries` + + """ + index = c_int() + part_libraries_list = list(PartLibraries) + status = self._dll.getPartLibraries(byref(index)) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + part_libraries = part_libraries_list[index.value] + return part_libraries + + @part_libraries.setter + def part_libraries(self, library_type: PartLibraries): + status = self._dll.setPartLibraries(library_type.value) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + @property + def interconnect_length_to_width_ratio(self) -> str: + """Length to width ratio of interconnect line. + The length to width ratio is a measure of the proportion between the length and width of the interconnect line. + This ratio is important for determining the electrical characteristics of the interconnect, such as impedance + and signal integrity. + The default is ``2``. + + Returns + ------- + str + """ + interconnect_length_to_width_ratio_string = self._dll_interface.get_string(self._dll.getLengthToWidthRatio) + return interconnect_length_to_width_ratio_string + + @interconnect_length_to_width_ratio.setter + def interconnect_length_to_width_ratio(self, interconnect_length_to_width_ratio_string): + self._dll_interface.set_string(self._dll.setLengthToWidthRatio, interconnect_length_to_width_ratio_string) + + @property + def interconnect_minimum_length_to_width_ratio(self) -> str: + """Minimum length to width ratio of interconnect line. + The minimum length to width ratio is a measure of the smallest proportion between the length and width + of the interconnect line that is allowed. This parameter is used to determine the minimum dimensions of + interconnect lines for optimization purposes. + The default is ``0.5``. + + Returns + ------- + str + """ + interconnect_minimum_length_to_width_ratio_string = self._dll_interface.get_string( + self._dll.getLowerLengthGeometricLimitRatio + ) + return interconnect_minimum_length_to_width_ratio_string + + @interconnect_minimum_length_to_width_ratio.setter + def interconnect_minimum_length_to_width_ratio(self, interconnect_minimum_length_to_width_ratio_string): + self._dll_interface.set_string( + self._dll.setLowerLengthGeometricLimitRatio, interconnect_minimum_length_to_width_ratio_string + ) + + @property + def interconnect_maximum_length_to_width_ratio(self) -> str: + """Maximum length to width ratio of interconnect line. + The maximum length to width ratio is a measure of the largest proportion between the length and width + of the interconnect line that is allowed. This parameter is used to determine the maximum dimensions of + interconnect lines for optimization purposes. + The default is ``2``. + + Returns + ------- + str + """ + interconnect_maximum_length_to_width_ratio_string = self._dll_interface.get_string( + self._dll.getUpperLengthGeometricLimitRatio + ) + return interconnect_maximum_length_to_width_ratio_string + + @interconnect_maximum_length_to_width_ratio.setter + def interconnect_maximum_length_to_width_ratio(self, interconnect_maximum_length_to_width_ratio_string): + self._dll_interface.set_string( + self._dll.setUpperLengthGeometricLimitRatio, interconnect_maximum_length_to_width_ratio_string + ) + + @property + def interconnect_line_to_termination_width_ratio(self) -> str: + """Line width to termination width ratio of interconnect line. + The line width to termination width ratio is a measure of the proportion between the width of the + interconnect line and the width of its termination. This ratio is crucial for ensuring proper + impedance matching and signal integrity at the points where the interconnect line connects to + other components or circuits. + The default is ``1``. + + Returns + ------- + str + """ + interconnect_line_to_termination_width_ratio_string = self._dll_interface.get_string( + self._dll.getLineWidthToTerminationWidthRatio + ) + return interconnect_line_to_termination_width_ratio_string + + @interconnect_line_to_termination_width_ratio.setter + def interconnect_line_to_termination_width_ratio(self, interconnect_line_to_termination_width_ratio_string): + self._dll_interface.set_string( + self._dll.setLineWidthToTerminationWidthRatio, interconnect_line_to_termination_width_ratio_string + ) + + @property + def interconnect_minimum_line_to_termination_width_ratio(self) -> str: + """Minimum line width to termination width ratio of interconnect line. + The minimum line width to termination width ratio is a measure of the smallest proportion between the + width of the interconnect line and the width of its termination that is allowed. This parameter is used + to determine the minimum dimensions of interconnect lines for optimization purposes. + The default is ``0.5``. + + Returns + ------- + str + """ + interconnect_minimum_line_to_termination_width_ratio_string = self._dll_interface.get_string( + self._dll.getLowerWidthGeometricLimitRatio + ) + return interconnect_minimum_line_to_termination_width_ratio_string + + @interconnect_minimum_line_to_termination_width_ratio.setter + def interconnect_minimum_line_to_termination_width_ratio( + self, interconnect_minimum_line_to_termination_width_ratio_string + ): + self._dll_interface.set_string( + self._dll.setLowerWidthGeometricLimitRatio, interconnect_minimum_line_to_termination_width_ratio_string + ) + + @property + def interconnect_maximum_line_to_termination_width_ratio(self) -> str: + """Maximum line width to termination width ratio of interconnect line. + The maximum line width to termination width ratio is a measure of the largest proportion between the + width of the interconnect line and the width of its termination that is allowed. This parameter is used + to determine the maximum dimensions of interconnect lines for optimization purposes. + The default is ``2``. + + Returns + ------- + str + """ + interconnect_maximum_line_to_termination_width_ratio_string = self._dll_interface.get_string( + self._dll.getUpperWidthGeometricLimitRatio + ) + return interconnect_maximum_line_to_termination_width_ratio_string + + @interconnect_maximum_line_to_termination_width_ratio.setter + def interconnect_maximum_line_to_termination_width_ratio( + self, interconnect_maximum_line_to_termination_width_ratio_string + ): + self._dll_interface.set_string( + self._dll.setUpperWidthGeometricLimitRatio, interconnect_maximum_line_to_termination_width_ratio_string + ) + + @property + def interconnect_length_value(self) -> str: + """Interconnect physical length value. + The interconnect physical length value represents the actual length of the interconnect line in the design. + This value is crucial for determining the electrical characteristics of the interconnect, such as signal delay, + impedance, and potential signal loss. Accurate length measurements are essential for ensuring that the + interconnect performsas expected in high-frequency and high-speed applications. + The default is ``2.54 mm``. + + Returns + ------- + str + """ + interconnect_length_value_string = self._dll_interface.get_string(self._dll.getLengthToWidthValue) + return interconnect_length_value_string + + @interconnect_length_value.setter + def interconnect_length_value(self, interconnect_length_value_string): + self._dll_interface.set_string(self._dll.setLengthToWidthValue, interconnect_length_value_string) + + @property + def interconnect_minimum_length_value(self) -> str: + """Minimum value of interconnect physical length. + The minimum value of the interconnect physical length represents the smallest length that the interconnect + line can have in the design. This value is used to determine the minimum dimensions of interconnect lines + for optimization purposes. + The default is ``1.27 mm``. + + Returns + ------- + str + """ + interconnect_minimum_length_value_string = self._dll_interface.get_string( + self._dll.getLowerLengthGeometricLimitValue + ) + return interconnect_minimum_length_value_string + + @interconnect_minimum_length_value.setter + def interconnect_minimum_length_value(self, interconnect_minimum_length_value_string): + self._dll_interface.set_string( + self._dll.setLowerLengthGeometricLimitValue, interconnect_minimum_length_value_string + ) + + @property + def interconnect_maximum_length_value(self) -> str: + """Maximum value of interconnect physical length. + The maximum value of the interconnect physical length represents the largest length that the interconnect + line can have in the design. This value is used to determine the maximum dimensions of interconnect lines + for optimization purposes. + The default is ``5.08 mm``. + + Returns + ------- + str + """ + interconnect_maximum_length_value_string = self._dll_interface.get_string( + self._dll.getUpperLengthGeometricLimitValue + ) + return interconnect_maximum_length_value_string + + @interconnect_maximum_length_value.setter + def interconnect_maximum_length_value(self, interconnect_maximum_length_value_string): + self._dll_interface.set_string( + self._dll.setUpperLengthGeometricLimitValue, interconnect_maximum_length_value_string + ) + + @property + def interconnect_line_width_value(self) -> str: + """Interconnect conductor width value. + The interconnect conductor width value represents the actual width of the interconnect line in the design. + This value is crucial for determining the electrical characteristics of the interconnect, such as impedance, + signal integrity, and potential signal loss. Accurate width measurements are essential for ensuring that the + interconnect performs as expected in high-frequency and high-speed applications. + The default is ``1.27 mm``. + + Returns + ------- + str + """ + interconnect_line_width_value_string = self._dll_interface.get_string( + self._dll.getLineWidthToTerminationWidthValue + ) + return interconnect_line_width_value_string + + @interconnect_line_width_value.setter + def interconnect_line_width_value(self, interconnect_line_width_value_string): + self._dll_interface.set_string( + self._dll.setLineWidthToTerminationWidthValue, interconnect_line_width_value_string + ) + + @property + def interconnect_minimum_width_value(self) -> str: + """Minimum value of interconnect conductor width. + The minimum value of the interconnect conductor width represents the smallest width that the interconnect + line can have in the design. This value is used to determine the minimum dimensions of interconnect lines + for optimization purposes. + The default is ``635 um``. + + Returns + ------- + str + """ + interconnect_minimum_width_value_string = self._dll_interface.get_string( + self._dll.getLowerWidthGeometricLimitValue + ) + return interconnect_minimum_width_value_string + + @interconnect_minimum_width_value.setter + def interconnect_minimum_width_value(self, interconnect_minimum_width_value_string): + self._dll_interface.set_string( + self._dll.setLowerWidthGeometricLimitValue, interconnect_minimum_width_value_string + ) + + @property + def interconnect_maximum_width_value(self) -> str: + """Maximum value of interconnect conductor width. + The maximum value of the interconnect conductor width represents the largest width that the interconnect + line can have in the design. This value is used to determine the maximum dimensions of interconnect lines + for optimization purposes. + The default is ``2.54 mm``. + + Returns + ------- + str + """ + interconnect_maximum_width_value_string = self._dll_interface.get_string( + self._dll.getUpperWidthGeometricLimitValue + ) + return interconnect_maximum_width_value_string + + @interconnect_maximum_width_value.setter + def interconnect_maximum_width_value(self, interconnect_maximum_width_value_string): + self._dll_interface.set_string( + self._dll.setUpperWidthGeometricLimitValue, interconnect_maximum_width_value_string + ) + + @property + def interconnect_inductor_tolerance_value(self) -> str: + """Tolerance value of interconnect inductor in ``%``. + The default is ``1``. + + Returns + ------- + str + """ + interconnect_inductor_tolerance_value_string = self._dll_interface.get_string( + self._dll.getInterConnectInductorTolerance + ) + return interconnect_inductor_tolerance_value_string + + @interconnect_inductor_tolerance_value.setter + def interconnect_inductor_tolerance_value(self, interconnect_inductor_tolerance_value_string): + self._dll_interface.set_string( + self._dll.setInterConnectInductorTolerance, interconnect_inductor_tolerance_value_string + ) + + @property + def interconnect_capacitor_tolerance_value(self) -> str: + """Tolerance value of interconnect capacitor in ``%``. + The default is ``1``. + + Returns + ------- + str + """ + interconnect_capacitor_tolerance_value_string = self._dll_interface.get_string( + self._dll.getInterConnectCapacitorTolerance + ) + return interconnect_capacitor_tolerance_value_string + + @interconnect_capacitor_tolerance_value.setter + def interconnect_capacitor_tolerance_value(self, interconnect_capacitor_tolerance_value_string): + self._dll_interface.set_string( + self._dll.setInterConnectCapacitorTolerance, interconnect_capacitor_tolerance_value_string + ) + + @property + def interconnect_geometry_optimization_enabled(self) -> bool: + """Flag indicating if the interconnect geometry optimization is enabled. + + Returns + ------- + bool + """ + interconnect_geometry_optimization_enabled = c_bool() + status = self._dll.getInterconnectGeometryOptimization(byref(interconnect_geometry_optimization_enabled)) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + return bool(interconnect_geometry_optimization_enabled.value) + + @interconnect_geometry_optimization_enabled.setter + def interconnect_geometry_optimization_enabled(self, interconnect_geometry_optimization_enabled: bool): + status = self._dll.setInterconnectGeometryOptimization(interconnect_geometry_optimization_enabled) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + def update_interconncet_parameters(self): + """Update interconnect geometry equations with entered and selected parameters""" + status = self._dll.updateInterConnectParmeters() + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + def update_inductor_capacitor_tolerances(self): + """Update interconnect inductor and capacitor tolerances with entered values""" + status = self._dll.updatePartsTolerances() + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + @property + def substrate_type(self) -> SubstrateType: + """Subctrate type of the filter. + The ``SubstrateType`` enum provides a list of all substrate types. + + Returns + ------- + :enum:`SubstrateType` + """ + type_string = self._dll_interface.get_string(self._dll.getSubstrateType) + return self._dll_interface.string_to_enum(SubstrateType, type_string) + + @substrate_type.setter + def substrate_type(self, substrate_type: SubstrateType): + if substrate_type: + string_value = self._dll_interface.enum_to_string(substrate_type) + self._dll_interface.set_string(self._dll.setSubstrateType, string_value) + + @property + def substrate_er(self) -> Union[SubstrateType, str]: + """Substrate's relative permittivity ``Er``. + The value can be either a string or an instance of the ``SubstrateEr`` enum. + The default is ``9.8`` for ``SubstrateEr.ALUMINA``. + + Returns: + ------- + Union[SubstrateEr, str] + + """ + substrate_er_index = c_int() + substrate_er_value_str = create_string_buffer(100) + status = self._dll.getEr(substrate_er_value_str, byref(substrate_er_index), 100) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + if substrate_er_index.value in [e.value for e in SubstrateEr]: + return SubstrateEr(substrate_er_index.value) + else: + return substrate_er_value_str.value.decode("ascii") + + @substrate_er.setter + def substrate_er(self, substrate_input): + if substrate_input in list(SubstrateEr): + substrate_er_index = SubstrateEr(substrate_input).value + substrate_er_value = "" + elif isinstance(substrate_input, str): + substrate_er_value = substrate_input + substrate_er_index = -1 + else: + raise ValueError("Invalid substrate input. Must be a SubstrateEr enum member or a string.") + + substrate_er_value_bytes = bytes(substrate_er_value, "ascii") + status = self._dll.setEr(substrate_er_value_bytes, substrate_er_index) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + @property + def substrate_resistivity(self) -> Union[SubstrateResistivity, str]: + """Substrate's resistivity. + The value can be either a string or an instance of the ``SubstrateResistivity`` enum. + The default is ``1.43`` for ``SubstrateResistivity.GOLD``. + + Returns: + ------- + Union[SubstrateResistivity, str] + """ + substrate_resistivity_index = c_int() + substrate_resistivity_value_str = create_string_buffer(100) + status = self._dll.getResistivity(substrate_resistivity_value_str, byref(substrate_resistivity_index), 100) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + if substrate_resistivity_index.value in [e.value for e in SubstrateResistivity]: + return SubstrateResistivity(substrate_resistivity_index.value) + else: + return substrate_resistivity_value_str.value.decode("ascii") + + @substrate_resistivity.setter + def substrate_resistivity(self, substrate_input): + if substrate_input in list(SubstrateResistivity): + substrate_resistivity_index = SubstrateResistivity(substrate_input).value + substrate_resistivity_value = "" + elif isinstance(substrate_input, str): + substrate_resistivity_value = substrate_input + substrate_resistivity_index = -1 + else: + raise ValueError("Invalid substrate input. Must be a SubstrateResistivity enum member or a string.") + substrate_resistivity_value_bytes = bytes(substrate_resistivity_value, "ascii") + status = self._dll.setResistivity(substrate_resistivity_value_bytes, substrate_resistivity_index) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + @property + def substrate_loss_tangent(self) -> Union[SubstrateType, str]: + """Substrate's loss tangent. + The value can be either a string or an instance of the ``SubstrateEr`` enum. + The default is ``0.0005`` for ``SubstrateEr.ALUMINA``. + + Returns: + ------- + Union[SubstrateEr, str] + """ + substrate_loss_tangent_index = c_int() + substrate_loss_tangent_value_str = create_string_buffer(100) + status = self._dll.getLossTangent(substrate_loss_tangent_value_str, byref(substrate_loss_tangent_index), 100) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + if substrate_loss_tangent_index.value in [e.value for e in SubstrateEr]: + return SubstrateEr(substrate_loss_tangent_index.value) + else: + return substrate_loss_tangent_value_str.value.decode("ascii") + + @substrate_loss_tangent.setter + def substrate_loss_tangent(self, substrate_input): + if substrate_input in list(SubstrateEr): + substrate_loss_tangent_index = SubstrateEr(substrate_input).value + substrate_loss_tangent_value = "" + elif isinstance(substrate_input, str): + substrate_loss_tangent_value = substrate_input + substrate_loss_tangent_index = -1 + else: + raise ValueError("Invalid substrate input. Must be a SubstrateEr enum member or a string.") + substrate_loss_tangent_value_bytes = bytes(substrate_loss_tangent_value, "ascii") + status = self._dll.setLossTangent(substrate_loss_tangent_value_bytes, substrate_loss_tangent_index) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + @property + def substrate_conductor_thickness(self) -> str: + """Substrate's conductor thickness. + The default is ``2.54 um``. + + Returns + ------- + str + """ + substrate_conductor_thickness_string = self._dll_interface.get_string(self._dll.getConductorThickness) + return substrate_conductor_thickness_string + + @substrate_conductor_thickness.setter + def substrate_conductor_thickness(self, substrate_conductor_thickness_string): + self._dll_interface.set_string(self._dll.setConductorThickness, substrate_conductor_thickness_string) + + @property + def substrate_dielectric_height(self) -> str: + """Substrate's dielectric height. + The default is ``1.27 mm``. + + Returns + ------- + str + """ + substrate_dielectric_height_string = self._dll_interface.get_string(self._dll.getDielectricHeight) + return substrate_dielectric_height_string + + @substrate_dielectric_height.setter + def substrate_dielectric_height(self, substrate_dielectric_height_string): + self._dll_interface.set_string(self._dll.setDielectricHeight, substrate_dielectric_height_string) + + @property + def substrate_unbalanced_lower_dielectric_height(self) -> str: + """Substrate's lower dielectric height for unbalanced stripline substrate type. + The default is ``6.35 mm``. + + Returns + ------- + str + """ + substrate_unbalanced_lower_dielectric_height_string = self._dll_interface.get_string( + self._dll.getLowerDielectricHeight + ) + return substrate_unbalanced_lower_dielectric_height_string + + @substrate_unbalanced_lower_dielectric_height.setter + def substrate_unbalanced_lower_dielectric_height(self, substrate_unbalanced_lower_dielectric_height_string): + self._dll_interface.set_string( + self._dll.setLowerDielectricHeight, substrate_unbalanced_lower_dielectric_height_string + ) + + @property + def substrate_suspend_dielectric_height(self) -> str: + """Substrate's suspend dielectric height above ground plane for suspend and inverted substrate types. + The default is ``1.27 mm``. + + Returns + ------- + str + """ + substrate_suspend_dielectric_height_string = self._dll_interface.get_string( + self._dll.getSuspendDielectricHeight + ) + return substrate_suspend_dielectric_height_string + + @substrate_suspend_dielectric_height.setter + def substrate_suspend_dielectric_height(self, substrate_suspend_dielectric_height_string): + self._dll_interface.set_string(self._dll.setSuspendDielectricHeight, substrate_suspend_dielectric_height_string) + + @property + def substrate_cover_height(self) -> str: + """Substrate's cover height for microstrip, suspend, and inverted substrate types. + The default is ``6.35 mm``. + + Returns + ------- + str + """ + substrate_cover_height_string = self._dll_interface.get_string(self._dll.getCoverHeight) + return substrate_cover_height_string + + @substrate_cover_height.setter + def substrate_cover_height(self, substrate_cover_height_string): + self._dll_interface.set_string(self._dll.setCoverHeight, substrate_cover_height_string) + + @property + def substrate_unbalanced_stripline_enabled(self) -> bool: + """Flag indicating if the substrate unbalanced stripline is enabled. + + Returns + ------- + bool + """ + substrate_unbalanced_stripline_enabled = c_bool() + status = self._dll.getUnbalancedStripLine(byref(substrate_unbalanced_stripline_enabled)) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + return bool(substrate_unbalanced_stripline_enabled.value) + + @substrate_unbalanced_stripline_enabled.setter + def substrate_unbalanced_stripline_enabled(self, substrate_unbalanced_stripline_enabled: bool): + status = self._dll.setUnbalancedStripLine(substrate_unbalanced_stripline_enabled) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + @property + def substrate_cover_height_enabled(self) -> bool: + """Flag indicating if the substrate cover height is enabled. + + Returns + ------- + bool + """ + substrate_cover_height_enabled = c_bool() + status = self._dll.getGroundedCoverAboveLine(byref(substrate_cover_height_enabled)) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + return bool(substrate_cover_height_enabled.value) + + @substrate_cover_height_enabled.setter + def substrate_cover_height_enabled(self, substrate_cover_height_enabled: bool): + status = self._dll.setGroundedCoverAboveLine(substrate_cover_height_enabled) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + def load_modelithics_models(self): + """Load ``Modelithics`` models from ``AEDT``.""" + status = self._dll.loadModelitichsModels() + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + @property + def modelithics_include_interconnect_enabled(self) -> bool: + """Flag indicating if the inclusion of interconnects is enabled for``Modelithics`` export. + + Returns + ------- + bool + """ + modelithics_include_interconnect_enabled = c_bool() + status = self._dll.getModelithicsIncludeInterconnect(byref(modelithics_include_interconnect_enabled)) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + return bool(modelithics_include_interconnect_enabled.value) + + @modelithics_include_interconnect_enabled.setter + def modelithics_include_interconnect_enabled(self, modelithics_include_interconnect_enabled: bool): + status = self._dll.setModelithicsIncludeInterconnect(modelithics_include_interconnect_enabled) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + @property + def modelithics_inductor_list_count(self) -> int: + """Total count of ``Modelithics`` inductor families that have been loaded into the current design. + + Returns + ------- + int + """ + count = c_int() + status = self._dll.getModelithicsInductorsListCount(byref(count)) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + return int(count.value) + + def modelithics_inductor_list(self, row_index) -> str: + """Get the name of the ``Modelithics` inductor family model from the loaded list based + on the specified index.""" + + modelithics_inductor_buffer = create_string_buffer(100) + status = self._dll.getModelithicsInductorsList(row_index, modelithics_inductor_buffer, 100) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + modelithics_inductor = modelithics_inductor_buffer.value.decode("utf-8") + return modelithics_inductor + + @property + def modelithics_inductor_selection(self) -> str: + """Selected ``Modelithics`` inductor family from the loaded list. + The Modelithics inductor family selection allows you to choose a specific inductor model from the + Modelithics library. + + Returns + ------- + str + """ + modelithics_inductor_selection_string = self._dll_interface.get_string(self._dll.getModelithicsInductors) + return modelithics_inductor_selection_string + + @modelithics_inductor_selection.setter + def modelithics_inductor_selection(self, modelithics_inductor_selection_string): + self._dll_interface.set_string(self._dll.setModelithicsInductors, modelithics_inductor_selection_string) + + @property + def modelithics_inductor_family_list_count(self) -> int: + """Total count of ``Modelithics`` family inductors added to the inductor family list. + + Returns + ------- + int + """ + count = c_int() + status = self._dll.getModelithicsInductorsFamilyListCount(byref(count)) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + return int(count.value) + + def modelithics_inductor_family_list(self, index) -> str: + """Get the name of ``Modelithics`` inductor family from the inductor family list based on the specified index. + + Parameters + ---------- + index : int + Index of the inductor family list. + + Returns + ------- + str + """ + modelithics_inductor_family_buffer = create_string_buffer(100) + status = self._dll.getModelithicsInductorsFamilyList(index, modelithics_inductor_family_buffer, 100) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + modelithics_inductor_family = modelithics_inductor_family_buffer.value.decode("utf-8") + return modelithics_inductor_family + + def modelithics_inductor_add_family(self, modelithics_inductor) -> str: + """Add a specified ``Modelithics`` inductor family to the inductor family list. + + Parameters + ---------- + modelithics_inductor : str + Name of the inductor family. + """ + self._dll_interface.set_string(self._dll.addModelithicsInductorsFamily, modelithics_inductor) + + def modelithics_inductor_remove_family(self, modelithics_inductor) -> str: + """Remove a specified ``Modelithics`` inductor family from the inductor family list. + + Parameters + ---------- + modelithics_inductor : str + Name of the inductor family. + """ + self._dll_interface.set_string(self._dll.removeModelithicsInductorsFamily, modelithics_inductor) + + @property + def modelithics_capacitor_list_count(self) -> int: + """Total count of ``Modelithics`` capacitor families that have been loaded into the current design. + + Returns + ------- + int + """ + count = c_int() + status = self._dll.getModelithicsCapacitorsListCount(byref(count)) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + return int(count.value) + + def modelithics_capacitor_list(self, row_index) -> str: + """Get the name of the ``Modelithics`` capacitor family model from the loaded list based on + the specified index.""" + + modelithics_capacitor_buffer = create_string_buffer(100) + status = self._dll.getModelithicsCapacitorsList(row_index, modelithics_capacitor_buffer, 100) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + modelithics_capacitor = modelithics_capacitor_buffer.value.decode("utf-8") + return modelithics_capacitor + + @property + def modelithics_capacitor_selection(self) -> str: + """Selected ``Modelithics`` capacitor family from the loaded list. + The Modelithics capacitor family selection allows you to choose a specific capacitor model from the + Modelithics library. + + Returns + ------- + str + """ + modelithics_capacitor_selection_string = self._dll_interface.get_string(self._dll.getModelithicsCapacitors) + return modelithics_capacitor_selection_string + + @modelithics_capacitor_selection.setter + def modelithics_capacitor_selection(self, modelithics_capacitor_selection_string): + self._dll_interface.set_string(self._dll.setModelithicsCapacitors, modelithics_capacitor_selection_string) + + @property + def modelithics_capacitor_family_list_count(self) -> int: + """Total count of ``Modelithics`` family capacitors added to the capacitor family list. + + Returns + ------- + int + """ + count = c_int() + status = self._dll.getModelithicsCapacitorsFamilyListCount(byref(count)) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + return int(count.value) + + def modelithics_capacitor_family_list(self, index) -> str: + """Get the name of ``Modelithics`` capacitor family from the capacitor family list based on the specified index. + + Parameters + ---------- + index : int + Index of the capacitor family list. + + Returns + ------- + str + """ + modelithics_capacitor_family_buffer = create_string_buffer(100) + status = self._dll.getModelithicsCapacitorsFamilyList(index, modelithics_capacitor_family_buffer, 100) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + modelithics_capacitor_family = modelithics_capacitor_family_buffer.value.decode("utf-8") + return modelithics_capacitor_family + + def modelithics_capacitor_add_family(self, modelithics_capacitor) -> str: + """Add a specified``Modelithics`` capacitor family to the capacitor family list. + + Parameters + ---------- + modelithics_capacitor : str + Name of the capacitor family. + """ + self._dll_interface.set_string(self._dll.addModelithicsCapacitorsFamily, modelithics_capacitor) + + def modelithics_capacitor_remove_family(self, modelithics_capacitor) -> str: + """Remove a specified ``Modelithics`` capacitor family from the capacitor family list. + Parameters + ---------- + modelithics_capacitor : str + Name of the capacitor family. + """ + self._dll_interface.set_string(self._dll.removeModelithicsCapacitorsFamily, modelithics_capacitor) + + @property + def modelithics_resistor_list_count(self) -> int: + """Total count of ``Modelithics`` resistor families that have been loaded into the current design. + + Returns + ------- + int + """ + count = c_int() + status = self._dll.getModelithicsResistorsListCount(byref(count)) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + return int(count.value) + + def modelithics_resistor_list(self, row_index) -> str: + """Get the name of the ``Modelithics`` resistor family model from the loaded list based on the + specified index.""" + + modelithics_resistor_buffer = create_string_buffer(100) + status = self._dll.getModelithicsResistorsList(row_index, modelithics_resistor_buffer, 100) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + modelithics_resistor = modelithics_resistor_buffer.value.decode("utf-8") + return modelithics_resistor + + @property + def modelithics_resistor_selection(self) -> str: + """Selected ``Modelithics`` resistor family from the loaded list. + The Modelithics resistor family selection allows you to choose a specific resistor model from the + Modelithics library. + Returns + ------- + str + """ + modelithics_resistor_selection_string = self._dll_interface.get_string(self._dll.getModelithicsResistors) + return modelithics_resistor_selection_string + + @modelithics_resistor_selection.setter + def modelithics_resistor_selection(self, modelithics_resistor_selection_string): + self._dll_interface.set_string(self._dll.setModelithicsResistors, modelithics_resistor_selection_string) + + @property + def modelithics_resistor_family_list_count(self) -> int: + """Total count of ``Modelithics`` family resistors added to the resistor family list. + + Returns + ------- + int + """ + count = c_int() + status = self._dll.getModelithicsResistorsFamilyListCount(byref(count)) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + return int(count.value) + + def modelithics_resistor_family_list(self, index) -> str: + """Get the name of ``Modelithics`` resistor family from the resistor family list based on + the specified index. + + Parameters + ---------- + index : int + Index of the resistor family list. + + Returns + ------- + str + """ + modelithics_resistor_family_buffer = create_string_buffer(100) + status = self._dll.getModelithicsResistorsFamilyList(index, modelithics_resistor_family_buffer, 100) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + modelithics_resistor_family = modelithics_resistor_family_buffer.value.decode("utf-8") + return modelithics_resistor_family + + def modelithics_resistor_add_family(self, modelithics_resistor) -> str: + """Add a specified ``Modelithics`` resistor family to the resistor family list. + + Parameters + ---------- + modelithics_resistor : str + Name of the resistor family. + """ + self._dll_interface.set_string(self._dll.addModelithicsResistorsFamily, modelithics_resistor) + + def modelithics_resistor_remove_family(self, modelithics_resistor) -> str: + """Remove a specified ``Modelithics`` resistor family from the resistor family list. + + Parameters + ---------- + modelithics_resistor : str + Name of the resistor family. + """ + self._dll_interface.set_string(self._dll.removeModelithicsResistorsFamily, modelithics_resistor) diff --git a/src/ansys/aedt/core/filtersolutions_core/lumped_termination_impedance.py b/src/ansys/aedt/core/filtersolutions_core/lumped_termination_impedance_table.py similarity index 100% rename from src/ansys/aedt/core/filtersolutions_core/lumped_termination_impedance.py rename to src/ansys/aedt/core/filtersolutions_core/lumped_termination_impedance_table.py diff --git a/src/ansys/aedt/core/filtersolutions_core/optimization_goals_table.py b/src/ansys/aedt/core/filtersolutions_core/optimization_goals_table.py new file mode 100644 index 00000000000..79852ae2753 --- /dev/null +++ b/src/ansys/aedt/core/filtersolutions_core/optimization_goals_table.py @@ -0,0 +1,342 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2021 - 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. + +import csv +from ctypes import POINTER +from ctypes import byref +from ctypes import c_char_p +from ctypes import c_int +from ctypes import create_string_buffer +from enum import Enum + +import ansys.aedt.core + + +class OptimizationGoalParameter(Enum): + """Enumeration of optimization goals parameters table. + + **Attributes:** + + - LOWER_FREQUENCY: Represents the lower frequency parameter, positioned + as the first value in the optimization goal table. + - UPPER_FREQUENCY: Represents the upper frequency parameter, positioned + as the second value in the optimization goal table. + - GOAL_VALUE: Represents the goal value parameter, positioned + as the third value in the optimization goal table. + - CONDITION: Represents the condition parameter, positioned + as the fourth value in the optimization goal table. + - PARAMETER_NAME: Represents the name of the parameter, positioned + as the fifth value in the optimization goal table. + - WEIGHT: Represents the weight parameter, positioned + as the sixth value in the optimization goal table. + - ENABLED: Represents the status of using the goal parameters, positioned + as the seventh value in the optimization goal table. + """ + + LOWER_FREQUENCY = 0 + UPPER_FREQUENCY = 1 + GOAL_VALUE = 2 + CONDITION = 3 + PARAMETER_NAME = 4 + WEIGHT = 5 + ENABLED = 6 + + +class OptimizationGoalsTable: + """Provides management of optimization goals within a table structure. + + This class offers functionality to add, update, or delete entries in the optimization goals table, + facilitating the manipulation of optimization parameters for simulation tasks. + Each entry in the table can specify a range of parameters including lower and upper frequency limits, + a target value for the optimization goal, a condition that defines how the goal is evaluated, + the name of the parameter to optimize, the weight of the goal in the overall optimization process, + and whether the goal is active or not. + """ + + def __init__(self): + self._dll = ansys.aedt.core.filtersolutions_core._dll_interface()._dll + self._dll_interface = ansys.aedt.core.filtersolutions_core._dll_interface() + self._define_optimization_goals_dll_functions() + + def _define_optimization_goals_dll_functions(self): + """Define C++ API DLL functions.""" + self._dll.getOptimizationGoalDefinitionRowCount.argtype = POINTER(c_int) + self._dll.getOptimizationGoalDefinitionRowCount.restype = c_int + + self._dll.getOptimizationGoalDefinitionRow.argtype = [c_int, POINTER(c_char_p), c_int] + self._dll.getOptimizationGoalDefinitionRow.restype = c_int + + self._dll.updateOptimizationGoalDefinitionRow.argtype = [c_int, c_int, c_char_p] + self._dll.updateOptimizationGoalDefinitionRow.restype = c_int + + self._dll.appendOptimizationGoalDefinitionRow.argtype = [c_int, c_char_p] + self._dll.appendOptimizationGoalDefinitionRow.restype = c_int + + self._dll.insertOptimizationGoalDefinitionRow.argtypes = [c_int, c_char_p, c_char_p] + self._dll.insertOptimizationGoalDefinitionRow.restype = c_int + + self._dll.removeOptimizationGoalDefinitionRow.argtype = c_int + self._dll.removeOptimizationGoalDefinitionRow.restype = c_int + + self._dll.adjustGoalFrequency.argtype = c_char_p + self._dll.adjustGoalFrequency.restype = c_int + + def _bytes_or_none(self, str_value): + if str_value: + return bytes(str_value, "ascii") + return None + + @property + def row_count(self) -> int: + """Number of golas in the optimization goals table. + The default is `0`. + + Returns + ------- + int + """ + table_row_count = c_int() + status = self._dll.getOptimizationGoalDefinitionRowCount(byref(table_row_count)) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + return int(table_row_count.value) + + def row(self, row_index) -> list: + """Get the values for one row of the optimization goals table. + The values are returned as a list: [value1, value2, ..., value7]. + + Parameters + ---------- + row_index: int + Index of the row. Valid values range from ``0`` to ``49``, inclusive. + + Returns + ------- + list + A list of strings representing the row parameters. + """ + row_parameter_buffer = create_string_buffer(1024) + # Call the DLL function. Assuming it fills the buffer with comma-separated values. + status = self._dll.getOptimizationGoalDefinitionRow(row_index, byref(row_parameter_buffer), 1024) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + # Decode the buffer to a Python string and split by comma to get a list. + row_parameters = row_parameter_buffer.value.decode("utf-8").split("|") + return row_parameters + + def update_row( + self, + row_index, + lower_frequency=None, + upper_frequency=None, + goal_value=None, + condition=None, + parameter_name=None, + weight=None, + enabled=None, + ): + """Update the row parameters for an existing row in the optimization goals table. + + Parameters + ---------- + row_index: int + Index of the row. Valid values range from ``0`` to ``49``, inclusive. + lower_frequency: str, optional + New lower frequency value to set. + If no value is specified, the value remains unchanged. + upper_frequency: str, optional + New upper frequency value to set. + If no value is specified, the value remains unchanged. + goal_value: str, optional + New goal value to set. + If no value is specified, the value remains unchanged. + condition: str, optional + New condition value to set. + If no value is specified, the value remains unchanged. + parameter_name: str, optional + New parameter name value to set. + If no value is specified, the value remains unchanged. + weight: str, optional + New weight value to set. + If no value is specified, the value remains unchanged. + enabled: str, optional + New enabled value to set. + If no value is specified, the value remains unchanged. + """ + status = self._dll.updateOptimizationGoalDefinitionRow( + row_index, + self._bytes_or_none(lower_frequency), + self._bytes_or_none(upper_frequency), + self._bytes_or_none(goal_value), + self._bytes_or_none(condition), + self._bytes_or_none(parameter_name), + self._bytes_or_none(weight), + self._bytes_or_none(enabled), + ) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + def append_row( + self, + lower_frequency=None, + upper_frequency=None, + goal_value=None, + condition=None, + parameter_name=None, + weight=None, + enabled=None, + ): + """Append a new row of parameters to the optimization goals table, + ensuring the total does not exceed 50 entries. + + Parameters + ---------- + lower_frequency: str, optional + Lower frequency value to set. + upper_frequency: str, optional + Upper frequency value to set. + goal_value: str, optional + Goal value to set. + condition: str, optional + Condition value to set. + parameter_name: str, optional + Parameter name value to set. + weight: str, optional + Weight value to set. + enabled: str, optional + Enabled value to set. + """ + status = self._dll.appendOptimizationGoalDefinitionRow( + self._bytes_or_none(lower_frequency), + self._bytes_or_none(upper_frequency), + self._bytes_or_none(goal_value), + self._bytes_or_none(condition), + self._bytes_or_none(parameter_name), + self._bytes_or_none(weight), + self._bytes_or_none(enabled), + ) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + def insert_row( + self, + row_index, + lower_frequency=None, + upper_frequency=None, + goal_value=None, + condition=None, + parameter_name=None, + weight=None, + enabled=None, + ): + """Insert a new row of parameters to the optimization goals table, + ensuring the total does not exceed 50 entries. + + Parameters + ---------- + row_index: int + Index of the row. Valid values range from ``0`` to ``49``, inclusive. + lower_frequency: str, optional + Lower frequency value. + upper_frequency: str, optional + Upper frequency value. + goal_value: str, optional + Goal value. + condition: str, optional + Condition value. + parameter_name: str, optional + Parameter name. + weight: str, optional + Weight value. + enabled: str, optional + Enabled value. + """ + status = self._dll.insertOptimizationGoalDefinitionRow( + row_index, + self._bytes_or_none(lower_frequency), + self._bytes_or_none(upper_frequency), + self._bytes_or_none(goal_value), + self._bytes_or_none(condition), + self._bytes_or_none(parameter_name), + self._bytes_or_none(weight), + self._bytes_or_none(enabled), + ) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + def remove_row(self, row_index): + """Remove a row from the optimization goals table. + + Parameters + ---------- + row_index: int + Index of the row. Valid values range from ``0`` to ``49``, inclusive. + """ + status = self._dll.removeOptimizationGoalDefinitionRow(row_index) + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + def restore_design_goals(self): + """Configure the optimization goal table according to the recommended goals for the current design.""" + status = self._dll.setDesignGoals() + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) + + def save_goals(self, design, file_path) -> str: + """Save the optimization goals from a design's optimization goals table to a CSV file. + + Parameters: + ---------- + design: The design object containing the optimization goals table. + file_path: The path to the CSV file where the goals will be saved. + """ + with open(file_path, mode="w", newline="") as file: + writer = csv.writer(file) + writer.writerow( + ["Start Frequency", "Stop Frequency", "Goal Value", "Condition", "Parameter", "Weight", "Enabled"] + ) + for row_index in range(design.optimization_goals_table.row_count): + row_data = design.optimization_goals_table.row(row_index) + writer.writerow(row_data) + + def load_goals(self, file_path) -> str: + """Load optimization goals from a CSV file into this optimization goals table. + + Parameters: + ---------- + file_path: The path to the CSV file from which the goals will be loaded. + """ + try: + with open(file_path, mode="r", newline="") as file: + reader = csv.reader(file) + next(reader, None) + for row in reader: + self.append_row(*row) + except FileNotFoundError: + print(f"File {file_path} not found.") + except Exception as e: + print(f"An error occurred while loading goals: {e}") + + def adjust_goal_frequency(self, adjust_goal_frequency_string): + """Adjust all goal frequencies in the table by the adjusting + frequency value which can be positive or negative.""" + self._dll_interface.set_string(self._dll.adjustGoalFrequency, adjust_goal_frequency_string) + + def clear_goal_entries(self): + """Clear the goal entries from optimization goals table.""" + status = self._dll.clearGoalEntries() + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) diff --git a/src/ansys/aedt/core/filtersolutions_core/transmission_zeros.py b/src/ansys/aedt/core/filtersolutions_core/transmission_zeros.py index 9b370e0751d..58a0e1b557d 100644 --- a/src/ansys/aedt/core/filtersolutions_core/transmission_zeros.py +++ b/src/ansys/aedt/core/filtersolutions_core/transmission_zeros.py @@ -38,8 +38,8 @@ class TableFormat(Enum): **Attributes:** - - RATIO: Represents transmission zeros ratio table. - - BANDWIDTH: Represents transmission zeros bandwidth table. + - RATIO: Represents transmission zeros ratio. + - BANDWIDTH: Represents transmission zeros bandwidth. """ RATIO = 0 diff --git a/src/ansys/aedt/core/generic/configurations.py b/src/ansys/aedt/core/generic/configurations.py index c1f967166eb..ac878b051fb 100644 --- a/src/ansys/aedt/core/generic/configurations.py +++ b/src/ansys/aedt/core/generic/configurations.py @@ -22,7 +22,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -from collections import OrderedDict import copy from datetime import datetime import json @@ -63,7 +62,7 @@ def _find_datasets(d, out_list): for v in list(d.values()): - if isinstance(v, (dict, OrderedDict)): + if isinstance(v, dict): _find_datasets(v, out_list) else: a = copy.deepcopy(v) @@ -910,14 +909,14 @@ def _update_boundaries(self, name, props): x2 = self._app.modeler._arg_with_dim(float(current[1]["XPosition"]), self._app.modeler.model_units) y2 = self._app.modeler._arg_with_dim(float(current[1]["YPosition"]), self._app.modeler.model_units) z2 = self._app.modeler._arg_with_dim(float(current[1]["ZPosition"]), self._app.modeler.model_units) - p1 = OrderedDict({"Coordinate System": "Global", "Start": [x1, y1, z1], "End": [x2, y2, z2]}) + p1 = {"Coordinate System": "Global", "Start": [x1, y1, z1], "End": [x2, y2, z2]} bound.auto_update = False bound.props["CurrentLine"] = BoundaryProps(bound, p1) bound.auto_update = True if bound.props.get("Modes", None): - modes = OrderedDict({}) + modes = {} for k, v in bound.props["Modes"].items(): - p1 = OrderedDict({"ModeNum": v["ModeNum"], "UseIntLine": v["UseIntLine"]}) + p1 = {"ModeNum": v["ModeNum"], "UseIntLine": v["UseIntLine"]} if v["UseIntLine"] and v["IntLine"].get("GeometryPosition", None): current = v["IntLine"]["GeometryPosition"] x1 = self._app.modeler._arg_with_dim(float(current[0]["XPosition"]), self._app.modeler.model_units) @@ -926,9 +925,7 @@ def _update_boundaries(self, name, props): x2 = self._app.modeler._arg_with_dim(float(current[1]["XPosition"]), self._app.modeler.model_units) y2 = self._app.modeler._arg_with_dim(float(current[1]["YPosition"]), self._app.modeler.model_units) z2 = self._app.modeler._arg_with_dim(float(current[1]["ZPosition"]), self._app.modeler.model_units) - p1["IntLine"] = OrderedDict( - {"Coordinate System": "Global", "Start": [x1, y1, z1], "End": [x2, y2, z2]} - ) + p1["IntLine"] = {"Coordinate System": "Global", "Start": [x1, y1, z1], "End": [x2, y2, z2]} elif v["UseIntLine"]: p1["IntLine"] = v["IntLine"] if v.get("AlignmentGroup", None): @@ -1456,7 +1453,7 @@ def _export_materials(self, dict_out): output_dict[val.name] = copy.deepcopy(val._props) out_list = [] _find_datasets(output_dict, out_list) - datasets = OrderedDict() + datasets = {} for ds in out_list: if ds in list(self._app.project_datasets.keys()): d = self._app.project_datasets[ds] @@ -1466,16 +1463,12 @@ def _export_materials(self, dict_out): else: units = [d.xunit, d.yunit] points = [val for tup in zip(d.x, d.y) for val in tup] - datasets[ds] = OrderedDict( - { - "Coordinates": OrderedDict( - { - "DimUnits": units, - "Points": points, - } - ) + datasets[ds] = { + "Coordinates": { + "DimUnits": units, + "Points": points, } - ) + } dict_out["materials"] = output_dict if datasets: @@ -1707,7 +1700,7 @@ def _export_mesh_operations(self, dict_out): dict_out["mesh"] = {} args = ["NAME:Settings"] args += self._app.mesh.global_mesh_region.settings.parse_settings_as_args() - mop = OrderedDict({}) + mop = {} _arg2dict(args, mop) dict_out["mesh"]["Settings"] = mop["Settings"] if self._app.mesh.meshregions: @@ -1720,7 +1713,7 @@ def _export_mesh_operations(self, dict_out): if mesh.name not in ["Settings", "Global"]: args += getattr(mesh, "_parse_assignment_value")() args += ["UserSpecifiedSettings:=", not mesh.manual_settings] - mop = OrderedDict({}) + mop = {} _arg2dict(args, mop) if ( mesh.name not in ["Settings", "Global"] diff --git a/src/ansys/aedt/core/generic/constants.py b/src/ansys/aedt/core/generic/constants.py index 33bcb86eda6..356944514cd 100644 --- a/src/ansys/aedt/core/generic/constants.py +++ b/src/ansys/aedt/core/generic/constants.py @@ -22,6 +22,9 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +from enum import IntEnum +from enum import auto +from enum import unique import math import warnings @@ -1089,3 +1092,1149 @@ class SymbolStyle(object): "HorizontalLeftTriangle", "HorizontalRightTriangle", ) + + +@unique +class EnumUnits(IntEnum): + # Frequency + hz = 0 + khz = auto() + mhz = auto() + ghz = auto() + thz = auto() + rps = auto() + dbFrequency = auto() + # Resistance + mohm = auto() + ohm = auto() + kohm = auto() + megohm = auto() + gohm = auto() + dbResistance = auto() + # Conductance + fsie = auto() + psie = auto() + nsie = auto() + usie = auto() + msie = auto() + sie = auto() + dbConductance = auto() + # Inductance + fh = auto() + ph = auto() + nh = auto() + uh = auto() + mh = auto() + h = auto() + dbInductance = auto() + # Capacitance + ff = auto() + pf = auto() + nf = auto() + uf = auto() + mf = auto() + farad = auto() + dbCapacitance = auto() + # Length + nm = auto() + um = auto() + mm = auto() + meter = auto() + cm = auto() + ft = auto() + inch = auto() # actually it is "in" but would not be valid + mil = auto() + uin = auto() + dbLength = auto() + # Time + fs = auto() + ps = auto() + ns = auto() + us = auto() + ms = auto() + s = auto() + dbTime = auto() + # Angle + deg = auto() + rad = auto() + dbAngle = auto() + # Power + fw = auto() + pw = auto() + nw = auto() + uw = auto() + mw = auto() + w = auto() + dbm = auto() + dbw = auto() + dbPower = auto() + # Voltage + fv = auto() + pv = auto() + nv = auto() + uv = auto() + mv = auto() + v = auto() + kv = auto() + dbv = auto() + dbVoltage = auto() + # Current + fa = auto() + pa = auto() + na = auto() + ua = auto() + ma = auto() + a = auto() + dbCurrent = auto() + # Temperature + kel = auto() + cel = auto() + fah = auto() + dbTemperature = auto() + # Noise spectrum (dBc/Hz) + dbchz = auto() + dbNoiseSpectrum = auto() + # Mass (obsolete: replaced with new enum below) + oz_obsolete = auto() + dbWeight_obsolete = auto() + # Volume + l = auto() + ml = auto() + dbVolume = auto() + # Magnetic Induction + gauss = auto() + ugauss = auto() + tesla = auto() + utesla = auto() + dbMagInduction = auto() + # Magnetic Field Strength + oersted = auto() + a_per_meter = auto() + dbMagFieldStrength = auto() + # Force + fnewton = auto() + pnewton = auto() + nnewton = auto() + unewton = auto() + mnewton = auto() + newton = auto() + knewton = auto() + megnewton = auto() + gnewton = auto() + lbForce = auto() + dbForce = auto() + # Torque + fnewtonmeter = auto() + pnewtonmeter = auto() + nnewtonmeter = auto() + unewtonmeter = auto() + mnewtonmeter = auto() + newtonmeter = auto() + knewtonmeter = auto() + megnewtonmeter = auto() + gnewtonmeter = auto() + OzIn = auto() + LbIn = auto() + ftlb = auto() + GmCm = auto() + KgCm = auto() + KgMeter = auto() + dbTorque = auto() + # Speed (mph is meter_per_hour) + mmps = auto() + cmps = auto() + mps = auto() + mph = auto() + fps = auto() + fpm = auto() + miph = auto() + dbSpeed = auto() + # AngularSpeed + rpm = auto() + degps = auto() + degpm = auto() + degph = auto() + radps = auto() + radpm = auto() + radph = auto() + dbAngularSpeed = auto() + # Flux + weber = auto() + dbFlux = auto() + # ElectricFieldStrength + vpm = auto() + # Mass (replaces obsolete previous) + ugram = auto() + mgram = auto() + gram = auto() + kgram = auto() + oz = auto() + lb = auto() + dbMass = auto() + # More Length + km = auto() + # More Voltage + megv = auto() + # More Current + ka = auto() + # More MagneticInduction + mtesla = auto() + mgauss = auto() + kgauss = auto() + ktesla = auto() + # More MagneticFieldStrength + ka_per_meter = auto() + koersted = auto() + # More power units + kw = auto() + horsepower = auto() + btu_per_hr = auto() + # More speed units + km_per_hr = auto() + km_per_min = auto() + km_per_sec = auto() + mi_per_min = auto() + mi_per_sec = auto() + in_per_sec = auto() + # Pressure units + n_per_msq = auto() + kn_per_msq = auto() + megn_per_msq = auto() + gn_per_msq = auto() + psi = auto() + kpsi = auto() + megpsi = auto() + gpsi = auto() + # + upascal = auto() + mpascal = auto() + cpascal = auto() + dpascal = auto() + pascal = auto() + hpascal = auto() + kpascal = auto() + megpascal = auto() + gpascal = auto() + # kAcceleration + inps2 = auto() + mmps2 = auto() + cmps2 = auto() + mps2 = auto() + # kAIGB + aigb2 = auto() + aigb1 = auto() + # kAmountOfSubstance + nmol = auto() + umol = auto() + mmol = auto() + mol = auto() + kmol = auto() + # kAngle + degsec = auto() + degmin = auto() + # kAngleCoefficient + perdeg = auto() + perrad = auto() + vpervperdeg = auto() + vpervperrad = auto() + # kAngularAcceleration + degpers2 = auto() + pers2 = auto() + radpers2 = auto() + # kAngularDamping + dmsperrad = auto() + nmsperrad = auto() + kmsperrad = auto() + # kAngularJerk + jerk_degpers2 = auto() + jerk_radpers2 = auto() + # kAngularMomentum + kgm2pers = auto() + newtonmetersec = auto() + # kAngularSpeed + AngRps = auto() + AngSpers = auto() + # kAngularStiffness + newtonmeterperdeg = auto() + newtonmeterperrad = auto() + # kAngularWindage + kgm2perrad2 = auto() + nms2perrad2 = auto() + # kArea + in2 = auto() + ft2 = auto() + um2 = auto() + mm2 = auto() + cm2 = auto() + m2 = auto() + km2 = auto() + # kAreaCoefficient + percm2 = auto() + perm2 = auto() + # kArealFlowRate (also Diffusivity) + m2perhour = auto() + m2permin = auto() + m2pers = auto() + # kAreaPerPower + m2perJs = auto() + m2perw = auto() + # kAreaPerVoltage + Am2perkW = auto() + Am2perW = auto() + m2perkV = auto() + m2perV = auto() + # kAreaPerVoltageTemperature + Am2perWKel = auto() + m2perVKel = auto() + # kBIGB + bigB1 = auto() + bigB2 = auto() + # kCapacitancePerArea + Fpercm2 = auto() + nFperm2 = auto() + uFperm2 = auto() + mFperm2 = auto() + Fperm2 = auto() + # kCapacitancePerAreaPerVoltage + pFperVm2 = auto() + nFperVm2 = auto() + uFperVm2 = auto() + mFperVm2 = auto() + FperVm2 = auto() + # kCapacitancePerLength + pFperm = auto() + nFperm = auto() + uFperm = auto() + mFperm = auto() + Fperm = auto() + # kCapacitanceTemperatureCoeff + nFperCel = auto() + uFperCel = auto() + FperCel = auto() + pFperFah = auto() + nFperFah = auto() + uFperFah = auto() + mFperFah = auto() + FperFah = auto() + mFperCel = auto() + pFperCel = auto() + pFperKel = auto() + nFperKel = auto() + uFperKel = auto() + mFperKel = auto() + FperKel = auto() + # kCharge + As = auto() + Ah = auto() + nC = auto() + uC = auto() + mC = auto() + C = auto() + kC = auto() + # kCompliance + inperlbf = auto() + cmperN = auto() + mperN = auto() + # kConductance + mho = auto() + inverseohm = auto() + apv = auto() + ksie = auto() + megsie = auto() + # kConductancePerLength + uSperm = auto() + mSperm = auto() + cSperm = auto() + Sperm = auto() + kSperm = auto() + # kCurrentChangeRate + Apermin = auto() + Aperhour = auto() + uApers = auto() + mApers = auto() + Apers = auto() + kApers = auto() + # kCurrentDensity + uApercm2 = auto() + mApercm2 = auto() + Apercm2 = auto() + uAperm2 = auto() + mAperm2 = auto() + Aperm2 = auto() + Apermm2 = auto() + # kCurrentGain + ApermA = auto() + mAperA = auto() + AperA = auto() + # kCurrentLengthPerVoltage + uAmperV = auto() + mAmperV = auto() + AmperV = auto() + # kCurrentPerCharge + AperC = auto() + AperAhour = auto() + AperAs = auto() + # kCurrentPerIrradiance + uAperWperm2 = auto() + mAperWperm2 = auto() + AperWperm2 = auto() + kAperWperm2 = auto() + # kCurrentPerLength + uAperm = auto() + mAperm = auto() + Aperm = auto() + kAperm = auto() + # kCurrentPerTemperature2_half + AperKel2half = auto() + # kCurrentPerTemperatureCubed + AperKel3 = auto() + # kCurrentPerTemperatureDiffCubed + AperCelDiff3 = auto() + AperKelDiff3 = auto() + # kCurrentSquaredTime + mA2s = auto() + A2s = auto() + # kCurrentTemperatureCoeff + uAperCel = auto() + mAperCel = auto() + AperCel = auto() + mAperFah = auto() + AperFah = auto() + uAperKel = auto() + mAperKel = auto() + AperKel = auto() + kAperKel = auto() + # kDamping + mNsperm = auto() + cNsperm = auto() + dNsperm = auto() + Nsperm = auto() + kNsperm = auto() + # kDensity + gpcm3 = auto() + gpl = auto() + kgpl = auto() + kgpdm3 = auto() + kgpm3 = auto() + # kElectricFieldStrength + vpcm = auto() + # kElectricFluxDensity + nCperm2 = auto() + uCperm2 = auto() + mCperm2 = auto() + Cperm2 = auto() + # kEnergy + Whour = auto() + kWhour = auto() + eV = auto() + erg = auto() + Ws = auto() + uJ = auto() + mJ = auto() + J = auto() + kJ = auto() + megJ = auto() + GJ = auto() + # kFluidicCapacitance + cm3perPa = auto() + m3perPa = auto() + # kFluidicConductance + cm3perPas = auto() + m3perPas = auto() + # kFluidicResistance + Nsperm5 = auto() + Pasperm3 = auto() + # kFlux + maxwell = auto() + vh = auto() + vs = auto() + # kForce + dyne = auto() + kpond = auto() + # kFrequency + persec = auto() + # kIlluminance + lmperm2 = auto() + lmpercm2 = auto() + Wperm2 = auto() + Wpercm2 = auto() + lmperin2 = auto() + lx = auto() + klx = auto() + meglx = auto() + # kInductancePerLength + pHperm = auto() + nHperm = auto() + uHperm = auto() + mHperm = auto() + Hperm = auto() + # kInertance + kgperm4 = auto() + Ns2perm5 = auto() + Pas2perm3 = auto() + # kIrradiance + IrradWpercm2 = auto() + Wperin2 = auto() + uWperm2 = auto() + mWperm2 = auto() + IrradWperm2 = auto() + kWperm2 = auto() + megWperm2 = auto() + # kJerk + inpers3 = auto() + nmpers3 = auto() + umpers3 = auto() + mmpers3 = auto() + cmpers3 = auto() + mpers3 = auto() + # kLength + yd = auto() + mileUS = auto() + ltyr = auto() + mileNaut = auto() + fm = auto() + pm = auto() + dm = auto() + mileTerr = auto() + # kLength2PerVoltage2 + m2perV2 = auto() + # kLengthCoefficient + percm = auto() + permm = auto() + perum = auto() + perkm = auto() + perin = auto() + VperVperm = auto() + VperVperin = auto() + perm = auto() + # kLengthPerVoltage + umperV = auto() + mmperV = auto() + cmperV = auto() + dmperV = auto() + mperV = auto() + kmperV = auto() + # kLengthPerVoltageRoot + umperVhalf = auto() + mmperVhalf = auto() + cmperVhalf = auto() + dmperVhalf = auto() + mperVhalf = auto() + kmperVhalf = auto() + # kLuminousFlux + gm2pers3 = auto() + mlm = auto() + lm = auto() + klm = auto() + meglm = auto() + # kLuminousIntensity + mCd = auto() + Cd = auto() + kCd = auto() + megCd = auto() + GCd = auto() + # kMagneticReluctance + AperVs = auto() + AperWb = auto() + # kMassFlowRate + gpers = auto() + kgpers = auto() + # kMolarDensity + molperdm3 = auto() + molpercm3 = auto() + molperl = auto() + molperm3 = auto() + # kMolarEnergy + uJpermol = auto() + mJpermol = auto() + Jpermol = auto() + kJpermol = auto() + megJpermol = auto() + gJpermol = auto() + # kMolarVelocity + umolpers = auto() + mmolpers = auto() + cmolpers = auto() + molpers = auto() + kmolpers = auto() + # kMolarViscosity + Paspermol = auto() + # kMomentInertia + lbin2 = auto() + lbft2 = auto() + kgm2 = auto() + # kMomentum + gmpers = auto() + kgmpers = auto() + # kPercentage + percent = auto() + # kPercentagePerTime + percentperm = auto() + percentperhour = auto() + percentperday = auto() + pers = auto() + permin = auto() + perhour = auto() + perday = auto() + percentpers = auto() + # kPermeance + VsperA = auto() + WbperA = auto() + # kPower + megw = auto() + gw = auto() + # kPressure + mbar = auto() + bar = auto() + mmh2o = auto() + mmhg = auto() + techAtm = auto() + torr = auto() + stAtm = auto() + # kPressureChangeRate + psipermin = auto() + statmpermin = auto() + techatmpermin = auto() + mmH2Opermin = auto() + torrpermin = auto() + Paperhour = auto() + mbarperhour = auto() + barperhour = auto() + psiperhour = auto() + statmperhour = auto() + techatmperhour = auto() + mbarpers = auto() + barpers = auto() + mmH2Operhour = auto() + torrperhour = auto() + psipers = auto() + statmpers = auto() + techatmpers = auto() + mmH2Opers = auto() + torrpers = auto() + Papermin = auto() + mbarpermin = auto() + barpermin = auto() + Papers = auto() + # kPressureCoefficient + perbar = auto() + permbar = auto() + perpsi = auto() + perstatm = auto() + pertechatm = auto() + permmHg = auto() + permmH2O = auto() + VperVperPa = auto() + perPa = auto() + # kRatio + bel = auto() + # kReciprocalPower + permegW = auto() + permW = auto() + perkW = auto() + pergW = auto() + perJs = auto() + perW = auto() + # kReciprocalResistanceCharge + perOhmAs = auto() + perOhmAh = auto() + perOhmC = auto() + # kReciprocalResistanceTime + perOhmmin = auto() + perOhmhour = auto() + perOhms = auto() + # kResistance + uohm = auto() + # kResistancePerCharge + OhmperAs = auto() + OhmperAhour = auto() + nOhmperC = auto() + uOhmperC = auto() + mOhmperC = auto() + OhmperC = auto() + kOhmperC = auto() + megOhmperC = auto() + gOhmperC = auto() + # kResistancePerLength + Ohmperum = auto() + uOhmperm = auto() + mOhmperm = auto() + Ohmperm = auto() + kOhmperm = auto() + megOhmperm = auto() + # kResistanceTemperatureCoeff + OhmperCel = auto() + mOhmperKel = auto() + OhmperKel = auto() + kOhmperKel = auto() + # kResistivity + Ohmmm2permm = auto() + Ohmum = auto() + Ohmcm = auto() + Ohmm = auto() + # kSpecificHeatCapacity + mJperKelkg = auto() + JperKelkg = auto() + kJperKelkg = auto() + # kStiffness + Npercm = auto() + lbfperin = auto() + Nperm = auto() + kNperm = auto() + # kSurfaceChargeDensity + SufCDAsperm2 = auto() + SufCDnCperm2 = auto() + SufCDuCperm2 = auto() + SufCDmCperm2 = auto() + SufCDCperm2 = auto() + # kSurfaceMobility + cm2perVs = auto() + m2perVs = auto() + # kSurfaceMobilityPerVoltage + cm2pV2s = auto() + m2pV2s = auto() + # kTemperature + mkel = auto() + ckel = auto() + dkel = auto() + # kTemperatureAreaPerPower + kelm2pw = auto() + celm2pw = auto() + # kTemperatureCoefficient + perCel = auto() + perFah = auto() + percentperKel = auto() + percentperCel = auto() + percentperFah = auto() + perKel = auto() + # kTemperatureCoefficient2 + perCel2 = auto() + perFah2 = auto() + perKel2 = auto() + # kTemperatureDifference + celdiff = auto() + mkeldiff = auto() + keldiff = auto() + # kThermalCapacitance + WsperKel = auto() + JperKel = auto() + # kThermalConductance + mWperCel = auto() + WperCel = auto() + kWperCel = auto() + mWperKel = auto() + WperKel = auto() + kWperKel = auto() + # kThermalConductivity + mWperKelm = auto() + WperKelm = auto() + # kThermalConvection + wpcm2kel = auto() + wpm2kel = auto() + # kThermalRadiationCoeff + mWperKel4 = auto() + WperKel4 = auto() + kWperKel4 = auto() + # kThermalRadiationConstant + Wpercm2Kel4 = auto() + Wperm2Kel4 = auto() + # kThermalResistance + KelsperJ = auto() + KelperW = auto() + # kTime + min = auto() + hour = auto() + day = auto() + # kTimePerAngle + sperdeg = auto() + sperrev = auto() + msperrad = auto() + sperrad = auto() + # kTimeSqPerAngleSq + s2perdeg2 = auto() + s2perrad2 = auto() + # kTorque + cnewtonmeter = auto() + # kTransconductanceParameter + mAperV = auto() + AperV = auto() + kAperV = auto() + # kTransistorConstant + mAperV2 = auto() + AperV2 = auto() + # kTranslationalAcceleration + inpers2 = auto() + cmpers2 = auto() + dmpers2 = auto() + mpers2 = auto() + # kVelocitySaturation + VelSatumperV = auto() + VelSatmmperV = auto() + VelSatcmperV = auto() + VelSatmperV = auto() + # kVelocitySaturationPerVoltage + umperV2 = auto() + mmperV2 = auto() + cmperV2 = auto() + mperV2 = auto() + # kViscocity + Nsperm2 = auto() + cpoise = auto() + poise = auto() + uPas = auto() + mPas = auto() + cPas = auto() + dPas = auto() + Pas = auto() + hPas = auto() + kPas = auto() + # kViscousFriction + VisFricmNsperm = auto() + VisFricCNsperm = auto() + VisFricNsperm = auto() + VisFrickNsperm = auto() + # kVoltage + gv = auto() + # kVoltageAccelerationCoefficient + mVperm2pers2 = auto() + Vperm2pers2 = auto() + # kVoltageChangeRate + Vpermin = auto() + Vperhour = auto() + mVpers = auto() + Vpers = auto() + kVpers = auto() + # kVoltageCoefficient + permV = auto() + perkV = auto() + perV = auto() + # kVoltageCoefficient2 + perV2 = auto() + # kVoltageCubed + mV3 = auto() + V3 = auto() + # kVoltageGain + VpermV = auto() + mVperV = auto() + VperV = auto() + # kVoltageJerkCoefficient + mVpermpers3 = auto() + Vpermpers3 = auto() + # kVoltageLength + uVm = auto() + mVm = auto() + Vm = auto() + kVm = auto() + # kVoltagePerCell + pVpercell = auto() + nVpercell = auto() + uVpercell = auto() + mVpercell = auto() + Vpercell = auto() + kVpercell = auto() + megVpercell = auto() + gVpercell = auto() + # kVoltagePerLengthRoot + Vpermhalf = auto() + # kVoltagePressureRootCoeff + mVperPahalf = auto() + VperPahalf = auto() + # kVoltageRoot + Vhalf = auto() + # kVoltageRootCoefficient + perVhalf = auto() + # kVoltageTemperature10Coeff + uVperCel10 = auto() + mVperCel10 = auto() + VperCel10 = auto() + uVperKel10 = auto() + mVperKel10 = auto() + VperKel10 = auto() + # kVoltageTemperature11Coeff + uVperCel11 = auto() + mVperCel11 = auto() + VperCel11 = auto() + uVperKel11 = auto() + mVperKel11 = auto() + VperKel11 = auto() + # kVoltageTemperature12Coeff + uVperCel12 = auto() + mVperCel12 = auto() + VperCel12 = auto() + uVperKel12 = auto() + mVperKel12 = auto() + VperKel12 = auto() + # kVoltageTemperature13Coeff + uVperCel13 = auto() + mVperCel13 = auto() + VperCel13 = auto() + uVperKel13 = auto() + mVperKel13 = auto() + VperKel13 = auto() + # kVoltageTemperature14Coeff + uVperCel14 = auto() + mVperCel14 = auto() + VperCel14 = auto() + uVperKel14 = auto() + mVperKel14 = auto() + VperKel14 = auto() + # kVoltageTemperature15Coeff + uVperCel15 = auto() + mVperCel15 = auto() + VperCel15 = auto() + uVperKel15 = auto() + mVperKel15 = auto() + VperKel15 = auto() + # kVoltageTemperature2Coeff + uVperCel2 = auto() + mVperCel2 = auto() + VperCel2 = auto() + uVperKel2 = auto() + mVperKel2 = auto() + VperKel2 = auto() + # kVoltageTemperature3Coeff + uVperCel3 = auto() + mVperCel3 = auto() + VperCel3 = auto() + uVperKel3 = auto() + mVperKel3 = auto() + VperKel3 = auto() + # kVoltageTemperature4Coeff + uVperCel4 = auto() + mVperCel4 = auto() + VperCel4 = auto() + uVperKel4 = auto() + mVperKel4 = auto() + VperKel4 = auto() + # kVoltageTemperature5Coeff + uVperCel5 = auto() + mVperCel5 = auto() + VperCel5 = auto() + uVperKel5 = auto() + mVperKel5 = auto() + VperKel5 = auto() + # kVoltageTemperature6Coeff + uVperCel6 = auto() + mVperCel6 = auto() + VperCel6 = auto() + uVperKel6 = auto() + mVperKel6 = auto() + VperKel6 = auto() + # kVoltageTemperature7Coeff + uVperCel7 = auto() + mVperCel7 = auto() + VperCel7 = auto() + uVperKel7 = auto() + mVperKel7 = auto() + VperKel7 = auto() + # kVoltageTemperature8Coeff + uVperCel8 = auto() + mVperCel8 = auto() + VperCel8 = auto() + uVperKel8 = auto() + mVperKel8 = auto() + VperKel8 = auto() + # kVoltageTemperature9Coeff + uVperCel9 = auto() + mVperCel9 = auto() + VperCel9 = auto() + uVperKel9 = auto() + mVperKel9 = auto() + VperKel9 = auto() + # kVoltageTemperatureCoeff + uVperCel = auto() + mVperCel = auto() + VperCel = auto() + uVperKel = auto() + mVperKel = auto() + VperKel = auto() + # kVolume + mm3 = auto() + m3 = auto() + galUK = auto() + cup = auto() + galUS = auto() + # kVolumeCoefficient + percm3 = auto() + perm3 = auto() + # kVolumeFlowConductance + VolFConcm3perPas = auto() + VolFConm3perPas = auto() + # kVolumeFlowPerPressureRoot + m3persPahalf = auto() + # kVolumeFlowRate + m3permin = auto() + m3perhour = auto() + cm3pers = auto() + m3pers = auto() + ltrpermin = auto() + # kVolumeFlowRateChangeRate + cm3pers2 = auto() + m3pers2 = auto() + # kMass + mton = auto() + # kWireCrossSection + Wirein2 = auto() + Wireft2 = auto() + Wireum2 = auto() + Wiremm2 = auto() + Wirecm2 = auto() + Wirem2 = auto() + # kEnergyDensity + JPerM3 = auto() + kJPerM3 = auto() + # Additional Volume Units + cm3 = auto() + inch3 = auto() + foot3 = auto() + yard3 = auto() + # Magnetomotive Force + at = auto() + uat = auto() + nat = auto() + mat = auto() + kat = auto() + # additional kPercentage + Fraction = auto() + # delta temperature + fah_diff = auto() + # Delta Fahrenheit + ckel_diff = auto() + dkel_diff = auto() + # Delta Kelvin + # Additional units for Areal Flow Rate (e.g. Diffusivity) + ft2pers = auto() + cm2pers = auto() + # kMolarMass + kgpermol = auto() + gpermol = auto() + # Additional units for kViscocity + kgperms = auto() + lbmperfts = auto() + slugperfts = auto() + # Additions for kTemperatureAreaPerPower (e.g. Thermal Impedance) + celin2pw = auto() + # C-in2/W + celmm2pw = auto() + # C-mm2/W + # Additions for kIrradiance (e.g. Heat Flux Density) + btupspft2 = auto() + # BTU/s-ft2 + btuphrpft2 = auto() + # BTU/h-ft2 + ergpspcm2 = auto() + # erg/s-cm2 + # Additional units for area + micron2 = auto() + mil2 = auto() + # Additional units for thermal conductance + btuPerFahSec = auto() + btuPerRankSec = auto() + btuPerFahHr = auto() + btuPerRankHr = auto() + # Additional units for thermal conductivity + btuPerFahFtSec = auto() + btuPerRankFtSec = auto() + btuPerFahFtHr = auto() + btuPerRankFtHr = auto() + calpersmCel = auto() + calpersmKel = auto() + ergperscmKel = auto() + wPerCelM = auto() + # Additional units for density + lbmPerFt3 = auto() + slugPerFt3 = auto() + # Additional units for thermal convection + btuPerFahSecFt2 = auto() + btuPerFahHrFt2 = auto() + btuPerRankSecFt2 = auto() + btuPerRankHrFt2 = auto() + wPerCelM2 = auto() + # Additional unit(s) for length + copperOzPerFt2 = auto() + # Additional units for mass flow rate + lbmPerSec = auto() + lbmPerMin = auto() + # Additional units for power + btuPerSec = auto() + ergPerSec = auto() + # Additional units for power-per-area (surface heat) + IrradWPerMm2 = auto() + IrradMet = auto() + # Power per volume + btuPerSecFt3 = auto() + btuPerHrFt3 = auto() + ergPerSecCm3 = auto() + wPerM3 = auto() + # Additional unit(s) for pressure + lbfPerFt2 = auto() + # Additional units for thermal resistance + celPerW = auto() + fahSecPerBtu = auto() + # Additional units for specific heat capacity + btuPerLbmFah = auto() + btuPerLbmRank = auto() + calPerGKel = auto() + calPerGCel = auto() + ergPerGKel = auto() + JPerCelKg = auto() + kcalPerKgKel = auto() + kcalPerKgCel = auto() + # Additional units for temperature and delta-temperature (Rankine) + rank = auto() + rankdiff = auto() + # Turbulent dissipation rate + m2PerSec3 = auto() + ft2PerSec3 = auto() + # Turbulent kinetic energy + m2PerSec2 = auto() + ft2PerSec2 = auto() + # Specific turbulence dissipation rate + dissPerSec = auto() + # Additional unit for temperature coefficient (volumetric expansion coefficient) + perRank = auto() + percentperRank = auto() + # Additional units for volumetric flow rate + ft3PerMin = auto() + ft3PerSec = auto() + cfm = auto() + # Additional unit for pressure + pressWaterInches = auto() + # Additional unit for kCharge + q = auto() + # change of a proton (negative for electron) + # data rate units of bits/sec (added for EMIT) + bps = auto() + kbps = auto() + mbps = auto() + gbps = auto() + # kMassFlux + kgpersm2 = auto() + lbmperminft2 = auto() + gperscm2 = auto() + # kThermalConductancePerArea + Wperm2perCel = auto() + Wperin2perCel = auto() + Wpermm2perCel = auto() + # kAttenutation + dBperm = auto() + dBpercm = auto() + dBperdm = auto() + dBperkm = auto() + dBperft = auto() + dBpermi = auto() + Nppercm = auto() + Npperdm = auto() + Npperft = auto() + Npperkm = auto() + Npperm = auto() + Nppermi = auto() + + +@unique +class AllowedMarkers(IntEnum): + Octahedron = 12 + Tetrahedron = 11 + Sphere = 9 + Box = 10 + Arrow = 0 diff --git a/src/ansys/aedt/core/generic/data_handlers.py b/src/ansys/aedt/core/generic/data_handlers.py index 2d135493220..a2ded2d0436 100644 --- a/src/ansys/aedt/core/generic/data_handlers.py +++ b/src/ansys/aedt/core/generic/data_handlers.py @@ -22,7 +22,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -from collections import OrderedDict from decimal import Decimal import math import random @@ -85,12 +84,12 @@ def _tuple2dict(t, d): if k in d: if not isinstance(d[k], list): d[k] = [d[k]] - d1 = OrderedDict() + d1 = {} for tt in v: _tuple2dict(tt, d1) d[k].append(d1) else: - d[k] = OrderedDict() + d[k] = {} for tt in v: _tuple2dict(tt, d[k]) else: @@ -134,13 +133,13 @@ def _dict2arg(d, arg_out): else: arg_out.append(k + ":=") arg_out.append([i for i in v]) - elif isinstance(v, (OrderedDict, dict)): + elif isinstance(v, dict): arg = ["NAME:" + k] _dict2arg(v, arg) arg_out.append(arg) elif v is None: arg_out.append(["NAME:" + k]) - elif isinstance(v, list) and len(v) > 0 and isinstance(v[0], (OrderedDict, dict)): + elif isinstance(v, list) and len(v) > 0 and isinstance(v[0], dict): for el in v: arg = ["NAME:" + k] _dict2arg(el, arg) @@ -167,7 +166,7 @@ def _arg2dict(arg, dict_out): dict_out[arg[0][5:]] = list(arg[1:]) elif arg[0][:5] == "NAME:": top_key = arg[0][5:] - dict_in = OrderedDict() + dict_in = {} i = 1 while i < len(arg): if arg[i][0][:5] == "NAME:" and ( diff --git a/src/ansys/aedt/core/generic/farfield_visualization.py b/src/ansys/aedt/core/generic/farfield_visualization.py index 97af6ccb2b6..c1422d1108c 100644 --- a/src/ansys/aedt/core/generic/farfield_visualization.py +++ b/src/ansys/aedt/core/generic/farfield_visualization.py @@ -22,7 +22,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -from collections import OrderedDict import json import math import os @@ -586,7 +585,7 @@ def combine_farfield(self, phi_scan=0.0, theta_scan=0.0): rEtheta_fields_sum = np.reshape(rETheta_fields_sum, (n_theta, n_phi)) rEphi_fields_sum = np.reshape(rEphi_fields_sum, (n_theta, n_phi)) - farfield_data = OrderedDict() + farfield_data = {} farfield_data["rEPhi"] = rEphi_fields_sum farfield_data["rETheta"] = rEtheta_fields_sum farfield_data["rETotal"] = np.sqrt( diff --git a/src/ansys/aedt/core/generic/general_methods.py b/src/ansys/aedt/core/generic/general_methods.py index eabcc54dcd8..6a1242803e1 100644 --- a/src/ansys/aedt/core/generic/general_methods.py +++ b/src/ansys/aedt/core/generic/general_methods.py @@ -26,7 +26,6 @@ import ast import codecs -from collections import OrderedDict import csv import datetime import difflib @@ -92,11 +91,11 @@ def _write_mes(mes_text): def _get_args_dicts(func, args, kwargs): if int(sys.version[0]) > 2: - args_name = list(OrderedDict.fromkeys(inspect.getfullargspec(func)[0] + list(kwargs.keys()))) - args_dict = OrderedDict(list(itertools.zip_longest(args_name, args)) + list(kwargs.items())) + args_name = list(dict.fromkeys(inspect.getfullargspec(func)[0] + list(kwargs.keys()))) + args_dict = dict(list(itertools.zip_longest(args_name, args)) + list(kwargs.items())) else: - args_name = list(OrderedDict.fromkeys(inspect.getargspec(func)[0] + list(kwargs.keys()))) - args_dict = OrderedDict(list(itertools.izip(args_name, args)) + list(kwargs.iteritems())) + args_name = list(dict.fromkeys(inspect.getargspec(func)[0] + list(kwargs.keys()))) + args_dict = dict(list(itertools.izip(args_name, args)) + list(kwargs.iteritems())) return args_dict @@ -1394,7 +1393,7 @@ def write_configuration_file(input_data, output_file): if ext == ".json": return _create_json_file(input_data, output_file) elif ext == ".toml": - return _create_toml_file(OrderedDict(input_data), output_file) + return _create_toml_file(input_data, output_file) # @pyaedt_function_handler() @@ -2003,11 +2002,11 @@ def _recursive_search(self, dict_in, key="", matching_percentage=0.8): return True, dict_in, f[0] else: for v in list(dict_in.values()): - if isinstance(v, (dict, OrderedDict)): + if isinstance(v, dict): out_val = self._recursive_search(v, key, matching_percentage) if out_val: return out_val - elif isinstance(v, list) and isinstance(v[0], (dict, OrderedDict)): + elif isinstance(v, list) and isinstance(v[0], dict): for val in v: out_val = self._recursive_search(val, key, matching_percentage) if out_val: @@ -2023,7 +2022,7 @@ def _recursive_list(self, dict_in, prefix=""): else: name = k available_list.append(name) - if isinstance(v, (dict, OrderedDict)): + if isinstance(v, dict): available_list.extend(self._recursive_list(v, name)) return available_list @@ -2081,7 +2080,7 @@ def _arg2dict(arg, dict_out): dict_out[arg[0][5:]] = list(arg[1:]) elif arg[0][:5] == "NAME:": top_key = arg[0][5:] - dict_in = OrderedDict() + dict_in = {} i = 1 while i < len(arg): if arg[i][0][:5] == "NAME:" and ( diff --git a/src/ansys/aedt/core/generic/load_aedt_file.py b/src/ansys/aedt/core/generic/load_aedt_file.py index 008a392b360..226a73fddc9 100644 --- a/src/ansys/aedt/core/generic/load_aedt_file.py +++ b/src/ansys/aedt/core/generic/load_aedt_file.py @@ -421,7 +421,7 @@ def _walk_through_structure(keyword, save_dict, design_name=None): _count += 1 continue # end_key is found - if end_key == line: + if end_key == line and design_found: break # between begin_key and end_key if found: diff --git a/src/ansys/aedt/core/generic/spisim.py b/src/ansys/aedt/core/generic/spisim.py index b02534c8b13..214c88f033a 100644 --- a/src/ansys/aedt/core/generic/spisim.py +++ b/src/ansys/aedt/core/generic/spisim.py @@ -23,7 +23,6 @@ # SOFTWARE. # coding=utf-8 -from collections import OrderedDict import os from pathlib import Path import re @@ -533,7 +532,7 @@ def __init__(self, raw_filename: str, **kwargs): else: # pragma: no cover raise RuntimeError("Unrecognized encoding") settings.logger.info(f"Reading the file with encoding: '{self.encoding}' ") - self.raw_params = OrderedDict(Filename=raw_filename) + self.raw_params = {"Filename": raw_filename} self.backannotations = [] header = [] binary_start = 6 diff --git a/src/ansys/aedt/core/hfss.py b/src/ansys/aedt/core/hfss.py index 849f2f7f93c..589ad5d3f0f 100644 --- a/src/ansys/aedt/core/hfss.py +++ b/src/ansys/aedt/core/hfss.py @@ -27,7 +27,6 @@ from __future__ import absolute_import # noreorder import ast -from collections import OrderedDict import math import os import tempfile @@ -354,12 +353,12 @@ def _get_rad_fields(self): if self.design_properties["RadField"].get("FarFieldSetups"): for val in self.design_properties["RadField"]["FarFieldSetups"]: p = self.design_properties["RadField"]["FarFieldSetups"][val] - if isinstance(p, (dict, OrderedDict)) and p.get("Type") == "Infinite Sphere": + if isinstance(p, dict) and p.get("Type") == "Infinite Sphere": fields.append(FarFieldSetup(self, val, p, "FarFieldSphere")) if self.design_properties["RadField"].get("NearFieldSetups"): for val in self.design_properties["RadField"]["NearFieldSetups"]: p = self.design_properties["RadField"]["NearFieldSetups"][val] - if isinstance(p, (dict, OrderedDict)): + if isinstance(p, dict): if p["Type"] == "Near Rectangle": fields.append(NearFieldSetup(self, val, p, "NearFieldRectangle")) elif p["Type"] == "Near Line": @@ -405,7 +404,7 @@ def _create_lumped_driven(self, assignment, int_line_start, int_line_stop, imped assignment = self.modeler.convert_to_selections(assignment, True) start = [str(i) + self.modeler.model_units for i in int_line_start] stop = [str(i) + self.modeler.model_units for i in int_line_stop] - props = OrderedDict({}) + props = {} if isinstance(assignment[0], str): props["Objects"] = assignment else: @@ -413,34 +412,27 @@ def _create_lumped_driven(self, assignment, int_line_start, int_line_stop, imped props["DoDeembed"] = deemb props["RenormalizeAllTerminals"] = renorm if renorm: - props["Modes"] = OrderedDict( - { - "Mode1": OrderedDict( - { - "ModeNum": 1, - "UseIntLine": True, - "IntLine": OrderedDict({"Start": start, "End": stop}), - "AlignmentGroup": 0, - "CharImp": "Zpi", - "RenormImp": str(impedance) + "ohm", - } - ) + props["Modes"] = { + "Mode1": { + "ModeNum": 1, + "UseIntLine": True, + "IntLine": {"Start": start, "End": stop}, + "AlignmentGroup": 0, + "CharImp": "Zpi", + "RenormImp": str(impedance) + "ohm", } - ) + } else: - props["Modes"] = OrderedDict( - { - "Mode1": OrderedDict( - { - "ModeNum": 1, - "UseIntLine": True, - "IntLine": OrderedDict({"Start": start, "End": stop}), - "AlignmentGroup": 0, - "CharImp": "Zpi", - } - ) + props["Modes"] = { + "Mode1": { + "ModeNum": 1, + "UseIntLine": True, + "IntLine": {"Start": start, "End": stop}, + "AlignmentGroup": 0, + "CharImp": "Zpi", } - ) + } + props["ShowReporterFilter"] = False props["ReporterFilter"] = [True] props["Impedance"] = str(impedance) + "ohm" @@ -459,7 +451,7 @@ def _create_port_terminal( terminals_rename=True, ): ref_conductors = self.modeler.convert_to_selections(int_line_stop, True) - props = OrderedDict() + props = {} props["Faces"] = int(assignment) props["IsWavePort"] = iswaveport props["ReferenceConductors"] = ref_conductors @@ -470,7 +462,7 @@ def _create_port_terminal( new_ports = list(self.oboundary.GetExcitationsOfType("Terminal")) terminals = [i for i in new_ports if i not in ports] for count, terminal in enumerate(terminals, start=1): - props_terminal = OrderedDict() + props_terminal = {} props_terminal["TerminalResistance"] = "50ohm" props_terminal["ParentBndID"] = boundary.name terminal_name = terminal @@ -555,7 +547,7 @@ def _create_port_terminal( @pyaedt_function_handler(edgelist="assignment") def _create_circuit_port(self, assignment, impedance, name, renorm, deemb, renorm_impedance=""): edgelist = self.modeler.convert_to_selections(assignment, True) - props = OrderedDict( + props = dict( { "Edges": edgelist, "Impedance": str(impedance) + "ohm", @@ -598,7 +590,7 @@ def _create_waveport_driven( else: useintline = False - props = OrderedDict({}) # Used to create the argument to pass to native api: oModule.AssignWavePort() + props = {} # Used to create the argument to pass to native api: oModule.AssignWavePort() if isinstance(assignment, int): # Assumes a Face ID is passed in objectname props["Faces"] = [assignment] elif isinstance(assignment, list): # Assume [x, y, z] point is passed in objectname @@ -614,23 +606,23 @@ def _create_waveport_driven( else: props["DoDeembed"] = False props["RenormalizeAllTerminals"] = renorm - modes = OrderedDict({}) + modes = {} i = 1 report_filter = [] while i <= nummodes: if i == 1: - mode = OrderedDict({}) + mode = {} mode["ModeNum"] = i mode["UseIntLine"] = useintline if useintline: - mode["IntLine"] = OrderedDict({"Start": start, "End": stop}) + mode["IntLine"] = dict({"Start": start, "End": stop}) mode["AlignmentGroup"] = 0 mode["CharImp"] = "Zpi" if renorm: mode["RenormImp"] = str(impedance) + "ohm" modes["Mode1"] = mode else: - mode = OrderedDict({}) + mode = {} mode["ModeNum"] = i mode["UseIntLine"] = False @@ -1162,120 +1154,6 @@ def create_single_point_sweep( ) return False - @pyaedt_function_handler(source_object="assignment", solution="setup", fieldtype="field_type", source_name="name") - def create_sbr_linked_antenna( - self, - assignment, - target_cs="Global", - setup=None, - field_type="nearfield", - use_composite_ports=False, - use_global_current=True, - current_conformance=False, - thin_sources=True, - power_fraction="0.95", - visible=True, - name=None, - ): - """Create a linked antennas. - - Parameters - ---------- - assignment : ansys.aedt.core.Hfss - Source object. - target_cs : str, optional - Target coordinate system. The default is ``"Global"``. - setup : optional - Name of the setup. The default is ``None``, in which - case a name is automatically assigned. - field_type : str, optional - Field type. The options are ``"nearfield"`` and ``"farfield"``. - The default is ``"nearfield"``. - use_composite_ports : bool, optional - Whether to use composite ports. The default is ``False``. - use_global_current : bool, optional - Whether to use the global current. The default is ``True``. - current_conformance : bool, optional - Whether to enable current conformance. The default is ``False``. - thin_sources : bool, optional - Whether to enable thin sources. The default is ``True``. - power_fraction : str, optional - The default is ``"0.95"``. - visible : bool, optional. - Whether to make source objects in the target design visible. The default is ``True``. - name : str, optional - Name of the source. - The default is ``None`` in which case a name is automatically assigned. - - References - ---------- - - >>> oEditor.InsertNativeComponent - - Examples - -------- - >>> from ansys.aedt.core import Hfss - >>> target_project = "my/path/to/targetProject.aedt" - >>> source_project = "my/path/to/sourceProject.aedt" - >>> target = Hfss(project=target_project, solution_type="SBR+", - ... version="2021.2", new_desktop=False) # doctest: +SKIP - >>> source = Hfss(project=source_project, design="feeder", - ... version="2021.2", new_desktop=False) # doctest: +SKIP - >>> target.create_sbr_linked_antenna(source,target_cs="feederPosition",field_type="farfield") # doctest: +SKIP - - """ - if self.solution_type != "SBR+": - self.logger.error("Native components only apply to the SBR+ solution.") - return False - - if name is None: - uniquename = generate_unique_name(assignment.design_name) - else: - uniquename = generate_unique_name(name) - - if assignment.project_name == self.project_name: - project_name = "This Project*" - else: - project_name = os.path.join(assignment.project_path, assignment.project_name + ".aedt") - design_name = assignment.design_name - if not setup: - setup = assignment.nominal_adaptive - params = OrderedDict({}) - pars = assignment.available_variations.nominal_w_values_dict - for el in pars: - params[el] = pars[el] - native_props = OrderedDict( - { - "Type": "Linked Antenna", - "Unit": self.modeler.model_units, - "Is Parametric Array": False, - "Project": project_name, - "Product": "HFSS", - "Design": design_name, - "Soln": setup, - "Params": params, - "ForceSourceToSolve": True, - "PreservePartnerSoln": True, - "PathRelativeTo": "TargetProject", - "FieldType": field_type, - "UseCompositePort": use_composite_ports, - "SourceBlockageStructure": OrderedDict({"NonModelObject": []}), - } - ) - if field_type == "nearfield": - native_props["UseGlobalCurrentSrcOption"] = use_global_current - if current_conformance: - native_props["Current Source Conformance"] = "Enable" - else: - native_props["Current Source Conformance"] = "Disable" - native_props["Thin Sources"] = thin_sources - native_props["Power Fraction"] = power_fraction - if visible: - native_props["VisualizationObjects"] = assignment.modeler.solid_names - return self._create_native_component( - "Linked Antenna", target_cs, self.modeler.model_units, native_props, uniquename - ) - @pyaedt_function_handler() def _create_native_component( self, antenna_type, target_cs=None, model_units=None, parameters_dict=None, antenna_name=None @@ -1287,9 +1165,7 @@ def _create_native_component( if not model_units: model_units = self.modeler.model_units - native_props = OrderedDict( - {"NativeComponentDefinitionProvider": OrderedDict({"Type": antenna_type, "Unit": model_units})} - ) + native_props = dict({"NativeComponentDefinitionProvider": dict({"Type": antenna_type, "Unit": model_units})}) if isinstance(target_cs, CoordinateSystem): target_cs = target_cs.name native_props["TargetCS"] = target_cs @@ -1345,7 +1221,7 @@ class SbrAntennas: ) class SBRAntennaDefaults: - _conical = OrderedDict( + _conical = dict( { "Is Parametric Array": False, "MatchedPortImpedance": "50ohm", @@ -1355,7 +1231,7 @@ class SBRAntennaDefaults: "Flare Half Angle": "20deg", } ) - _cross = OrderedDict( + _cross = dict( { "Is Parametric Array": False, "MatchedPortImpedance": "50ohm", @@ -1368,7 +1244,7 @@ class SBRAntennaDefaults: "Mode": 0, } ) - _horizontal = OrderedDict( + _horizontal = dict( { "Is Parametric Array": False, "MatchedPortImpedance": "50ohm", @@ -1382,7 +1258,7 @@ class SBRAntennaDefaults: "Use Default Height": True, } ) - _parametricbeam = OrderedDict( + _parametricbeam = dict( { "Is Parametric Array": False, "Size": "0.1meter", @@ -1393,7 +1269,7 @@ class SBRAntennaDefaults: "Horizontal BeamWidth": "60deg", } ) - _slot = OrderedDict( + _slot = dict( { "Is Parametric Array": False, "MatchedPortImpedance": "50ohm", @@ -1402,7 +1278,7 @@ class SBRAntennaDefaults: "Slot Length": "499.654096666667mm", } ) - _horn = OrderedDict( + _horn = dict( { "Is Parametric Array": False, "MatchedPortImpedance": "50ohm", @@ -1414,7 +1290,7 @@ class SBRAntennaDefaults: "Height Flare Half Angle": "35deg", } ) - _dipole = OrderedDict( + _dipole = dict( { "Is Parametric Array": False, "Size": "1mm", @@ -1422,7 +1298,7 @@ class SBRAntennaDefaults: "Representation": "Far Field", } ) - _smallloop = OrderedDict( + _smallloop = dict( { "Is Parametric Array": False, "MatchedPortImpedance": "50ohm", @@ -1437,7 +1313,7 @@ class SBRAntennaDefaults: "Flare Half Angle": "20deg", } ) - _wiredipole = OrderedDict( + _wiredipole = dict( { "Is Parametric Array": False, "MatchedPortImpedance": "50ohm", @@ -1645,7 +1521,7 @@ def create_sbr_file_based_antenna( if target_cs is None: target_cs = self.modeler.oeditor.GetActiveCoordinateSystem() - par_dicts = OrderedDict( + par_dicts = dict( { "Size": antenna_size, "MatchedPortImpedance": antenna_impedance, @@ -1658,6 +1534,252 @@ def create_sbr_file_based_antenna( return self._create_native_component("File Based Antenna", target_cs, units, par_dicts, name) + @pyaedt_function_handler(source_object="assignment", solution="setup", fieldtype="field_type", source_name="name") + def create_sbr_linked_antenna( + self, + assignment, + target_cs="Global", + setup=None, + field_type="nearfield", + use_composite_ports=False, + use_global_current=True, + current_conformance=False, + thin_sources=True, + power_fraction="0.95", + visible=True, + name=None, + ): + """Create a linked antennas. + + Parameters + ---------- + assignment : ansys.aedt.core.Hfss + Source object. + target_cs : str, optional + Target coordinate system. The default is ``"Global"``. + setup : optional + Name of the setup. The default is ``None``, in which + case a name is automatically assigned. + field_type : str, optional + Field type. The options are ``"nearfield"`` and ``"farfield"``. + The default is ``"nearfield"``. + use_composite_ports : bool, optional + Whether to use composite ports. The default is ``False``. + use_global_current : bool, optional + Whether to use the global current. The default is ``True``. + current_conformance : bool, optional + Whether to enable current conformance. The default is ``False``. + thin_sources : bool, optional + Whether to enable thin sources. The default is ``True``. + power_fraction : str, optional + The default is ``"0.95"``. + visible : bool, optional. + Whether to make source objects in the target design visible. The default is ``True``. + name : str, optional + Name of the source. + The default is ``None`` in which case a name is automatically assigned. + + References + ---------- + + >>> oEditor.InsertNativeComponent + + Examples + -------- + >>> from ansys.aedt.core import Hfss + >>> target_project = "my/path/to/targetProject.aedt" + >>> source_project = "my/path/to/sourceProject.aedt" + >>> target = Hfss(project=target_project, solution_type="SBR+", + ... version="2021.2", new_desktop=False) # doctest: +SKIP + >>> source = Hfss(project=source_project, design="feeder", + ... version="2021.2", new_desktop=False) # doctest: +SKIP + >>> target.create_sbr_linked_antenna(source,target_cs="feederPosition",field_type="farfield") # doctest: +SKIP + + """ + if self.solution_type != "SBR+": + self.logger.error("Native components only apply to the SBR+ solution.") + return False + + if name is None: + uniquename = generate_unique_name(assignment.design_name) + else: + uniquename = generate_unique_name(name) + + if assignment.project_name == self.project_name: + project_name = "This Project*" + else: + project_name = os.path.join(assignment.project_path, assignment.project_name + ".aedt") + design_name = assignment.design_name + if not setup: + setup = assignment.nominal_adaptive + params = {} + pars = assignment.available_variations.nominal_w_values_dict + for el in pars: + params[el] = pars[el] + native_props = dict( + { + "Type": "Linked Antenna", + "Unit": self.modeler.model_units, + "Is Parametric Array": False, + "Project": project_name, + "Product": "HFSS", + "Design": design_name, + "Soln": setup, + "Params": params, + "ForceSourceToSolve": True, + "PreservePartnerSoln": True, + "PathRelativeTo": "TargetProject", + "FieldType": field_type, + "UseCompositePort": use_composite_ports, + "SourceBlockageStructure": dict({"NonModelObject": []}), + } + ) + if field_type == "nearfield": + native_props["UseGlobalCurrentSrcOption"] = use_global_current + if current_conformance: + native_props["Current Source Conformance"] = "Enable" + else: + native_props["Current Source Conformance"] = "Disable" + native_props["Thin Sources"] = thin_sources + native_props["Power Fraction"] = power_fraction + if visible: + native_props["VisualizationObjects"] = assignment.modeler.solid_names + return self._create_native_component( + "Linked Antenna", target_cs, self.modeler.model_units, native_props, uniquename + ) + + @pyaedt_function_handler() + def create_sbr_custom_array( + self, + output_file=None, + frequencies=None, + element_number=1, + state_number=1, + position=None, + x_axis=None, + y_axis=None, + weight=None, + ): + """Create custom array file with sarr format. + + Parameters + ---------- + output_file : str, optional + Full path and name for the file. + The default is ``None``, in which case the file is exported to the working directory. + frequencies : list, optional + List of frequencies in GHz. The default is ``[1.0]``. + element_number : int, optional + Number of elements in the array. The default is ``1``. + state_number : int, optional + Number of states. The default is ``1``. + position : list of list + List of the ``[x, y, z]`` coordinates for each element. The default is ``[1, 0, 0]``. + x_axis : list of list + List of X, Y, Z components of X-axis unit vector. + y_axis : list of list + List of X, Y, Z components of Y-axis unit vector. The default is ``[0, 1, 0]``. + weight : list of list + Weight of each element. The default is ``None`` in which case all elements have uniform weight. + The second dimension contains the weights for each element, organized as follows: + The first ``frequencies`` entries correspond to the weights for that element at each + of the ``frequencies``, for the first state. + If there are multiple states, the next ``frequencies`` entries represent the weights for the second state, + and so on. + For example, for 3 frequencies ``(f1, f2, f3)``, 2 elements ``(e1, e2)``, and 2 states ``(s1, s2)``, + the weight would be represented as: ``[[w_f1_e1_s1, w_f1_e2_s1], [w_f2_e1_s1, w_f2_e2_s1], + [w_f3_e1_s1, w_f3_e2_s1], [w_f1_e1_s2, w_f1_e2_s2], [w_f2_e1_s2, w_f2_e2_s2], [w_f3_e1_s2, w_f3_e2_s2]]``. + ``` + + Returns + ------- + str + File name when successful, ``False`` when failed. + + Examples + -------- + >>> from ansys.aedt.core import Hfss + >>> hfss = Hfss() + >>> hfss.create_sbr_custom_array() + >>> hfss.release_desktop() + """ + if output_file is None: + output_file = os.path.join(self.working_directory, "custom_array.sarr") + + if frequencies is None: + frequencies = [1.0] + + if position is None: + position = [[0.0, 0.0, 0.0]] * element_number + + if x_axis is None: + x_axis = [[1.0, 0.0, 0.0]] * element_number + + if y_axis is None: + y_axis = [[0.0, 1.0, 0.0]] * element_number + + try: + with open(output_file, "w") as sarr_file: + sarr_file.write("# Array Element List (.sarr) file\n") + sarr_file.write("# Blank lines and lines beginning with pound sign ('#') are ignored\n") + + # Write whether weight exists + has_weight = weight is not None + sarr_file.write("\n") + sarr_file.write("# has_weights flags whether array file includes element weight data.\n") + sarr_file.write("# If not, then array file only specifies element positions and orientations.\n") + sarr_file.write(f"has_weights {'true' if has_weight else 'false'}\n") + + # Write frequency domain + nf = len(frequencies) + if len(frequencies) == 1 or all( + abs(frequencies[i + 1] - frequencies[i] - (frequencies[1] - frequencies[0])) < 1e-9 + for i in range(len(frequencies) - 1) + ): + sarr_file.write("\n") + sarr_file.write("# freq # nstep = nfreq - 1\n") + sarr_file.write(f"freq {frequencies[0]} {frequencies[-1]} {nf - 1}\n") + else: + sarr_file.write("\n") + sarr_file.write("# freq_list\n") + sarr_file.write(f"freq_list {nf}\n") + for freq in frequencies: + sarr_file.write(f"{freq}\n") + + # Handle states + ns = state_number + nfns = nf * ns + if has_weight: + sarr_file.write("\n") + sarr_file.write("# num_states\n") + sarr_file.write(f"num_states {ns}\n") + # Flatten weights + weight_reshaped = [[weight[i][j] for i in range(nfns)] for j in range(element_number)] + + # Number of elements + sarr_file.write("\n") + sarr_file.write("# num_elements\n") + sarr_file.write(f"num_elements {element_number}\n") + + # Element data block + sarr_file.write("\n") + sarr_file.write("# Element List Data Block\n") + for elem in range(element_number): + sarr_file.write(f"\n# Element {elem + 1}\n") + sarr_file.write(f"{position[elem][0]:13.7e} {position[elem][1]:13.7e} {position[elem][2]:13.7e}\n") + sarr_file.write(f"{x_axis[elem][0]:13.7e} {x_axis[elem][1]:13.7e} {x_axis[elem][2]:13.7e}\n") + sarr_file.write(f"{y_axis[elem][0]:13.7e} {y_axis[elem][1]:13.7e} {y_axis[elem][2]:13.7e}\n") + + if has_weight: + for ifs in range(nfns): + weight0 = weight_reshaped[elem][ifs] + sarr_file.write(f"{weight0.real:13.7e} {weight0.imag:13.7e}\n") + except Exception as e: # pragma: no cover + self.logger.error(f"Error: {e}") + return False + + return output_file + @pyaedt_function_handler() def set_sbr_txrx_settings(self, txrx_settings): """Set SBR+ TX RX antennas settings. @@ -1681,9 +1803,9 @@ def set_sbr_txrx_settings(self, txrx_settings): self.logger.error("This boundary only applies to a SBR+ solution.") return False id_ = 0 - props = OrderedDict({}) + props = {} for el, val in txrx_settings.items(): - props["Tx/Rx List " + str(id_)] = OrderedDict({"Tx Antenna": el, "Rx Antennas": txrx_settings[el]}) + props["Tx/Rx List " + str(id_)] = dict({"Tx Antenna": el, "Rx Antennas": txrx_settings[el]}) id_ += 1 return self._create_boundary("SBRTxRxSettings", props, "SBRTxRxSettings") @@ -2009,7 +2131,7 @@ def create_source_excitation(self, assignment, point1, point2, name, source_type >>> oModule.AssignCurrent """ - props = OrderedDict({"Objects": [assignment], "Direction": OrderedDict({"Start": point1, "End": point2})}) + props = dict({"Objects": [assignment], "Direction": dict({"Start": point1, "End": point2})}) return self._create_boundary(name, props, source_type) @pyaedt_function_handler( @@ -2071,7 +2193,7 @@ def create_floquet_port( >>> oModule.AssignFloquetPort """ face_id = self.modeler.convert_to_selections(assignment, True) - props = OrderedDict({}) + props = {} if isinstance(face_id[0], int): props["Faces"] = face_id else: @@ -2085,9 +2207,9 @@ def create_floquet_port( props["DoDeembed"] = False props["DeembedDist"] = "0mm" props["RenormalizeAllTerminals"] = renormalize - props["Modes"] = OrderedDict({}) + props["Modes"] = {} for i in range(1, 1 + modes): - props["Modes"]["Mode{}".format(i)] = OrderedDict({}) + props["Modes"]["Mode{}".format(i)] = {} props["Modes"]["Mode{}".format(i)]["ModeNum"] = i props["Modes"]["Mode{}".format(i)]["UseIntLine"] = False props["Modes"]["Mode{}".format(i)]["CharImp"] = "Zpi" @@ -2101,11 +2223,11 @@ def create_floquet_port( lattice_origin = output[0] lattice_a_end = output[1] lattice_b_end = output[2] - props["LatticeAVector"] = OrderedDict({}) + props["LatticeAVector"] = {} props["LatticeAVector"]["Coordinate System"] = lattice_cs props["LatticeAVector"]["Start"] = lattice_origin props["LatticeAVector"]["End"] = lattice_a_end - props["LatticeBVector"] = OrderedDict({}) + props["LatticeBVector"] = {} props["LatticeBVector"]["Coordinate System"] = lattice_cs props["LatticeBVector"]["Start"] = lattice_origin props["LatticeBVector"]["End"] = lattice_b_end @@ -2164,7 +2286,7 @@ def assign_lattice_pair( >>> oModule.AssignLatticePair """ - props = OrderedDict({}) + props = {} face_id = self.modeler.convert_to_selections(assignment, True) props["Faces"] = face_id props["ReverseV"] = reverse_v @@ -2278,7 +2400,7 @@ def assign_secondary( >>> oModule.AssignSecondary """ - props = OrderedDict({}) + props = {} face_id = self.modeler.convert_to_selections(assignment, True) if isinstance(face_id[0], str): props["Objects"] = face_id @@ -2286,7 +2408,7 @@ def assign_secondary( else: props["Faces"] = face_id - props["CoordSysVector"] = OrderedDict({}) + props["CoordSysVector"] = {} props["CoordSysVector"]["Coordinate System"] = coordinate_system props["CoordSysVector"]["Origin"] = u_start props["CoordSysVector"]["UPos"] = u_end @@ -2337,7 +2459,7 @@ def assign_primary(self, assignment, u_start, u_end, reverse_v=False, coordinate >>> oModule.AssignPrimary """ - props = OrderedDict({}) + props = {} face_id = self.modeler.convert_to_selections(assignment, True) if isinstance(face_id[0], str): props["Objects"] = face_id @@ -2345,7 +2467,7 @@ def assign_primary(self, assignment, u_start, u_end, reverse_v=False, coordinate else: props["Faces"] = face_id props["ReverseV"] = reverse_v - props["CoordSysVector"] = OrderedDict({}) + props["CoordSysVector"] = {} props["CoordSysVector"]["Coordinate System"] = coordinate_system props["CoordSysVector"]["Origin"] = u_start props["CoordSysVector"]["UPos"] = u_end @@ -2718,9 +2840,9 @@ def create_lumped_rlc_between_objects( start = [str(i) + self.modeler.model_units for i in point0] stop = [str(i) + self.modeler.model_units for i in point1] - props = OrderedDict() + props = {} props["Objects"] = [sheet_name] - props["CurrentLine"] = OrderedDict({"Start": start, "End": stop}) + props["CurrentLine"] = dict({"Start": start, "End": stop}) props["RLC Type"] = rlc_type if resistance: props["UseResist"] = True @@ -2814,7 +2936,7 @@ def create_impedance_between_objects( source_name = generate_unique_name("Imped") elif source_name in self.modeler.get_boundaries_name(): source_name = generate_unique_name(source_name) - props = OrderedDict( + props = dict( { "Objects": [sheet_name], "Resistance": str(resistance), @@ -3213,9 +3335,9 @@ def assign_lumped_rlc_to_sheet( name = generate_unique_name(name) start = [str(i) + self.modeler.model_units for i in point0] stop = [str(i) + self.modeler.model_units for i in point1] - props = OrderedDict() + props = {} props["Objects"] = [assignment] - props["CurrentLine"] = OrderedDict({"Start": start, "End": stop}) + props["CurrentLine"] = dict({"Start": start, "End": stop}) props["RLC Type"] = rlc_type if resistance: props["UseResist"] = True @@ -3280,13 +3402,13 @@ def assign_impedance_to_sheet(self, assignment, name=None, resistance=50, reacta objects = self.modeler.convert_to_selections(assignment, True) - props = OrderedDict( + props = dict( { "Faces": objects, } ) if isinstance(objects[0], str): - props = OrderedDict( + props = dict( { "Objects": objects, } @@ -3372,13 +3494,13 @@ def assign_impedance_to_sheet( objects = self.modeler.convert_to_selections(assignment, True) - props = OrderedDict( + props = dict( { "Faces": objects, } ) if isinstance(objects[0], str): - props = OrderedDict( + props = dict( { "Objects": objects, } @@ -4895,7 +5017,7 @@ def insert_infinite_sphere( if not name: name = generate_unique_name("Infinite") - props = OrderedDict({"UseCustomRadiationSurface": custom_radiation_faces is not None}) + props = dict({"UseCustomRadiationSurface": custom_radiation_faces is not None}) if custom_radiation_faces: props["CustomRadiationSurface"] = custom_radiation_faces else: @@ -4987,7 +5109,7 @@ def insert_near_field_sphere( if not name: name = generate_unique_name("Sphere") - props = OrderedDict({"UseCustomRadiationSurface": custom_radiation_faces is not None}) + props = dict({"UseCustomRadiationSurface": custom_radiation_faces is not None}) if custom_radiation_faces: props["CustomRadiationSurface"] = custom_radiation_faces else: @@ -5064,7 +5186,7 @@ def insert_near_field_box( if not name: name = generate_unique_name("Box") - props = OrderedDict({"UseCustomRadiationSurface": custom_radiation_faces is not None}) + props = dict({"UseCustomRadiationSurface": custom_radiation_faces is not None}) if custom_radiation_faces: props["CustomRadiationSurface"] = custom_radiation_faces else: @@ -5133,7 +5255,7 @@ def insert_near_field_rectangle( if not name: name = generate_unique_name("Rectangle") - props = OrderedDict({"UseCustomRadiationSurface": custom_radiation_faces is not None}) + props = dict({"UseCustomRadiationSurface": custom_radiation_faces is not None}) if custom_radiation_faces: props["CustomRadiationSurface"] = custom_radiation_faces else: @@ -5188,7 +5310,7 @@ def insert_near_field_line( if not name: name = generate_unique_name("Line") - props = OrderedDict({"UseCustomRadiationSurface": custom_radiation_faces is not None}) + props = dict({"UseCustomRadiationSurface": custom_radiation_faces is not None}) if custom_radiation_faces: props["CustomRadiationSurface"] = custom_radiation_faces else: @@ -5303,7 +5425,7 @@ def set_differential_pair( if self.solution_type not in ["Transient Network", "Terminal"]: # pragma: no cover raise AttributeError("Differential pairs can be defined only in Terminal and Transient solution types.") - props = OrderedDict() + props = {} props["PosBoundary"] = assignment props["NegBoundary"] = reference if not common_mode: @@ -5766,7 +5888,7 @@ def assign_symmetry(self, assignment, name=None, is_perfect_e=True): assignment = self.modeler.convert_to_selections(assignment, True) - props = OrderedDict({"Name": name, "Faces": assignment, "IsPerfectE": is_perfect_e}) + props = dict({"Name": name, "Faces": assignment, "IsPerfectE": is_perfect_e}) return self._create_boundary(name, props, "Symmetry") except Exception: return False diff --git a/src/ansys/aedt/core/hfss3dlayout.py b/src/ansys/aedt/core/hfss3dlayout.py index 5b7b21791f8..c935b4e2d46 100644 --- a/src/ansys/aedt/core/hfss3dlayout.py +++ b/src/ansys/aedt/core/hfss3dlayout.py @@ -26,7 +26,6 @@ from __future__ import absolute_import # noreorder -from collections import OrderedDict import fnmatch import io import os @@ -1992,7 +1991,7 @@ def edit_hfss_extents( @pyaedt_function_handler() def _update_port_info(self, port): propnames = self.oeditor.GetProperties("EM Design", "Excitations:{}".format(port)) - props = OrderedDict() + props = {} for prop in propnames: props[prop] = self.oeditor.GetPropertyValue("EM Design", "Excitations:{}".format(port), prop) return BoundaryObject3dLayout(self, port, props, "Port") diff --git a/src/ansys/aedt/core/icepak.py b/src/ansys/aedt/core/icepak.py index a01b999a50f..83e26b7b960 100644 --- a/src/ansys/aedt/core/icepak.py +++ b/src/ansys/aedt/core/icepak.py @@ -26,7 +26,6 @@ from __future__ import absolute_import # noreorder -from collections import OrderedDict import csv import os import re @@ -640,17 +639,18 @@ def create_conduting_plate( elif isinstance(face_id[0], str): props["Objects"] = face_id if radiate_low: - props["LowSide"] = OrderedDict( - {"Radiate": True, "RadiateTo": "AllObjects", "Surface Material": low_surf_material} - ) + props["LowSide"] = {"Radiate": True, "RadiateTo": "AllObjects", "Surface Material": low_surf_material} else: - props["LowSide"] = OrderedDict({"Radiate": False}) + props["LowSide"] = {"Radiate": False} if radiate_high: - props["HighSide"] = OrderedDict( - {"Radiate": True, "RadiateTo": "AllObjects - High", "Surface Material - High": high_surf_material} - ) + props["HighSide"] = { + "Radiate": True, + "RadiateTo": "AllObjects - High", + "Surface Material - High": high_surf_material, + } + else: - props["HighSide"] = OrderedDict({"Radiate": False}) + props["HighSide"] = {"Radiate": False} props["Thermal Specification"] = thermal_specification props["Thickness"] = thickness props["Solid Material"] = solid_material @@ -660,13 +660,12 @@ def create_conduting_plate( if thermal_dependent_dataset is None: props["Total Power"] = input_power else: - props["Total Power Variation Data"] = OrderedDict( - { - "Variation Type": "Temp Dep", - "Variation Function": "Piecewise Linear", - "Variation Value": '["1W", "pwl({},Temp)"]'.format(thermal_dependent_dataset), - } - ) + props["Total Power Variation Data"] = { + "Variation Type": "Temp Dep", + "Variation Function": "Piecewise Linear", + "Variation Value": '["1W", "pwl({},Temp)"]'.format(thermal_dependent_dataset), + } + props["Shell Conduction"] = shell_conduction bound = BoundaryObject(self, bc_name, props, "Conducting Plate") return _create_boundary(bound) @@ -748,16 +747,14 @@ def create_source_power( if thermal_dependent_dataset is None: props["Total Power"] = input_power else: - props["Total Power Variation Data"] = OrderedDict( - { - "Variation Type": "Temp Dep", - "Variation Function": "Piecewise Linear", - "Variation Value": '["1W", "pwl({},Temp)"]'.format(thermal_dependent_dataset), - } - ) + props["Total Power Variation Data"] = { + "Variation Type": "Temp Dep", + "Variation Function": "Piecewise Linear", + "Variation Value": '["1W", "pwl({},Temp)"]'.format(thermal_dependent_dataset), + } props["Surface Heat"] = surface_heat props["Temperature"] = temperature - props["Radiation"] = OrderedDict({"Radiate": radiate}) + props["Radiation"] = {"Radiate": radiate} bound = BoundaryObject(self, source_name, props, "SourceIcepak") return _create_boundary(bound) @@ -855,20 +852,16 @@ def create_network_block( else: boundary_name = generate_unique_name("Block") props["Faces"] = [fcrjc, fcrjb] - props["Nodes"] = OrderedDict( - { - "Face" + str(fcrjc): [fcrjc, "NoResistance"], - "Face" + str(fcrjb): [fcrjb, "NoResistance"], - "Internal": [power], - } - ) - props["Links"] = OrderedDict( - { - "Link1": ["Face" + str(fcrjc), "Internal", "R", str(rjc) + "cel_per_w"], - "Link2": ["Face" + str(fcrjb), "Internal", "R", str(rjb) + "cel_per_w"], - } - ) - props["SchematicData"] = OrderedDict({}) + props["Nodes"] = { + "Face" + str(fcrjc): [fcrjc, "NoResistance"], + "Face" + str(fcrjb): [fcrjb, "NoResistance"], + "Internal": [power], + } + props["Links"] = { + "Link1": ["Face" + str(fcrjc), "Internal", "R", str(rjc) + "cel_per_w"], + "Link2": ["Face" + str(fcrjb), "Internal", "R", str(rjb) + "cel_per_w"], + } + props["SchematicData"] = {} bound = BoundaryObject(self, boundary_name, props, "Network") if bound.create(): self._boundaries[bound.name] = bound @@ -1859,7 +1852,7 @@ def assign_em_losses( else: intr = [] - argparam = OrderedDict({}) + argparam = {} for el in self.available_variations.nominal_w_values_dict: argparam[el] = self.available_variations.nominal_w_values_dict[el] @@ -1870,19 +1863,18 @@ def assign_em_losses( for el in parameters: argparam[el] = parameters[el] - props = OrderedDict( - { - "Objects": assignment, - "Project": project_name, - "Product": "ElectronicsDesktop", - "Design": design, - "Soln": setup + " : " + sweep, - "Params": argparam, - "ForceSourceToSolve": True, - "PreservePartnerSoln": True, - "PathRelativeTo": "TargetProject", - } - ) + props = { + "Objects": assignment, + "Project": project_name, + "Product": "ElectronicsDesktop", + "Design": design, + "Soln": setup + " : " + sweep, + "Params": argparam, + "ForceSourceToSolve": True, + "PreservePartnerSoln": True, + "PathRelativeTo": "TargetProject", + } + props["Intrinsics"] = intr props["SurfaceOnly"] = surfaces @@ -2280,76 +2272,71 @@ def create_fan( if not name: name = generate_unique_name("Fan") - basic_component = OrderedDict( - { - "ComponentName": name, - "Company": "", - "Company URL": "", - "Model Number": "", - "Help URL": "", - "Version": "1.0", - "Notes": "", - "IconType": "Fan", - } - ) + basic_component = { + "ComponentName": name, + "Company": "", + "Company URL": "", + "Model Number": "", + "Help URL": "", + "Version": "1.0", + "Notes": "", + "IconType": "Fan", + } + if is_2d: model = "2D" else: model = "3D" cross_section = GeometryOperators.cs_plane_to_plane_str(cross_section) - native_component = OrderedDict( - { - "Type": "Fan", - "Unit": self.modeler.model_units, - "ModelAs": model, - "Shape": shape, - "MovePlane": cross_section, - "Radius": self._arg_with_units(radius), - "HubRadius": self._arg_with_units(hub_radius), - "CaseSide": True, - "FlowDirChoice": "NormalPositive", - "FlowType": "Curve", - "SwirlType": "Magnitude", - "FailedFan": False, - "DimUnits": ["m3_per_s", "n_per_meter_sq"], - "X": ["0", "0.01"], - "Y": ["3", "0"], - "Pressure Loss Curve": OrderedDict( - {"DimUnits": ["m_per_sec", "n_per_meter_sq"], "X": ["", "", "", "3"], "Y": ["", "1", "10", "0"]} - ), - "IntakeTemp": "AmbientTemp", - "Swirl": "0", - "OperatingRPM": "0", - "Magnitude": "1", - } - ) - native_props = OrderedDict( - { - "TargetCS": "Global", - "SubmodelDefinitionName": name, - "ComponentPriorityLists": OrderedDict({}), - "NextUniqueID": 0, - "MoveBackwards": False, - "DatasetType": "ComponentDatasetType", - "DatasetDefinitions": OrderedDict({}), - "BasicComponentInfo": basic_component, - "GeometryDefinitionParameters": OrderedDict({"VariableOrders": OrderedDict()}), - "DesignDefinitionParameters": OrderedDict({"VariableOrders": OrderedDict()}), - "MaterialDefinitionParameters": OrderedDict({"VariableOrders": OrderedDict()}), - "MapInstanceParameters": "DesignVariable", - "UniqueDefinitionIdentifier": "57c8ab4e-4db9-4881-b6bb-" - + random_string(12, char_set="abcdef0123456789"), - "OriginFilePath": "", - "IsLocal": False, - "ChecksumString": "", - "ChecksumHistory": [], - "VersionHistory": [], - "NativeComponentDefinitionProvider": native_component, - "InstanceParameters": OrderedDict( - {"GeometryParameters": "", "MaterialParameters": "", "DesignParameters": ""} - ), - } - ) + native_component = { + "Type": "Fan", + "Unit": self.modeler.model_units, + "ModelAs": model, + "Shape": shape, + "MovePlane": cross_section, + "Radius": self._arg_with_units(radius), + "HubRadius": self._arg_with_units(hub_radius), + "CaseSide": True, + "FlowDirChoice": "NormalPositive", + "FlowType": "Curve", + "SwirlType": "Magnitude", + "FailedFan": False, + "DimUnits": ["m3_per_s", "n_per_meter_sq"], + "X": ["0", "0.01"], + "Y": ["3", "0"], + "Pressure Loss Curve": { + "DimUnits": ["m_per_sec", "n_per_meter_sq"], + "X": ["", "", "", "3"], + "Y": ["", "1", "10", "0"], + }, + "IntakeTemp": "AmbientTemp", + "Swirl": "0", + "OperatingRPM": "0", + "Magnitude": "1", + } + + native_props = { + "TargetCS": "Global", + "SubmodelDefinitionName": name, + "ComponentPriorityLists": {}, + "NextUniqueID": 0, + "MoveBackwards": False, + "DatasetType": "ComponentDatasetType", + "DatasetDefinitions": {}, + "BasicComponentInfo": basic_component, + "GeometryDefinitionParameters": {"VariableOrders": {}}, + "DesignDefinitionParameters": {"VariableOrders": {}}, + "MaterialDefinitionParameters": {"VariableOrders": {}}, + "MapInstanceParameters": "DesignVariable", + "UniqueDefinitionIdentifier": "57c8ab4e-4db9-4881-b6bb-" + random_string(12, char_set="abcdef0123456789"), + "OriginFilePath": "", + "IsLocal": False, + "ChecksumString": "", + "ChecksumHistory": [], + "VersionHistory": [], + "NativeComponentDefinitionProvider": native_component, + "InstanceParameters": {"GeometryParameters": "", "MaterialParameters": "", "DesignParameters": ""}, + } component3d_names = list(self.modeler.oeditor.Get3DComponentInstanceNames(name)) @@ -2442,50 +2429,43 @@ def create_ipk_3dcomponent_pcb( outline_polygon = kwargs["outlinepolygon"] low_radiation, high_radiation = self.get_radiation_settings(rad) - hfss_link_info = OrderedDict({}) + hfss_link_info = {} _arg2dict(self.get_link_data(setupLinkInfo), hfss_link_info) if extent_type == "Polygon" and not outline_polygon: - native_props = OrderedDict( - { - "NativeComponentDefinitionProvider": OrderedDict( - { - "Type": "PCB", - "Unit": self.modeler.model_units, - "MovePlane": "XY", - "Use3DLayoutExtents": True, - "ExtentsType": extent_type, - "CreateDevices": False, - "CreateTopSolderballs": False, - "CreateBottomSolderballs": False, - "Resolution": int(resolution), - "LowSide": OrderedDict({"Radiate": low_radiation}), - "HighSide": OrderedDict({"Radiate": high_radiation}), - } - ) + native_props = { + "NativeComponentDefinitionProvider": { + "Type": "PCB", + "Unit": self.modeler.model_units, + "MovePlane": "XY", + "Use3DLayoutExtents": True, + "ExtentsType": extent_type, + "CreateDevices": False, + "CreateTopSolderballs": False, + "CreateBottomSolderballs": False, + "Resolution": int(resolution), + "LowSide": {"Radiate": low_radiation}, + "HighSide": {"Radiate": high_radiation}, } - ) + } + else: - native_props = OrderedDict( - { - "NativeComponentDefinitionProvider": OrderedDict( - { - "Type": "PCB", - "Unit": self.modeler.model_units, - "MovePlane": "XY", - "Use3DLayoutExtents": False, - "ExtentsType": extent_type, - "OutlinePolygon": outline_polygon, - "CreateDevices": False, - "CreateTopSolderballs": False, - "CreateBottomSolderballs": False, - "Resolution": int(resolution), - "LowSide": OrderedDict({"Radiate": low_radiation}), - "HighSide": OrderedDict({"Radiate": high_radiation}), - } - ) + native_props = { + "NativeComponentDefinitionProvider": { + "Type": "PCB", + "Unit": self.modeler.model_units, + "MovePlane": "XY", + "Use3DLayoutExtents": False, + "ExtentsType": extent_type, + "OutlinePolygon": outline_polygon, + "CreateDevices": False, + "CreateTopSolderballs": False, + "CreateBottomSolderballs": False, + "Resolution": int(resolution), + "LowSide": {"Radiate": low_radiation}, + "HighSide": {"Radiate": high_radiation}, } - ) - native_props["BasicComponentInfo"] = OrderedDict({"IconType": "PCB"}) + } + native_props["BasicComponentInfo"] = {"IconType": "PCB"} if settings.aedt_version > "2023.2": # pragma: no cover native_props["ViaHoleMaterial"] = "copper" native_props["IncludeMCAD"] = False @@ -3502,19 +3482,15 @@ def get_face_normal(obj_face): props = { "Faces": [board_side.id, case_side.id], - "Nodes": OrderedDict( - { - "Case_side(" + str(case_side) + ")": [case_side.id, "NoResistance"], - "Board_side(" + str(board_side) + ")": [board_side.id, "NoResistance"], - "Internal": [power], - } - ), - "Links": OrderedDict( - { - "Rjc": ["Case_side(" + str(case_side) + ")", "Internal", "R", str(rjc) + "cel_per_w"], - "Rjb": ["Board_side(" + str(board_side) + ")", "Internal", "R", str(rjb) + "cel_per_w"], - } - ), + "Nodes": { + "Case_side(" + str(case_side) + ")": [case_side.id, "NoResistance"], + "Board_side(" + str(board_side) + ")": [board_side.id, "NoResistance"], + "Internal": [power], + }, + "Links": { + "Rjc": ["Case_side(" + str(case_side) + ")", "Internal", "R", str(rjc) + "cel_per_w"], + "Rjb": ["Board_side(" + str(board_side) + ")", "Internal", "R", str(rjb) + "cel_per_w"], + }, "SchematicData": ({}), } @@ -4200,7 +4176,7 @@ def assign_source( props[quantity] = assignment_value else: props[quantity] = value - props["Radiation"] = OrderedDict({"Radiate": radiate}) + props["Radiation"] = {"Radiate": radiate} props["Voltage/Current - Enabled"] = bool(voltage_current_choice) default_values = {"Current": "0A", "Voltage": "0V"} props["Voltage/Current Option"] = voltage_current_choice diff --git a/src/ansys/aedt/core/maxwell.py b/src/ansys/aedt/core/maxwell.py index cbf9efba2a8..9449704434f 100644 --- a/src/ansys/aedt/core/maxwell.py +++ b/src/ansys/aedt/core/maxwell.py @@ -26,7 +26,6 @@ from __future__ import absolute_import # noreorder -from collections import OrderedDict import io import os import re @@ -347,7 +346,7 @@ def assign_matrix( elif self.solution_type in ["EddyCurrent", "Magnetostatic"]: if self.solution_type == "Magnetostatic": if group_sources: - if isinstance(group_sources, (dict, OrderedDict)): + if isinstance(group_sources, dict): new_group = group_sources.copy() for element in new_group: if not all(item in assignment for item in group_sources[element]): @@ -404,15 +403,13 @@ def assign_matrix( return False if group_sources and self.solution_type in ["EddyCurrent", "Magnetostatic"]: - props = OrderedDict( - {"MatrixEntry": OrderedDict({"MatrixEntry": []}), "MatrixGroup": OrderedDict({"MatrixGroup": []})} - ) + props = dict({"MatrixEntry": dict({"MatrixEntry": []}), "MatrixGroup": dict({"MatrixGroup": []})}) else: - props = OrderedDict({"MatrixEntry": OrderedDict({"MatrixEntry": []}), "MatrixGroup": []}) + props = dict({"MatrixEntry": dict({"MatrixEntry": []}), "MatrixGroup": []}) for element in range(len(assignment)): if self.solution_type == "Magnetostatic" and self.design_type == "Maxwell 2D": - prop = OrderedDict( + prop = dict( { "Source": assignment[element], "NumberOfTurns": turns[element], @@ -420,9 +417,9 @@ def assign_matrix( } ) elif self.solution_type == "EddyCurrent": - prop = OrderedDict({"Source": assignment[element], "ReturnPath": return_path[element]}) + prop = dict({"Source": assignment[element], "ReturnPath": return_path[element]}) else: - prop = OrderedDict({"Source": assignment[element], "NumberOfTurns": turns[element]}) + prop = dict({"Source": assignment[element], "NumberOfTurns": turns[element]}) props["MatrixEntry"]["MatrixEntry"].append(prop) if group_sources: @@ -434,9 +431,7 @@ def assign_matrix( for element in group_sources: source_list = ",".join(group_sources[element]) # GroundSources - prop = OrderedDict( - {"GroupName": element, "NumberOfBranches": branches[cont], "Sources": source_list} - ) + prop = dict({"GroupName": element, "NumberOfBranches": branches[cont], "Sources": source_list}) props["MatrixGroup"]["MatrixGroup"].append(prop) cont += 1 @@ -734,14 +729,14 @@ def assign_current(self, assignment, amplitude=1, phase="0deg", solid=True, swap assignment = self.modeler.convert_to_selections(assignment, True) if self.is3d: if type(assignment[0]) is int: - props = OrderedDict( + props = dict( { "Faces": assignment, "Current": amplitude, } ) else: - props = OrderedDict( + props = dict( { "Objects": assignment, "Current": amplitude, @@ -760,7 +755,7 @@ def assign_current(self, assignment, amplitude=1, phase="0deg", solid=True, swap props["Point out of terminal"] = swap_direction else: if type(assignment[0]) is str: - props = OrderedDict({"Objects": assignment, "Current": amplitude, "IsPositive": swap_direction}) + props = dict({"Objects": assignment, "Current": amplitude, "IsPositive": swap_direction}) else: self.logger.warning("Input must be a 2D object.") return False @@ -845,7 +840,7 @@ def assign_translate_motion( if not motion_name: motion_name = generate_unique_name("Motion") object_list = self.modeler.convert_to_selections(assignment, True) - props = OrderedDict( + props = dict( { "Move Type": "Translate", "Coordinate System": coordinate_system, @@ -943,7 +938,7 @@ def assign_rotate_motion( names = list(self.omodelsetup.GetMotionSetupNames()) motion_name = "MotionSetup" + str(len(names) + 1) object_list = self.modeler.convert_to_selections(assignment, True) - props = OrderedDict( + props = dict( { "Move Type": "Rotate", "Coordinate System": coordinate_system, @@ -1000,16 +995,16 @@ def assign_voltage(self, assignment, amplitude=1, name=None): assignment = self.modeler.convert_to_selections(assignment, True) if self.design_type == "Maxwell 2D": - props = OrderedDict({"Objects": assignment, "Value": amplitude}) + props = dict({"Objects": assignment, "Value": amplitude}) else: if len(assignment) == 1: if isinstance(assignment[0], str) and assignment[0] in self.modeler.object_names: - props = OrderedDict({"Objects": assignment, "Voltage": amplitude}) + props = dict({"Objects": assignment, "Voltage": amplitude}) else: - props = OrderedDict({"Faces": assignment, "Value": amplitude}) + props = dict({"Faces": assignment, "Value": amplitude}) else: object_names_set = set(self.modeler.object_names) - props = OrderedDict({"Faces": [], "Objects": [], "Voltage": amplitude}) + props = dict({"Faces": [], "Objects": [], "Voltage": amplitude}) for element in assignment: if isinstance(element, str) and element in object_names_set: props["Objects"].append(element) @@ -1056,7 +1051,7 @@ def assign_voltage_drop(self, assignment, amplitude=1, swap_direction=False, nam name = generate_unique_name("VoltageDrop") assignment = self.modeler.convert_to_selections(assignment, True) - props = OrderedDict({"Faces": assignment, "Voltage Drop": amplitude, "Point out of terminal": swap_direction}) + props = dict({"Faces": assignment, "Voltage Drop": amplitude, "Point out of terminal": swap_direction}) bound = BoundaryObject(self, name, props, "VoltageDrop") if bound.create(): self._boundaries[bound.name] = bound @@ -1130,7 +1125,7 @@ def assign_floating(self, assignment, charge_value=0, name=None): assignment = self.modeler.convert_to_selections(assignment, True) - props = OrderedDict({assignment_type: assignment, "Value": charge_value}) + props = dict({assignment_type: assignment, "Value": charge_value}) if not name: name = generate_unique_name("Floating") @@ -1198,7 +1193,7 @@ def assign_winding( if not name: name = generate_unique_name("Winding") - props = OrderedDict( + props = dict( { "Type": winding_type, "IsSolid": is_solid, @@ -1294,12 +1289,12 @@ def assign_coil(self, assignment, conductors_number=1, polarity="Positive", name if type(assignment[0]) is str: if self.modeler._is3d: - props2 = OrderedDict( + props2 = dict( {"Objects": assignment, "Conductor number": str(conductors_number), "Point out of terminal": point} ) bound = BoundaryObject(self, name, props2, "CoilTerminal") else: - props2 = OrderedDict( + props2 = dict( { "Objects": assignment, "Conductor number": str(conductors_number), @@ -1309,7 +1304,7 @@ def assign_coil(self, assignment, conductors_number=1, polarity="Positive", name bound = BoundaryObject(self, name, props2, "Coil") else: if self.modeler._is3d: - props2 = OrderedDict( + props2 = dict( {"Faces": assignment, "Conductor number": str(conductors_number), "Point out of terminal": point} ) bound = BoundaryObject(self, name, props2, "CoilTerminal") @@ -1381,7 +1376,7 @@ def assign_force(self, assignment, coordinate_system="Global", is_virtual=True, if not force_name: force_name = generate_unique_name("Force") if self.design_type == "Maxwell 3D": - prop = OrderedDict( + prop = dict( { "Name": force_name, "Reference CS": coordinate_system, @@ -1390,7 +1385,7 @@ def assign_force(self, assignment, coordinate_system="Global", is_virtual=True, } ) else: - prop = OrderedDict( + prop = dict( { "Name": force_name, "Reference CS": coordinate_system, @@ -1451,7 +1446,7 @@ def assign_torque( if not torque_name: torque_name = generate_unique_name("Torque") if self.design_type == "Maxwell 3D": - prop = OrderedDict( + prop = dict( { "Name": torque_name, "Is Virtual": is_virtual, @@ -1462,7 +1457,7 @@ def assign_torque( } ) else: - prop = OrderedDict( + prop = dict( { "Name": torque_name, "Coordinate System": coordinate_system, @@ -1598,10 +1593,10 @@ def assign_symmetry(self, assignment, symmetry_name=None, is_odd=True): if assignment: if self.design_type == "Maxwell 2D": assignment = self.modeler.convert_to_selections(assignment, True) - prop = OrderedDict({"Name": symmetry_name, "Edges": assignment, "IsOdd": is_odd}) + prop = dict({"Name": symmetry_name, "Edges": assignment, "IsOdd": is_odd}) else: assignment = self.modeler.convert_to_selections(assignment, True) - prop = OrderedDict({"Name": symmetry_name, "Faces": assignment, "IsOdd": is_odd}) + prop = dict({"Name": symmetry_name, "Faces": assignment, "IsOdd": is_odd}) else: msg = "At least one edge must be provided." ValueError(msg) @@ -1689,9 +1684,9 @@ def assign_current_density( current_density_group_names = [] for x in range(0, len(objects_list)): current_density_group_names.append(current_density_name + "_{}".format(str(x + 1))) - props = OrderedDict({}) + props = {} props["items"] = current_density_group_names - props[current_density_group_names[0]] = OrderedDict( + props[current_density_group_names[0]] = dict( { "Objects": objects_list, "Phase": phase, @@ -1704,7 +1699,7 @@ def assign_current_density( ) bound = BoundaryObject(self, current_density_group_names[0], props, "CurrentDensityGroup") else: - props = OrderedDict( + props = dict( { "Objects": objects_list, "Phase": phase, @@ -1721,9 +1716,9 @@ def assign_current_density( current_density_group_names = [] for x in range(0, len(objects_list)): current_density_group_names.append(current_density_name + "_{}".format(str(x + 1))) - props = OrderedDict({}) + props = {} props["items"] = current_density_group_names - props[current_density_group_names[0]] = OrderedDict( + props[current_density_group_names[0]] = dict( { "Objects": objects_list, "Phase": phase, @@ -1733,7 +1728,7 @@ def assign_current_density( ) bound = BoundaryObject(self, current_density_group_names[0], props, "CurrentDensityGroup") else: - props = OrderedDict( + props = dict( { "Objects": objects_list, "Phase": phase, @@ -2514,12 +2509,12 @@ def assign_current_density_terminal(self, assignment, current_density_name=None) current_density_group_names = [] for x in range(0, len(objects_list)): current_density_group_names.append(current_density_name + "_{}".format(str(x + 1))) - props = OrderedDict({}) + props = {} props["items"] = current_density_group_names - props[current_density_group_names[0]] = OrderedDict({"Objects": objects_list}) + props[current_density_group_names[0]] = dict({"Objects": objects_list}) bound = BoundaryObject(self, current_density_group_names[0], props, "CurrentDensityTerminalGroup") else: - props = OrderedDict({"Objects": objects_list}) + props = dict({"Objects": objects_list}) bound = BoundaryObject(self, current_density_name, props, "CurrentDensityTerminal") if bound.create(): @@ -2666,21 +2661,21 @@ def assign_master_slave( raise ValueError("Vector must contain 3 elements for x, y and z coordinates.") elif len(u_vector_pos_coordinates_slave) != 3: raise ValueError("Vector must contain 3 elements for x, y and z coordinates.") - u_master_vector_coordinates = OrderedDict( + u_master_vector_coordinates = dict( { "Coordinate System": "Global", "Origin": u_vector_origin_coordinates_master, "UPos": u_vector_pos_coordinates_master, } ) - props2 = OrderedDict( + props2 = dict( {"Faces": independent, "CoordSysVector": u_master_vector_coordinates, "ReverseV": reverse_master} ) bound = BoundaryObject(self, bound_name_m, props2, "Independent") if bound.create(): self._boundaries[bound.name] = bound - u_slave_vector_coordinates = OrderedDict( + u_slave_vector_coordinates = dict( { "Coordinate System": "Global", "Origin": u_vector_origin_coordinates_slave, @@ -2688,7 +2683,7 @@ def assign_master_slave( } ) - props2 = OrderedDict( + props2 = dict( { "Faces": dependent, "CoordSysVector": u_slave_vector_coordinates, @@ -2823,16 +2818,14 @@ def assign_layout_force( if include_no_layer: layers = layers[:] + [""] if nets_layers_props: - nets_layers_props.append(OrderedDict({key: OrderedDict({"LayerSet": layers})})) + nets_layers_props.append(dict({key: dict({"LayerSet": layers})})) else: - nets_layers_props = [OrderedDict({key: OrderedDict({"LayerSet": layers})})] + nets_layers_props = [dict({key: dict({"LayerSet": layers})})] - props = OrderedDict( + props = dict( { "Reference CS": coordinate_system, - "NetsAndLayersChoices": OrderedDict( - {component_name: OrderedDict({"NetLayerSetMap": nets_layers_props})} - ), + "NetsAndLayersChoices": dict({component_name: dict({"NetLayerSetMap": nets_layers_props})}), } ) bound = MaxwellParameters(self, force_name, props, "LayoutForce") @@ -2898,13 +2891,13 @@ def assign_tangential_h_field( assignment = self.modeler.convert_to_selections(assignment, True) if not bound_name: bound_name = generate_unique_name("TangentialHField") - props = OrderedDict( + props = dict( { "Faces": assignment, } ) if isinstance(assignment[0], str): - props = OrderedDict( + props = dict( { "Objects": assignment, } @@ -2921,7 +2914,7 @@ def assign_tangential_h_field( if not u_pos: u_pos = self.oeditor.GetEdgePositionAtNormalizedParameter(edges[0], 1) - props["CoordSysVector"] = OrderedDict({"Coordinate System": coordinate_system, "Origin": origin, "UPos": u_pos}) + props["CoordSysVector"] = dict({"Coordinate System": coordinate_system, "Origin": origin, "UPos": u_pos}) props["ReverseV"] = reverse bound = BoundaryObject(self, bound_name, props, "Tangential H Field") if bound.create(): @@ -2957,7 +2950,7 @@ def assign_zero_tangential_h_field(self, assignment, boundary=None): assignment = self.modeler.convert_to_selections(assignment, True) if not boundary: boundary = generate_unique_name("ZeroTangentialHField") - props = OrderedDict( + props = dict( { "Faces": assignment, } @@ -3241,7 +3234,7 @@ def assign_balloon(self, assignment, boundary=None): if not boundary: boundary = generate_unique_name("Balloon") - props2 = OrderedDict({"Edges": assignment}) + props2 = dict({"Edges": assignment}) bound = BoundaryObject(self, boundary, props2, "Balloon") if bound.create(): @@ -3291,9 +3284,9 @@ def assign_vector_potential(self, assignment, vector_value=0, boundary=None): if not boundary: boundary = generate_unique_name("Vector") if type(assignment[0]) is str: - props2 = OrderedDict({"Objects": assignment, "Value": str(vector_value), "CoordinateSystem": ""}) + props2 = dict({"Objects": assignment, "Value": str(vector_value), "CoordinateSystem": ""}) else: - props2 = OrderedDict({"Edges": assignment, "Value": str(vector_value), "CoordinateSystem": ""}) + props2 = dict({"Edges": assignment, "Value": str(vector_value), "CoordinateSystem": ""}) bound = BoundaryObject(self, boundary, props2, "Vector Potential") if bound.create(): @@ -3342,12 +3335,12 @@ def assign_master_slave( else: bound_name_m = boundary bound_name_s = boundary + "_dep" - props2 = OrderedDict({"Edges": independent, "ReverseV": reverse_master}) + props2 = dict({"Edges": independent, "ReverseV": reverse_master}) bound = BoundaryObject(self, bound_name_m, props2, "Independent") if bound.create(): self._boundaries[bound.name] = bound - props2 = OrderedDict( + props2 = dict( { "Edges": dependent, "ReverseU": reverse_slave, @@ -3401,7 +3394,7 @@ def assign_end_connection(self, assignment, resistance=0, inductance=0, boundary if not boundary: boundary = generate_unique_name("EndConnection") - props = OrderedDict( + props = dict( { "Objects": assignment, "ResistanceValue": self.modeler._arg_with_dim(resistance, "ohm"), diff --git a/src/ansys/aedt/core/mechanical.py b/src/ansys/aedt/core/mechanical.py index d2c2bf1a665..2f212fa4862 100644 --- a/src/ansys/aedt/core/mechanical.py +++ b/src/ansys/aedt/core/mechanical.py @@ -26,8 +26,6 @@ from __future__ import absolute_import # noreorder -from collections import OrderedDict - from ansys.aedt.core.application.analysis_3d import FieldAnalysis3D from ansys.aedt.core.generic.general_methods import generate_unique_name from ansys.aedt.core.generic.general_methods import pyaedt_function_handler @@ -246,27 +244,25 @@ def assign_em_losses( else: intr = [] - argparam = OrderedDict({}) + argparam = {} for el in self.available_variations.nominal_w_values_dict: argparam[el] = self.available_variations.nominal_w_values_dict[el] for el in parameters: argparam[el] = el - props = OrderedDict( - { - "Objects": allObjects, - "allObjects": False, - "Project": projname, - "projname": "ElectronicsDesktop", - "Design": design, - "Soln": setup + " : " + sweep, - "Params": argparam, - "ForceSourceToSolve": True, - "PreservePartnerSoln": True, - "PathRelativeTo": "TargetProject", - } - ) + props = { + "Objects": allObjects, + "allObjects": False, + "Project": projname, + "projname": "ElectronicsDesktop", + "Design": design, + "Soln": setup + " : " + sweep, + "Params": argparam, + "ForceSourceToSolve": True, + "PreservePartnerSoln": True, + "PathRelativeTo": "TargetProject", + } if intr: props["Intrinsics"] = intr props["SurfaceOnly"] = surfaces @@ -345,27 +341,25 @@ def assign_thermal_map( allObjects = self.modeler.object_names else: allObjects = object_list[:] - argparam = OrderedDict({}) + argparam = {} for el in self.available_variations.nominal_w_values_dict: argparam[el] = self.available_variations.nominal_w_values_dict[el] for el in parameters: argparam[el] = el - props = OrderedDict( - { - "Objects": allObjects, - "Uniform": False, - "Project": projname, - "Product": "ElectronicsDesktop", - "Design": design, - "Soln": setup + " : " + sweep, - "Params": argparam, - "ForceSourceToSolve": True, - "PreservePartnerSoln": True, - "PathRelativeTo": "TargetProject", - } - ) + props = { + "Objects": allObjects, + "Uniform": False, + "Project": projname, + "Product": "ElectronicsDesktop", + "Design": design, + "Soln": setup + " : " + sweep, + "Params": argparam, + "ForceSourceToSolve": True, + "PreservePartnerSoln": True, + "PathRelativeTo": "TargetProject", + } name = generate_unique_name("ThermalLink") bound = BoundaryObject(self, name, props, "ThermalCondition") @@ -681,6 +675,53 @@ def assign_heat_generation(self, assignment, value, name=""): return bound return False + @pyaedt_function_handler() + def assign_2way_coupling(self, setup=None, number_of_iterations=2): + """Assign two-way coupling to a setup. + + Parameters + ---------- + setup : str, optional + Name of the setup. The default is ``None``, in which case the active setup is used. + number_of_iterations : int, optional + Number of iterations. The default is ``2``. + + Returns + ------- + bool + ``True`` when successful, ``False`` when failed. + + References + ---------- + + >>> oModule.AddTwoWayCoupling + + Examples + -------- + >>> from ansys.aedt.core import Mechanical + >>> mech = Mechanical() + >>> setup = mech.create_setup() + >>> mech.assign_2way_coupling(setup.name, 1) + >>> mech.release_desktop() + + """ + if not setup: + if self.setups: + setup = self.setups[0].name + else: + self.logger.error("Setup is not defined.") + return False + + self.oanalysis.AddTwoWayCoupling( + setup, + [ + "NAME:Options", + "NumCouplingIters:=", + number_of_iterations, + ], + ) + return True + @pyaedt_function_handler(setupname="name", setuptype="setup_type") def create_setup(self, name="MySetupAuto", setup_type=None, **kwargs): """Create an analysis setup for Mechanical. diff --git a/src/ansys/aedt/core/modeler/advanced_cad/stackup_3d.py b/src/ansys/aedt/core/modeler/advanced_cad/stackup_3d.py index e08835155a8..f9b15ad2318 100644 --- a/src/ansys/aedt/core/modeler/advanced_cad/stackup_3d.py +++ b/src/ansys/aedt/core/modeler/advanced_cad/stackup_3d.py @@ -22,7 +22,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -from collections import OrderedDict import os from ansys.aedt.core.generic.general_methods import is_ironpython @@ -1008,7 +1007,7 @@ def __init__(self, app, stackup, name, material="copper"): self._app = app self._stackup = stackup self.name = name - self._padstacks_by_layer = OrderedDict({}) + self._padstacks_by_layer = {} self._vias_objects = [] self._num_sides = 16 self._plating_ratio = 1 @@ -1117,7 +1116,7 @@ def set_start_layer(self, layer): """ found = False - new_stackup = OrderedDict({}) + new_stackup = {} for k, v in self._stackup.stackup_layers.items(): if k == layer: found = True @@ -1146,7 +1145,7 @@ def set_stop_layer(self, layer): """ found = False - new_stackup = OrderedDict({}) + new_stackup = {} for k in list(self._stackup.stackup_layers.keys()): if not found and k in list(self._padstacks_by_layer.keys()): new_stackup[k] = self._padstacks_by_layer[k] @@ -1279,7 +1278,7 @@ def __init__(self, application, frequency=None): self._z_position_offset = 0 self._first_layer_position = "layer_1_position" self._shifted_index = 0 - self._stackup = OrderedDict({}) + self._stackup = {} self._start_position = NamedVariable(self._app, self._first_layer_position, "0mm") self._dielectric_x_position = NamedVariable(self._app, "dielectric_x_position", "0mm") self._dielectric_y_position = NamedVariable(self._app, "dielectric_y_position", "0mm") diff --git a/src/ansys/aedt/core/modeler/cad/component_array.py b/src/ansys/aedt/core/modeler/cad/component_array.py index 4ea9add940a..24814daa977 100644 --- a/src/ansys/aedt/core/modeler/cad/component_array.py +++ b/src/ansys/aedt/core/modeler/cad/component_array.py @@ -24,7 +24,6 @@ from __future__ import absolute_import -from collections import OrderedDict import os import re @@ -488,7 +487,7 @@ def parse_array_info_from_csv(self, input_file): # pragma: no cover array_matrix_active.append(active_passive) elif element_data == start_str: capture_data = True - res = OrderedDict() + res = {} res["component"] = components res["active"] = array_matrix_active res["rotation"] = array_matrix_rotation @@ -713,7 +712,7 @@ def __get_properties_from_aedt(self): for c in components_map: m = re.search(r"'(\d+)'=(\d+)", c) components[int(m.group(1))] = component_id[int(m.group(2))] - res = OrderedDict() + res = {} res["component"] = components res["active"] = props["ArrayDefinition"]["ArrayObject"]["Active"]["matrix"] res["rotation"] = props["ArrayDefinition"]["ArrayObject"]["Rotation"]["matrix"] @@ -767,13 +766,12 @@ def __init__(self, row, col, array_props, component_names, array_obj): self.__row = row + 1 self.__col = col + 1 self.__array_obj = array_obj - self.__cell_props = OrderedDict( - { - "component": array_props["cells"][row][col], - "active": array_props["active"][row][col], - "rotation": array_props["rotation"][row][col], - } - ) + self.__cell_props = { + "component": array_props["cells"][row][col], + "active": array_props["active"][row][col], + "rotation": array_props["rotation"][row][col], + } + self.__rotation = self.__cell_props["rotation"] self.__is_active = self.__cell_props["active"] diff --git a/src/ansys/aedt/core/modeler/cad/components_3d.py b/src/ansys/aedt/core/modeler/cad/components_3d.py index 3b802188ea2..32fb372aa9b 100644 --- a/src/ansys/aedt/core/modeler/cad/components_3d.py +++ b/src/ansys/aedt/core/modeler/cad/components_3d.py @@ -24,7 +24,6 @@ from __future__ import absolute_import -from collections import OrderedDict import os import random import re @@ -60,28 +59,28 @@ def __init__(self, component, *args, **kw): self._component = component -class UserDefinedComponentProps(OrderedDict): +class UserDefinedComponentProps(dict): """User Defined Component Internal Parameters.""" def __setitem__(self, key, value): - OrderedDict.__setitem__(self, key, value) + dict.__setitem__(self, key, value) if self._pyaedt_user_defined_component.auto_update: res = self._pyaedt_user_defined_component.update_native() if not res: self._pyaedt_user_defined_component._logger.warning("Update of %s failed. Check needed arguments", key) def __init__(self, user_defined_components, props): - OrderedDict.__init__(self) + dict.__init__(self) if props: for key, value in props.items(): - if isinstance(value, (dict, OrderedDict)): - OrderedDict.__setitem__(self, key, UserDefinedComponentProps(user_defined_components, value)) + if isinstance(value, dict): + dict.__setitem__(self, key, UserDefinedComponentProps(user_defined_components, value)) else: - OrderedDict.__setitem__(self, key, value) + dict.__setitem__(self, key, value) self._pyaedt_user_defined_component = user_defined_components def _setitem_without_update(self, key, value): - OrderedDict.__setitem__(self, key, value) + dict.__setitem__(self, key, value) class UserDefinedComponent(object): @@ -150,44 +149,38 @@ def __init__(self, primitives, name=None, props=None, component_type=None): self.auto_update = False self._props = UserDefinedComponentProps( self, - OrderedDict( - { - "TargetCS": self._target_coordinate_system, - "SubmodelDefinitionName": self.definition_name, - "ComponentPriorityLists": OrderedDict({}), - "NextUniqueID": 0, - "MoveBackwards": False, - "DatasetType": "ComponentDatasetType", - "DatasetDefinitions": OrderedDict({}), - "BasicComponentInfo": OrderedDict( - { - "ComponentName": self.definition_name, - "Company": "", - "Company URL": "", - "Model Number": "", - "Help URL": "", - "Version": "1.0", - "Notes": "", - "IconType": "", - } - ), - "GeometryDefinitionParameters": OrderedDict({"VariableOrders": OrderedDict({})}), - "DesignDefinitionParameters": OrderedDict({"VariableOrders": OrderedDict({})}), - "MaterialDefinitionParameters": OrderedDict({"VariableOrders": OrderedDict({})}), - "MapInstanceParameters": "DesignVariable", - "UniqueDefinitionIdentifier": "89d26167-fb77-480e-a7ab-" - + "".join(random.choice("abcdef0123456789") for _ in range(int(12))), - "OriginFilePath": "", - "IsLocal": False, - "ChecksumString": "", - "ChecksumHistory": [], - "VersionHistory": [], - "NativeComponentDefinitionProvider": OrderedDict({"Type": component_type}), - "InstanceParameters": OrderedDict( - {"GeometryParameters": "", "MaterialParameters": "", "DesignParameters": ""} - ), - } - ), + { + "TargetCS": self._target_coordinate_system, + "SubmodelDefinitionName": self.definition_name, + "ComponentPriorityLists": {}, + "NextUniqueID": 0, + "MoveBackwards": False, + "DatasetType": "ComponentDatasetType", + "DatasetDefinitions": {}, + "BasicComponentInfo": { + "ComponentName": self.definition_name, + "Company": "", + "Company URL": "", + "Model Number": "", + "Help URL": "", + "Version": "1.0", + "Notes": "", + "IconType": "", + }, + "GeometryDefinitionParameters": {"VariableOrders": {}}, + "DesignDefinitionParameters": {"VariableOrders": {}}, + "MaterialDefinitionParameters": {"VariableOrders": {}}, + "MapInstanceParameters": "DesignVariable", + "UniqueDefinitionIdentifier": "89d26167-fb77-480e-a7ab-" + + "".join(random.choice("abcdef0123456789") for _ in range(int(12))), + "OriginFilePath": "", + "IsLocal": False, + "ChecksumString": "", + "ChecksumHistory": [], + "VersionHistory": [], + "NativeComponentDefinitionProvider": {"Type": component_type}, + "InstanceParameters": {"GeometryParameters": "", "MaterialParameters": "", "DesignParameters": ""}, + }, ) if props: self._update_props(self._props["NativeComponentDefinitionProvider"], props) @@ -715,7 +708,7 @@ def update_native(self): """ - self.update_props = OrderedDict({}) + self.update_props = {} self.update_props["DefinitionName"] = self._props["SubmodelDefinitionName"] self.update_props["GeometryDefinitionParameters"] = self._props["GeometryDefinitionParameters"] self.update_props["DesignDefinitionParameters"] = self._props["DesignDefinitionParameters"] @@ -788,9 +781,9 @@ def _change_property(self, vPropChange): @pyaedt_function_handler() def _update_props(self, d, u): for k, v in u.items(): - if isinstance(v, (dict, OrderedDict)): + if isinstance(v, dict): if k not in d: - d[k] = OrderedDict({}) + d[k] = {} d[k] = self._update_props(d[k], v) else: d[k] = v diff --git a/src/ansys/aedt/core/modeler/cad/elements_3d.py b/src/ansys/aedt/core/modeler/cad/elements_3d.py index 80ad5f82dde..174d8b76a11 100644 --- a/src/ansys/aedt/core/modeler/cad/elements_3d.py +++ b/src/ansys/aedt/core/modeler/cad/elements_3d.py @@ -24,8 +24,6 @@ from __future__ import absolute_import -from collections import OrderedDict - from ansys.aedt.core.generic.general_methods import _dim_arg from ansys.aedt.core.generic.general_methods import clamp from ansys.aedt.core.generic.general_methods import pyaedt_function_handler @@ -68,13 +66,13 @@ def _dict2arg(d, arg_out): else: arg_out.append(k + ":=") arg_out.append([i for i in v]) - elif isinstance(v, (OrderedDict, dict)): + elif isinstance(v, dict): arg = ["NAME:" + k] _dict2arg(v, arg) arg_out.append(arg) elif v is None: arg_out.append(["NAME:" + k]) - elif isinstance(v, list) and len(v) > 0 and isinstance(v[0], (OrderedDict, dict)): + elif isinstance(v, list) and len(v) > 0 and isinstance(v[0], dict): for el in v: arg = ["NAME:" + k] _dict2arg(el, arg) @@ -1365,23 +1363,23 @@ def _change_property(self, vPropChange): return self._primitives._change_plane_property(vPropChange, self.name) -class HistoryProps(OrderedDict): +class HistoryProps(dict): """Manages an object's history properties.""" def __setitem__(self, key, value): - OrderedDict.__setitem__(self, key, value) + dict.__setitem__(self, key, value) if self._pyaedt_child.auto_update: self._pyaedt_child.update_property(key, value) def __init__(self, child_object, props): - OrderedDict.__init__(self) + dict.__init__(self) if props: for key, value in props.items(): - OrderedDict.__setitem__(self, key, value) + dict.__setitem__(self, key, value) self._pyaedt_child = child_object def _setitem_without_update(self, key, value): - OrderedDict.__setitem__(self, key, value) + dict.__setitem__(self, key, value) class BinaryTreeNode: diff --git a/src/ansys/aedt/core/modeler/cad/modeler.py b/src/ansys/aedt/core/modeler/cad/modeler.py index c2cabe6a693..c624f4161df 100644 --- a/src/ansys/aedt/core/modeler/cad/modeler.py +++ b/src/ansys/aedt/core/modeler/cad/modeler.py @@ -32,8 +32,6 @@ from __future__ import absolute_import # noreorder -from collections import OrderedDict - from ansys.aedt.core.generic.data_handlers import _dict2arg from ansys.aedt.core.generic.general_methods import PropsManager from ansys.aedt.core.generic.general_methods import generate_unique_name @@ -46,52 +44,52 @@ from ansys.aedt.core.modeler.geometry_operators import GeometryOperators -class CsProps(OrderedDict): +class CsProps(dict): """AEDT Cooardinate System Internal Parameters.""" def __setitem__(self, key, value): - OrderedDict.__setitem__(self, key, value) + dict.__setitem__(self, key, value) if self._pyaedt_cs.auto_update: res = self._pyaedt_cs.update() if not res: self._pyaedt_cs._app.logger.warning("Update of %s Failed. Check needed arguments", key) def __init__(self, cs_object, props): - OrderedDict.__init__(self) + dict.__init__(self) if props: for key, value in props.items(): - if isinstance(value, (dict, OrderedDict)): - OrderedDict.__setitem__(self, key, CsProps(cs_object, value)) + if isinstance(value, dict): + dict.__setitem__(self, key, CsProps(cs_object, value)) else: - OrderedDict.__setitem__(self, key, value) + dict.__setitem__(self, key, value) self._pyaedt_cs = cs_object def _setitem_without_update(self, key, value): - OrderedDict.__setitem__(self, key, value) + dict.__setitem__(self, key, value) -class ListsProps(OrderedDict): +class ListsProps(dict): """AEDT Lists Internal Parameters.""" def __setitem__(self, key, value): - OrderedDict.__setitem__(self, key, value) + dict.__setitem__(self, key, value) if self._pyaedt_lists.auto_update: res = self._pyaedt_lists.update() if not res: self._pyaedt_lists._app.logger.warning("Update of %s Failed. Check needed arguments", key) def __init__(self, cs_object, props): - OrderedDict.__init__(self) + dict.__init__(self) if props: for key, value in props.items(): - if isinstance(value, (dict, OrderedDict)): - OrderedDict.__setitem__(self, key, CsProps(cs_object, value)) + if isinstance(value, dict): + dict.__setitem__(self, key, CsProps(cs_object, value)) else: - OrderedDict.__setitem__(self, key, value) + dict.__setitem__(self, key, value) self._pyaedt_lists = cs_object def _setitem_without_update(self, key, value): - OrderedDict.__setitem__(self, key, value) + dict.__setitem__(self, key, value) class BaseCoordinateSystem(PropsManager, object): @@ -124,7 +122,7 @@ def _get_coordinates_data(self): ] for ds in cs: try: - if isinstance(cs[ds], (OrderedDict, dict)): + if isinstance(cs[ds], dict): if cs[ds]["OperationType"] == "CreateRelativeCoordinateSystem": props = cs[ds]["RelativeCSParameters"] name = cs[ds]["Attributes"]["Name"] @@ -150,9 +148,9 @@ def _get_coordinates_data(self): geometry_part = self._modeler._app.design_properties["ModelSetup"]["GeometryCore"][ "GeometryOperations" ]["ToplevelParts"]["GeometryPart"] - if isinstance(geometry_part, (OrderedDict, dict)): + if isinstance(geometry_part, dict): op = geometry_part["Operations"]["FaceCSHolderOperation"] - if isinstance(op, (OrderedDict, dict)): + if isinstance(op, dict): if op["ID"] == op_id: props = op["FaceCSParameters"] self._props = CsProps(self, props) @@ -165,7 +163,7 @@ def _get_coordinates_data(self): elif isinstance(geometry_part, list): for gp in geometry_part: op = gp["Operations"]["FaceCSHolderOperation"] - if isinstance(op, (OrderedDict, dict)): + if isinstance(op, dict): if op["ID"] == op_id: props = op["FaceCSParameters"] self._props = CsProps(self, props) @@ -185,9 +183,9 @@ def _get_coordinates_data(self): geometry_part = self._modeler._app.design_properties["ModelSetup"]["GeometryCore"][ "GeometryOperations" ]["ToplevelParts"]["GeometryPart"] - if isinstance(geometry_part, (OrderedDict, dict)): + if isinstance(geometry_part, dict): op = geometry_part["Operations"]["ObjectCSHolderOperation"] - if isinstance(op, (OrderedDict, dict)): + if isinstance(op, dict): if op["ID"] == op_id: props = op["ObjectCSParameters"] self._props = CsProps(self, props) @@ -200,7 +198,7 @@ def _get_coordinates_data(self): elif isinstance(geometry_part, list): for gp in geometry_part: op = gp["Operations"]["ObjectCSHolderOperation"] - if isinstance(op, (OrderedDict, dict)): + if isinstance(op, dict): if op["ID"] == op_id: props = op["ObjectCSParameters"] self._props = CsProps(self, props) @@ -237,9 +235,9 @@ def _get_coordinates_data(self): geometry_part = self._modeler._app.design_properties["ModelSetup"]["GeometryCore"][ "GeometryOperations" ]["ToplevelParts"]["GeometryPart"] - if isinstance(geometry_part, (OrderedDict, dict)): + if isinstance(geometry_part, dict): op = geometry_part["Operations"]["FaceCSHolderOperation"] - if isinstance(op, (OrderedDict, dict)): + if isinstance(op, dict): if op["ID"] == op_id: props = op["FaceCSParameters"] self._props = CsProps(self, props) @@ -255,7 +253,7 @@ def _get_coordinates_data(self): op = gp["Operations"]["FaceCSHolderOperation"] except KeyError: continue - if isinstance(op, (OrderedDict, dict)): + if isinstance(op, dict): if op["ID"] == op_id: props = op["FaceCSParameters"] self._props = CsProps(self, props) @@ -275,9 +273,9 @@ def _get_coordinates_data(self): geometry_part = self._modeler._app.design_properties["ModelSetup"]["GeometryCore"][ "GeometryOperations" ]["ToplevelParts"]["GeometryPart"] - if isinstance(geometry_part, (OrderedDict, dict)): + if isinstance(geometry_part, dict): op = geometry_part["Operations"]["ObjectCSHolderOperation"] - if isinstance(op, (OrderedDict, dict)): + if isinstance(op, dict): if op["ID"] == op_id: props = op["ObjectCSParameters"] self._props = CsProps(self, props) @@ -293,7 +291,7 @@ def _get_coordinates_data(self): op = gp["Operations"]["ObjectCSHolderOperation"] except KeyError: continue - if isinstance(op, (OrderedDict, dict)): + if isinstance(op, dict): if op["ID"] == op_id: props = op["ObjectCSParameters"] self._props = CsProps(self, props) @@ -577,7 +575,7 @@ def create( if not offset: offset = [0, 0] - originParameters = OrderedDict() + originParameters = {} originParameters["IsAttachedToEntity"] = True originParameters["EntityID"] = origin_id originParameters["FacetedBodyTriangleIndex"] = -1 @@ -589,7 +587,7 @@ def create( originParameters["YPosition"] = "0" originParameters["ZPosition"] = "0" - positioningParameters = OrderedDict() + positioningParameters = {} positioningParameters["IsAttachedToEntity"] = True positioningParameters["EntityID"] = axis_position_id positioningParameters["FacetedBodyTriangleIndex"] = -1 @@ -601,7 +599,7 @@ def create( positioningParameters["YPosition"] = "0" positioningParameters["ZPosition"] = "0" - parameters = OrderedDict() + parameters = {} parameters["Origin"] = originParameters parameters["MoveToEnd"] = always_move_to_end parameters["FaceID"] = face_id @@ -1039,7 +1037,7 @@ def create( originX = self._dim_arg(origin[0], self.model_units) originY = self._dim_arg(origin[1], self.model_units) originZ = self._dim_arg(origin[2], self.model_units) - orientationParameters = OrderedDict({"OriginX": originX, "OriginY": originY, "OriginZ": originZ}) + orientationParameters = dict({"OriginX": originX, "OriginY": originY, "OriginZ": originZ}) self.mode = mode if mode == "view": orientationParameters["Mode"] = "Axis/Position" @@ -1417,7 +1415,7 @@ def create( origin_y_position = self._position_parser(origin[1]) origin_z_position = self._position_parser(origin[2]) - originParameters = OrderedDict() + originParameters = {} originParameters["IsAttachedToEntity"] = is_attached_to_entity originParameters["EntityID"] = origin_entity_id originParameters["FacetedBodyTriangleIndex"] = -1 @@ -1454,7 +1452,7 @@ def create( x_axis_position_type = "OnVertex" else: # pragma: no cover raise ValueError("x axis must identify either Face or Edge or Vertex.") - xAxisParameters = OrderedDict() + xAxisParameters = {} xAxisParameters["IsAttachedToEntity"] = True xAxisParameters["EntityID"] = x_axis_entity_id xAxisParameters["FacetedBodyTriangleIndex"] = -1 @@ -1471,7 +1469,7 @@ def create( x_axis_y_direction = self._position_parser(x_axis[1]) x_axis_z_direction = self._position_parser(x_axis[2]) - xAxisParameters = OrderedDict() + xAxisParameters = {} xAxisParameters["DirectionType"] = "AbsoluteDirection" xAxisParameters["EdgeID"] = -1 xAxisParameters["FaceID"] = -1 @@ -1507,7 +1505,7 @@ def create( y_axis_position_type = "OnVertex" else: # pragma: no cover raise ValueError("x axis must identify either Face or Edge or Vertex.") - yAxisParameters = OrderedDict() + yAxisParameters = {} yAxisParameters["IsAttachedToEntity"] = True yAxisParameters["EntityID"] = y_axis_entity_id yAxisParameters["FacetedBodyTriangleIndex"] = -1 @@ -1524,7 +1522,7 @@ def create( y_axis_y_direction = self._position_parser(y_axis[1]) y_axis_z_direction = self._position_parser(y_axis[2]) - yAxisParameters = OrderedDict() + yAxisParameters = {} yAxisParameters["DirectionType"] = "AbsoluteDirection" yAxisParameters["EdgeID"] = -1 yAxisParameters["FaceID"] = -1 @@ -1535,7 +1533,7 @@ def create( yAxisParameters["VParam"] = 0 y_axis_dict_name = "yAxis" - parameters = OrderedDict() + parameters = {} parameters["Origin"] = originParameters parameters["MoveToEnd"] = move_to_end parameters["ReverseXAxis"] = reverse_x_axis diff --git a/src/ansys/aedt/core/modeler/cad/object_3d.py b/src/ansys/aedt/core/modeler/cad/object_3d.py index 42498c50b33..fb5bfe54eb7 100644 --- a/src/ansys/aedt/core/modeler/cad/object_3d.py +++ b/src/ansys/aedt/core/modeler/cad/object_3d.py @@ -1215,10 +1215,11 @@ def transparency(self): if self._transparency is not None: return self._transparency if "Transparent" in self.valid_properties: - transp = self._oeditor.GetPropertyValue("Geometry3DAttributeTab", self._m_name, "Transparent") try: + transp = self._oeditor.GetPropertyValue("Geometry3DAttributeTab", self._m_name, "Transparent") self._transparency = float(transp) except Exception: + self._all_props = None self._transparency = 0.3 return self._transparency diff --git a/src/ansys/aedt/core/modeler/cad/polylines.py b/src/ansys/aedt/core/modeler/cad/polylines.py index 208c3fcf8f8..3951624375d 100644 --- a/src/ansys/aedt/core/modeler/cad/polylines.py +++ b/src/ansys/aedt/core/modeler/cad/polylines.py @@ -347,7 +347,7 @@ def __init__( flag = "NonModel#" else: flag = "" - varg2 = self._primitives._default_object_attributes(name=name, matname=matname, flags=flag) + varg2 = self._primitives._default_object_attributes(name=name, material=matname, flags=flag) new_object_name = self._oeditor.CreatePolyline(varg1, varg2) Object3d.__init__(self, primitives, name=new_object_name) diff --git a/src/ansys/aedt/core/modeler/cad/primitives.py b/src/ansys/aedt/core/modeler/cad/primitives.py index ad48d2dad2e..c48bbc99cdc 100644 --- a/src/ansys/aedt/core/modeler/cad/primitives.py +++ b/src/ansys/aedt/core/modeler/cad/primitives.py @@ -28,7 +28,6 @@ from __future__ import absolute_import # noreorder -from collections import OrderedDict import copy import math import os @@ -37,6 +36,7 @@ import time import warnings +import ansys.aedt.core from ansys.aedt.core.application.variables import Variable from ansys.aedt.core.application.variables import decompose_variable_value from ansys.aedt.core.generic.constants import AEDT_UNITS @@ -863,7 +863,7 @@ def _refresh_all_ids_from_aedt_file(self): return 0 for el in dp["ModelSetup"]["GeometryCore"]["GeometryOperations"]["ToplevelParts"]["GeometryPart"]: - if isinstance(el, (OrderedDict, dict)): + if isinstance(el, dict): attribs = el["Attributes"] operations = el.get("Operations", None) else: @@ -876,7 +876,7 @@ def _refresh_all_ids_from_aedt_file(self): if attribs["Name"] in self._all_object_names: pid = 0 - if operations and isinstance(operations.get("Operation", None), (OrderedDict, dict)): + if operations and isinstance(operations.get("Operation", None), dict): try: pid = operations["Operation"]["ParentPartID"] except Exception as e: # pragma: no cover @@ -1165,7 +1165,7 @@ def _get_coordinates_data(self): # pragma: no cover cs = dp["ModelSetup"]["GeometryCore"]["GeometryOperations"]["CoordinateSystems"] for ds in cs: try: - if isinstance(cs[ds], (OrderedDict, dict)): + if isinstance(cs[ds], dict): if cs[ds]["OperationType"] == "CreateRelativeCoordinateSystem": props = cs[ds]["RelativeCSParameters"] name = cs[ds]["Attributes"]["Name"] @@ -1187,9 +1187,9 @@ def _get_coordinates_data(self): # pragma: no cover geometry_part = dp["ModelSetup"]["GeometryCore"]["GeometryOperations"]["ToplevelParts"][ "GeometryPart" ] - if isinstance(geometry_part, (OrderedDict, dict)): + if isinstance(geometry_part, dict): op = geometry_part["Operations"]["FaceCSHolderOperation"] - if isinstance(op, (OrderedDict, dict)): + if isinstance(op, dict): if op["ID"] == op_id: props = op["FaceCSParameters"] coord.append(FaceCoordinateSystem(self, props, name)) @@ -1202,7 +1202,7 @@ def _get_coordinates_data(self): # pragma: no cover elif isinstance(geometry_part, list): for gp in geometry_part: op = gp["Operations"]["FaceCSHolderOperation"] - if isinstance(op, (OrderedDict, dict)): + if isinstance(op, dict): if op["ID"] == op_id: props = op["FaceCSParameters"] coord.append(FaceCoordinateSystem(self, props, name)) @@ -1235,9 +1235,9 @@ def _get_coordinates_data(self): # pragma: no cover geometry_part = dp["ModelSetup"]["GeometryCore"]["GeometryOperations"]["ToplevelParts"][ "GeometryPart" ] - if isinstance(geometry_part, (OrderedDict, dict)): + if isinstance(geometry_part, dict): op = geometry_part["Operations"]["FaceCSHolderOperation"] - if isinstance(op, (OrderedDict, dict)): + if isinstance(op, dict): if op["ID"] == op_id: props = op["FaceCSParameters"] coord.append(FaceCoordinateSystem(self, props, name)) @@ -1253,7 +1253,7 @@ def _get_coordinates_data(self): # pragma: no cover op = gp["Operations"]["FaceCSHolderOperation"] except KeyError: continue - if isinstance(op, (OrderedDict, dict)): + if isinstance(op, dict): if op["ID"] == op_id: props = op["FaceCSParameters"] coord.append(FaceCoordinateSystem(self, props, name)) @@ -1291,7 +1291,7 @@ def _get_lists_data(self): entity_list = dp["ModelSetup"]["GeometryCore"][key1][key2] if entity_list: geom_entry = copy.deepcopy(entity_list[key3]) - if isinstance(geom_entry, (dict, OrderedDict)): + if isinstance(geom_entry, dict): geom_entry = [geom_entry] for data in geom_entry: props = {} @@ -6569,7 +6569,7 @@ def create_object_from_edge(self, assignment, non_model=False): >>> oEditor.CreateObjectFromFaces """ edge_ids = self.convert_to_selections(assignment, True) - objs = OrderedDict() + objs = {} for edge_id in edge_ids: obj_name = self._find_object_from_edge_id(edge_id) if obj_name not in objs: @@ -6619,7 +6619,7 @@ def create_object_from_face(self, assignment, non_model=False): >>> oEditor.CreateObjectFromFaces """ face_ids = self.convert_to_selections(assignment, True) - objs = OrderedDict() + objs = {} for face_id in face_ids: obj_name = self._find_object_from_face_id(face_id) if obj_name not in objs: @@ -8412,8 +8412,8 @@ def _get_model_objects(self, model=True): list_objs.append(obj.name) return list_objs - @pyaedt_function_handler() - def _check_material(self, matname, defaultmatname, threshold=100000): + @pyaedt_function_handler(matname="material", defaultmatname="default_material") + def _check_material(self, material, default_material, threshold=100000): """Check for a material name. If a material name exists, it is assigned. Otherwise, the material @@ -8421,10 +8421,10 @@ def _check_material(self, matname, defaultmatname, threshold=100000): Parameters ---------- - matname : str + material : str Name of the material. - defaultmatname : str - Name of the default material to assign if ``metname`` does not exist. + default_material : str + Name of the default material to assign if ``material`` does not exist. threshold : float Threshold conductivity in S/m to distinguish dielectric from conductor. The default value is ``100000``. @@ -8438,23 +8438,42 @@ def _check_material(self, matname, defaultmatname, threshold=100000): # Note: Material.is_dielectric() does not work if the conductivity # value is an expression. - if isinstance(matname, Material): + if isinstance(material, Material): if self._app._design_type == "HFSS": - return matname.name, matname.is_dielectric(threshold) + return material.name, material.is_dielectric(threshold) else: - return matname.name, True - if matname: - if self._app.materials[matname]: + return material.name, True + if material: + if "[" in material: + array = material.split("[") + if array[0] in self._app.variable_manager.design_variables.keys(): + if "(" not in array[1]: + index = int(array[1].strip("]")) + material = self._app.variable_manager.design_variables[array[0]].numeric_value[index] + else: + condition = array[1].strip("]") + condition_name = ansys.aedt.core.generate_unique_name("condition") + self._app.variable_manager.set_variable( + name=condition_name, expression=condition, is_post_processing=True + ) + condition_value = int( + self._app.variable_manager.post_processing_variables[condition_name].numeric_value + ) + material = self._app.variable_manager.design_variables[array[0]].numeric_value[condition_value] + self._app.variable_manager.delete_variable(name=condition_name) + else: + self.logger.debug(f"Design variable {array[0]} does not exist.") + if self._app.materials[material]: if self._app._design_type == "HFSS": - return self._app.materials[matname].name, self._app.materials[matname].is_dielectric(threshold) + return self._app.materials[material].name, self._app.materials[material].is_dielectric(threshold) else: - return self._app.materials[matname].name, True + return self._app.materials[material].name, True else: - self.logger.warning("Material %s doesn not exists. Assigning default material", matname) + self.logger.warning("Material %s does not exists. Assigning default material", material) if self._app._design_type == "HFSS": - return defaultmatname, self._app.materials.material_keys[defaultmatname].is_dielectric(threshold) + return default_material, self._app.materials.material_keys[default_material].is_dielectric(threshold) else: - return defaultmatname, True + return default_material, True @pyaedt_function_handler() def _refresh_solids(self): @@ -8596,12 +8615,12 @@ def _create_object(self, name, pid=0, use_cached=False, is_polyline=False, **kwa self.logger.debug("'" + str(k) + "' is not a valid property of the primitive.") return o - @pyaedt_function_handler() - def _default_object_attributes(self, name=None, matname=None, flags=""): - if not matname: - matname = self.defaultmaterial + @pyaedt_function_handler(matname="material") + def _default_object_attributes(self, name=None, material=None, flags=""): + if not material: + material = self.defaultmaterial - material, is_dielectric = self._check_material(matname, self.defaultmaterial) + material, is_dielectric = self._check_material(material, self.defaultmaterial) solve_inside = True if is_dielectric else False @@ -8788,7 +8807,7 @@ def _get_native_component_properties(self, name): "NativeComponentDefinition" ] if native_comp_entry: - if isinstance(native_comp_entry, (dict, OrderedDict)): + if isinstance(native_comp_entry, dict): native_comp_entry = [native_comp_entry] for data in native_comp_entry: native_comp_name = data["SubmodelDefinitionName"] diff --git a/src/ansys/aedt/core/modeler/cad/primitives_2d.py b/src/ansys/aedt/core/modeler/cad/primitives_2d.py index 2238f4abb1d..d6abe3506b1 100644 --- a/src/ansys/aedt/core/modeler/cad/primitives_2d.py +++ b/src/ansys/aedt/core/modeler/cad/primitives_2d.py @@ -115,7 +115,7 @@ def create_circle( vArg1.append("WhichAxis:="), vArg1.append(szAxis) vArg1.append("NumSegments:="), vArg1.append("{}".format(num_sides)) - vArg2 = self._default_object_attributes(name=name, matname=material, flags="NonModel#" if non_model else "") + vArg2 = self._default_object_attributes(name=name, material=material, flags="NonModel#" if non_model else "") new_object_name = self.oeditor.CreateCircle(vArg1, vArg2) return self._create_object(new_object_name, **kwargs) @@ -190,7 +190,7 @@ def create_ellipse( vArg1.append("WhichAxis:="), vArg1.append(szAxis) vArg1.append("NumSegments:="), vArg1.append(segments) - vArg2 = self._default_object_attributes(name=name, matname=material, flags="NonModel#" if non_model else "") + vArg2 = self._default_object_attributes(name=name, material=material, flags="NonModel#" if non_model else "") new_object_name = self.oeditor.CreateEllipse(vArg1, vArg2) return self._create_object(new_object_name, **kwargs) @@ -246,7 +246,7 @@ def create_rectangle(self, origin, sizes, is_covered=True, name=None, material=N vArg1.append("Height:="), vArg1.append(height) vArg1.append("WhichAxis:="), vArg1.append(axis) - vArg2 = self._default_object_attributes(name=name, matname=material, flags="NonModel#" if non_model else "") + vArg2 = self._default_object_attributes(name=name, material=material, flags="NonModel#" if non_model else "") new_object_name = self.oeditor.CreateRectangle(vArg1, vArg2) return self._create_object(new_object_name, **kwargs) @@ -311,7 +311,7 @@ def create_regular_polygon( vArg1.append("NumSides:="), vArg1.append(n_sides) vArg1.append("WhichAxis:="), vArg1.append(self.plane2d) - vArg2 = self._default_object_attributes(name=name, matname=material, flags="NonModel#" if non_model else "") + vArg2 = self._default_object_attributes(name=name, material=material, flags="NonModel#" if non_model else "") new_object_name = self.oeditor.CreateRegularPolygon(vArg1, vArg2) return self._create_object(new_object_name, **kwargs) diff --git a/src/ansys/aedt/core/modeler/cad/primitives_3d.py b/src/ansys/aedt/core/modeler/cad/primitives_3d.py index 6c1954babf5..aed255fb1cc 100644 --- a/src/ansys/aedt/core/modeler/cad/primitives_3d.py +++ b/src/ansys/aedt/core/modeler/cad/primitives_3d.py @@ -170,7 +170,7 @@ def create_box(self, origin, sizes, name=None, material=None, **kwargs): vArg1.append("XSize:="), vArg1.append(XSize) vArg1.append("YSize:="), vArg1.append(YSize) vArg1.append("ZSize:="), vArg1.append(ZSize) - vArg2 = self._default_object_attributes(name=name, matname=material) + vArg2 = self._default_object_attributes(name=name, material=material) new_object_name = self.oeditor.CreateBox(vArg1, vArg2) return self._create_object(new_object_name, **kwargs) @@ -251,7 +251,7 @@ def create_cylinder(self, orientation, origin, radius, height, num_sides=0, name vArg1.append("Height:="), vArg1.append(Height) vArg1.append("WhichAxis:="), vArg1.append(szAxis) vArg1.append("NumSides:="), vArg1.append("{}".format(num_sides)) - vArg2 = self._default_object_attributes(name=name, matname=material) + vArg2 = self._default_object_attributes(name=name, material=material) new_object_name = self.oeditor.CreateCylinder(vArg1, vArg2) return self._create_object(new_object_name, **kwargs) @@ -336,7 +336,7 @@ def create_polyhedron(self, orientation=None, center=(0.0, 0.0, 0.0), origin=(0. vArg1.append("Height:="), vArg1.append(height) vArg1.append("NumSides:="), vArg1.append(int(num_sides)) vArg1.append("WhichAxis:="), vArg1.append(orientation) - vArg2 = self._default_object_attributes(name=name, matname=material) + vArg2 = self._default_object_attributes(name=name, material=material) new_object_name = self.oeditor.CreateRegularPolyhedron(vArg1, vArg2) return self._create_object(new_object_name, **kwargs) @@ -392,14 +392,11 @@ def create_cone(self, orientation, origin, bottom_radius, top_radius, height, na >>> from ansys.aedt.core import Hfss >>> aedtapp = Hfss() - >>> cone_object = aedtapp.modeler.create_cone(orientation='Z',origin=[0, 0, 0], - ... bottom_radius=2,top_radius=3,height=4, - ... name="mybox",material="copper") + >>> cone_object = aedtapp.modeler.create_cone(orientation='Z', origin=[0, 0, 0], + ... bottom_radius=2, top_radius=3, height=4, + ... name="mybox", material="copper") """ - if bottom_radius == top_radius: - self.logger.error("the ``bottom_radius`` and ``top_radius`` arguments must have different values.") - return False if isinstance(bottom_radius, (int, float)) and bottom_radius < 0: self.logger.error("The ``bottom_radius`` argument must be greater than 0.") return False @@ -427,7 +424,7 @@ def create_cone(self, orientation, origin, bottom_radius, top_radius, height, na vArg1.append("Height:="), vArg1.append(Height) vArg1.append("BottomRadius:="), vArg1.append(RadiusBt) vArg1.append("TopRadius:="), vArg1.append(RadiusUp) - vArg2 = self._default_object_attributes(name=name, matname=material) + vArg2 = self._default_object_attributes(name=name, material=material) new_object_name = self.oeditor.CreateCone(vArg1, vArg2) return self._create_object(new_object_name, **kwargs) @@ -490,7 +487,7 @@ def create_sphere(self, origin, radius, name=None, material=None, **kwargs): vArg1.append("YCenter:="), vArg1.append(YCenter) vArg1.append("ZCenter:="), vArg1.append(ZCenter) vArg1.append("Radius:="), vArg1.append(Radius) - vArg2 = self._default_object_attributes(name=name, matname=material) + vArg2 = self._default_object_attributes(name=name, material=material) new_object_name = self.oeditor.CreateSphere(vArg1, vArg2) return self._create_object(new_object_name, **kwargs) @@ -567,7 +564,7 @@ def create_torus(self, origin, major_radius, minor_radius, axis=None, name=None, first_argument.append("MajorRadius:="), first_argument.append(major_radius) first_argument.append("MinorRadius:="), first_argument.append(minor_radius) first_argument.append("WhichAxis:="), first_argument.append(axis) - second_argument = self._default_object_attributes(name=name, matname=material) + second_argument = self._default_object_attributes(name=name, material=material) new_object_name = self.oeditor.CreateTorus(first_argument, second_argument) return self._create_object(new_object_name, **kwargs) @@ -716,7 +713,7 @@ def create_bondwire(self, start, end, h1=0.2, h2=0, alpha=80, beta=5, bond_type= first_argument.append("beta:="), first_argument.append(self._arg_with_dim(beta, "deg")) first_argument.append("WhichAxis:="), first_argument.append(GeometryOperators.cs_axis_str(orientation)) first_argument.append("ReverseDirection:="), first_argument.append(False) - second_argument = self._default_object_attributes(name=name, matname=material) + second_argument = self._default_object_attributes(name=name, material=material) new_object_name = self.oeditor.CreateBondwire(first_argument, second_argument) return self._create_object(new_object_name, **kwargs) @@ -773,7 +770,7 @@ def create_rectangle(self, orientation, origin, sizes, name=None, material=None, vArg1.append("Width:="), vArg1.append(Width) vArg1.append("Height:="), vArg1.append(Height) vArg1.append("WhichAxis:="), vArg1.append(szAxis) - vArg2 = self._default_object_attributes(name=name, matname=material) + vArg2 = self._default_object_attributes(name=name, material=material) new_object_name = self.oeditor.CreateRectangle(vArg1, vArg2) return self._create_object(new_object_name, **kwargs) @@ -852,7 +849,7 @@ def create_circle(self, orientation, origin, radius, num_sides=0, is_covered=Tru vArg1.append("Radius:="), vArg1.append(Radius) vArg1.append("WhichAxis:="), vArg1.append(szAxis) vArg1.append("NumSegments:="), vArg1.append("{}".format(num_sides)) - vArg2 = self._default_object_attributes(name=name, matname=material, flags=non_model_flag) + vArg2 = self._default_object_attributes(name=name, material=material, flags=non_model_flag) new_object_name = self.oeditor.CreateCircle(vArg1, vArg2) return self._create_object(new_object_name, **kwargs) @@ -948,7 +945,7 @@ def create_ellipse( vArg1.append("WhichAxis:="), vArg1.append(szAxis) vArg1.append("NumSegments:="), vArg1.append(segments) - vArg2 = self._default_object_attributes(name=name, matname=material) + vArg2 = self._default_object_attributes(name=name, material=material) new_object_name = self.oeditor.CreateEllipse(vArg1, vArg2) return self._create_object(new_object_name, **kwargs) diff --git a/src/ansys/aedt/core/modeler/circuits/object_3d_circuit.py b/src/ansys/aedt/core/modeler/circuits/object_3d_circuit.py index 019f4db268c..1042b54d5d9 100644 --- a/src/ansys/aedt/core/modeler/circuits/object_3d_circuit.py +++ b/src/ansys/aedt/core/modeler/circuits/object_3d_circuit.py @@ -24,7 +24,6 @@ from __future__ import absolute_import -from collections import OrderedDict import math import time @@ -396,7 +395,7 @@ def update(self): bool """ try: - a = OrderedDict({}) + a = {} a[self.name] = self.props arg = ["NAME:" + self.name] _dict2arg(self.props, arg) @@ -514,7 +513,7 @@ def model_data(self): if self._model_data: return self._model_data if self.model_name: - _parameters = OrderedDict({}) + _parameters = {} _arg2dict(list(self._circuit_components.o_model_manager.GetData(self.model_name)), _parameters) self._model_data = ModelParameters(self, self.model_name, _parameters[self.model_name]) return self._model_data @@ -938,7 +937,7 @@ def enforce_touchstone_model_passive(self): >>> oModelManager.EditWithComps """ props = self.model_data.props - passive = OrderedDict( + passive = dict( [ ("DCOption", -1), ("InterpOption", 1), diff --git a/src/ansys/aedt/core/modules/advanced_post_processing.py b/src/ansys/aedt/core/modules/advanced_post_processing.py index d7bf52dc65d..cc2fb24864b 100644 --- a/src/ansys/aedt/core/modules/advanced_post_processing.py +++ b/src/ansys/aedt/core/modules/advanced_post_processing.py @@ -447,7 +447,13 @@ def plot_field_from_fieldplot( if is_pcb: model.z_scale = 5 - if scale_min and scale_max: + if scale_min is not None and scale_max is None or scale_min is None and scale_max is not None: + self.logger.warning("Invalid scale values: both values must be None or different from None.") + elif scale_min is not None and scale_max is not None and not 0 <= scale_min < scale_max: + self.logger.warning("Invalid scale values: scale_min must be greater than zero and less than scale_max.") + elif log_scale and scale_min == 0: + self.logger.warning("Invalid scale minimum value for logarithm scale.") + else: model.range_min = scale_min model.range_max = scale_max if project_path: diff --git a/src/ansys/aedt/core/modules/boundary.py b/src/ansys/aedt/core/modules/boundary.py index bd79fef00b6..d28fcd8f44a 100644 --- a/src/ansys/aedt/core/modules/boundary.py +++ b/src/ansys/aedt/core/modules/boundary.py @@ -27,7 +27,6 @@ """ from abc import abstractmethod -from collections import OrderedDict import copy import re @@ -46,11 +45,11 @@ from ansys.aedt.core.modules.circuit_templates import SourceKeys -class BoundaryProps(OrderedDict): +class BoundaryProps(dict): """AEDT Boundary Component Internal Parameters.""" def __setitem__(self, key, value): - OrderedDict.__setitem__(self, key, value) + dict.__setitem__(self, key, value) if self._pyaedt_boundary.auto_update: if key in ["Edges", "Faces", "Objects"]: res = self._pyaedt_boundary.update_assignment() @@ -60,25 +59,25 @@ def __setitem__(self, key, value): self._pyaedt_boundary._app.logger.warning("Update of %s Failed. Check needed arguments", key) def __init__(self, boundary, props): - OrderedDict.__init__(self) + dict.__init__(self) if props: for key, value in props.items(): - if isinstance(value, (OrderedDict, dict)): - OrderedDict.__setitem__(self, key, BoundaryProps(boundary, value)) + if isinstance(value, dict): + dict.__setitem__(self, key, BoundaryProps(boundary, value)) elif isinstance(value, list): list_els = [] for el in value: - if isinstance(el, (OrderedDict, dict)): + if isinstance(el, dict): list_els.append(BoundaryProps(boundary, el)) else: list_els.append(el) - OrderedDict.__setitem__(self, key, list_els) + dict.__setitem__(self, key, list_els) else: - OrderedDict.__setitem__(self, key, value) + dict.__setitem__(self, key, value) self._pyaedt_boundary = boundary def _setitem_without_update(self, key, value): - OrderedDict.__setitem__(self, key, value) + dict.__setitem__(self, key, value) class BoundaryCommon(PropsManager): @@ -129,7 +128,7 @@ def _get_boundary_data(self, ds): if "MaxwellParameterSetup" in self._app.design_properties: param = "MaxwellParameters" setup = "MaxwellParameterSetup" - if isinstance(self._app.design_properties[setup][param][ds], (OrderedDict, dict)): + if isinstance(self._app.design_properties[setup][param][ds], dict): return [ self._app.design_properties["MaxwellParameterSetup"]["MaxwellParameters"][ds], self._app.design_properties["MaxwellParameterSetup"]["MaxwellParameters"][ds][ @@ -148,7 +147,7 @@ def _get_boundary_data(self, ds): motion_list = "MotionSetupList" setup = "ModelSetup" # check moving part - if isinstance(self._app.design_properties[setup][motion_list][ds], (OrderedDict, dict)): + if isinstance(self._app.design_properties[setup][motion_list][ds], dict): return [ self._app.design_properties["ModelSetup"]["MotionSetupList"][ds], self._app.design_properties["ModelSetup"]["MotionSetupList"][ds]["MotionType"], @@ -208,44 +207,38 @@ def __init__(self, app, component_type, component_name, props): self.props = BoundaryProps( self, - OrderedDict( - { - "TargetCS": "Global", - "SubmodelDefinitionName": self.component_name, - "ComponentPriorityLists": OrderedDict({}), - "NextUniqueID": 0, - "MoveBackwards": False, - "DatasetType": "ComponentDatasetType", - "DatasetDefinitions": OrderedDict({}), - "BasicComponentInfo": OrderedDict( - { - "ComponentName": self.component_name, - "Company": "", - "Company URL": "", - "Model Number": "", - "Help URL": "", - "Version": "1.0", - "Notes": "", - "IconType": "", - } - ), - "GeometryDefinitionParameters": OrderedDict({"VariableOrders": OrderedDict({})}), - "DesignDefinitionParameters": OrderedDict({"VariableOrders": OrderedDict({})}), - "MaterialDefinitionParameters": OrderedDict({"VariableOrders": OrderedDict({})}), - "MapInstanceParameters": "DesignVariable", - "UniqueDefinitionIdentifier": "89d26167-fb77-480e-a7ab-" - + random_string(12, char_set="abcdef0123456789"), - "OriginFilePath": "", - "IsLocal": False, - "ChecksumString": "", - "ChecksumHistory": [], - "VersionHistory": [], - "NativeComponentDefinitionProvider": OrderedDict({"Type": component_type}), - "InstanceParameters": OrderedDict( - {"GeometryParameters": "", "MaterialParameters": "", "DesignParameters": ""} - ), - } - ), + { + "TargetCS": "Global", + "SubmodelDefinitionName": self.component_name, + "ComponentPriorityLists": {}, + "NextUniqueID": 0, + "MoveBackwards": False, + "DatasetType": "ComponentDatasetType", + "DatasetDefinitions": {}, + "BasicComponentInfo": { + "ComponentName": self.component_name, + "Company": "", + "Company URL": "", + "Model Number": "", + "Help URL": "", + "Version": "1.0", + "Notes": "", + "IconType": "", + }, + "GeometryDefinitionParameters": {"VariableOrders": {}}, + "DesignDefinitionParameters": {"VariableOrders": {}}, + "MaterialDefinitionParameters": {"VariableOrders": {}}, + "MapInstanceParameters": "DesignVariable", + "UniqueDefinitionIdentifier": "89d26167-fb77-480e-a7ab-" + + random_string(12, char_set="abcdef0123456789"), + "OriginFilePath": "", + "IsLocal": False, + "ChecksumString": "", + "ChecksumHistory": [], + "VersionHistory": [], + "NativeComponentDefinitionProvider": {"Type": component_type}, + "InstanceParameters": {"GeometryParameters": "", "MaterialParameters": "", "DesignParameters": ""}, + }, ) if props: self._update_props(self.props, props) @@ -272,9 +265,9 @@ def targetcs(self, cs): def _update_props(self, d, u): for k, v in u.items(): - if isinstance(v, (dict, OrderedDict)): + if isinstance(v, dict): if k not in d: - d[k] = OrderedDict({}) + d[k] = {} d[k] = self._update_props(d[k], v) else: d[k] = v @@ -321,7 +314,7 @@ def update(self): """ - self.update_props = OrderedDict({}) + self.update_props = {} self.update_props["DefinitionName"] = self.props["SubmodelDefinitionName"] self.update_props["GeometryDefinitionParameters"] = self.props["GeometryDefinitionParameters"] self.update_props["DesignDefinitionParameters"] = self.props["DesignDefinitionParameters"] @@ -815,7 +808,7 @@ def _override_common( for o in override_component: if o["overridePartNumberName"] == part: override_component.remove(o) - new_filter = OrderedDict() + new_filter = {} if filter_component or any(override_val is not None for override_val in [power, r_jb, r_jc, height]): if map_name == "instanceOverridesMap": new_filter.update({"overrideName": reference_designator}) @@ -823,19 +816,17 @@ def _override_common( new_filter.update({"overridePartNumberName": part, "overrideGeometryName": package}) new_filter.update( { - "overrideProps": OrderedDict( - { - "isFiltered": filter_component, - "isOverridePower": power is not None, - "isOverrideThetaJb": r_jb is not None, - "isOverrideThetaJc": r_jc is not None, - "isOverrideHeight": height is not None, - "powerOverride": power if power is not None else "nan", - "thetaJbOverride": r_jb if r_jb is not None else "nan", - "thetaJcOverride": r_jc if r_jc is not None else "nan", - "heightOverride": height if height is not None else "nan", - } - ), + "overrideProps": { + "isFiltered": filter_component, + "isOverridePower": power is not None, + "isOverrideThetaJb": r_jb is not None, + "isOverrideThetaJc": r_jc is not None, + "isOverrideHeight": height is not None, + "powerOverride": power if power is not None else "nan", + "thetaJbOverride": r_jb if r_jb is not None else "nan", + "thetaJcOverride": r_jc if r_jc is not None else "nan", + "heightOverride": height if height is not None else "nan", + }, } ) override_component.append(new_filter) @@ -1429,7 +1420,7 @@ def __init__(self, app, name, props=None, boundarytype=None, auto_update=True): self._name = name self._props = None if props: - self._props = BoundaryProps(self, OrderedDict(props)) + self._props = BoundaryProps(self, props) self._type = boundarytype self._boundary_name = self.name self.auto_update = auto_update @@ -1497,7 +1488,7 @@ def props(self): props = self._get_boundary_data(self.name) if props: - self._props = BoundaryProps(self, OrderedDict(props[0])) + self._props = BoundaryProps(self, props[0]) self._type = props[1] return self._props @@ -1960,7 +1951,7 @@ def __init__(self, app, name, props=None, boundarytype=None): self._name = name self._props = None if props: - self._props = BoundaryProps(self, OrderedDict(props)) + self._props = BoundaryProps(self, props) self.type = boundarytype self._boundary_name = self.name self.auto_update = True @@ -2027,7 +2018,7 @@ def props(self): props = self._get_boundary_data(self.name) if props: - self._props = BoundaryProps(self, OrderedDict(props[0])) + self._props = BoundaryProps(self, props[0]) self._type = props[1] return self._props @@ -2278,7 +2269,7 @@ def __init__(self, app, component_name, props, component_type): self._app = app self.type = component_type self._name = component_name - self.props = BoundaryProps(self, OrderedDict(props)) + self.props = BoundaryProps(self, props) self.auto_update = True @property @@ -2985,7 +2976,7 @@ def __init__(self, app, name, props, boundarytype): self._name = name self._props = None if props: - self._props = BoundaryProps(self, OrderedDict(props)) + self._props = BoundaryProps(self, props) self.type = boundarytype self._boundary_name = self.name self.auto_update = True @@ -3047,7 +3038,7 @@ def props(self): props = self._get_boundary_data(self.name) if props: - self._props = BoundaryProps(self, OrderedDict(props[0])) + self._props = BoundaryProps(self, props[0]) self._type = props[1] return self._props @@ -3076,7 +3067,7 @@ def _get_args(self, props=None): def _refresh_properties(self): if len(self._app.oeditor.GetProperties("EM Design", "Excitations:{}".format(self.name))) != len(self.props): propnames = self._app.oeditor.GetProperties("EM Design", "Excitations:{}".format(self.name)) - props = OrderedDict() + props = {} for prop in propnames: props[prop] = self._app.oeditor.GetPropertyValue("EM Design", "Excitations:{}".format(self.name), prop) self._props = BoundaryProps(self, props) @@ -3223,7 +3214,7 @@ def _source_props(self, source, source_type=None): elif el[0] != "ModelName" and el[0] != "LabelID": source_prop_dict[el[0]] = el[3] - return OrderedDict(source_prop_dict) + return source_prop_dict @pyaedt_function_handler() def _update_command(self, name, source_prop_dict, source_type, fds_filename=None): @@ -4692,7 +4683,7 @@ def _excitation_props(self, port): ): port_analyses[source] = enabled_analyses[source][port] excitation_prop_dict["EnabledAnalyses"] = port_analyses - return OrderedDict(excitation_prop_dict) + return excitation_prop_dict @pyaedt_function_handler() def update(self): @@ -4787,7 +4778,7 @@ def __init__(self, app, name=None, props=None, create=False): self._props = {} self._nodes = [] self._links = [] - self._schematic_data = OrderedDict({}) + self._schematic_data = {} self._update_from_props() if create: self.create() @@ -4827,7 +4818,7 @@ def create(self): if not self.props.get("Faces", None): self.props["Faces"] = [node.props["FaceID"] for _, node in self.face_nodes.items()] if not self.props.get("SchematicData", None): - self.props["SchematicData"] = OrderedDict({}) + self.props["SchematicData"] = {} if self.props.get("Links", None): self.props["Links"] = {link_name: link_values.props for link_name, link_values in self.links.items()} @@ -5253,7 +5244,7 @@ def add_face_node( ... material="Al-Extruded",thickness="2mm") >>> network.add_face_node(faces_ids[2],name="TestNode",thermal_resistance="Specified",resistance=2) """ - props_dict = OrderedDict({}) + props_dict = {} props_dict["FaceID"] = assignment if thermal_resistance is not None: if thermal_resistance == "Compute": diff --git a/src/ansys/aedt/core/modules/design_xploration.py b/src/ansys/aedt/core/modules/design_xploration.py index 29643737ded..6bc6a14a0fb 100644 --- a/src/ansys/aedt/core/modules/design_xploration.py +++ b/src/ansys/aedt/core/modules/design_xploration.py @@ -22,7 +22,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -from collections import OrderedDict import copy import csv @@ -69,9 +68,11 @@ def __init__(self, p_app, name, dictinputs, optimtype): if optimtype == "OptiParametric": self.props = SetupProps(self, inputd or copy.deepcopy(defaultparametricSetup)) if not inputd and self._app.design_type == "Icepak": - self.props["ProdOptiSetupDataV2"] = OrderedDict( - {"SaveFields": False, "FastOptimetrics": False, "SolveWithCopiedMeshOnly": True} - ) + self.props["ProdOptiSetupDataV2"] = { + "SaveFields": False, + "FastOptimetrics": False, + "SolveWithCopiedMeshOnly": True, + } if optimtype == "OptiDesignExplorer": self.props = SetupProps(self, inputd or copy.deepcopy(defaultdxSetup)) if optimtype == "OptiOptimization": @@ -115,7 +116,7 @@ def __init__(self, p_app, name, dictinputs, optimtype): oparam = [i for i in oparams[0]] calculation = ["NAME:Goal"] calculation.extend(oparam) - arg1 = OrderedDict() + arg1 = {} _arg2dict(calculation, arg1) self.props["Goals"] = arg1 @@ -154,12 +155,12 @@ def _get_context( did = 3 if domain != "Sweep": did = 1 - sweepdefinition = OrderedDict() + sweepdefinition = {} sweepdefinition["ReportType"] = report_category if not setup_sweep_name: setup_sweep_name = self._app.nominal_sweep sweepdefinition["Solution"] = setup_sweep_name - ctxt = OrderedDict({}) + ctxt = {} if self._app.solution_type in ["TR", "AC", "DC"]: ctxt["SimValueContext"] = [did, 0, 2, 0, False, False, -1, 1, 0, 1, 1, "", 0, 0] @@ -213,11 +214,11 @@ def _get_context( if context in self._app.modeler.line_names: ctxt["PointCount"] = polyline_points else: - ctxt = OrderedDict({"Domain": domain}) + ctxt = {"Domain": domain} sweepdefinition["SimValueContext"] = ctxt sweepdefinition["Calculation"] = expressions sweepdefinition["Name"] = expressions - sweepdefinition["Ranges"] = OrderedDict({}) + sweepdefinition["Ranges"] = {} if context and context in self._app.modeler.line_names and intrinsics and "Distance" not in intrinsics: sweepdefinition["Ranges"]["Range"] = ("Var:=", "Distance", "Type:=", "a") if not setup_sweep_name: @@ -257,9 +258,11 @@ def _get_context( sweepdefinition["Ranges"]["Range"].append(tuple(r)) if is_goal: sweepdefinition["Condition"] = condition - sweepdefinition["GoalValue"] = OrderedDict( - {"GoalValueType": "Independent", "Format": "Real/Imag", "bG": ["v:=", "[{};]".format(goal_value)]} - ) + sweepdefinition["GoalValue"] = { + "GoalValueType": "Independent", + "Format": "Real/Imag", + "bG": ["v:=", "[{};]".format(goal_value)], + } sweepdefinition["Weight"] = "[{};]".format(goal_weight) return sweepdefinition @@ -396,7 +399,7 @@ def _add_calculation( else: self.props[optigoalname]["Goal"].append(sweepdefinition) else: - self.props[optigoalname] = OrderedDict({}) + self.props[optigoalname] = {} self.props[optigoalname]["Goal"] = sweepdefinition self.auto_update = True return self.update() @@ -451,7 +454,7 @@ def _add_goal( """ self.auto_update = False - sweepdefinition = OrderedDict() + sweepdefinition = {} sweepdefinition["ReportType"] = reporttype if not solution: solution = self._app.nominal_sweep @@ -459,7 +462,7 @@ def _add_goal( if setupname not in self.props["Sim. Setups"]: self.props["Sim. Setups"].append(setupname) sweepdefinition["Solution"] = solution - sweepdefinition["SimValueContext"] = OrderedDict({"Domain": domain}) + sweepdefinition["SimValueContext"] = {"Domain": domain} sweepdefinition["Calculation"] = calculation if goal_name: sweepdefinition["Name"] = goal_name @@ -474,39 +477,37 @@ def _add_goal( dr = ",".join(calc_val1) else: dr = calc_val1 - sweepdefinition["Ranges"] = OrderedDict({"Range": ["Var:=", var, "Type:=", "d", "DiscreteValues:=", dr]}) + sweepdefinition["Ranges"] = {"Range": ["Var:=", var, "Type:=", "d", "DiscreteValues:=", dr]} elif calculation_type == "all": - sweepdefinition["Ranges"] = OrderedDict( - { - "Range": [ - "Var:=", - var, - "Type:=", - "a", - ] - } - ) + sweepdefinition["Ranges"] = { + "Range": [ + "Var:=", + var, + "Type:=", + "a", + ] + } else: - sweepdefinition["Ranges"] = OrderedDict( - { - "Range": [ - "Var:=", - var, - "Type:=", - calculation_type, - "Start:=", - calc_val1, - "Stop:=", - calc_val2, - "DiscreteValues:=", - "", - ] - } - ) + sweepdefinition["Ranges"] = { + "Range": [ + "Var:=", + var, + "Type:=", + calculation_type, + "Start:=", + calc_val1, + "Stop:=", + calc_val2, + "DiscreteValues:=", + "", + ] + } sweepdefinition["Condition"] = condition - sweepdefinition["GoalValue"] = OrderedDict( - {"GoalValueType": "Independent", "Format": "Real/Imag", "bG": ["v:=", "[{};]".format(goal_value)]} - ) + sweepdefinition["GoalValue"] = { + "GoalValueType": "Independent", + "Format": "Real/Imag", + "bG": ["v:=", "[{};]".format(goal_value)], + } sweepdefinition["Weight"] = "[{};]".format(goal_weight) if "Goal" in self.props[optigoalname]: if type(self.props[optigoalname]["Goal"]) is not list: @@ -514,7 +515,7 @@ def _add_goal( else: self.props[optigoalname]["Goal"].append(sweepdefinition) else: - self.props[optigoalname] = OrderedDict({}) + self.props[optigoalname] = {} self.props[optigoalname]["Goal"] = sweepdefinition self.auto_update = True return self.update() @@ -823,7 +824,7 @@ def add_variation( break cont += 1 if not variable_included: - sweepdefinition = OrderedDict() + sweepdefinition = {} sweepdefinition["Variable"] = variable_name sweepdefinition["Data"] = self._app.variable_manager.variables[variable_name].evaluated_value sweepdefinition["OffsetF1"] = False @@ -859,10 +860,10 @@ def add_variation( if self._app.aedt_version_id > "2023.2": arg.extend(["DiscreteLevel:=", levels]) if not self.props.get("Variables", None): - self.props["Variables"] = OrderedDict({}) + self.props["Variables"] = {} self.props["Variables"][variable_name] = arg if not self.props.get("StartingPoint", None): - self.props["StartingPoint"] = OrderedDict({}) + self.props["StartingPoint"] = {} if not starting_point: starting_point = self._app.variable_manager[variable_name].numeric_value if starting_point < min_value or starting_point > max_value: @@ -952,7 +953,7 @@ def add_variation( if not sweep_range: return False self._activate_variable(sweep_variable) - sweepdefinition = OrderedDict() + sweepdefinition = {} sweepdefinition["Variable"] = sweep_variable sweepdefinition["Data"] = sweep_range sweepdefinition["OffsetF1"] = False @@ -1111,10 +1112,7 @@ def __init__(self, p_app): try: setups_data = self._app.design_properties["Optimetrics"]["OptimetricsSetups"] for data in setups_data: - if ( - isinstance(setups_data[data], (OrderedDict, dict)) - and setups_data[data]["SetupType"] == "OptiParametric" - ): + if isinstance(setups_data[data], dict) and setups_data[data]["SetupType"] == "OptiParametric": self.setups.append(SetupParam(p_app, data, setups_data[data], setups_data[data]["SetupType"])) except Exception: self._app.logger.debug( @@ -1195,7 +1193,7 @@ def add( setup.auto_update = False setup.props["Sim. Setups"] = [setupname] - setup.props["Sweeps"] = OrderedDict({"SweepDefinition": None}) + setup.props["Sweeps"] = {"SweepDefinition": None} setup.create() unit = self._app.variable_manager[variable].units setup.add_variation(variable, start_point, end_point, step, unit, variation_type) @@ -1247,26 +1245,24 @@ def add_from_file(self, input_file, name=None): with open_file(input_file, "r") as csvfile: csvreader = csv.DictReader(csvfile) first_data_line = next(csvreader) - setup.props["Sweeps"] = {"SweepDefinition": OrderedDict()} + setup.props["Sweeps"] = {"SweepDefinition": {}} sweep_definition = [] for var_name in csvreader.fieldnames: if var_name != "*": sweep_definition.append( - OrderedDict( - { - "Variable": var_name, - "Data": first_data_line[var_name], - "OffsetF1": False, - "Synchronize": 0, - } - ) + { + "Variable": var_name, + "Data": first_data_line[var_name], + "OffsetF1": False, + "Synchronize": 0, + } ) setup.props["Sweeps"]["SweepDefinition"] = sweep_definition args = ["NAME:" + name] _dict2arg(setup.props, args) - setup.props["Sweep Operations"] = OrderedDict({"add": []}) + setup.props["Sweep Operations"] = {"add": []} table = [] for var_name in csvreader.fieldnames: if var_name != "*": @@ -1317,7 +1313,7 @@ def __init__(self, p_app): try: setups_data = self._app.design_properties["Optimetrics"]["OptimetricsSetups"] for data in setups_data: - if isinstance(setups_data[data], (OrderedDict, dict)) and setups_data[data]["SetupType"] in [ + if isinstance(setups_data[data], dict) and setups_data[data]["SetupType"] in [ "OptiOptimization", "OptiDXDOE", "OptiDesignExplorer", @@ -1511,18 +1507,16 @@ def add( for variable in dx_variables.keys(): self._app.activate_variable_optimization(variable) for var in dx_variables: - arg = OrderedDict( - { - "Variable": var, - "Data": dx_variables[var].evaluated_value, - "OffsetF1": False, - "Synchronize": 0, - } - ) + arg = { + "Variable": var, + "Data": dx_variables[var].evaluated_value, + "OffsetF1": False, + "Synchronize": 0, + } setup.props["Sweeps"]["SweepDefinition"].append(arg) else: for l, k in dx_variables.items(): - arg = OrderedDict({"Variable": l, "Data": k, "OffsetF1": False, "Synchronize": 0}) + arg = {"Variable": l, "Data": k, "OffsetF1": False, "Synchronize": 0} setup.props["Sweeps"]["SweepDefinition"].append(arg) setup.create() diff --git a/src/ansys/aedt/core/modules/fields_calculator.py b/src/ansys/aedt/core/modules/fields_calculator.py index 117a18b6a01..d4084b27121 100644 --- a/src/ansys/aedt/core/modules/fields_calculator.py +++ b/src/ansys/aedt/core/modules/fields_calculator.py @@ -37,6 +37,51 @@ class FieldsCalculator: + """Provides the Advanced fields calculator methods. + + Provide methods to add, load and delete named expressions on top of the + already existing ones in AEDT Fields calculator. + + Parameters + ---------- + app : + Inherited parent object. + + Examples + -------- + Custom expressions can be added as dictionary on-the-fly: + >>> from ansys.aedt.core import Hfss + >>> hfss = Hfss() + >>> poly = hfss.modeler.create_polyline([[0, 0, 0], [1, 0, 1]], name="Polyline1") + >>> my_expression = { + ... "name": "test", + ... "description": "Voltage drop along a line", + ... "design_type": ["HFSS", "Q3D Extractor"], + ... "fields_type": ["Fields", "CG Fields"], + ... "solution_type": "", + ... "primary_sweep": "Freq", + ... "assignment": "", + ... "assignment_type": ["Line"], + ... "operations": ["Fundamental_Quantity('E')", + ... "Operation('Real')", + ... "Operation('Tangent')", + ... "Operation('Dot')", + ... "EnterLine('assignment')", + ... "Operation('LineValue')", + ... "Operation('Integrate')", + ... "Operation('CmplxR')"], + ... "report": ["Data Table", "Rectangular Plot"], + ... } + >>> expr_name = hfss.post.fields_calculator.add_expression(my_expression, "Polyline1") + >>> hfss.release_desktop(False, False) + or they can be added from the ``expression_catalog.toml``: + >>> from ansys.aedt.core import Hfss + >>> hfss = Hfss() + >>> poly = hfss.modeler.create_polyline([[0, 0, 0], [1, 0, 1]], name="Polyline1") + >>> expr_name = hfss.post.fields_calculator.add_expression("voltage_line", "Polyline1") + >>> hfss.release_desktop(False, False) + """ + def __init__(self, app): self.expression_catalog = read_configuration_file( os.path.join(ansys.aedt.core.__path__[0], "misc", "expression_catalog.toml") @@ -55,6 +100,7 @@ def expression_names(self): Returns ------- list + List of available expressions in the catalog. """ return list(self.expression_catalog.keys()) @@ -79,6 +125,33 @@ def add_expression(self, calculation, assignment, name=None): ------- str, bool Named expression when successful, ``False`` when failed. + + Examples + -------- + >>> from ansys.aedt.core import Hfss + >>> hfss = Hfss() + >>> poly = hfss.modeler.create_polyline([[0, 0, 0], [1, 0, 1]], name="Polyline1") + >>> my_expression = { + ... "name": "test", + ... "description": "Voltage drop along a line", + ... "design_type": ["HFSS", "Q3D Extractor"], + ... "fields_type": ["Fields", "CG Fields"], + ... "solution_type": "", + ... "primary_sweep": "Freq", + ... "assignment": "", + ... "assignment_type": ["Line"], + ... "operations": ["Fundamental_Quantity('E')", + ... "Operation('Real')", + ... "Operation('Tangent')", + ... "Operation('Dot')", + ... "EnterLine('assignment')", + ... "Operation('LineValue')", + ... "Operation('Integrate')", + ... "Operation('CmplxR')"], + ... "report": ["Data Table", "Rectangular Plot"], + ... } + >>> expr_name = hfss.post.fields_calculator.add_expression(my_expression, "Polyline1") + >>> hfss.release_desktop(False, False) """ if assignment is not None: assignment = self.__app.modeler.convert_to_selections(assignment, return_list=True)[0] @@ -196,7 +269,7 @@ def create_expression_file(self, name, operations): @pyaedt_function_handler() def expression_plot(self, calculation, assignment, names, setup=None): - """Add a named expression. + """Create plots defined in the expression catalog. Parameters ---------- @@ -213,6 +286,15 @@ def expression_plot(self, calculation, assignment, names, setup=None): ------- list List of created reports. + + Examples + -------- + >>> from ansys.aedt.core import Hfss + >>> hfss = Hfss() + >>> poly = hfss.modeler.create_polyline([[0, 0, 0], [1, 0, 1]], name="Polyline1") + >>> expr_name = hfss.post.fields_calculator.add_expression("voltage_line", "Polyline1") + >>> reports = hfss.post.fields_calculator.expression_plot("voltage_line", "Polyline1", [name]) + >>> hfss.release_desktop(False, False) """ if assignment is not None: assignment = self.__app.modeler.convert_to_selections(assignment, return_list=True) @@ -291,6 +373,15 @@ def delete_expression(self, name=None): ------- bool ``True`` when successful, ``False`` when failed. + + Examples + -------- + >>> from ansys.aedt.core import Hfss + >>> hfss = Hfss() + >>> poly = hfss.modeler.create_polyline([[0, 0, 0], [1, 0, 1]], name="Polyline1") + >>> expr_name = hfss.post.fields_calculator.add_expression("voltage_line", "Polyline1") + >>> hfss.post.fields_calculator.delete_expression(expr_name) + >>> hfss.release_desktop(False, False) """ if not name: self.ofieldsreporter.ClearAllNamedExpr() @@ -311,7 +402,7 @@ def is_expression_defined(self, name): Returns ------- bool - ``True`` when exists. + ``True`` when it exists, ``False`` otherwise. """ is_defined = self.ofieldsreporter.DoesNamedExpressionExists(name) if is_defined == 1: @@ -330,7 +421,7 @@ def is_general_expression(self, name): Returns ------- bool - ``True`` if the named expression is general. + ``True`` if the named expression is general, ``False`` otherwise. """ if name not in self.expression_names: self.__app.logger.error("Named expression not available.") @@ -344,7 +435,7 @@ def is_general_expression(self, name): @pyaedt_function_handler() def load_expression_file(self, input_file): - """Load expressions from a TOML file. + """Load expressions from an external TOML file. Parameters ---------- @@ -355,6 +446,14 @@ def load_expression_file(self, input_file): ------- dict Dictionary of available expressions. + + Examples + -------- + >>> from ansys.aedt.core import Hfss + >>> hfss = Hfss() + >>> my_toml = os.path.join("my_path_to_toml", "my_toml.toml") + >>> new_catalog = hfss.post.fields_calculator.load_expression_file(my_toml) + >>> hfss.release_desktop(False, False) """ if not os.path.isfile(input_file): self.__app.logger.error("File does not exist.") diff --git a/src/ansys/aedt/core/modules/layer_stackup.py b/src/ansys/aedt/core/modules/layer_stackup.py index 4c556ebfe08..53fd6fe4af6 100644 --- a/src/ansys/aedt/core/modules/layer_stackup.py +++ b/src/ansys/aedt/core/modules/layer_stackup.py @@ -30,8 +30,6 @@ from __future__ import absolute_import # noreorder -from collections import OrderedDict - from ansys.aedt.core.application.variables import decompose_variable_value from ansys.aedt.core.generic.constants import unit_converter from ansys.aedt.core.generic.general_methods import pyaedt_function_handler @@ -1353,7 +1351,7 @@ def layers(self): Dict[int, :class:`ansys.aedt.core.modules.layer_stackup.Layer`] Number of layers in the current stackup. """ - layers = OrderedDict({}) + layers = {} for el in self.all_layers: o = Layer(self, "signal") o.name = el diff --git a/src/ansys/aedt/core/modules/material.py b/src/ansys/aedt/core/modules/material.py index af5efa25ed4..83640242e86 100644 --- a/src/ansys/aedt/core/modules/material.py +++ b/src/ansys/aedt/core/modules/material.py @@ -37,7 +37,7 @@ """ -from collections import OrderedDict + import copy import warnings @@ -79,7 +79,7 @@ class MatProperties(object): 0, 0, 0, - OrderedDict( + dict( { "Magnitude": 0, "DirComp1": 1, @@ -316,7 +316,7 @@ def __init__(self, material, name, val=None, thermalmodifier=None, spatialmodifi self.value = pair_list elif e == "Temperatures": self.temperatures = v - elif val is not None and isinstance(val, OrderedDict) and "Magnitude" in val.keys(): + elif val is not None and isinstance(val, dict) and "Magnitude" in val.keys(): self.type = "vector" magnitude = val["Magnitude"] units = None @@ -498,7 +498,7 @@ def _add_thermal_modifier(self, formula, index): and bool(self._material._props["ModifierData"]["ThermalModifierData"]["all_thermal_modifiers"]) == False ) ): - tm = OrderedDict( + tm = dict( { "Property:": self.name, "Index:": index, @@ -511,24 +511,24 @@ def _add_thermal_modifier(self, formula, index): "ModifierData" in self._material._props and "SpatialModifierData" in self._material._props["ModifierData"] ): - self._material._props["ModifierData"] = OrderedDict( + self._material._props["ModifierData"] = dict( { "SpatialModifierData": self._material._props["ModifierData"]["SpatialModifierData"], - "ThermalModifierData": OrderedDict( + "ThermalModifierData": dict( { "modifier_data": "thermal_modifier_data", - "all_thermal_modifiers": OrderedDict({"one_spatial_modifier": tm}), + "all_thermal_modifiers": dict({"one_spatial_modifier": tm}), } ), } ) else: - self._material._props["ModifierData"] = OrderedDict( + self._material._props["ModifierData"] = dict( { - "ThermalModifierData": OrderedDict( + "ThermalModifierData": dict( { "modifier_data": "thermal_modifier_data", - "all_thermal_modifiers": OrderedDict({"one_thermal_modifier": tm}), + "all_thermal_modifiers": dict({"one_thermal_modifier": tm}), } ) } @@ -553,7 +553,7 @@ def _add_thermal_modifier(self, formula, index): tm.pop("TL", None) tm.pop("TU", None) if not found: - tm = OrderedDict( + tm = dict( { "Property:": self.name, "Index:": index, @@ -601,7 +601,7 @@ def _add_thermal_modifier(self, formula, index): self._material._props["ModifierData"]["ThermalModifierData"]["all_thermal_modifiers"][tmname] = [ self._material._props["ModifierData"]["ThermalModifierData"]["all_thermal_modifiers"][tmname] ] - tm = OrderedDict( + tm = dict( { "Property:": self.name, "Index:": index, @@ -781,7 +781,7 @@ def add_thermal_modifier_closed_form( self._property_value[index].thermalmodifier.TML = tml self._property_value[index].thermalmodifier.TMU = tmu if auto_calc: - tm_new = OrderedDict( + tm_new = dict( { "Property:": self.name, "Index:": index, @@ -796,7 +796,7 @@ def add_thermal_modifier_closed_form( } ) else: - tm_new = OrderedDict( + tm_new = dict( { "Property:": self.name, "Index:": index, @@ -824,24 +824,24 @@ def add_thermal_modifier_closed_form( "ModifierData" in self._material._props and "SpatialModifierData" in self._material._props["ModifierData"] ): - self._material._props["ModifierData"] = OrderedDict( + self._material._props["ModifierData"] = dict( { "SpatialModifierData": self._material._props["ModifierData"]["SpatialModifierData"], - "ThermalModifierData": OrderedDict( + "ThermalModifierData": dict( { "modifier_data": "thermal_modifier_data", - "all_thermal_modifiers": OrderedDict({"one_spatial_modifier": tm_new}), + "all_thermal_modifiers": dict({"one_spatial_modifier": tm_new}), } ), } ) else: - self._material._props["ModifierData"] = OrderedDict( + self._material._props["ModifierData"] = dict( { - "ThermalModifierData": OrderedDict( + "ThermalModifierData": dict( { "modifier_data": "thermal_modifier_data", - "all_thermal_modifiers": OrderedDict({"one_thermal_modifier": tm_new}), + "all_thermal_modifiers": dict({"one_thermal_modifier": tm_new}), } ) } @@ -890,12 +890,12 @@ def add_thermal_modifier_closed_form( else: tm_definition = [tm_definition] tm_definition.append(tm_new) - self._material._props["ModifierData"] = OrderedDict( + self._material._props["ModifierData"] = dict( { - "ThermalModifierData": OrderedDict( + "ThermalModifierData": dict( { "modifier_data": "thermal_modifier_data", - "all_thermal_modifiers": OrderedDict({"one_thermal_modifier": tm_definition}), + "all_thermal_modifiers": dict({"one_thermal_modifier": tm_definition}), } ) } @@ -945,7 +945,7 @@ def _set_non_linear(self, x_unit=None, y_unit=None): self.hunit = y_unit self.is_temperature_dependent = False self.btype_for_single_curve = "normal" - self.temperatures = OrderedDict({}) + self.temperatures = {} elif self.name == "permittivity": if not x_unit: x_unit = "V_per_meter" @@ -1018,7 +1018,7 @@ def _add_spatial_modifier(self, formula, index): and bool(self._material._props["ModifierData"]["SpatialModifierData"]["all_spatial_modifiers"]) == False ) ): - sm = OrderedDict( + sm = dict( { "Property:": self.name, "Index:": index, @@ -1030,24 +1030,24 @@ def _add_spatial_modifier(self, formula, index): "ModifierData" in self._material._props and "ThermalModifierData" in self._material._props["ModifierData"] ): - self._material._props["ModifierData"] = OrderedDict( + self._material._props["ModifierData"] = dict( { "ThermalModifierData": self._material._props["ModifierData"]["ThermalModifierData"], - "SpatialModifierData": OrderedDict( + "SpatialModifierData": dict( { "modifier_data": "spatial_modifier_data", - "all_spatial_modifiers": OrderedDict({"one_spatial_modifier": sm}), + "all_spatial_modifiers": dict({"one_spatial_modifier": sm}), } ), } ) else: - self._material._props["ModifierData"] = OrderedDict( + self._material._props["ModifierData"] = dict( { - "SpatialModifierData": OrderedDict( + "SpatialModifierData": dict( { "modifier_data": "spatial_modifier_data", - "all_spatial_modifiers": OrderedDict({"one_spatial_modifier": sm}), + "all_spatial_modifiers": dict({"one_spatial_modifier": sm}), } ) } @@ -1066,7 +1066,7 @@ def _add_spatial_modifier(self, formula, index): sm["free_form_value"] = formula if not found: - sm = OrderedDict( + sm = dict( { "Property:": self.name, "Index:": index, @@ -1095,7 +1095,7 @@ def _add_spatial_modifier(self, formula, index): self._material._props["ModifierData"]["SpatialModifierData"]["all_spatial_modifiers"][smname] = [ self._material._props["ModifierData"]["SpatialModifierData"]["all_spatial_modifiers"][smname] ] - sm = OrderedDict( + sm = dict( { "Property:": self.name, "Index:": index, @@ -1232,7 +1232,7 @@ def __init__(self, materials, name, props=None): if props: self._props = props.copy() else: - self._props = OrderedDict() + self._props = {} if "CoordinateSystemType" in self._props: self._coordinate_system = self._props["CoordinateSystemType"] else: @@ -1310,10 +1310,10 @@ def _update_props(self, propname, propvalue, update_aedt=True): for val in propvalue: if not self._props.get(propname, None) or not isinstance(self._props[propname], dict): if material_props_type == "tensor": - self._props[propname] = OrderedDict({"property_type": "TensorProperty"}) + self._props[propname] = dict({"property_type": "TensorProperty"}) self._props[propname]["Symmetric"] = False else: - self._props[propname] = OrderedDict({"property_type": "AnisoProperty"}) + self._props[propname] = dict({"property_type": "AnisoProperty"}) self._props[propname]["unit"] = "" self._props[propname]["component" + str(i)] = str(val) i += 1 @@ -1323,19 +1323,19 @@ def _update_props(self, propname, propvalue, update_aedt=True): self._props[propname] = str(propvalue) if update_aedt: return self.update() - elif isinstance(propvalue, OrderedDict): + elif isinstance(propvalue, dict): self._props[propname] = propvalue if update_aedt: return self.update() elif isinstance(propvalue, list) and material_props_type and material_props_type == "nonlinear": if propname == "permeability": - bh = OrderedDict({"DimUnits": ["", ""]}) + bh = dict({"DimUnits": ["", ""]}) for point in propvalue: if "Point" in bh: bh["Point"].append(point) else: bh["Point"] = [point] - self._props[propname] = OrderedDict({"property_type": "nonlinear"}) + self._props[propname] = dict({"property_type": "nonlinear"}) self._props[propname]["BTypeForSingleCurve"] = self.__dict__["_" + propname].btype_for_single_curve self._props[propname]["HUnit"] = self.__dict__["_" + propname].hunit self._props[propname]["BUnit"] = self.__dict__["_" + propname].bunit @@ -1344,9 +1344,9 @@ def _update_props(self, propname, propvalue, update_aedt=True): try: self._props[propname]["BHCoordinates"]["Temperatures"] = self.__dict__["_" + propname].temperatures except Exception: - self._props[propname]["BHCoordinates"]["Temperatures"] = OrderedDict({}) + self._props[propname]["BHCoordinates"]["Temperatures"] = {} else: - bh = OrderedDict({"DimUnits": [self.__dict__["_" + propname]._unit]}) + bh = dict({"DimUnits": [self.__dict__["_" + propname]._unit]}) for point in propvalue: if "Point" in bh: bh["Point"].append(point) @@ -1356,7 +1356,7 @@ def _update_props(self, propname, propvalue, update_aedt=True): pr_name = "JECoordinates" else: pr_name = "DECoordinates" - self._props[propname] = OrderedDict({"property_type": "nonlinear", pr_name: bh}) + self._props[propname] = dict({"property_type": "nonlinear", pr_name: bh}) if update_aedt: return self.update() elif isinstance(propvalue, list) and material_props_type and material_props_type == "vector": @@ -1407,7 +1407,7 @@ def __init__(self, materiallib, name, props=None, material_update=True): self.physics_type = self._props["PhysicsTypes"]["set"] else: self.physics_type = ["Electromagnetic", "Thermal", "Structural"] - self._props["PhysicsTypes"] = OrderedDict({"set": ["Electromagnetic", "Thermal", "Structural"]}) + self._props["PhysicsTypes"] = dict({"set": ["Electromagnetic", "Thermal", "Structural"]}) if "AttachedData" in self._props and "MatAppearanceData" in self._props["AttachedData"]: self._material_appearance = [] self._material_appearance.append(self._props["AttachedData"]["MatAppearanceData"]["Red"]) @@ -1422,9 +1422,9 @@ def __init__(self, materiallib, name, props=None, material_update=True): self._material_appearance = list(int(h[i : i + 2], 16) for i in (0, 2, 4)) materiallib._color_id += 1 self._material_appearance.append(0) - self._props["AttachedData"] = OrderedDict( + self._props["AttachedData"] = dict( { - "MatAppearanceData": OrderedDict( + "MatAppearanceData": dict( { "property_data": "appearance_data", "Red": self._material_appearance[0], @@ -1527,9 +1527,9 @@ def material_appearance(self, appearance_props): raise ValueError("Transparency value must be between 0 and 1.") value.append(transparency) self._material_appearance = value - self._props["AttachedData"] = OrderedDict( + self._props["AttachedData"] = dict( { - "MatAppearanceData": OrderedDict( + "MatAppearanceData": dict( { "property_data": "appearance_data", "Red": value[0], @@ -1655,7 +1655,7 @@ def thermal_conductivity(self): @thermal_conductivity.setter def thermal_conductivity(self, value): - self._props["PhysicsTypes"] = OrderedDict({"set": ["Electromagnetic", "Thermal", "Structural"]}) + self._props["PhysicsTypes"] = dict({"set": ["Electromagnetic", "Thermal", "Structural"]}) self.physics_type = ["Electromagnetic", "Thermal", "Structural"] self._thermal_conductivity.value = value @@ -1738,7 +1738,7 @@ def youngs_modulus(self): @youngs_modulus.setter def youngs_modulus(self, value): self.physics_type = ["Electromagnetic", "Thermal", "Structural"] - self._props["PhysicsTypes"] = OrderedDict({"set": ["Electromagnetic", "Thermal", "Structural"]}) + self._props["PhysicsTypes"] = dict({"set": ["Electromagnetic", "Thermal", "Structural"]}) self._youngs_modulus.value = value @property @@ -1760,7 +1760,7 @@ def poissons_ratio(self): @poissons_ratio.setter def poissons_ratio(self, value): self.physics_type = ["Electromagnetic", "Thermal", "Structural"] - self._props["PhysicsTypes"] = OrderedDict({"set": ["Electromagnetic", "Thermal", "Structural"]}) + self._props["PhysicsTypes"] = dict({"set": ["Electromagnetic", "Thermal", "Structural"]}) self._poissons_ratio.value = value @property @@ -1870,7 +1870,7 @@ def stacking_type(self, value): if self._material_update: self._update_props( "stacking_type", - OrderedDict( + dict( { "property_type": "ChoiceProperty", "Choice": value, @@ -1901,7 +1901,7 @@ def wire_type(self, value): self._wire_type = value if self._material_update: - self._update_props("wire_type", OrderedDict({"property_type": "ChoiceProperty", "Choice": value})) + self._update_props("wire_type", dict({"property_type": "ChoiceProperty", "Choice": value})) @property def wire_thickness_direction(self): @@ -1926,9 +1926,7 @@ def wire_thickness_direction(self, value): self._wire_thickness_direction = value if self._material_update: - self._update_props( - "wire_thickness_direction", OrderedDict({"property_type": "ChoiceProperty", "Choice": value}) - ) + self._update_props("wire_thickness_direction", dict({"property_type": "ChoiceProperty", "Choice": value})) @property def wire_width_direction(self): @@ -1953,9 +1951,7 @@ def wire_width_direction(self, value): self._wire_width_direction = value if self._material_update: - self._update_props( - "wire_width_direction", OrderedDict({"property_type": "ChoiceProperty", "Choice": value}) - ) + self._update_props("wire_width_direction", dict({"property_type": "ChoiceProperty", "Choice": value})) @property def strand_number(self): @@ -2090,7 +2086,7 @@ def stacking_direction(self, value): self._stacking_direction = value if self._material_update: - self._update_props("stacking_direction", OrderedDict({"property_type": "ChoiceProperty", "Choice": value})) + self._update_props("stacking_direction", dict({"property_type": "ChoiceProperty", "Choice": value})) @pyaedt_function_handler() def set_magnetic_coercitivity(self, value=0, x=1, y=0, z=0): # pragma: no cover @@ -2127,7 +2123,7 @@ def set_magnetic_coercivity(self, value=0, x=1, y=0, z=0): ------- bool """ - self._props["magnetic_coercivity"] = OrderedDict( + self._props["magnetic_coercivity"] = dict( { "property_type": "VectorProperty", "Magnitude": "{}A_per_meter".format(value), @@ -2202,7 +2198,7 @@ def get_core_loss_coefficients( raise TypeError("Thickness must be provided as a string with value and unit.") if len(points_at_frequency) <= 1 and core_loss_model_type == "Power Ferrite": raise ValueError("At least 2 frequencies must be included.") - props = OrderedDict({}) + props = {} freq_keys = list(points_at_frequency.keys()) for i in range(0, len(freq_keys)): if isinstance(freq_keys[i], str): @@ -2213,7 +2209,7 @@ def get_core_loss_coefficients( del points_at_frequency[freq_keys[i]] if len(points_at_frequency) == 1: - props["CoefficientSetupData"] = OrderedDict({}) + props["CoefficientSetupData"] = {} props["CoefficientSetupData"]["property_data"] = "coreloss_data" props["CoefficientSetupData"]["coefficient_setup"] = coefficient_setup frequency = list(points_at_frequency.keys())[0] @@ -2221,20 +2217,20 @@ def get_core_loss_coefficients( props["CoefficientSetupData"]["Thickness"] = thickness props["CoefficientSetupData"]["Conductivity"] = str(conductivity) points = [i for p in points_at_frequency[frequency] for i in p] - props["CoefficientSetupData"]["Coordinates"] = OrderedDict({"DimUnits": ["", ""], "Points": points}) + props["CoefficientSetupData"]["Coordinates"] = dict({"DimUnits": ["", ""], "Points": points}) elif len(points_at_frequency) > 1: - props["CoreLossMultiCurveData"] = OrderedDict({}) + props["CoreLossMultiCurveData"] = {} props["CoreLossMultiCurveData"]["property_data"] = "coreloss_multi_curve_data" props["CoreLossMultiCurveData"]["coreloss_unit"] = coefficient_setup - props["CoreLossMultiCurveData"]["AllCurves"] = OrderedDict({}) + props["CoreLossMultiCurveData"]["AllCurves"] = {} props["CoreLossMultiCurveData"]["AllCurves"]["OneCurve"] = [] for freq in points_at_frequency.keys(): points = [i for p in points_at_frequency[freq] for i in p] - one_curve = OrderedDict( + one_curve = dict( { "Frequency": "{}Hz".format(freq), - "Coordinates": OrderedDict({"DimUnits": ["", ""], "Points": points}), + "Coordinates": dict({"DimUnits": ["", ""], "Points": points}), } ) props["CoreLossMultiCurveData"]["AllCurves"]["OneCurve"].append(one_curve) @@ -2348,7 +2344,7 @@ def set_coreloss_at_frequency( del points_at_frequency[freq_keys[i]] if "core_loss_type" not in self._props: choice = "Electrical Steel" if core_loss_model_type == "Electrical Steel" else "Power Ferrite" - self._props["core_loss_type"] = OrderedDict({"property_type": "ChoiceProperty", "Choice": choice}) + self._props["core_loss_type"] = dict({"property_type": "ChoiceProperty", "Choice": choice}) else: self._props.pop("core_loss_cm", None) self._props.pop("core_loss_x", None) @@ -2359,7 +2355,7 @@ def set_coreloss_at_frequency( self._props.pop("core_loss_curves", None) self._props["core_loss_type"]["Choice"] = core_loss_model_type if len(points_at_frequency) == 1: - self._props["AttachedData"]["CoefficientSetupData"] = OrderedDict({}) + self._props["AttachedData"]["CoefficientSetupData"] = {} self._props["AttachedData"]["CoefficientSetupData"]["property_data"] = "coreloss_data" self._props["AttachedData"]["CoefficientSetupData"]["coefficient_setup"] = coefficient_setup frequency = list(points_at_frequency.keys())[0] @@ -2367,22 +2363,22 @@ def set_coreloss_at_frequency( self._props["AttachedData"]["CoefficientSetupData"]["Thickness"] = thickness self._props["AttachedData"]["CoefficientSetupData"]["Conductivity"] = str(conductivity) points = [i for p in points_at_frequency[frequency] for i in p] - self._props["AttachedData"]["CoefficientSetupData"]["Coordinates"] = OrderedDict( + self._props["AttachedData"]["CoefficientSetupData"]["Coordinates"] = dict( {"DimUnits": ["", ""], "Points": points} ) elif len(points_at_frequency) > 1: - self._props["AttachedData"]["CoreLossMultiCurveData"] = OrderedDict({}) + self._props["AttachedData"]["CoreLossMultiCurveData"] = {} self._props["AttachedData"]["CoreLossMultiCurveData"]["property_data"] = "coreloss_multi_curve_data" self._props["AttachedData"]["CoreLossMultiCurveData"]["coreloss_unit"] = coefficient_setup - self._props["AttachedData"]["CoreLossMultiCurveData"]["AllCurves"] = OrderedDict({}) + self._props["AttachedData"]["CoreLossMultiCurveData"]["AllCurves"] = {} self._props["AttachedData"]["CoreLossMultiCurveData"]["AllCurves"]["OneCurve"] = [] for freq in points_at_frequency.keys(): points = [i for p in points_at_frequency[freq] for i in p] - one_curve = OrderedDict( + one_curve = dict( { "Frequency": "{}Hz".format(freq), - "Coordinates": OrderedDict({"DimUnits": ["", ""], "Points": points}), + "Coordinates": dict({"DimUnits": ["", ""], "Points": points}), } ) self._props["AttachedData"]["CoreLossMultiCurveData"]["AllCurves"]["OneCurve"].append(one_curve) @@ -2429,9 +2425,7 @@ def set_electrical_steel_coreloss(self, kh=0, kc=0, ke=0, kdc=0, cut_depth="1mm" bool """ if "core_loss_type" not in self._props: - self._props["core_loss_type"] = OrderedDict( - {"property_type": "ChoiceProperty", "Choice": "Electrical Steel"} - ) + self._props["core_loss_type"] = dict({"property_type": "ChoiceProperty", "Choice": "Electrical Steel"}) else: self._props.pop("core_loss_cm", None) self._props.pop("core_loss_x", None) @@ -2465,9 +2459,7 @@ def set_hysteresis_coreloss(self, kdc=0, hci=0, br=0, hkc=0, cut_depth=0.0001): bool """ if "core_loss_type" not in self._props: - self._props["core_loss_type"] = OrderedDict( - {"property_type": "ChoiceProperty", "Choice": "Hysteresis Model"} - ) + self._props["core_loss_type"] = dict({"property_type": "ChoiceProperty", "Choice": "Hysteresis Model"}) else: self._props.pop("core_loss_kh", None) self._props.pop("core_loss_kc", None) @@ -2504,7 +2496,7 @@ def set_power_ferrite_coreloss(self, cm=0, x=0, y=0, kdc=0, cut_depth=0.0001): bool """ if "core_loss_type" not in self._props: - self._props["core_loss_type"] = OrderedDict({"property_type": "ChoiceProperty", "Choice": "Power Ferrite"}) + self._props["core_loss_type"] = dict({"property_type": "ChoiceProperty", "Choice": "Power Ferrite"}) else: self._props.pop("core_loss_kh", None) self._props.pop("core_loss_kc", None) @@ -2549,7 +2541,7 @@ def set_bp_curve_coreloss( bool """ if "core_loss_type" not in self._props: - self._props["core_loss_type"] = OrderedDict({"property_type": "ChoiceProperty", "Choice": "B-P Curve"}) + self._props["core_loss_type"] = dict({"property_type": "ChoiceProperty", "Choice": "B-P Curve"}) else: self._props.pop("core_loss_kh", None) self._props.pop("core_loss_kc", None) @@ -2564,7 +2556,7 @@ def set_bp_curve_coreloss( self._props["core_loss_type"]["Choice"] = "B-P Curve" self._props["core_loss_kdc"] = str(kdc) self._props["core_loss_equiv_cut_depth"] = "{}meter".format(cut_depth) - self._props["core_loss_curves"] = OrderedDict({}) + self._props["core_loss_curves"] = {} self._props["core_loss_curves"]["property_type"] = "nonlinear" self._props["core_loss_curves"]["PUnit"] = units self._props["core_loss_curves"]["BUnit"] = bunit @@ -2572,7 +2564,7 @@ def set_bp_curve_coreloss( self._props["core_loss_curves"]["Thickness"] = thickness self._props["core_loss_curves"]["IsTemperatureDependent"] = False - self._props["core_loss_curves"]["BPCoordinates"] = OrderedDict({}) + self._props["core_loss_curves"]["BPCoordinates"] = {} self._props["core_loss_curves"]["BPCoordinates"]["Point"] = [] for points in points: self._props["core_loss_curves"]["BPCoordinates"]["Point"].append(points) @@ -2811,7 +2803,7 @@ def __init__(self, materiallib, name, props=None, material_update=True): self.physics_type = self._props["PhysicsTypes"]["set"] else: self.physics_type = ["Thermal"] - self._props["PhysicsTypes"] = OrderedDict({"set": ["Thermal"]}) + self._props["PhysicsTypes"] = dict({"set": ["Thermal"]}) for property in SurfMatProperties.aedtname: if property in self._props: mods = None diff --git a/src/ansys/aedt/core/modules/material_lib.py b/src/ansys/aedt/core/modules/material_lib.py index 9b70a9b2d61..2f9dbdac29e 100644 --- a/src/ansys/aedt/core/modules/material_lib.py +++ b/src/ansys/aedt/core/modules/material_lib.py @@ -46,7 +46,6 @@ from ansys.aedt.core.generic.settings import settings from ansys.aedt.core.modules.material import MatProperties from ansys.aedt.core.modules.material import Material -from ansys.aedt.core.modules.material import OrderedDict from ansys.aedt.core.modules.material import SurfaceMaterial @@ -722,7 +721,7 @@ def export_materials_to_file(self, output_file): def find_datasets(d, out_list): for k, v in d.items(): - if isinstance(v, (dict, OrderedDict)): + if isinstance(v, dict): find_datasets(v, out_list) else: a = copy.deepcopy(v) @@ -744,32 +743,24 @@ def find_datasets(d, out_list): output_dict[el] = copy.deepcopy(val._props) out_list = [] find_datasets(output_dict, out_list) - datasets = OrderedDict() + datasets = {} for ds in out_list: if ds in list(self._app.project_datasets.keys()): d = self._app.project_datasets[ds] if d.z: - datasets[ds] = OrderedDict( - { - "Coordinates": OrderedDict( - { - "DimUnits": [d.xunit, d.yunit, d.zunit], - "Points": [val for tup in zip(d.x, d.y, d.z) for val in tup], - } - ) + datasets[ds] = { + "Coordinates": { + "DimUnits": [d.xunit, d.yunit, d.zunit], + "Points": [val for tup in zip(d.x, d.y, d.z) for val in tup], } - ) + } else: - datasets[ds] = OrderedDict( - { - "Coordinates": OrderedDict( - { - "DimUnits": [d.xunit, d.yunit], - "Points": [val for tup in zip(d.x, d.y) for val in tup], - } - ) + datasets[ds] = { + "Coordinates": { + "DimUnits": [d.xunit, d.yunit], + "Points": [val for tup in zip(d.x, d.y) for val in tup], } - ) + } json_dict = {} json_dict["materials"] = output_dict if datasets: diff --git a/src/ansys/aedt/core/modules/mesh.py b/src/ansys/aedt/core/modules/mesh.py index cf1522607ae..ef80de6f9e3 100644 --- a/src/ansys/aedt/core/modules/mesh.py +++ b/src/ansys/aedt/core/modules/mesh.py @@ -28,7 +28,6 @@ from __future__ import absolute_import # noreorder -from collections import OrderedDict import os import shutil @@ -82,11 +81,11 @@ } -class MeshProps(OrderedDict): +class MeshProps(dict): """AEDT Mesh Component Internal Parameters.""" def __setitem__(self, key, value): - OrderedDict.__setitem__(self, key, value) + dict.__setitem__(self, key, value) if self._pyaedt_mesh.auto_update: if key in ["Edges", "Faces", "Objects"]: res = self._pyaedt_mesh.update_assignment() @@ -96,17 +95,17 @@ def __setitem__(self, key, value): self._pyaedt_mesh._app.logger.warning("Update of %s Failed. Check needed arguments", key) def __init__(self, mesh_object, props): - OrderedDict.__init__(self) + dict.__init__(self) if props: for key, value in props.items(): - if isinstance(value, (OrderedDict, OrderedDict)): - OrderedDict.__setitem__(self, key, MeshProps(mesh_object, value)) + if isinstance(value, (dict, dict)): + dict.__setitem__(self, key, MeshProps(mesh_object, value)) else: - OrderedDict.__setitem__(self, key, value) + dict.__setitem__(self, key, value) self._pyaedt_mesh = mesh_object def _setitem_without_update(self, key, value): - OrderedDict.__setitem__(self, key, value) + dict.__setitem__(self, key, value) class MeshOperation(object): @@ -511,7 +510,7 @@ def _get_design_global_mesh(self): if props: bound = MeshOperation(self, "MeshSettings", props, "InitialMeshSettings") return bound - return OrderedDict() + return {} @pyaedt_function_handler() def _get_design_mesh_operations(self): @@ -606,7 +605,7 @@ def assign_surface_mesh(self, assignment, level, name=None): seltype = "Faces" else: seltype = "Objects" - props = OrderedDict( + props = dict( { "Type": "SurfApproxBased", "CurvedSurfaceApproxChoice": "UseSlider", @@ -682,7 +681,7 @@ def assign_surface_mesh_manual( aspect_ratio_enable = 1 aspect_ratio = "10" - props = OrderedDict( + props = dict( { "Type": "SurfApproxBased", "Objects": assignment, @@ -746,9 +745,9 @@ def assign_model_resolution(self, assignment, defeature_length=None, name=None): self.logger.error("Mesh Operation Applies to Objects only") return False if defeature_length is None: - props = OrderedDict({"Objects": assignment, "UseAutoLength": True}) + props = dict({"Objects": assignment, "UseAutoLength": True}) else: - props = OrderedDict( + props = dict( { "Type": "DefeatureBased", "Objects": assignment, @@ -878,9 +877,7 @@ def assign_surf_priority_for_tau(self, assignment, surface_priority=0): >>> oModule.AssignSurfPriorityForTauOp """ meshop_name = generate_unique_name("SurfaceRepPriority") - props = OrderedDict( - {"Type": "SurfaceRepPriority", "Objects": assignment, "SurfaceRepPriority": surface_priority} - ) + props = dict({"Type": "SurfaceRepPriority", "Objects": assignment, "SurfaceRepPriority": surface_priority}) mop = MeshOperation(self, meshop_name, props, "SurfaceRepPriority") mop.create() self.meshoperations.append(mop) @@ -1023,7 +1020,7 @@ def assign_length_mesh(self, assignment, inside_selection=True, maximum_length=1 if seltype is None: self.logger.error("Error in Assignment") return - props = OrderedDict( + props = dict( { "Type": "LengthBased", "RefineInside": inside_selection, @@ -1102,7 +1099,7 @@ def assign_skin_depth( name = generate_unique_name("SkinDepth") if self._app.design_type == "Maxwell 2D": - props = OrderedDict( + props = dict( { "Edges": assignment, "SkinDepth": skin_depth, @@ -1121,7 +1118,7 @@ def assign_skin_depth( elif isinstance(assignment[0], str): seltype = "Objects" - props = OrderedDict( + props = dict( { "Type": "SkinDepthBased", "Enabled": True, @@ -1183,7 +1180,7 @@ def assign_curvilinear_elements(self, assignment, enable=True, name=None): if seltype is None: self.logger.error("Error in Assignment") return - props = OrderedDict({"Type": "Curvilinear", seltype: assignment, "Apply": enable}) + props = dict({"Type": "Curvilinear", seltype: assignment, "Apply": enable}) mop = MeshOperation(self, name, props, "Curvilinear") mop.create() self.meshoperations.append(mop) @@ -1235,7 +1232,7 @@ def assign_curvature_extraction(self, assignment, disabled_for_faceted=True, nam if seltype is None: self.logger.error("Error in Assignment") return - props = OrderedDict( + props = dict( {"Type": "CurvatureExtraction", seltype: assignment, "DisableForFacetedSurfaces": disabled_for_faceted} ) mop = MeshOperation(self, name, props, "CurvatureExtraction") @@ -1280,7 +1277,7 @@ def assign_rotational_layer(self, assignment, layers_number=3, total_thickness=" else: name = generate_unique_name("RotationalLayer") seltype = "Objects" - props = OrderedDict( + props = dict( { "Type": "RotationalLayerMesh", seltype: assignment, @@ -1329,7 +1326,7 @@ def assign_edge_cut(self, assignment, layer_thickness="1mm", name=None): else: name = generate_unique_name("EdgeCut") seltype = "Objects" - props = OrderedDict({"Type": "EdgeCutLayerMesh", seltype: assignment, "Layer Thickness": layer_thickness}) + props = dict({"Type": "EdgeCutLayerMesh", seltype: assignment, "Layer Thickness": layer_thickness}) mop = MeshOperation(self, name, props, "EdgeCutLayerMesh") mop.create() @@ -1393,7 +1390,7 @@ def assign_density_control( else: restrlay = True restrlaynum = str(layers_number) - props = OrderedDict( + props = dict( { "Type": "DensityControlBased", "RefineInside": refine_inside, @@ -1489,7 +1486,7 @@ def assign_cylindrical_gap( raise ValueError if clone_mesh and not band_mapping_angle: band_mapping_angle = 3 - props = OrderedDict( + props = dict( { "Name": name, "Objects": entity, @@ -1505,7 +1502,7 @@ def assign_cylindrical_gap( else: use_band_mapping_angle = False band_mapping_angle = 3 - props = OrderedDict( + props = dict( { "Name": name, "Objects": entity, diff --git a/src/ansys/aedt/core/modules/mesh_3d_layout.py b/src/ansys/aedt/core/modules/mesh_3d_layout.py index 54bf8cd80ae..0b3e2380f5f 100644 --- a/src/ansys/aedt/core/modules/mesh_3d_layout.py +++ b/src/ansys/aedt/core/modules/mesh_3d_layout.py @@ -31,8 +31,6 @@ from __future__ import absolute_import # noreorder -from collections import OrderedDict - from ansys.aedt.core.generic.data_handlers import _dict2arg from ansys.aedt.core.generic.general_methods import PropsManager from ansys.aedt.core.generic.general_methods import generate_unique_name @@ -312,22 +310,18 @@ def assign_length_mesh(self, setup, layer, net, is_inside=True, maximum_length=1 self.logger.error("mesh not assigned due to incorrect settings") return if isinstance(layer, list) and isinstance(net, list): - assignment = OrderedDict({"MeshEntityInfo": []}) + assignment = dict({"MeshEntityInfo": []}) for l, n in zip(layer, net): - meshbody = OrderedDict({"Id": -1, "Nam": "", "Layer": l, "Net": n, "OrigNet": n}) + meshbody = dict({"Id": -1, "Nam": "", "Layer": l, "Net": n, "OrigNet": n}) assignment["MeshEntityInfo"].append( - OrderedDict({"IsFcSel": False, "EntID": -1, "FcIDs": [], "MeshBody": meshbody, "BBox": []}) + dict({"IsFcSel": False, "EntID": -1, "FcIDs": [], "MeshBody": meshbody, "BBox": []}) ) else: - meshbody = OrderedDict({"Id": -1, "Nam": "", "Layer": layer, "Net": net, "OrigNet": net}) - assignment = OrderedDict( - { - "MeshEntityInfo": OrderedDict( - {"IsFcSel": False, "EntID": -1, "FcIDs": [], "MeshBody": meshbody, "BBox": []} - ) - } + meshbody = dict({"Id": -1, "Nam": "", "Layer": layer, "Net": net, "OrigNet": net}) + assignment = dict( + {"MeshEntityInfo": dict({"IsFcSel": False, "EntID": -1, "FcIDs": [], "MeshBody": meshbody, "BBox": []})} ) - props = OrderedDict( + props = dict( { "Type": "LengthBased", "RefineInside": is_inside, @@ -411,15 +405,11 @@ def assign_skin_depth( restrictlength = True skin_depth = self.modeler.modeler_variable(skin_depth) triangulation_max_length = self.modeler.modeler_variable(triangulation_max_length) - meshbody = OrderedDict({"Id": -1, "Nam": "", "Layer": layer, "Net": net, "OrigNet": net}) - assignment = OrderedDict( - { - "MeshEntityInfo": OrderedDict( - {"IsFcSel": False, "EntID": -1, "FcIDs": [], "MeshBody": meshbody, "BBox": []} - ) - } + meshbody = dict({"Id": -1, "Nam": "", "Layer": layer, "Net": net, "OrigNet": net}) + assignment = dict( + {"MeshEntityInfo": dict({"IsFcSel": False, "EntID": -1, "FcIDs": [], "MeshBody": meshbody, "BBox": []})} ) - props = OrderedDict( + props = dict( { "Type": "SkinDepthLengthBased", "Enabled": True, diff --git a/src/ansys/aedt/core/modules/mesh_icepak.py b/src/ansys/aedt/core/modules/mesh_icepak.py index bc6838e3f65..27f3545545a 100644 --- a/src/ansys/aedt/core/modules/mesh_icepak.py +++ b/src/ansys/aedt/core/modules/mesh_icepak.py @@ -22,7 +22,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. from abc import abstractmethod -from collections import OrderedDict import os.path import warnings @@ -1095,7 +1094,7 @@ def _get_design_mesh_operations(self): try: if settings.aedt_version > "2023.2": for ds in dp["MeshRegion"]["MeshSetup"]: - if isinstance(dp["MeshRegion"]["MeshSetup"][ds], (OrderedDict, dict)): + if isinstance(dp["MeshRegion"]["MeshSetup"][ds], dict): if dp["MeshRegion"]["MeshSetup"][ds]["DType"] == "OpT": meshops.append( MeshOperation( @@ -1109,7 +1108,7 @@ def _get_design_mesh_operations(self): for ds in dp["MeshRegion"]["MeshSetup"]["MeshOperations"]: if isinstance( dp["MeshRegion"]["MeshSetup"]["MeshOperations"][ds], - (OrderedDict, dict), + dict, ): meshops.append( MeshOperation( @@ -1137,7 +1136,7 @@ def _get_design_mesh_regions(self): try: if settings.aedt_version > "2023.2": for ds in dp["MeshRegion"]["MeshSetup"]: - if isinstance(dp["MeshRegion"]["MeshSetup"][ds], (OrderedDict, dict)): + if isinstance(dp["MeshRegion"]["MeshSetup"][ds], dict): if dp["MeshRegion"]["MeshSetup"][ds]["DType"] == "RegionT": dict_prop = dp["MeshRegion"]["MeshSetup"][ds] if ds == "Global": @@ -1151,7 +1150,7 @@ def _get_design_mesh_regions(self): meshops.append(meshop) else: # pragma: no cover for ds in dp["MeshRegion"]["MeshSetup"]["MeshRegions"]: - if isinstance(dp["MeshRegion"]["MeshSetup"]["MeshRegions"][ds], (OrderedDict, dict)): + if isinstance(dp["MeshRegion"]["MeshSetup"]["MeshRegions"][ds], dict): dict_prop = dp["MeshRegion"]["MeshSetup"]["MeshRegions"][ds] if ds == "Global": meshop = GlobalMeshRegion(self._app) @@ -1204,7 +1203,7 @@ def assign_mesh_level(self, mesh_order, name=None): name = generate_unique_name(name, "L_" + str(level)) else: name = generate_unique_name("Icepak", "L_" + str(level)) - props = OrderedDict({"Enable": True, "Level": str(level), "Objects": level_order[level]}) + props = dict({"Enable": True, "Level": str(level), "Objects": level_order[level]}) mop = MeshOperation(self, name, props, "Icepak") mop.create() self.meshoperations.append(mop) @@ -1239,7 +1238,7 @@ def assign_mesh_from_file(self, assignment, file_name, name=None): name = generate_unique_name("MeshFile") else: name = generate_unique_name("MeshFile") - props = OrderedDict({"Enable": True, "MaxLevel": str(0), "MinLevel": str(0), "Objects": objs}) + props = dict({"Enable": True, "MaxLevel": str(0), "MinLevel": str(0), "Objects": objs}) props["Local Mesh Parameters Enabled"] = False props["Mesh Reuse Enabled"] = True props["Mesh Reuse File"] = file_name @@ -1653,7 +1652,7 @@ def assign_mesh_level_to_group( break else: name = generate_unique_name("MeshLevel") - props = OrderedDict( + props = dict( { "Enable": True, "Level": mesh_level, @@ -1701,9 +1700,7 @@ def assign_mesh_reuse(self, assignment, mesh_file, name=None): name = generate_unique_name("MeshReuse") if not isinstance(assignment, list): assignment = [assignment] - props = OrderedDict( - {"Enable": True, "Mesh Reuse Enabled": True, "Mesh Reuse File": mesh_file, "Objects": assignment} - ) + props = dict({"Enable": True, "Mesh Reuse Enabled": True, "Mesh Reuse File": mesh_file, "Objects": assignment}) mop = MeshOperation(self, name, props, "Icepak") mop.create() self.meshoperations.append(mop) diff --git a/src/ansys/aedt/core/modules/optimetrics_templates.py b/src/ansys/aedt/core/modules/optimetrics_templates.py index efa3dc5d1a1..76da1ac27c4 100644 --- a/src/ansys/aedt/core/modules/optimetrics_templates.py +++ b/src/ansys/aedt/core/modules/optimetrics_templates.py @@ -22,48 +22,43 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -from collections import OrderedDict -defaultparametricSetup = OrderedDict( +defaultparametricSetup = dict( { "IsEnabled": True, - "ProdOptiSetupDataV2": OrderedDict({"SaveFields": False, "CopyMesh": False, "SolveWithCopiedMeshOnly": True}), - "StartingPoint": OrderedDict(), + "ProdOptiSetupDataV2": dict({"SaveFields": False, "CopyMesh": False, "SolveWithCopiedMeshOnly": True}), + "StartingPoint": {}, "Sim. Setups": [], - "Sweeps": OrderedDict( - {"SweepDefinition": OrderedDict({"Variable": "", "Data": "", "OffsetF1": False, "Synchronize": 0})} - ), - "Sweep Operations": OrderedDict(), - "Goals": OrderedDict(), + "Sweeps": dict({"SweepDefinition": dict({"Variable": "", "Data": "", "OffsetF1": False, "Synchronize": 0})}), + "Sweep Operations": {}, + "Goals": {}, } ) -defaultdxSetup = OrderedDict( +defaultdxSetup = dict( { "IsEnabled": True, - "ProdOptiSetupDataV2": OrderedDict({"SaveFields": False, "CopyMesh": False, "SolveWithCopiedMeshOnly": True}), - "StartingPoint": OrderedDict(), + "ProdOptiSetupDataV2": dict({"SaveFields": False, "CopyMesh": False, "SolveWithCopiedMeshOnly": True}), + "StartingPoint": {}, "Sim. Setups": [], - "Sweeps": OrderedDict( - {"SweepDefinition": OrderedDict({"Variable": "", "Data": "", "OffsetF1": False, "Synchronize": 0})} - ), - "Sweep Operations": OrderedDict(), + "Sweeps": dict({"SweepDefinition": dict({"Variable": "", "Data": "", "OffsetF1": False, "Synchronize": 0})}), + "Sweep Operations": {}, "CostFunctionName": "Cost", "CostFuncNormType": "L2", - "CostFunctionGoals": OrderedDict(), + "CostFunctionGoals": {}, "EmbeddedParamSetup": -1, - "Goals": OrderedDict(), + "Goals": {}, } ) -defaultoptiSetup = OrderedDict( +defaultoptiSetup = dict( { "IsEnabled": True, - "ProdOptiSetupDataV2": OrderedDict({"SaveFields": False, "CopyMesh": False, "SolveWithCopiedMeshOnly": True}), - "StartingPoint": OrderedDict(), + "ProdOptiSetupDataV2": dict({"SaveFields": False, "CopyMesh": False, "SolveWithCopiedMeshOnly": True}), + "StartingPoint": {}, "Optimizer": "Quasi Newton", - "AnalysisStopOptions": OrderedDict( + "AnalysisStopOptions": dict( { "StopForNumIteration": True, "StopForElapsTime": False, @@ -78,9 +73,9 @@ "CostFuncNormType": "L2", "PriorPSetup": "", "PreSolvePSetup": True, - "Variables": OrderedDict(), - "LCS": OrderedDict(), - "Goals": OrderedDict(), + "Variables": {}, + "LCS": {}, + "Goals": {}, "Acceptable_Cost": 0, "Noise": 0.0001, "UpdateDesign": False, @@ -90,48 +85,48 @@ } ) -defaultsensitivitySetup = OrderedDict( +defaultsensitivitySetup = dict( { "IsEnabled": True, - "ProdOptiSetupDataV2": OrderedDict({"SaveFields": False, "CopyMesh": False, "SolveWithCopiedMeshOnly": True}), - "StartingPoint": OrderedDict(), + "ProdOptiSetupDataV2": dict({"SaveFields": False, "CopyMesh": False, "SolveWithCopiedMeshOnly": True}), + "StartingPoint": {}, "MaxIterations": 10, "PriorPSetup": "", "PreSolvePSetup": True, - "Variables": OrderedDict(), - "LCS": OrderedDict(), - "Goals": OrderedDict(), + "Variables": {}, + "LCS": {}, + "Goals": {}, "Primary Goal": 0, "PrimaryError": 0.0001, "Perform Worst Case Analysis": False, } ) -defaultstatisticalSetup = OrderedDict( +defaultstatisticalSetup = dict( { "IsEnabled": True, - "ProdOptiSetupDataV2": OrderedDict({"SaveFields": False, "CopyMesh": False, "SolveWithCopiedMeshOnly": True}), - "StartingPoint": OrderedDict(), + "ProdOptiSetupDataV2": dict({"SaveFields": False, "CopyMesh": False, "SolveWithCopiedMeshOnly": True}), + "StartingPoint": {}, "MaxIterations": 50, "SeedValue": 0, "PriorPSetup": "", - "Variables": OrderedDict(), - "Goals": OrderedDict(), + "Variables": {}, + "Goals": {}, } ) -defaultdoeSetup = OrderedDict( +defaultdoeSetup = dict( { "IsEnabled": True, - "ProdOptiSetupDataV2": OrderedDict({"SaveFields": False, "CopyMesh": False, "SolveWithCopiedMeshOnly": True}), - "StartingPoint": OrderedDict(), + "ProdOptiSetupDataV2": dict({"SaveFields": False, "CopyMesh": False, "SolveWithCopiedMeshOnly": True}), + "StartingPoint": {}, "Sim. Setups": [], "CostFunctionName": "Cost", "CostFuncNormType": "L2", - "CostFunctionGoals": OrderedDict(), - "Variables": OrderedDict(), - "Goals": OrderedDict(), - "DesignExprData": OrderedDict( + "CostFunctionGoals": {}, + "Variables": {}, + "Goals": {}, + "DesignExprData": dict( { "Type": "kOSF", "CCDDeignType": "kFaceCentered", @@ -143,10 +138,10 @@ "MaxCydes": 10, } ), - "RespSurfaceSetupData": OrderedDict({"Type": "kGenAggr", "RefineType": "kManual"}), - "ResponsePoints": OrderedDict({"NumOfStrs": 0}), - "ManualRefinePoints": OrderedDict({"NumOfStrs": 0}), - "CustomVerifyPoints": OrderedDict({"NumOfStrs": 0}), + "RespSurfaceSetupData": dict({"Type": "kGenAggr", "RefineType": "kManual"}), + "ResponsePoints": dict({"NumOfStrs": 0}), + "ManualRefinePoints": dict({"NumOfStrs": 0}), + "CustomVerifyPoints": dict({"NumOfStrs": 0}), "Tolerances": [], } ) diff --git a/src/ansys/aedt/core/modules/post_processor.py b/src/ansys/aedt/core/modules/post_processor.py index 9de451e4188..9ce93d343fe 100644 --- a/src/ansys/aedt/core/modules/post_processor.py +++ b/src/ansys/aedt/core/modules/post_processor.py @@ -32,7 +32,6 @@ from __future__ import absolute_import # noreorder import ast -from collections import OrderedDict from collections import defaultdict import csv import os @@ -1667,7 +1666,7 @@ def _get_report_inputs( elif setup_sweep_name not in self._app.existing_analysis_sweeps: self.logger.error("Sweep not Available.") return False - families_input = OrderedDict({}) + families_input = {} did = 3 if domain == "Sweep" and not primary_sweep_variable: primary_sweep_variable = "Freq" @@ -2473,7 +2472,7 @@ def _get_base_name(self, setup): if isinstance(sim_data["SimSetup"], list): # pragma: no cover for solution in sim_data["SimSetup"]: base_name = solution["Name"] - if isinstance(solution["Solution"], (dict, OrderedDict)): + if isinstance(solution["Solution"], dict): sols = [solution["Solution"]] else: sols = solution["Solution"] @@ -2538,7 +2537,7 @@ def _get_cs_plane_ids(self): cs = self._app.design_properties["ModelSetup"]["GeometryCore"]["GeometryOperations"]["CoordinateSystems"] for ds in cs: try: - if isinstance(cs[ds], (OrderedDict, dict)): + if isinstance(cs[ds], dict): name = cs[ds]["Attributes"]["Name"] cs_id = cs[ds]["XYPlaneID"] name2refid[cs_id] = name + ":XY" @@ -2568,7 +2567,7 @@ def _get_fields_plot(self): setups_data = self._app.design_properties["FieldsReporter"]["FieldsPlotManagerID"] for setup in setups_data: try: - if isinstance(setups_data[setup], (OrderedDict, dict)) and "PlotDefinition" in setup: + if isinstance(setups_data[setup], dict) and "PlotDefinition" in setup: plot_name = setups_data[setup]["PlotName"] plots[plot_name] = FieldPlot(self) plots[plot_name].solution = self._get_base_name(setup) @@ -3266,6 +3265,9 @@ def change_field_plot_scale( ): """Change Field Plot Scale. + .. deprecated:: 0.10.1 + Use :class:`FieldPlot.folder_settings` methods instead. + Parameters ---------- plot_name : str diff --git a/src/ansys/aedt/core/modules/report_templates.py b/src/ansys/aedt/core/modules/report_templates.py index 985abbdc448..8955d5be075 100644 --- a/src/ansys/aedt/core/modules/report_templates.py +++ b/src/ansys/aedt/core/modules/report_templates.py @@ -22,7 +22,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -from collections import OrderedDict + import copy import os import re @@ -356,11 +356,11 @@ class CommonReport(object): def __init__(self, app, report_category, setup_name, expressions=None): self._post = app - self.props = OrderedDict() + self.props = {} self.props["report_category"] = report_category self.setup = setup_name self.props["report_type"] = "Rectangular Plot" - self.props["context"] = OrderedDict() + self.props["context"] = {} self.props["context"]["domain"] = "Sweep" self.props["context"]["primary_sweep"] = "Freq" self.props["context"]["primary_sweep_range"] = ["All"] diff --git a/src/ansys/aedt/core/modules/setup_templates.py b/src/ansys/aedt/core/modules/setup_templates.py index 0d6f950ac8b..d1887a2f896 100644 --- a/src/ansys/aedt/core/modules/setup_templates.py +++ b/src/ansys/aedt/core/modules/setup_templates.py @@ -24,7 +24,6 @@ from __future__ import absolute_import -from collections import OrderedDict import copy @@ -43,19 +42,19 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): List of frequency data. """ - value = OrderedDict({"AdaptiveFrequency": freq, "MaxDelta": "0.02", "MaxPasses": 10, "Expressions": []}) + value = dict({"AdaptiveFrequency": freq, "MaxDelta": "0.02", "MaxPasses": 10, "Expressions": []}) return value -meshlink = OrderedDict({"ImportMesh": False}) -autosweep = OrderedDict({"RangeType": "LinearStep", "RangeStart": "1GHz", "RangeEnd": "10GHz", "RangeStep": "1GHz"}) -autosweeps = OrderedDict({"Sweep": autosweep}) -multifreq = OrderedDict({"1GHz": [0.02], "2GHz": [0.02], "5GHz": [0.02]}) -sweepsbr = OrderedDict({"RangeType": "LinearStep", "RangeStart": "1GHz", "RangeEnd": "10GHz", "RangeStep": "1GHz"}) -sweepssbr = OrderedDict({"Sweep": sweepsbr}) -muoption = OrderedDict({"MuNonLinearBH": True}) -transientelectrostatic = OrderedDict({"SaveField": True, "Stop": "100s", "InitialStep": "0.01s", "MaxStep": "5s"}) -transienthfss = OrderedDict( +meshlink = dict({"ImportMesh": False}) +autosweep = dict({"RangeType": "LinearStep", "RangeStart": "1GHz", "RangeEnd": "10GHz", "RangeStep": "1GHz"}) +autosweeps = dict({"Sweep": autosweep}) +multifreq = dict({"1GHz": [0.02], "2GHz": [0.02], "5GHz": [0.02]}) +sweepsbr = dict({"RangeType": "LinearStep", "RangeStart": "1GHz", "RangeEnd": "10GHz", "RangeStep": "1GHz"}) +sweepssbr = dict({"Sweep": sweepsbr}) +muoption = dict({"MuNonLinearBH": True}) +transientelectrostatic = dict({"SaveField": True, "Stop": "100s", "InitialStep": "0.01s", "MaxStep": "5s"}) +transienthfss = dict( { "TimeProfile": "Broadband Pulse", "HfssFrequency": "5GHz", @@ -70,7 +69,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): "TerminateOnMaximum": 0, } ) -HFSSDrivenAuto = OrderedDict( +HFSSDrivenAuto = dict( { "IsEnabled": True, "MeshLink": meshlink, @@ -83,7 +82,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): ) """HFSS automatic setup properties and default values.""" -HFSSDrivenDefault = OrderedDict( +HFSSDrivenDefault = dict( { "SolveType": "Single", "MultipleAdaptiveFreqsSetup": multifreq, @@ -118,7 +117,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): ) """HFSS driven properties and default values.""" -HFSSEigen = OrderedDict( +HFSSEigen = dict( { "MinimumFrequency": "2GHz", "NumModes": 1, @@ -140,7 +139,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): ) """HFSS Eigenmode properties and default values.""" -HFSSTransient = OrderedDict( +HFSSTransient = dict( { "Frequency": "5GHz", "MaxDeltaS": 0.02, @@ -154,7 +153,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): ) """HFSS transient setup properties and default values.""" -HFSSSBR = OrderedDict( +HFSSSBR = dict( { "IsEnabled": True, "MeshLink": meshlink, @@ -169,7 +168,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): ) """HFSS SBR+ setup properties and default values.""" -MaxwellTransient = OrderedDict( +MaxwellTransient = dict( { "Enabled": True, "MeshLink": meshlink, @@ -196,7 +195,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): ) """Maxwell transient setup properties and default values.""" -Magnetostatic = OrderedDict( +Magnetostatic = dict( { "Enabled": True, "MeshLink": meshlink, @@ -216,7 +215,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): ) """Maxwell magnetostatic setup properties and default values.""" -DCConduction = OrderedDict( +DCConduction = dict( { "Enabled": True, "MeshLink": meshlink, @@ -235,7 +234,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): ) """Maxwell DCConduction setup properties and default values.""" -ElectroDCConduction = OrderedDict( +ElectroDCConduction = dict( { "Enabled": True, "MeshLink": meshlink, @@ -254,7 +253,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): ) """Maxwell ElectroDCConduction setup properties and default values.""" -ACConduction = OrderedDict( +ACConduction = dict( { "Enabled": True, "MeshLink": meshlink, @@ -273,7 +272,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): ) """Maxwell ACConduction setup properties and default values.""" -Electrostatic = OrderedDict( +Electrostatic = dict( { "Enabled": True, "MeshLink": meshlink, @@ -291,7 +290,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): ) """Maxwell electrostatic setup properties and default values.""" -subrange = OrderedDict( +subrange = dict( { "SweepSetupType": "LinearStep", "StartValue": "1e-08GHz", @@ -299,9 +298,9 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): "StepSize": "1e-08GHz", } ) -subranges = OrderedDict({"Subrange": subrange}) +subranges = dict({"Subrange": subrange}) -EddyCurrent = OrderedDict( +EddyCurrent = dict( { "Enabled": True, "MeshLink": meshlink, @@ -325,7 +324,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): ) """Maxwell eddy current setup properties and default values.""" -ElectricTransient = OrderedDict( +ElectricTransient = dict( { "Enabled": True, "MeshLink": meshlink, @@ -337,7 +336,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): ) """Maxwell electric transient setup properties and default values.""" -SteadyTemperatureAndFlow = OrderedDict( +SteadyTemperatureAndFlow = dict( { "Enabled": True, "Flow Regime": "Laminar", @@ -401,7 +400,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): ) """Icepak steady temperature and steady flow setup properties and default values.""" -SteadyTemperatureOnly = OrderedDict( +SteadyTemperatureOnly = dict( { "Enabled": True, "Flow Regime": "Laminar", @@ -463,7 +462,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): ) """Icepak steady temperature setup properties and default values.""" -SteadyFlowOnly = OrderedDict( +SteadyFlowOnly = dict( { "Enabled": True, "Flow Regime": "Laminar", @@ -526,10 +525,10 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): ) """Icepak steady flow setup properties and default values.""" -Q3DCond = OrderedDict({"MaxPass": 10, "MinPass": 1, "MinConvPass": 1, "PerError": 1, "PerRefine": 30}) -Q3DMult = OrderedDict({"MaxPass": 1, "MinPass": 1, "MinConvPass": 1, "PerError": 1, "PerRefine": 30}) -Q3DDC = OrderedDict({"SolveResOnly": False, "Cond": Q3DCond, "Mult": Q3DMult}) -Q3DCap = OrderedDict( +Q3DCond = dict({"MaxPass": 10, "MinPass": 1, "MinConvPass": 1, "PerError": 1, "PerRefine": 30}) +Q3DMult = dict({"MaxPass": 1, "MinPass": 1, "MinConvPass": 1, "PerError": 1, "PerRefine": 30}) +Q3DDC = dict({"SolveResOnly": False, "Cond": Q3DCond, "Mult": Q3DMult}) +Q3DCap = dict( { "MaxPass": 10, "MinPass": 1, @@ -541,8 +540,8 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): "Solver Type": "Iterative", } ) -Q3DAC = OrderedDict({"MaxPass": 10, "MinPass": 1, "MinConvPass": 1, "PerError": 1, "PerRefine": 30}) -Matrix = OrderedDict( +Q3DAC = dict({"MaxPass": 10, "MinPass": 1, "MinConvPass": 1, "PerError": 1, "PerRefine": 30}) +Matrix = dict( { "AdaptiveFreq": "1GHz", "SaveFields": False, @@ -554,10 +553,10 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): ) """Q3D Extractor setup properties and default values.""" -OutputQuantities = OrderedDict({}) -NoiseOutputQuantities = OrderedDict({}) -SweepDefinition = OrderedDict({"Variable": "Freq", "Data": "LINC 1GHz 5GHz 501", "OffsetF1": False, "Synchronize": 0}) -NexximLNA = OrderedDict( +OutputQuantities = {} +NoiseOutputQuantities = {} +SweepDefinition = dict({"Variable": "Freq", "Data": "LINC 1GHz 5GHz 501", "OffsetF1": False, "Synchronize": 0}) +NexximLNA = dict( { "DataBlockID": 16, "OptionName": "Default Options", @@ -574,7 +573,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): ) """Nexxim linear network setup properties and default values.""" -NexximDC = OrderedDict( +NexximDC = dict( { "DataBlockID": 15, "OptionName": "Default Options", @@ -589,7 +588,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): ) """Nexxim DC setup properties and default values.""" -NexximTransient = OrderedDict( +NexximTransient = dict( { "DataBlockID": 10, "OptionName": "Default Options", @@ -607,7 +606,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): ) """Nexxim transient setup properties and default values.""" -NexximQuickEye = OrderedDict( +NexximQuickEye = dict( { "DataBlockID": 28, "OptionName": "Default Options", @@ -621,7 +620,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): "QuickEyeAnalysis": [False, "1e-9", False, "0", "", True], } ) -NexximVerifEye = OrderedDict( +NexximVerifEye = dict( { "DataBlockID": 27, "OptionName": "Default Options", @@ -635,7 +634,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): "VerifEyeAnalysis": [False, "1e-9", False, "0", "", True], } ) -NexximAMI = OrderedDict( +NexximAMI = dict( { "DataBlockID": 29, "OptionName": "Default Options", @@ -651,12 +650,12 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): "AMIAnalysis": [32, False, False], } ) -NexximOscillatorRSF = OrderedDict({}) -NexximOscillator1T = OrderedDict({}) -NexximOscillatorNT = OrderedDict({}) -NexximHarmonicBalance1T = OrderedDict({}) -NexximHarmonicBalanceNT = OrderedDict({}) -NexximSystem = OrderedDict( +NexximOscillatorRSF = {} +NexximOscillator1T = {} +NexximOscillatorNT = {} +NexximHarmonicBalance1T = {} +NexximHarmonicBalanceNT = {} +NexximSystem = dict( { "DataBlockID": 32, "OptionName": "Default Options", @@ -671,8 +670,8 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): "HSPICETransientOtherData": [3], } ) -NexximTVNoise = OrderedDict({}) -HSPICE = OrderedDict( +NexximTVNoise = {} +HSPICE = dict( { "DataBlockID": 30, "OptionName": "Default Options", @@ -687,8 +686,8 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): } ) -HFSS3DLayout_Properties = OrderedDict({"Enable": "true"}) -HFSS3DLayout_AdvancedSettings = OrderedDict( +HFSS3DLayout_Properties = dict({"Enable": "true"}) +HFSS3DLayout_AdvancedSettings = dict( { "AccuracyLevel": 2, "GapPortCalibration": True, @@ -738,7 +737,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): "PhiMesherDeltaZRatio": 100000, # 2023.1 } ) -HFSS3DLayout_CurveApproximation = OrderedDict( +HFSS3DLayout_CurveApproximation = dict( { "ArcAngle": "30deg", "StartAzimuth": "0deg", @@ -749,7 +748,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): "Replace3DTriangles": True, } ) -HFSS3DLayout_Q3D_DCSettings = OrderedDict( +HFSS3DLayout_Q3D_DCSettings = dict( { "SolveResOnly": True, "Cond": Q3DCond, @@ -758,7 +757,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): } ) -CGDataBlock = OrderedDict( +CGDataBlock = dict( { "MaxPass": 10, "MinPass": 1, @@ -773,7 +772,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): "UseLossConv": True, } ) -RLDataBlock = OrderedDict( +RLDataBlock = dict( { "MaxPass": 10, "MinPass": 1, @@ -788,7 +787,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): "UseLossConv": True, } ) -Open = OrderedDict( +Open = dict( { "AdaptiveFreq": "1GHz", "SaveFields": True, @@ -802,7 +801,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): ) """Q2D open setup properties and default values.""" -Close = OrderedDict( +Close = dict( { "AdaptiveFreq": "1GHz", "SaveFields": True, @@ -816,7 +815,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): ) """Q2D close setup properties and default values.""" -TransientTemperatureAndFlow = OrderedDict( +TransientTemperatureAndFlow = dict( { "Enabled": True, "Flow Regime": "Laminar", @@ -907,7 +906,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): ) """Icepak Transient Temperature and Flow setup properties and default values.""" -TransientTemperatureOnly = OrderedDict( +TransientTemperatureOnly = dict( { "Enabled": True, "Flow Regime": "Laminar", @@ -998,7 +997,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): ) """Icepak Transient Temperature only setup properties and default values.""" -TransientFlowOnly = OrderedDict( +TransientFlowOnly = dict( { "Enabled": True, "Flow Regime": "Laminar", @@ -1089,10 +1088,8 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): ) """Icepak Transient Flow only setup properties and default values.""" -HFSS3DLayout_SingleFrequencyDataList = OrderedDict( - {"AdaptiveFrequencyData": HFSS3DLayout_AdaptiveFrequencyData("5GHz")} -) -HFSS3DLayout_BroadbandFrequencyDataList = OrderedDict( +HFSS3DLayout_SingleFrequencyDataList = dict({"AdaptiveFrequencyData": HFSS3DLayout_AdaptiveFrequencyData("5GHz")}) +HFSS3DLayout_BroadbandFrequencyDataList = dict( { "AdaptiveFrequencyData": [ HFSS3DLayout_AdaptiveFrequencyData("5GHz"), @@ -1100,7 +1097,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): ] } ) -HFSS3DLayout_MultiFrequencyDataList = OrderedDict( +HFSS3DLayout_MultiFrequencyDataList = dict( { "AdaptiveFrequencyData": [ HFSS3DLayout_AdaptiveFrequencyData("2.5GHz"), @@ -1109,7 +1106,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): ] } ) -HFSS3DLayout_AdaptiveSettings = OrderedDict( +HFSS3DLayout_AdaptiveSettings = dict( { "DoAdaptive": True, "SaveFields": False, @@ -1124,7 +1121,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): "MultiFrequencyDataList": HFSS3DLayout_MultiFrequencyDataList, } ) -HFSS3DLayout = OrderedDict( +HFSS3DLayout = dict( { "Properties": HFSS3DLayout_Properties, "CustomSetup": False, @@ -1178,7 +1175,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): "SmallVoidArea": -2e-09, "HealingOption": 1, "InclBBoxOption": 1, - "AuxBlock": OrderedDict({}), + "AuxBlock": {}, "DoAdaptive": True, "Color": ["R", 0, "G", 0, "B", 0], # TODO: create something smart for color arrays: like a class "AdvancedSettings": HFSS3DLayout_AdvancedSettings, @@ -1188,7 +1185,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): } ) -HFSS3DLayout_v231 = OrderedDict( +HFSS3DLayout_v231 = dict( { "Properties": HFSS3DLayout_Properties, "CustomSetup": False, @@ -1253,21 +1250,21 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): "ModelType": 0, "ICModeAuto": 1, "ICModeLength": "50nm", - "AuxBlock": OrderedDict({}), + "AuxBlock": {}, "DoAdaptive": True, "Color": ["R", 0, "G", 0, "B", 0], # TODO: create something smart for color arrays: like a class "AdvancedSettings": HFSS3DLayout_AdvancedSettings, "CurveApproximation": HFSS3DLayout_CurveApproximation, "Q3D_DCSettings": HFSS3DLayout_Q3D_DCSettings, "AdaptiveSettings": HFSS3DLayout_AdaptiveSettings, - "Data": OrderedDict({}), - "MeshOps": OrderedDict({}), + "Data": {}, + "MeshOps": {}, } ) """HFSS 3D Layout setup properties and default values.""" -HFSS3DLayout_SweepDataList = OrderedDict({}) -HFSS3DLayout_SIWAdvancedSettings = OrderedDict( +HFSS3DLayout_SweepDataList = {} +HFSS3DLayout_SIWAdvancedSettings = dict( { "IncludeCoPlaneCoupling": True, "IncludeInterPlaneCoupling": False, @@ -1290,7 +1287,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): "IgnoreNonFunctionalPads": True, } ) -HFSS3DLayout_SIWDCSettings = OrderedDict( +HFSS3DLayout_SIWDCSettings = dict( { "UseDCCustomSettings": False, "PlotJV": True, @@ -1299,7 +1296,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): "DCSliderPos": 1, } ) -HFSS3DLayout_SIWDCAdvancedSettings = OrderedDict( +HFSS3DLayout_SIWDCAdvancedSettings = dict( { "DcMinPlaneAreaToMesh": "0.25mm2", "DcMinVoidAreaToMesh": "0.01mm2", @@ -1317,10 +1314,10 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): "NumViaSides": 8, } ) -HFSS3DLayout_SIWDCIRSettings = OrderedDict( +HFSS3DLayout_SIWDCIRSettings = dict( { "IcepakTempFile": "D:/Program Files/AnsysEM/AnsysEM21.2/Win64/", - "SourceTermsToGround": OrderedDict({}), + "SourceTermsToGround": {}, "ExportDCThermalData": False, "ImportThermalData": False, "FullDCReportPath": "", @@ -1333,7 +1330,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): } ) -HFSS3DLayout_SimulationSettings = OrderedDict( +HFSS3DLayout_SimulationSettings = dict( { "Enabled": True, "UseSISettings": True, @@ -1347,7 +1344,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): } ) -HFSS3DLayout_ACSimulationSettings = OrderedDict( +HFSS3DLayout_ACSimulationSettings = dict( { "Enabled": True, "UseSISettings": True, @@ -1359,7 +1356,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): "SIWDCAdvancedSettings": HFSS3DLayout_SIWDCAdvancedSettings, } ) -SiwaveAC3DLayout = OrderedDict( +SiwaveAC3DLayout = dict( { "Properties": HFSS3DLayout_Properties, "CustomSetup": False, @@ -1372,7 +1369,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): } ) -SiwaveDC3DLayout = OrderedDict( +SiwaveDC3DLayout = dict( { "Properties": HFSS3DLayout_Properties, "CustomSetup": False, @@ -1384,7 +1381,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): } ) -HFSS3DLayout_LNASimulationSettings = OrderedDict( +HFSS3DLayout_LNASimulationSettings = dict( { "Enabled": True, "GroupDelay": False, @@ -1396,7 +1393,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): "FilterText": "", } ) -LNA_Sweep = OrderedDict( +LNA_Sweep = dict( { "DataId": "Sweep0", "Properties": HFSS3DLayout_Properties, @@ -1404,8 +1401,8 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): "SolutionID": -1, } ) -HFSS3DLayout_LNAData = OrderedDict({"LNA Sweep 1": LNA_Sweep}) -LNA3DLayout = OrderedDict( +HFSS3DLayout_LNAData = dict({"LNA Sweep 1": LNA_Sweep}) +LNA3DLayout = dict( { "Properties": HFSS3DLayout_Properties, "CustomSetup": False, @@ -1417,7 +1414,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): "Data": HFSS3DLayout_LNAData, } ) -MechTerm = OrderedDict( +MechTerm = dict( { "Enabled": True, "MeshLink": meshlink, @@ -1427,7 +1424,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): ) """Mechanical thermal setup properties and default values.""" -MechTransientThermal = OrderedDict( +MechTransientThermal = dict( { "Enabled": True, "MeshLink": meshlink, @@ -1448,7 +1445,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): } ) -MechModal = OrderedDict( +MechModal = dict( { "Enabled": True, "MeshLink": meshlink, @@ -1461,7 +1458,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): ) """Mechanical modal setup properties and default values.""" -MechStructural = OrderedDict( +MechStructural = dict( { "Enabled": True, "MeshLink": meshlink, @@ -1473,7 +1470,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): # TODO complete the list of templates for other Solvers -RmxprtDefault = OrderedDict( +RmxprtDefault = dict( { "Enabled": True, "OperationType": "Motor", @@ -1493,7 +1490,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): GRM["Frequency"] = "60Hz" GRM["CapacitivePowerFactor"] = False -DFIG = OrderedDict( +DFIG = dict( { "Enabled": True, "RatedOutputPower": "1kW", @@ -1519,7 +1516,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): """RMxprt SPIM Single-Phase Induction Machine setup properties.""" -TPSM = OrderedDict( +TPSM = dict( { "Enabled": True, "RatedOutputPower": "100", @@ -1555,7 +1552,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): """RMxprt UNIM Universal Machine setup properties.""" -DCM = OrderedDict( +DCM = dict( { "Enabled": True, "RatedOutputPower": "1kW", @@ -1572,7 +1569,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): ) """RMxprt DCM DC Machine/Generator setup properties.""" -CPSM = OrderedDict( +CPSM = dict( { "Enabled": True, "RatedOutputPower": "100", @@ -1588,9 +1585,9 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): ) """RMxprt CPSM Claw-pole synchronous machine/generator setup properties.""" -TR = OrderedDict({}) +TR = {} -SweepHfss3D = OrderedDict( +SweepHfss3D = dict( { "Type": "Interpolating", "IsEnabled": True, @@ -1623,9 +1620,9 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): } ) -enabled = OrderedDict({"Enable": "true"}) +enabled = dict({"Enable": "true"}) -Sweep3DLayout = OrderedDict( +Sweep3DLayout = dict( { "Properties": enabled, "Sweeps": SweepDefinition, @@ -1657,7 +1654,7 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): } ) -SweepSiwave = OrderedDict( +SweepSiwave = dict( { "Properties": enabled, "Sweeps": SweepDefinition, @@ -1691,8 +1688,8 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq): "EnforceDCAndCausality": False, "AdvDCExtrapolation": False, "MinSolvedFreq": "0.01GHz", - "MatrixConvEntryList": OrderedDict({}), - "HFSSRegionsParallelSimConfig": OrderedDict({}), + "MatrixConvEntryList": {}, + "HFSSRegionsParallelSimConfig": {}, } ) diff --git a/src/ansys/aedt/core/modules/solutions.py b/src/ansys/aedt/core/modules/solutions.py index ce75924dac7..5e64b0fa8a6 100644 --- a/src/ansys/aedt/core/modules/solutions.py +++ b/src/ansys/aedt/core/modules/solutions.py @@ -21,7 +21,8 @@ # 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 collections import OrderedDict + +from abc import abstractmethod from collections import defaultdict import csv import itertools @@ -33,15 +34,19 @@ import tempfile from ansys.aedt.core.generic.constants import AEDT_UNITS +from ansys.aedt.core.generic.constants import AllowedMarkers from ansys.aedt.core.generic.constants import CSS4_COLORS +from ansys.aedt.core.generic.constants import EnumUnits from ansys.aedt.core.generic.constants import db10 from ansys.aedt.core.generic.constants import db20 +from ansys.aedt.core.generic.data_handlers import _dict2arg from ansys.aedt.core.generic.general_methods import GrpcApiError from ansys.aedt.core.generic.general_methods import check_and_download_file from ansys.aedt.core.generic.general_methods import is_ironpython from ansys.aedt.core.generic.general_methods import open_file from ansys.aedt.core.generic.general_methods import pyaedt_function_handler from ansys.aedt.core.generic.general_methods import write_csv +from ansys.aedt.core.generic.load_aedt_file import load_keyword_in_aedt_file from ansys.aedt.core.generic.plot import plot_2d_chart from ansys.aedt.core.generic.plot import plot_3d_chart from ansys.aedt.core.generic.plot import plot_polar_chart @@ -489,7 +494,7 @@ def __init__(self, aedtdata): self._sweeps_names = [] self.update_sweeps() self.variations = self._get_variations() - self.active_intrinsic = OrderedDict({}) + self.active_intrinsic = {} for k, v in self.intrinsics.items(): self.active_intrinsic[k] = v[0] if len(self.intrinsics) > 0: @@ -551,7 +556,7 @@ def set_active_variation(self, var_id=0): def _get_variations(self): variations_lists = [] for data in self._original_data: - variations = OrderedDict({}) + variations = {} for v in data.GetDesignVariableNames(): variations[v] = data.GetDesignVariableValue(v) variations_lists.append(variations) @@ -584,12 +589,12 @@ def variation_values(self, variation): def intrinsics(self): """Get intrinsics dictionary on active variation.""" if not self._intrinsics: - self._intrinsics = OrderedDict({}) + self._intrinsics = {} intrinsics = [i for i in self._sweeps_names if i not in self.nominal_variation.GetDesignVariableNames()] for el in intrinsics: values = list(self.nominal_variation.GetSweepValues(el, False)) self._intrinsics[el] = [i for i in values] - self._intrinsics[el] = list(OrderedDict.fromkeys(self._intrinsics[el])) + self._intrinsics[el] = list(dict.fromkeys(self._intrinsics[el])) return self._intrinsics @property @@ -705,7 +710,7 @@ def _init_solution_data_real(self): solution = list(data.GetRealDataValues(expression, False)) values = [] for el in list(self.intrinsics.keys()): - values.append(list(OrderedDict.fromkeys(data.GetSweepValues(el, False)))) + values.append(list(dict.fromkeys(data.GetSweepValues(el, False)))) i = 0 c = [comb[v] for v in list(comb.keys())] @@ -733,7 +738,7 @@ def _init_solution_data_imag(self): solution = [0] * l values = [] for el in list(self.intrinsics.keys()): - values.append(list(OrderedDict.fromkeys(data.GetSweepValues(el, False)))) + values.append(list(dict.fromkeys(data.GetSweepValues(el, False)))) i = 0 c = [comb[v] for v in list(comb.keys())] for t in itertools.product(*values): @@ -1008,7 +1013,7 @@ def primary_sweep_variations(self): for el in self.primary_sweep_values: temp[position] = el if tuple(temp) in solution_data: - sol_dict = OrderedDict({}) + sol_dict = {} i = 0 for sn in self._sweeps_names: sol_dict[sn] = temp[i] @@ -1527,6 +1532,845 @@ def ifft_to_file( return txt_file_name +class BaseFolderPlot: + @abstractmethod + def to_dict(self): + """Convert the settings to a dictionary. + + Returns + ------- + dict + A dictionary containing settings. + """ + + @abstractmethod + def from_dict(self, dictionary): + """Initialize the settings from a dictionary. + + Parameters + ---------- + dictionary : dict + Dictionary containing the configuration settings. + Dictionary syntax must be the same of the AEDT file. + """ + + +class ColorMapSettings(BaseFolderPlot): + """Provides methods and variables for editing color map folder settings. + + Parameters + ---------- + map_type : str, optional + The type of colormap to use. Must be one of the allowed types + (`"Spectrum"`, `"Ramp"`, `"Uniform"`). + Default is `"Spectrum"`. + color : str or list[float], optional + Color to use. If "Spectrum" color map, a string is expected. + Else a list of 3 values (R,G,B). Default is `"Rainbow"`. + """ + + def __init__(self, map_type="Spectrum", color="Rainbow"): + self._map_type = None + self.map_type = map_type + + # Default color settings + self._color_spectrum = "Rainbow" + self._color_ramp = [255, 127, 127] + self._color_uniform = [127, 255, 255] + + # User-provided color settings + self.color = color + + @property + def map_type(self): + """Get the color map type for the field plot.""" + return self._map_type + + @map_type.setter + def map_type(self, value): + """Set the type of color mapping for the field plot. + + Parameters + ---------- + value : str + The type of mapping to set. Must be one of 'Spectrum', 'Ramp', or 'Uniform'. + + Raises + ------ + ValueError + If the provided `value` is not valid, raises a ``ValueError`` with an appropriate message. + """ + if value not in ["Spectrum", "Ramp", "Uniform"]: + raise ValueError(f"{value} is not valid. Only 'Spectrum', 'Ramp', and 'Uniform' are accepted.") + self._map_type = value + + @property + def color(self): + """Get the color based on the map type. + + Returns: + str or list of float: The color scheme based on the map type. + """ + if self.map_type == "Spectrum": + return self._color_spectrum + elif self.map_type == "Ramp": + return self._color_ramp + elif self.map_type == "Uniform": + return self._color_uniform + + @color.setter + def color(self, v): + """Set the colormap based on the map type. + + Parameters: + ----------- + v : str or list[float] + The color value to be set. If a string, it should represent a valid color + spectrum specification (`"Magenta"`, `"Rainbow"`, `"Temperature"` or `"Gray"`). + If a tuple, it should contain three elements representing RGB values. + + Raises: + ------- + ValueError: If the provided color value is not valid for the specified map type. + """ + if self.map_type == "Spectrum": + self._validate_color_spectrum(v) + self._color_spectrum = v + else: + self._validate_color(v) + if self.map_type == "Ramp": + self._color_ramp = v + else: + self._color_uniform = v + + @staticmethod + def _validate_color_spectrum(value): + if value not in ["Magenta", "Rainbow", "Temperature", "Gray"]: + raise ValueError( + f"{value} is not valid. Only 'Magenta', 'Rainbow', 'Temperature', and 'Gray' are accepted." + ) + + @staticmethod + def _validate_color(value): + if not isinstance(value, list) or len(value) != 3: + raise ValueError(f"{value} is not valid. Three values (R, G, B) must be passed.") + + def __repr__(self): + color_repr = self.color + return f"ColorMapSettings(map_type='{self.map_type}', color={color_repr})" + + def to_dict(self): + """Convert the color map settings to a dictionary. + + Returns + ------- + dict + A dictionary containing all the color map settings + for the folder field plot settings. + """ + return { + "ColorMapSettings": { + "ColorMapType": self.map_type, + {"Spectrum": "SpectrumType", "Uniform": "UniformColor", "Ramp": "RampColor"}[self.map_type]: self.color, + } + } + + def from_dict(self, settings): + """Initialize the number format settings of the colormap settings from a dictionary. + + Parameters + ---------- + dictionary : dict + Dictionary containing the configuration for colormap settings. + Dictionary syntax must be the same of relevant portion of the AEDT file. + """ + self._map_type = settings["ColorMapType"] + self._color_spectrum = settings["SpectrumType"] + self._color_ramp = settings["RampColor"] + self._color_uniform = settings["UniformColor"] + + +class AutoScale(BaseFolderPlot): + """Provides methods and variables for editing automatic scale folder settings. + + Parameters + ---------- + n_levels : int, optional + Number of color levels of the scale. Default is `10`. + limit_precision_digits : bool, optional + Whether to limit precision digits. Default is `False`. + precision_digits : int, optional + Precision digits. Default is `3`. + use_current_scale_for_animation : bool, optional + Whether to use the scale for the animation. Default is `False`. + """ + + def __init__( + self, n_levels=10, limit_precision_digits=False, precision_digits=3, use_current_scale_for_animation=False + ): + self.n_levels = n_levels + self.limit_precision_digits = limit_precision_digits + self.precision_digits = precision_digits + self.use_current_scale_for_animation = use_current_scale_for_animation + + def __repr__(self): + return ( + f"AutoScale(n_levels={self.n_levels}, " + f"limit_precision_digits={self.limit_precision_digits}, " + f"precision_digits={self.precision_digits}, " + f"use_current_scale_for_animation={self.use_current_scale_for_animation})" + ) + + def to_dict(self): + """Convert the auto-scale settings to a dictionary. + + Returns + ------- + dict + A dictionary containing all the auto-scale settings + for the folder field plot settings. + """ + return { + "m_nLevels": self.n_levels, + "LimitFieldValuePrecision": self.limit_precision_digits, + "FieldValuePrecisionDigits": self.precision_digits, + "AnimationStaticScale": self.use_current_scale_for_animation, + } + + def from_dict(self, dictionary): + """Initialize the auto-scale settings from a dictionary. + + Parameters + ---------- + dictionary : dict + Dictionary containing the configuration for auto-scale settings. + Dictionary syntax must be the same of relevant portion of the AEDT file. + """ + self.n_levels = dictionary["m_nLevels"] + self.limit_precision_digits = dictionary["LimitFieldValuePrecision"] + self.precision_digits = dictionary["FieldValuePrecisionDigits"] + self.use_current_scale_for_animation = dictionary["AnimationStaticScale"] + + +class MinMaxScale(BaseFolderPlot): + """Provides methods and variables for editing min-max scale folder settings. + + Parameters + ---------- + n_levels : int, optional + Number of color levels of the scale. Default is `10`. + min_value : float, optional + Minimum value of the scale. Default is `0`. + max_value : float, optional + Maximum value of the scale. Default is `1`. + """ + + def __init__(self, n_levels=10, min_value=0, max_value=1): + self.n_levels = n_levels + self.min_value = min_value + self.max_value = max_value + + def __repr__(self): + return f"MinMaxScale(n_levels={self.n_levels}, min_value={self.min_value}, max_value={self.max_value})" + + def to_dict(self): + """Convert the min-max scale settings to a dictionary. + + Returns + ------- + dict + A dictionary containing all the min-max scale settings + for the folder field plot settings. + """ + return {"minvalue": self.min_value, "maxvalue": self.max_value, "m_nLevels": self.n_levels} + + def from_dict(self, dictionary): + """Initialize the min-max scale settings from a dictionary. + + Parameters + ---------- + dictionary : dict + Dictionary containing the configuration for min-max scale settings. + Dictionary syntax must be the same of relevant portion of the AEDT file. + """ + self.min_value = dictionary["minvalue"] + self.max_value = dictionary["maxvalue"] + self.n_levels = dictionary["m_nLevels"] + + +class SpecifiedScale: + """Provides methods and variables for editing min-max scale folder settings. + + Parameters + ---------- + scale_values : int, optional + Scale levels. Default is `None`. + """ + + def __init__(self, scale_values=None): + if scale_values is None: + scale_values = [] + if not isinstance(scale_values, list): + raise ValueError("scale_values must be a list.") + self.scale_values = scale_values + + def __repr__(self): + return f"SpecifiedScale(scale_values={self.scale_values})" + + def to_dict(self): + """Convert the specified scale settings to a dictionary. + + Returns + ------- + dict + A dictionary containing all the specified scale settings + for the folder field plot settings. + """ + return {"UserSpecifyValues": [len(self.scale_values)] + self.scale_values} + + def from_dict(self, dictionary): + """Initialize the specified scale settings from a dictionary. + + Parameters + ---------- + dictionary : dict + Dictionary containing the configuration for specified scale settings. + Dictionary syntax must be the same of relevant portion of the AEDT file. + """ + self.scale_values = dictionary["UserSpecifyValues"][:-1] + + +class NumberFormat(BaseFolderPlot): + """Provides methods and variables for editing number format folder settings. + + Parameters + ---------- + format_type : int, optional + Scale levels. Default is `None`. + width : int, optional + Width of the numbers space. Default is `4`. + precision : int, optional + Precision of the numbers. Default is `4`. + """ + + def __init__(self, format_type="Automatic", width=4, precision=4): + self._format_type = format_type + self.width = width + self.precision = precision + self._accepted = ["Automatic", "Scientific", "Decimal"] + + @property + def format_type(self): + """Get the current number format type.""" + return self._format_type + + @format_type.setter + def format_type(self, v): + """Set the numeric format type of the scale. + + Parameters: + ----------- + v (str): The new format type to be set. Must be one of the accepted values + ("Automatic", "Scientific" or "Decimal"). + + Raises: + ------- + ValueError: If the provided value is not in the list of accepted values. + """ + if v is not None and v in self._accepted: + self._format_type = v + else: + raise ValueError(f"{v} is not valid. Accepted values are {', '.join(self._accepted)}.") + + def __repr__(self): + return f"NumberFormat(format_type={self.format_type}, width={self.width}, precision={self.precision})" + + def to_dict(self): + """Convert the number format settings to a dictionary. + + Returns + ------- + dict + A dictionary containing all the number format settings + for the folder field plot settings. + """ + return { + "ValueNumberFormatTypeAuto": self._accepted.index(self.format_type), + "ValueNumberFormatTypeScientific": self.format_type == "Scientific", + "ValueNumberFormatWidth": self.width, + "ValueNumberFormatPrecision": self.precision, + } + + def from_dict(self, dictionary): + """Initialize the number format settings of the field plot settings from a dictionary. + + Parameters + ---------- + dictionary : dict + Dictionary containing the configuration for number format settings. + Dictionary syntax must be the same of relevant portion of the AEDT file. + """ + self._format_type = self._accepted[dictionary["ValueNumberFormatTypeAuto"]] + self.width = dictionary["ValueNumberFormatWidth"] + self.precision = dictionary["ValueNumberFormatPrecision"] + + +class Scale3DSettings(BaseFolderPlot): + """Provides methods and variables for editing scale folder settings. + + Parameters + ---------- + scale_type : str, optional + Scale type. Default is `"Auto"`. + scale_settings : :class:`ansys.aedt.core.modules.post_processor.AutoScale`, + :class:`ansys.aedt.core.modules.post_processor.MinMaxScale` or + :class:`ansys.aedt.core.modules.post_processor.SpecifiedScale`, optional + Scale settings. Default is `AutoScale()`. + log : bool, optional + Whether to use a log scale. Default is `False`. + db : bool, optional + Whether to use dB scale. Default is `False`. + unit : int, optional + Unit to use in the scale. Default is `None`. + number_format : :class:`ansys.aedt.core.modules.post_processor.NumberFormat`, optional + Number format settings. Default is `NumberFormat()`. + """ + + def __init__( + self, + scale_type="Auto", + scale_settings=AutoScale(), + log=False, + db=False, + unit=None, + number_format=NumberFormat(), + ): + self._scale_type = None # Initialize with None to use the setter for validation + self._scale_settings = None + self._unit = None + self._auto_scale = AutoScale() + self._minmax_scale = MinMaxScale() + self._specified_scale = SpecifiedScale() + self._accepted = ["Auto", "MinMax", "Specified"] + self.number_format = number_format + self.log = log + self.db = db + self.unit = unit + self.scale_type = scale_type # This will trigger the setter and validate the scale_type + self.scale_settings = scale_settings + + @property + def unit(self): + """Get unit used in the plot.""" + return EnumUnits(self._unit).name + + @unit.setter + def unit(self, v): + """Set unit used in the plot. + + Parameters + ---------- + v: str + Unit to be set. + """ + if v is not None: + try: + self._unit = EnumUnits[v].value + except KeyError: + raise KeyError(f"{v} is not a valid unit.") + + @property + def scale_type(self): + """Get type of scale used for the field plot.""" + return self._scale_type + + @scale_type.setter + def scale_type(self, value): + """Set the scale type used for the field plot. + + Parameters: + ----------- + value (str): The type of scaling to set. + Must be one of the accepted values ("Auto", "MinMax" or "Specified"). + + Raises: + ------- + ValueError: If the provided value is not in the list of accepted values. + """ + if value is not None and value not in self._accepted: + raise ValueError(f"{value} is not valid. Accepted values are {', '.join(self._accepted)}.") + self._scale_type = value + # Automatically adjust scale_settings based on scale_type + if value == "Auto": + self._scale_settings = self._auto_scale + elif value == "MinMax": + self._scale_settings = self._minmax_scale + elif value == "Specified": + self._scale_settings = self._specified_scale + + @property + def scale_settings(self): + """Get the current scale settings based on the scale type.""" + self.scale_type = self.scale_type # update correct scale settings + return self._scale_settings + + @scale_settings.setter + def scale_settings(self, value): + """Set the current scale settings based on the scale type.""" + if self.scale_type == "Auto": + if isinstance(value, AutoScale): + self._scale_settings = value + return + elif self.scale_type == "MinMax": + if isinstance(value, MinMaxScale): + self._scale_settings = value + return + elif self.scale_type == "Specified": + if isinstance(value, SpecifiedScale): + self._scale_settings = value + return + raise ValueError("Invalid scale settings for current scale type.") + + def __repr__(self): + return ( + f"Scale3DSettings(scale_type='{self.scale_type}', scale_settings={self.scale_settings}, " + f"log={self.log}, db={self.db})" + ) + + def to_dict(self): + """Convert the scale settings to a dictionary. + + Returns + ------- + dict + A dictionary containing all scale settings + for the folder field plot settings. + """ + arg_out = { + "Scale3DSettings": { + "unit": self._unit, + "ScaleType": self._accepted.index(self.scale_type), + "log": self.log, + "dB": self.db, + } + } + arg_out["Scale3DSettings"].update(self.number_format.to_dict()) + arg_out["Scale3DSettings"].update(self.scale_settings.to_dict()) + return arg_out + + def from_dict(self, dictionary): + """Initialize the scale settings of the field plot settings from a dictionary. + + Parameters + ---------- + dictionary : dict + Dictionary containing the configuration for scale settings. + Dictionary syntax must be the same of relevant portion of the AEDT file. + """ + self._scale_type = self._accepted[dictionary["ScaleType"]] + self.number_format = NumberFormat() + self.number_format.from_dict(dictionary) + self.log = dictionary["log"] + self.db = dictionary["dB"] + self.unit = EnumUnits(int(dictionary["unit"])).name + self._auto_scale = AutoScale() + self._auto_scale.from_dict(dictionary) + self._minmax_scale = MinMaxScale() + self._minmax_scale.from_dict(dictionary) + self._specified_scale = SpecifiedScale() + self._specified_scale.from_dict(dictionary) + + +class MarkerSettings(BaseFolderPlot): + """Provides methods and variables for editing marker folder settings. + + Parameters + ---------- + marker_type : str, optional + The type of maker to use. Must be one of the allowed types + (`"Octahedron"`, `"Tetrahedron"`, `"Sphere"`, `"Box"`, `"Arrow"`). + Default is `"Box"`. + marker_size : float, optional + Size of the marker. Default is `0.005`. + map_size : bool, optional + Whether to map the field magnitude to the arrow type. Default is `False`. + map_color : bool, optional + Whether to map the field magnitude to the arrow color. Default is `True`. + """ + + def __init__(self, marker_type="Box", map_size=False, map_color=True, marker_size=0.005): + self._marker_type = None + self.marker_type = marker_type + self.map_size = map_size + self.map_color = map_color + self.marker_size = marker_size + + @property + def marker_type(self): + """Get the type of maker to use.""" + return AllowedMarkers(self._marker_type).name + + @marker_type.setter + def marker_type(self, v): + """Set the type of maker to use. + + Parameters: + ---------- + v : str + Marker type. Must be one of the allowed types + (`"Octahedron"`, `"Tetrahedron"`, `"Sphere"`, `"Box"`, `"Arrow"`). + """ + try: + self._marker_type = AllowedMarkers[v].value + except KeyError: + raise KeyError(f"{v} is not a valid marker type.") + + def __repr__(self): + return ( + f"MarkerSettings(marker_type='{self.marker_type}', map_size={self.map_size}, " + f"map_color={self.map_color}, marker_size={self.marker_size})" + ) + + def to_dict(self): + """Convert the marker settings to a dictionary. + + Returns + ------- + dict + A dictionary containing all the marker settings + for the folder field plot settings. + """ + return { + "Marker3DSettings": { + "MarkerType": self._marker_type, + "MarkerMapSize": self.map_size, + "MarkerMapColor": self.map_color, + "MarkerSize": self.marker_size, + } + } + + def from_dict(self, dictionary): + """Initialize the marker settings of the field plot settings from a dictionary. + + Parameters + ---------- + dictionary : dict + Dictionary containing the configuration for marker settings. + Dictionary syntax must be the same of relevant portion of the AEDT file. + """ + self.marker_type = AllowedMarkers(int(dictionary["MarkerType"])).name + self.map_size = dictionary["MarkerMapSize"] + self.map_color = dictionary["MarkerMapColor"] + self.marker_size = dictionary["MarkerSize"] + + +class ArrowSettings(BaseFolderPlot): + """Provides methods and variables for editing arrow folder settings. + + Parameters + ---------- + arrow_type : str, optional + The type of arrows to use. Must be one of the allowed types + (`"Line"`, `"Cylinder"`, `"Umbrella"`). Default is `"Line"`. + arrow_size : float, optional + Size of the arrow. Default is `0.005`. + map_size : bool, optional + Whether to map the field magnitude to the arrow type. Default is `False`. + map_color : bool, optional + Whether to map the field magnitude to the arrow color. Default is `True`. + show_arrow_tail : bool, optional + Whether to show the arrow tail. Default is `False`. + magnitude_filtering : bool, optional + Whether to filter the field magnitude for plotting vectors. Default is `False`. + magnitude_threshold : bool, optional + Threshold value for plotting vectors. Default is `0`. + min_magnitude : bool, optional + Minimum value for plotting vectors. Default is `0`. + max_magnitude : bool, optional + Maximum value for plotting vectors. Default is `0.5`. + """ + + def __init__( + self, + arrow_type="Line", + arrow_size=0.005, + map_size=False, + map_color=True, + show_arrow_tail=False, + magnitude_filtering=False, + magnitude_threshold=0, + min_magnitude=0, + max_magnitude=0.5, + ): + self._arrow_type = None + self._allowed_arrow_types = ["Line", "Cylinder", "Umbrella"] + self.arrow_type = arrow_type + self.arrow_size = arrow_size + self.map_size = map_size + self.map_color = map_color + self.show_arrow_tail = show_arrow_tail + self.magnitude_filtering = magnitude_filtering + self.magnitude_threshold = magnitude_threshold + self.min_magnitude = min_magnitude + self.max_magnitude = max_magnitude + + @property + def arrow_type(self): + """Get the type of arrows used in the field plot.""" + return self._arrow_type + + @arrow_type.setter + def arrow_type(self, v): + """Set the type of arrows for the field plot. + + Parameters: + ----------- + v (str): The type of arrows to use. Must be one of the allowed types ("Line", "Cylinder", "Umbrella"). + + Raises: + ------- + ValueError: If the provided value is not in the list of allowed arrow types. + """ + if v in self._allowed_arrow_types: + self._arrow_type = v + else: + raise ValueError(f"{v} is not valid. Accepted values are {','.join(self._allowed_arrow_types)}.") + + def __repr__(self): + return ( + f"Arrow3DSettings(arrow_type='{self.arrow_type}', arrow_size={self.arrow_size}, " + f"map_size={self.map_size}, map_color={self.map_color}, " + f"show_arrow_tail={self.show_arrow_tail}, magnitude_filtering={self.magnitude_filtering}, " + f"magnitude_threshold={self.magnitude_threshold}, min_magnitude={self.min_magnitude}, " + f"max_magnitude={self.max_magnitude})" + ) + + def to_dict(self): + """Convert the arrow settings to a dictionary. + + Returns + ------- + dict + A dictionary containing all the arrow settings + for the folder field plot settings. + """ + return { + "Arrow3DSettings": { + "ArrowType": self._allowed_arrow_types.index(self.arrow_type), + "ArrowMapSize": self.map_size, + "ArrowMapColor": self.map_color, # Missing option in ui + "ShowArrowTail": self.show_arrow_tail, + "ArrowSize": self.arrow_size, + "ArrowMinMagnitude": self.min_magnitude, + "ArrowMaxMagnitude": self.max_magnitude, + "ArrowMagnitudeThreshold": self.magnitude_threshold, + "ArrowMagnitudeFilteringFlag": self.magnitude_filtering, + } + } + + def from_dict(self, dictionary): + """Initialize the arrow settings of the field plot settings from a dictionary. + + Parameters + ---------- + dictionary : dict + Dictionary containing the configuration for arrow settings. + Dictionary syntax must be the same of relevant portion of the AEDT file. + """ + self.arrow_type = self._allowed_arrow_types[dictionary["ArrowType"]] + self.arrow_size = dictionary["ArrowType"] + self.map_size = dictionary["ArrowMapSize"] + self.map_color = dictionary["ArrowMapColor"] + self.show_arrow_tail = dictionary["ShowArrowTail"] + self.magnitude_filtering = dictionary["ArrowMagnitudeFilteringFlag"] + self.magnitude_threshold = dictionary["ArrowMagnitudeThreshold"] + self.min_magnitude = dictionary["ArrowMinMagnitude"] + self.max_magnitude = dictionary["ArrowMaxMagnitude"] + + +class FolderPlotSettings(BaseFolderPlot): + """Provides methods and variables for editing field plots folder settings. + + Parameters + ---------- + postprocessor : :class:`ansys.aedt.core.modules.post_processor.PostProcessor` + folder_name : str + Name of the plot field folder. + arrow_settings : :class:`ansys.aedt.core.modules.solution.ArrowSettings`, optional + Arrow settings. Default is `None`. + marker_settings : :class:`ansys.aedt.core.modules.solution.MarkerSettings`, optional + Marker settings. Default is `None`. + scale_settings : :class:`ansys.aedt.core.modules.solution.Scale3DSettings`, optional + Scale settings. Default is `None`. + color_map_settings : :class:`ansys.aedt.core.modules.solution.ColorMapSettings`, optional + Colormap settings. Default is `None`. + """ + + def __init__( + self, + postprocessor, + folder_name, + arrow_settings=None, + marker_settings=None, + scale_settings=None, + color_map_settings=None, + ): + self.arrow_settings = arrow_settings + self.marker_settings = marker_settings + self.scale_settings = scale_settings + self.color_map_settings = color_map_settings + self._postprocessor = postprocessor + self._folder_name = folder_name + + def update(self): + """ + Update folder plot settings. + """ + out = [] + _dict2arg(self.to_dict(), out) + self._postprocessor.ofieldsreporter.SetPlotFolderSettings(self._folder_name, out[0]) + + def to_dict(self): + """Convert the field plot settings to a dictionary. + + Returns + ------- + dict + A dictionary containing all the settings for the field plot, + including arrow settings, marker settings, + scale settings, and color map settings. + """ + out = {} + out.update(self.arrow_settings.to_dict()) + out.update(self.marker_settings.to_dict()) + out.update(self.scale_settings.to_dict()) + out.update(self.color_map_settings.to_dict()) + return {"FieldsPlotSettings": out} + + def from_dict(self, dictionary): + """Initialize the field plot settings from a dictionary. + + Parameters + ---------- + dictionary : dict + Dictionary containing the configuration for the color map, + scale, arrow, and marker settings. Dictionary syntax must + be the same of the AEDT file. + """ + cmap = ColorMapSettings() + cmap.from_dict(dictionary["ColorMapSettings"]) + self.color_map_settings = cmap + scale = Scale3DSettings() + scale.from_dict(dictionary["Scale3DSettings"]) + self.scale_settings = scale + arrow = ArrowSettings() + arrow.from_dict(dictionary["Arrow3DSettings"]) + marker = MarkerSettings() + marker.from_dict(dictionary["Marker3DSettings"]) + self.arrow_settings = arrow + self.marker_settings = marker + + class FieldPlot: """Provides for creating and editing field plots. @@ -1613,6 +2457,61 @@ def __init__( self.FractionOfMaximum = 0.8 self._filter_boxes = [] self.field_type = None + self._folder_settings = None + + def _parse_folder_settings(self): + """Parse the folder settings for the field plot from the AEDT file. + + Returns: + FolderPlotSettings or None: An instance of FolderPlotSettings if found, otherwise None. + """ + folder_settings_data = load_keyword_in_aedt_file( + self._postprocessor._app.project_file, + "FieldsPlotManagerID", + design_name=self._postprocessor._app.design_name, + ) + relevant_settings = [ + d + for d in folder_settings_data["FieldsPlotManagerID"].values() + if isinstance(d, dict) and d.get("PlotFolder", False) and d["PlotFolder"] == self.plot_folder + ] + + if not relevant_settings: + self._postprocessor._app.logger.error( + "Could not find settings data in the design properties." + " Define the `FolderPlotSettings` class from scratch or save the project file and try again." + ) + return None + else: + fps = FolderPlotSettings(self._postprocessor, self.plot_folder) + fps.from_dict(relevant_settings[0]) + return fps + + @property + def folder_settings(self): + """Get the folder settings.""" + if self._folder_settings is None: + self._folder_settings = self._parse_folder_settings() + return self._folder_settings + + @folder_settings.setter + def folder_settings(self, v): + """Set the fieldplot folder settings. + + Parameters + ---------- + v : FolderPlotSettings + The new folder plot settings to be set. + + Raises + ------ + ValueError + If the provided value is not an instance of `FolderPlotSettings`. + """ + if isinstance(v, FolderPlotSettings): + self._folder_settings = v + else: + raise ValueError("Invalid type for `folder_settings`, use `FolderPlotSettings` class.") @property def filter_boxes(self): @@ -2191,6 +3090,9 @@ def delete(self): def change_plot_scale(self, minimum_value, maximum_value, is_log=False, is_db=False, scale_levels=None): """Change Field Plot Scale. + .. deprecated:: 0.10.1 + Use :class:`FieldPlot.folder_settings` methods instead. + Parameters ---------- minimum_value : str, float diff --git a/src/ansys/aedt/core/modules/solve_setup.py b/src/ansys/aedt/core/modules/solve_setup.py index c70979c3cfa..565d4ec6951 100644 --- a/src/ansys/aedt/core/modules/solve_setup.py +++ b/src/ansys/aedt/core/modules/solve_setup.py @@ -32,7 +32,6 @@ from __future__ import absolute_import # noreorder -from collections import OrderedDict import os.path from random import randrange import re @@ -181,18 +180,18 @@ def _init_props(self, is_new_setup=False): app.pop("MoveBackForward", None) app.pop("MoveBackwards", None) for el in app: - if isinstance(app[el], (OrderedDict, dict)): + if isinstance(app[el], dict): self.sweeps.append(SweepHFSS(self, el, props=app[el])) else: app = setup_data["Sweeps"] for el in app: - if isinstance(app[el], (OrderedDict, dict)): + if isinstance(app[el], dict): self.sweeps.append(SweepMatrix(self, el, props=app[el])) setup_data.pop("Sweeps", None) - self.props = SetupProps(self, OrderedDict(setup_data)) + self.props = SetupProps(self, setup_data) except Exception: - self.props = SetupProps(self, OrderedDict()) + self.props = SetupProps(self, {}) @property def is_solved(self): @@ -880,7 +879,7 @@ def add_mesh_link( else: raise ValueError("Setup does not exist in current design.") # parameters - meshlinks["Params"] = OrderedDict({}) + meshlinks["Params"] = {} if parameters is None: parameters = self.p_app.available_variations.nominal_w_values_dict for el in parameters: @@ -905,7 +904,7 @@ def add_mesh_link( def _parse_link_parameters(self, map_variables_by_name, parameters): # parameters - params = OrderedDict({}) + params = {} if map_variables_by_name: parameters = self.p_app.available_variations.nominal_w_values_dict for k, v in parameters.items(): @@ -923,7 +922,7 @@ def _parse_link_parameters(self, map_variables_by_name, parameters): return params def _parse_link_solution(self, project, design, solution): - prev_solution = OrderedDict({}) + prev_solution = {} # project name if project != "This Project*": @@ -1062,7 +1061,7 @@ def _init_props(self, is_new_setup=False): setup_template = SetupKeys.get_setup_templates()[self.setuptype] self.props = SetupProps(self, setup_template) else: - self.props = SetupProps(self, OrderedDict()) + self.props = SetupProps(self, {}) try: setups_data = self.p_app.design_properties["SimSetups"]["SimSetup"] if not isinstance(setups_data, list): @@ -1073,7 +1072,7 @@ def _init_props(self, is_new_setup=False): setup_data.pop("Sweeps", None) self.props = SetupProps(self, setup_data) except Exception: - self.props = SetupProps(self, OrderedDict()) + self.props = SetupProps(self, {}) self.props["Name"] = self.name @property @@ -1350,9 +1349,9 @@ def _add_sweep(self, sweep_variable, equation, override_existing_sweep): else: self.props["SweepDefinition"]["Data"] += " " + equation return self.update() - if isinstance(self.props["SweepDefinition"], (OrderedDict, dict)): + if isinstance(self.props["SweepDefinition"], dict): self.props["SweepDefinition"] = [self.props["SweepDefinition"]] - prop = OrderedDict({"Variable": sweep_variable, "Data": equation, "OffsetF1": False, "Synchronize": 0}) + prop = {"Variable": sweep_variable, "Data": equation, "OffsetF1": False, "Synchronize": 0} self.props["SweepDefinition"].append(prop) return self.update() @@ -1758,12 +1757,12 @@ def _init_props(self, is_new_setup=False): if "Data" in setup_data: # 0 and 7 represent setup HFSSDrivenAuto app = setup_data["Data"] for el in app: - if isinstance(app[el], (OrderedDict, dict)): + if isinstance(app[el], dict): self.sweeps.append(SweepHFSS3DLayout(self, el, props=app[el])) - self.props = SetupProps(self, OrderedDict(setup_data)) + self.props = SetupProps(self, setup_data) except Exception: - self.props = SetupProps(self, OrderedDict()) + self.props = SetupProps(self, {}) settings.logger.error("Unable to set props.") @property @@ -2320,6 +2319,88 @@ def export_to_json(self, file_path, overwrite=False): return False return self.props._export_properties_to_json(file_path, overwrite=overwrite) + @pyaedt_function_handler() + def use_matrix_convergence( + self, + entry_selection=0, + ignore_phase_when_mag_is_less_than=0.01, + all_diagonal_entries=True, + max_delta=0.02, + max_delta_phase=5, + all_offdiagonal_entries=True, + off_diagonal_mag=0.02, + off_diagonal_phase=5, + custom_entries=None, + ): + """Enable Matrix Convergence criteria. + + Parameters + ---------- + entry_selection : int + Entry Selection. ``0`` for All, ``1`` for Diagonal Entries, ``2`` for custom entries. + ignore_phase_when_mag_is_less_than : float + Value of magnitude when phase is ignored. + all_diagonal_entries : bool + Whether diagonal entries has to be included in convergence or not. Default is ``True``. + max_delta : float + Maximum Delta S. + max_delta_phase : float, str + Maximum delta phase in degree. + all_offdiagonal_entries : bool + Whether off-diagonal entries has to be included in convergence or not. Default is ``True``. + off_diagonal_mag : float + Maximum offdiagonal Delta S. + off_diagonal_phase : float, str + Maximum off-diagonal delta phase in degree. + custom_entries : list, optional + Custom entry mapping list. + Every item of the listshall be a list with 4 elements: + ``[port 1 name, port 2 name, max_delta_s, max_delta_angle]``. + + Returns + ------- + bool + """ + legacy_update = self.auto_update + self.auto_update = False + self.props["UseConvergenceMatrix"] = True + self.props["AllEntries"] = True if entry_selection == 0 else False + self.props["AllDiagEntries"] = True if entry_selection == 1 and all_diagonal_entries else False + self.props["AllOffDiagEntries"] = True if entry_selection == 1 and all_offdiagonal_entries else False + self.props["MagMinThreshold"] = ignore_phase_when_mag_is_less_than + aa = self._app.excitations + if entry_selection < 2: + val = [] + if entry_selection == 0 or (entry_selection == 1 and all_diagonal_entries): + entry = { + "Port1": aa[0], + "Port2": aa[0], + "MagLimit": str(max_delta), + "PhaseLimit": self._app.value_with_units(max_delta_phase, "deg"), + } + val.append(SetupProps(self, entry)) + if entry_selection == 1 and all_offdiagonal_entries and len(aa) > 1: + entry = { + "Port1": aa[0], + "Port2": aa[1], + "MagLimit": str(off_diagonal_mag), + "PhaseLimit": self._app.value_with_units(off_diagonal_phase, "deg"), + } + val.append(SetupProps(self, entry)) + self.props["MatrixConvEntry"] = val + else: + self.props["MatrixConvEntry"] = [] + for entry_custom in custom_entries: + entry = { + "Port1": entry_custom[0], + "Port2": entry_custom[1], + "MagLimit": str(entry_custom[2]), + "PhaseLimit": self._app.value_with_units(entry_custom[3], "deg"), + } + self.props["MatrixConvEntry"].append(SetupProps(self, entry)) + self.auto_update = legacy_update + return self.update() + class SetupHFSS(Setup, object): """Initializes, creates, and updates an HFSS setup. @@ -2949,6 +3030,94 @@ def enable_adaptive_setup_multifrequency(self, frequencies, max_delta_s=0.02): self.auto_update = True return self.update() + @pyaedt_function_handler() + def use_matrix_convergence( + self, + entry_selection=0, + ignore_phase_when_mag_is_less_than=0.01, + all_diagonal_entries=True, + max_delta=0.02, + max_delta_phase=5, + all_offdiagonal_entries=True, + off_diagonal_mag=0.02, + off_diagonal_phase=5, + custom_entries=None, + ): + """Enable Matrix Convergence criteria. + + Parameters + ---------- + entry_selection : int + Entry Selection. ``0`` for All, ``1`` for Diagonal Entries, ``2`` for custom entries. + ignore_phase_when_mag_is_less_than : float + Value of magnitude when phase is ignored. + all_diagonal_entries : bool + Whether diagonal entries has to be included in convergence or not. Default is ``True``. + max_delta : float + Maximum Delta S. + max_delta_phase : float, str + Maximum delta phase in degree. + all_offdiagonal_entries : bool + Whether off-diagonal entries has to be included in convergence or not. Default is ``True``. + off_diagonal_mag : float + Maximum offdiagonal Delta S. + off_diagonal_phase : float, str + Maximum off-diagonal delta phase in degree. + custom_entries : list, optional + Custom entry mapping list. + Every item of the lists hall be a list with 4 elements: + ``[port 1 name, port 2 name, max_delta_s, max_delta_angle]``. + + Returns + ------- + bool + """ + legacy_update = self.auto_update + self.auto_update = False + conv_data = {} + if entry_selection == 0: + conv_data = { + "AllEntries": True, + "MagLimit": str(max_delta), + "PhaseLimit": self._app.value_with_units(max_delta_phase, "deg"), + "MagMinThreshold": ignore_phase_when_mag_is_less_than, + } + elif entry_selection == 1: + conv_data = {} + if all_diagonal_entries: + conv_data["AllDiagEntries"] = True + conv_data["DiagonalMag"] = str(max_delta) + conv_data["DiagonalPhase"] = self._app.value_with_units(max_delta_phase, "deg") + conv_data["MagMinThreshold"] = ignore_phase_when_mag_is_less_than + if all_offdiagonal_entries and len(self._app.excitations) > 1: + conv_data["AllOffDiagEntries"] = True + conv_data["OffDiagonalMag"] = str(off_diagonal_mag) + conv_data["OffDiagonalPhase"] = self._app.value_with_units(off_diagonal_phase, "deg") + conv_data["MagMinThreshold"] = ignore_phase_when_mag_is_less_than + elif entry_selection == 2 and custom_entries: + if len(custom_entries) > 1: + conv_data = {"Entries": []} + else: + conv_data = {"Entries": {}} + for entry_custom in custom_entries: + entry = { + "Port1": entry_custom[0], + "Port2": entry_custom[1], + "MagLimit": entry_custom[2], + "PhaseLimit": self._app.value_with_units(entry_custom[3], "deg"), + } + if isinstance(conv_data["Entries"], list): + conv_data["Entries"].append(SetupProps(self, {"Entry": entry})) + else: + conv_data["Entries"] = SetupProps(self, {"Entry": entry}) + if conv_data: + props = SetupProps(self, conv_data) + self.props["Matrix Convergence"] = props + self.props["UseMatrixConv"] = True + self.auto_update = legacy_update + return self.update() + return False + class SetupHFSSAuto(Setup, object): """Initializes, creates, and updates an HFSS SBR+ or HFSS Auto setup. @@ -3352,7 +3521,7 @@ def add_eddy_current_sweep( return False legacy_update = self.auto_update self.auto_update = False - props = OrderedDict() + props = {} props["RangeType"] = range_type props["RangeStart"] = "{}{}".format(start, units) if range_type == "LinearStep": diff --git a/src/ansys/aedt/core/modules/solve_sweeps.py b/src/ansys/aedt/core/modules/solve_sweeps.py index ad3712c14a4..5795272481f 100644 --- a/src/ansys/aedt/core/modules/solve_sweeps.py +++ b/src/ansys/aedt/core/modules/solve_sweeps.py @@ -22,7 +22,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -from collections import OrderedDict import copy from difflib import SequenceMatcher import json @@ -823,31 +822,31 @@ def _get_args(self, props=None): return arg -class SetupProps(OrderedDict): +class SetupProps(dict): """Provides internal parameters for the AEDT boundary component.""" def __setitem__(self, key, value): - if isinstance(value, (dict, OrderedDict)): - OrderedDict.__setitem__(self, key, SetupProps(self._pyaedt_setup, value)) + if isinstance(value, dict): + dict.__setitem__(self, key, SetupProps(self._pyaedt_setup, value)) else: - OrderedDict.__setitem__(self, key, value) + dict.__setitem__(self, key, value) if self._pyaedt_setup.auto_update: res = self._pyaedt_setup.update() if not res: self._pyaedt_setup._app.logger.warning("Update of %s failed. Check needed arguments", key) def __init__(self, setup, props): - OrderedDict.__init__(self) + dict.__init__(self) if props: for key, value in props.items(): - if isinstance(value, (dict, OrderedDict)): - OrderedDict.__setitem__(self, key, SetupProps(setup, value)) + if isinstance(value, dict): + dict.__setitem__(self, key, SetupProps(setup, value)) else: - OrderedDict.__setitem__(self, key, value) + dict.__setitem__(self, key, value) self._pyaedt_setup = setup def _setitem_without_update(self, key, value): - OrderedDict.__setitem__(self, key, value) + dict.__setitem__(self, key, value) def _export_properties_to_json(self, file_path, overwrite=False): """Export all setup properties to a JSON file. @@ -900,4 +899,4 @@ def set_props(target, source): def delete_all(self): for item in list(self.keys()): if item != "_pyaedt_setup": - OrderedDict.__delitem__(self, item) + dict.__delitem__(self, item) diff --git a/src/ansys/aedt/core/q3d.py b/src/ansys/aedt/core/q3d.py index 5b15154ef98..8882632d3d9 100644 --- a/src/ansys/aedt/core/q3d.py +++ b/src/ansys/aedt/core/q3d.py @@ -26,7 +26,6 @@ from __future__ import absolute_import # noreorder -from collections import OrderedDict import os import re import warnings @@ -726,7 +725,7 @@ def export_matrix_data( length_setting, length, matrix_type, - export_ac_dc_res, + 0, precision, field_width, use_sci_notation, @@ -749,6 +748,7 @@ def export_matrix_data( g_unit, freq, matrix_type, + 0, export_ac_dc_res, precision, field_width, @@ -1496,7 +1496,7 @@ def auto_identify_nets(self): objects = self.modeler.convert_to_selections( [int(i) for i in list(self.oboundary.GetExcitationAssignment(net))], True ) - props = OrderedDict({"Objects": objects}) + props = dict({"Objects": objects}) bound = BoundaryObject(self, net, props, "SignalNet") self._boundaries[bound.name] = bound if new_nets: @@ -1543,7 +1543,7 @@ def assign_net(self, assignment, net_name=None, net_type="Signal"): assignment = self.modeler.convert_to_selections(assignment, True) if not net_name: net_name = generate_unique_name("Net") - props = OrderedDict({"Objects": assignment}) + props = dict({"Objects": assignment}) type_bound = "SignalNet" if net_type.lower() == "ground": type_bound = "GroundNet" @@ -1639,9 +1639,9 @@ def _assign_source_or_sink(self, assignment, direction, name, net_name, terminal sheets.append(object_name) if is_face: - props = OrderedDict({"Faces": sheets}) + props = dict({"Faces": sheets}) else: - props = OrderedDict({"Objects": sheets}) + props = dict({"Objects": sheets}) if terminal_type == "current": terminal_str = "UniformCurrent" @@ -1708,9 +1708,7 @@ def assign_sink_to_objectface(self, assignment, direction=0, name=None, net_name if not net_name: net_name = assignment if a: - props = OrderedDict( - {"Faces": [a], "ParentBndID": assignment, "TerminalType": "ConstantVoltage", "Net": net_name} - ) + props = dict({"Faces": [a], "ParentBndID": assignment, "TerminalType": "ConstantVoltage", "Net": net_name}) bound = BoundaryObject(self, name, props, "Sink") if bound.create(): self._boundaries[bound.name] = bound @@ -1758,9 +1756,9 @@ def assign_sink_to_sheet( sink_name = generate_unique_name("Sink") assignment = self.modeler.convert_to_selections(assignment, True)[0] if isinstance(assignment, int): - props = OrderedDict({"Faces": [assignment]}) + props = dict({"Faces": [assignment]}) else: - props = OrderedDict({"Objects": [assignment]}) + props = dict({"Objects": [assignment]}) if object_name: props["ParentBndID"] = object_name @@ -2063,7 +2061,7 @@ def assign_thin_conductor(self, assignment, material="copper", thickness=1, name name = generate_unique_name("Thin_Cond") if isinstance(thickness, (float, int)): thickness = str(thickness) + self.modeler.model_units - props = OrderedDict({"Objects": new_ass, "Material": material, "Thickness": thickness}) + props = dict({"Objects": new_ass, "Material": material, "Thickness": thickness}) bound = BoundaryObject(self, name, props, "ThinConductor") if bound.create(): @@ -2466,7 +2464,7 @@ def assign_single_conductor( t_list.append(t_obj.faces[0].area / perimeter) thickness = sum(t_list) / len(t_list) - props = OrderedDict({"Objects": obj_names, "SolveOption": solve_option, "Thickness": str(thickness) + units}) + props = dict({"Objects": obj_names, "SolveOption": solve_option, "Thickness": str(thickness) + units}) bound = BoundaryObject(self, name, props, conductor_type) if bound.create(): @@ -2509,7 +2507,7 @@ def assign_huray_finitecond_to_edges(self, assignment, radius, ratio, units="um" a = self.modeler.convert_to_selections(assignment, True) - props = OrderedDict({"Edges": a, "UseCoating": False, "Radius": ra, "Ratio": str(ratio)}) + props = dict({"Edges": a, "UseCoating": False, "Radius": ra, "Ratio": str(ratio)}) bound = BoundaryObject(self, name, props, "Finite Conductivity") if bound.create(): @@ -2534,7 +2532,7 @@ def auto_assign_conductors(self): objects = self.modeler.convert_to_selections( [int(k) for k in list(self.oboundary.GetExcitationAssignment(new_nets[i]))], True ) - props = OrderedDict({"Objects": objects}) + props = dict({"Objects": objects}) bound = BoundaryObject(self, new_nets[i], props, new_nets[i + 1]) self._boundaries[bound.name] = bound i += 2 diff --git a/src/ansys/aedt/core/workflows/hfss3dlayout/generate_arbitrary_wave_ports.py b/src/ansys/aedt/core/workflows/hfss3dlayout/generate_arbitrary_wave_ports.py new file mode 100644 index 00000000000..90363289d98 --- /dev/null +++ b/src/ansys/aedt/core/workflows/hfss3dlayout/generate_arbitrary_wave_ports.py @@ -0,0 +1,259 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2021 - 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. + +import os +import time +from tkinter import filedialog +from tkinter import messagebox + +import ansys.aedt.core +from ansys.aedt.core.edb import Edb +from ansys.aedt.core.hfss3dlayout import Hfss3dLayout +from ansys.aedt.core.hfss import Hfss +from ansys.aedt.core.workflows.misc import get_aedt_version +from ansys.aedt.core.workflows.misc import get_arguments +from ansys.aedt.core.workflows.misc import get_port +from ansys.aedt.core.workflows.misc import get_process_id +from ansys.aedt.core.workflows.misc import is_student + +port = get_port() +version = get_aedt_version() +aedt_process_id = get_process_id() +is_student = is_student() + +# Extension batch arguments +extension_arguments = {"working_path": "", "source_path": "", "mounting_side": "top"} +extension_description = "Arbitrary wave port creator" + + +def frontend(): # pragma: no cover + import tkinter + from tkinter import ttk + + import PIL.Image + import PIL.ImageTk + + master = tkinter.Tk() + + master.geometry("680x220") + + master.minsize(680, 220) + master.maxsize(680, 220) + + master.title("Arbitrary wave-port generator") + + # Load the logo for the main window + icon_path = os.path.join(os.path.dirname(ansys.aedt.core.workflows.__file__), "images", "large", "logo.png") + im = PIL.Image.open(icon_path) + photo = PIL.ImageTk.PhotoImage(im) + + # Set the icon for the main window + master.iconphoto(True, photo) + + # Configure style for ttk buttons + style = ttk.Style() + style.configure("Toolbutton.TButton", padding=6, font=("Helvetica", 10)) + + work_dir_path = tkinter.StringVar() + source_file_path = tkinter.StringVar() + mounting_side_variable = tkinter.StringVar() + import_edb_variable = tkinter.BooleanVar() + # import_3d_component_variable = tkinter.BooleanVar() + + def browse_workdir_call_back(): + work_dir_path.set(filedialog.askdirectory()) + work_dir.delete("1.0", tkinter.END) + work_dir.insert(tkinter.END, work_dir_path.get()) + + def browse_source_file_call_back(): + if not import_edb_variable.get(): + file_type = (("odb++", "*.tgz"), ("cadence pcb", "*.brd"), (("cadence package", "*.mcm"), ("", "*.zip"))) + source_file_path.set( + filedialog.askopenfilename(filetypes=file_type, title="Please select the source design") + ) + else: + source_file_path.set(filedialog.askdirectory(title="Import aedb folder")) + source_file.delete("1.0", "end") + source_file.insert("end", source_file_path.get()) + + # Working directory + var1 = tkinter.StringVar() + label_work_dir = tkinter.Label(master, textvariable=var1) + var1.set("Working directory") + label_work_dir.grid(row=0, column=0, pady=10) + work_dir = tkinter.Text(master, width=60, height=1) + # work_dir.setvar(work_dir_path, "") + work_dir.grid(row=0, column=1, pady=10, padx=5) + work_dir_button = tkinter.Button(master, text="Browse", command=browse_workdir_call_back) + work_dir_button.grid(row=0, column=2, sticky="E") + + # source layout + var2 = tkinter.StringVar() + label_source = tkinter.Label(master, textvariable=var2) + var2.set("Source layout") + label_source.grid(row=1, column=0, pady=10) + source_file = tkinter.Text(master, width=60, height=1) + source_file.setvar(source_file_path.get(), "") + source_file.grid(row=1, column=1, pady=10, padx=5) + source_file_button = tkinter.Button(master, text="Browse", command=browse_source_file_call_back) + source_file_button.grid(row=1, column=2, sticky="E") + + # mounting side + var3 = tkinter.StringVar() + label_combobox = tkinter.Label(master, textvariable=var3) + var3.set("Mounting side") + label_combobox.grid(row=2, column=0) + mounting_side_combo_box = ttk.Combobox(master=master, width=10, textvariable=mounting_side_variable) + mounting_side_combo_box["values"] = ("top", "bottom") + mounting_side_combo_box.grid(row=3, column=0, padx=5, pady=10) + mounting_side_combo_box.set("top") + mounting_side_combo_box.current() + + # checkbox import EDB + import_edb_variable.set(True) + ttk.Checkbutton(master=master, text="Import EDB", variable=import_edb_variable).grid( + row=3, column=1, padx=5, pady=10 + ) + + def callback(): + master.working_path_ui = work_dir.get("1.0", tkinter.END).strip() + master.source_path_ui = source_file.get("1.0", tkinter.END).strip() + master.mounting_side_ui = mounting_side_combo_box.get() + master.import_edb = import_edb_variable.get() + master.destroy() + + # execute button + execute_button = tkinter.Button(master=master, text="Generate", command=callback) + execute_button.grid(row=4, column=0, padx=5, pady=10) + + tkinter.mainloop() + + working_path_ui = getattr(master, "working_path_ui", extension_arguments["working_path"]) + source_path_ui = getattr(master, "source_path_ui", extension_arguments["source_path"]) + mounting_side_ui = getattr(master, "mounting_side_ui", extension_arguments["mounting_side"]) + + output_dict = { + "working_path": working_path_ui, + "source_path": source_path_ui, + "mounting_side": mounting_side_ui, + } + + return output_dict + + +def main(extension_args): + working_dir = extension_args["working_path"] + edb_file = extension_args["source_path"] + mounting_side_variable = extension_args["mounting_side"] + + edb_project = os.path.join(working_dir, "arbitrary_wave_port.aedb") + out_3d_project = os.path.join(working_dir, "output_3d.aedt") + component_3d_file = os.path.join(working_dir, "wave_port.a3dcomp") + if os.path.exists(working_dir): + if len(os.listdir(working_dir)) > 0: # pragma: no cover + res = messagebox.askyesno( + title="Warning", + message="The selected working directory is not empty, " + "the entire content will be deleted. " + "Are you sure to continue ?", + ) + if res == "no": + return + + edb = Edb(edbpath=rf"{edb_file}", edbversion=version) + if not edb.create_model_for_arbitrary_wave_ports( + temp_directory=working_dir, mounting_side=mounting_side_variable, output_edb=edb_project + ): + messagebox.showerror( + "EDB model failure", + "Failed to create EDB model, please make sure you " + "selected the correct mounting side. The selected side must " + "must contain explicit voids with pad-stack instances inside.", + ) + signal_nets = list(edb.nets.signal.keys()) + edb.close() + time.sleep(1) + + app = ansys.aedt.core.Desktop( + new_desktop=False, + version=version, + port=port, + aedt_process_id=aedt_process_id, + student_version=is_student, + ) + + hfss3d = Hfss3dLayout(project=edb_project, version=version) + setup = hfss3d.create_setup("wave_ports") + setup.export_to_hfss(file_fullname=out_3d_project, keep_net_name=True) + time.sleep(1) + hfss3d.close_project() + + hfss = Hfss(projectname=out_3d_project, specified_version=version, new_desktop_session=False) + hfss.solution_type = "Modal" + + # Deleting dielectric objects + [obj.delete() for obj in hfss.modeler.solid_objects if obj.material_name in hfss.modeler.materials.dielectrics] + + # creating ports + sheets_for_ports = hfss.modeler.sheet_objects + terminal_faces = [] + terminal_objects = [obj for obj in hfss.modeler.object_list if obj.name in signal_nets] + for obj in terminal_objects: + if mounting_side_variable == "bottom": + face = obj.bottom_face_z + else: + face = obj.top_face_z + terminal_face = hfss.modeler.create_object_from_face(face.id, non_model=False) + hfss.assign_perfecte_to_sheets(terminal_face.name) + name = obj.name + terminal_faces.append(terminal_face) + obj.delete() + terminal_face.name = name + for sheet in sheets_for_ports: + hfss.wave_port(assignment=sheet.id, reference="GND", terminals_rename=False) + + # create 3D component + hfss.save_project(file_name=out_3d_project) + hfss.modeler.create_3dcomponent(input_file=component_3d_file) + hfss.logger.info( + f"3D component with arbitrary wave ports has been generated. " + f"You can import the file located in working directory {working_dir}" + ) + hfss.close_project() + + if not extension_args["is_test"]: # pragma: no cover + app.release_desktop(False, False) + return True + + +if __name__ == "__main__": # pragma: no cover + args = get_arguments(extension_arguments, extension_description) + + # Open UI + if not args["is_batch"]: # pragma: no cover + output = frontend() + if output: + for output_name, output_value in output.items(): + if output_name in extension_arguments: + args[output_name] = output_value + main(args) diff --git a/src/ansys/aedt/core/workflows/hfss3dlayout/images/large/arbitrary_wave_port.png b/src/ansys/aedt/core/workflows/hfss3dlayout/images/large/arbitrary_wave_port.png new file mode 100644 index 00000000000..22c807605b9 Binary files /dev/null and b/src/ansys/aedt/core/workflows/hfss3dlayout/images/large/arbitrary_wave_port.png differ diff --git a/src/ansys/aedt/core/workflows/hfss3dlayout/toolkits_catalog.toml b/src/ansys/aedt/core/workflows/hfss3dlayout/toolkits_catalog.toml index 2c537d65a4b..f2c1e3e473a 100644 --- a/src/ansys/aedt/core/workflows/hfss3dlayout/toolkits_catalog.toml +++ b/src/ansys/aedt/core/workflows/hfss3dlayout/toolkits_catalog.toml @@ -31,4 +31,11 @@ name = "Parametrize layout" script = "parametrize_edb.py" icon = "images/large/parametrize.png" template = "run_pyedb_toolkit_script" +pip = "" + +[ArbitraryWaveport] +name = "Arbitrary Waveports" +script = "generate_arbitrary_wave_ports.py" +icon = "images/large/arbitrary_wave_port.png" +template = "run_pyaedt_toolkit_script" pip = "" \ No newline at end of file diff --git a/src/ansys/aedt/core/workflows/installer/console_setup.py b/src/ansys/aedt/core/workflows/installer/console_setup.py index faef655e0ae..446d0e4c637 100644 --- a/src/ansys/aedt/core/workflows/installer/console_setup.py +++ b/src/ansys/aedt/core/workflows/installer/console_setup.py @@ -37,26 +37,31 @@ import os import sys +aedt_process_id = int(sys.argv[1]) +version = sys.argv[2] +print("Loading the PyAEDT Console.") + try: - import ansys.aedt.core + if version <= "2023.1": + import pyaedt + else: + import ansys.aedt.core as pyaedt except ImportError: # Debug only purpose. If the tool is added to the ribbon from a GitHub clone, then a link # to PyAEDT is created in the personal library. console_setup_dir = os.path.dirname(__file__) if "PersonalLib" in console_setup_dir: sys.path.append(os.path.join(console_setup_dir, "../..", "..", "..")) - import ansys.aedt.core - + if version <= "2023.1": + import pyaedt + else: + import ansys.aedt.core as pyaedt # ansys.aedt.core.settings.use_grpc_api = False -settings = ansys.aedt.core.settings -from ansys.aedt.core import Desktop -from ansys.aedt.core.generic.general_methods import active_sessions -from ansys.aedt.core.generic.general_methods import is_windows - -aedt_process_id = int(sys.argv[1]) -version = sys.argv[2] -print("Loading the PyAEDT Console.") +settings = pyaedt.settings +from pyaedt import Desktop +from pyaedt.generic.general_methods import active_sessions +from pyaedt.generic.general_methods import is_windows def release(d): diff --git a/src/ansys/aedt/core/workflows/installer/jupyter_template.ipynb b/src/ansys/aedt/core/workflows/installer/jupyter_template.ipynb index 16545246b28..b88ae0900f3 100644 --- a/src/ansys/aedt/core/workflows/installer/jupyter_template.ipynb +++ b/src/ansys/aedt/core/workflows/installer/jupyter_template.ipynb @@ -12,10 +12,7 @@ "outputs": [], "source": [ "import sys\n", - "import atexit\n", - "from ansys.aedt.core import *\n", - "import pyaedt\n", - "ansys.aedt.core.settings.use_grpc_api=False" + "import atexit" ] }, { @@ -34,6 +31,25 @@ "print(\"Loading the PyAEDT Console.\")" ] }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [ + "if version > \"2023.1\":\n", + " from ansys.aedt.core import *\n", + " import ansys.aedt.core\n", + " ansys.aedt.core.settings.use_grpc_api=False\n", + "else:\n", + " from pyaedt import *\n", + " import pyaedt\n", + " pyaedt.settings.use_grpc_api=False" + ], + "metadata": { + "collapsed": false + }, + "id": "6232be8729ad9638" + }, { "cell_type": "code", "execution_count": null, @@ -77,4 +93,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/src/ansys/aedt/core/workflows/project/configure_edb.py b/src/ansys/aedt/core/workflows/project/configure_edb.py index a4a32493b60..b45dcec1fa6 100644 --- a/src/ansys/aedt/core/workflows/project/configure_edb.py +++ b/src/ansys/aedt/core/workflows/project/configure_edb.py @@ -21,166 +21,389 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -import os.path - +import os +from pathlib import Path +import tkinter as tk +from tkinter import filedialog +from tkinter import messagebox +from tkinter import ttk + +import PIL.Image +import PIL.ImageTk import ansys.aedt.core from ansys.aedt.core import Hfss3dLayout from ansys.aedt.core import generate_unique_name -from ansys.aedt.core.generic.filesystem import search_files -import ansys.aedt.core.workflows +import ansys.aedt.core.workflows.hfss3dlayout from ansys.aedt.core.workflows.misc import get_aedt_version -from ansys.aedt.core.workflows.misc import get_arguments from ansys.aedt.core.workflows.misc import get_port from ansys.aedt.core.workflows.misc import get_process_id from ansys.aedt.core.workflows.misc import is_student from pyedb import Edb +from pyedb import Siwave port = get_port() version = get_aedt_version() aedt_process_id = get_process_id() is_student = is_student() -# Extension batch arguments -extension_arguments = {"aedb_path": "", "configuration_path": ""} -extension_description = "Configure project from aedb file" - - -def frontend(): # pragma: no cover - - import tkinter - from tkinter import filedialog - from tkinter import ttk - - import PIL.Image - import PIL.ImageTk - - master = tkinter.Tk() - master.geometry("750x250") - - master.title(extension_description) - - # Load the logo for the main window - icon_path = os.path.join(ansys.aedt.core.workflows.__path__[0], "images", "large", "logo.png") - im = PIL.Image.open(icon_path) - photo = PIL.ImageTk.PhotoImage(im) +class ConfigureEdbFrontend(tk.Tk): # pragma: no cover + app_options = ["Active Design", "HFSS 3D Layout", "SIwave"] + _execute = { + "active_load": [], + "siwave_load": [], + "aedt_load": [], + "active_export": [], + "siwave_export": [], + "aedt_export": [], + } - # Set the icon for the main window - master.iconphoto(True, photo) + def get_active_project_info(self): + desktop = self.desktop + active_project = desktop.active_project() + if active_project: + project_name = active_project.GetName() + project_dir = active_project.GetPath() + project_file = os.path.join(project_dir, project_name + ".aedt") + desktop.release_desktop(False, False) + return project_file + else: + desktop.release_desktop(False, False) + return + + @property + def desktop(self): + return ansys.aedt.core.Desktop( + new_desktop_session=False, + specified_version=version, + port=port, + aedt_process_id=aedt_process_id, + student_version=is_student, + ) - # Configure style for ttk buttons - style = ttk.Style() - style.configure("Toolbutton.TButton", padding=6, font=("Helvetica", 8)) + def __init__(self): + super().__init__() + + self.geometry("600x300") + self.title("EDB Configuration 2.0") + + self.status = tk.StringVar(value="") + self.selected_app_option = tk.StringVar(value="Active Design") + self.selected_project_file_path = "" + self.selected_project_file = tk.StringVar(value="") + self.selected_cfg_file_folder = tk.StringVar(value="") + + # Load the logo for the main window + icon_path = os.path.join(os.path.dirname(ansys.aedt.core.workflows.__file__), "images", "large", "logo.png") + im = PIL.Image.open(icon_path) + photo = PIL.ImageTk.PhotoImage(im) + + # Set the icon for the main window + self.iconphoto(True, photo) + + # Configure style for ttk buttons + style = ttk.Style() + style.configure("Toolbutton.TButton", padding=6, font=("Helvetica", 10)) + + # Main window + self.create_main_window() + + def create_main_window(self): + col_width = [50, 20, 30] + + # Section 1 + self.label_version = ttk.Label(self, text=f"AEDT {version}") + self.label_version.grid(row=0, column=0) + label = ttk.Label(self, textvariable=self.status) + label.grid(row=0, column=1) + + # Section 2 + s2_start_row = 1 + for index, option in enumerate(self.app_options): + ttk.Radiobutton(self, text=option, value=option, variable=self.selected_app_option).grid( + row=index + s2_start_row, column=0, sticky=tk.W + ) + + # Section 3 + s3_start_row = 4 + button_select_project_file = ttk.Button( + self, text="Select project file", width=col_width[0], command=self.call_select_project + ) + button_select_project_file.grid(row=s3_start_row, column=0) - var2 = tkinter.StringVar() - label2 = tkinter.Label(master, textvariable=var2) - var2.set("Browse file:") - label2.grid(row=0, column=0, pady=10) - text = tkinter.Text(master, width=40, height=1) - text.grid(row=0, column=1, pady=10, padx=5) + # Siwave + label_project_file = tk.Label(self, width=col_width[2], height=1, textvariable=self.selected_project_file) + label_project_file.grid(row=s3_start_row, column=2) - def browse_aedb(): - filename = filedialog.askopenfilename( - initialdir="/", - title="Select a layout folder or file", - filetypes=(("aedb file", "*.def"), ("brd", "*.brd"), ("all files", "*.*")), + # Apply cfg + button = ttk.Button( + self, text="Select and Apply Configuration", width=col_width[0], command=self.call_apply_cfg_file ) - if filename.endswith(".def"): - filename = os.path.dirname(filename) - text.insert(tkinter.END, filename) - - b1 = tkinter.Button(master, text="...", width=10, command=browse_aedb) - b1.grid(row=0, column=2, pady=10) - - var3 = tkinter.StringVar() - label3 = tkinter.Label(master, textvariable=var3) - var3.set("Browse configuration file or folder:") - label3.grid(row=1, column=0, pady=10) - text2 = tkinter.Text(master, width=40, height=1) - text2.grid(row=1, column=1, pady=10, padx=5) - - def browse_config(): - inital_dir = text.get("1.0", tkinter.END).strip() - filename = filedialog.askopenfilename( - initialdir=os.path.dirname(inital_dir) if inital_dir else "/", - title="Select configuration file", - filetypes=(("Configuration file", "*.json"), ("Configuration file", "*.toml")), + button.grid(row=s3_start_row + 2, column=0) + + # Export cfg + button = ttk.Button(self, text="Export Configuration", width=col_width[0], command=self.call_export_cfg) + button.grid(row=s3_start_row + 4, column=0) + + def call_select_project(self): + if self.selected_app_option.get() == "HFSS 3D Layout": + file_path = filedialog.askopenfilename( + initialdir="/", + title="Select File", + filetypes=(("Electronics Desktop", "*.aedt"),), + ) + elif self.selected_app_option.get() == "SIwave": + file_path = filedialog.askopenfilename( + initialdir="/", + title="Select File", + filetypes=(("SIwave project", "*.siw"),), + ) + else: + file_path = None + + if not file_path: + return + else: + self.selected_project_file_path = file_path + self.selected_project_file.set(Path(file_path).parts[-1]) + + def _call_apply_cfg_file(self): + if not self.selected_app_option.get() == "Active Design": + if not self.selected_project_file_path: + return + + init_dir = Path(self.selected_project_file_path).parent if self.selected_project_file_path else "/" + file_cfg_path = filedialog.askopenfilename( + initialdir=init_dir, + title="Select Configuration File", + filetypes=(("json file", "*.json"), ("toml", "*.toml")), + defaultextension=".json", ) - text2.insert(tkinter.END, filename) - b2 = tkinter.Button(master, text="...", width=10, command=browse_config) - b2.grid(row=1, column=2, pady=10) + if not file_cfg_path: + return + + if self.selected_app_option.get() == "SIwave": + project_file = self.selected_project_file_path + file_save_path = filedialog.asksaveasfilename( + initialdir=init_dir, + title="Save new project as", + filetypes=[("SIwave", "*.siw")], + defaultextension=".siw", + ) + if not file_save_path: + return + self._execute["siwave_load"].append( + {"project_file": project_file, "file_cfg_path": file_cfg_path, "file_save_path": file_save_path} + ) + # self.execute_load_cfg_siw(project_file, file_cfg_path, file_save_path) + elif self.selected_app_option.get() == "HFSS 3D Layout": + project_file = self.selected_project_file_path + file_save_path = filedialog.asksaveasfilename( + initialdir=init_dir, + title="Save new project as", + filetypes=[("Electronics Desktop", "*.aedt")], + defaultextension=".aedt", + ) + self._execute["aedt_load"].append( + {"project_file": project_file, "file_cfg_path": file_cfg_path, "file_save_path": file_save_path} + ) + # self.execute_load_cfg_aedt(project_file, file_cfg_path, file_save_path) + else: + data = self.get_active_project_info() + if data: + project_dir, project_file = data + else: + return + file_save_path = os.path.join( + project_dir, Path(project_file).stem + "_" + generate_unique_name(Path(file_cfg_path).stem) + ".aedt" + ) + self._execute["active_load"].append( + {"project_file": project_file, "file_cfg_path": file_cfg_path, "file_save_path": file_save_path} + ) + self.execute() + + def call_select_cfg_folder(self): + pass + + def call_apply_cfg_file(self): + init_dir = Path(self.selected_project_file_path).parent if self.selected_project_file_path else "/" + # Get original project file path + if self.selected_app_option.get() == "Active Design": + project_file = self.get_active_project_info() + if not project_file: + return + else: + project_file = self.selected_project_file_path + + # Get cfg files + cfg_files = filedialog.askopenfilenames( + initialdir=init_dir, + title="Select Configuration", + filetypes=(("json file", "*.json"), ("toml", "*.toml")), + defaultextension=".json", + ) + if not cfg_files: + return - def callback(): - master.aedb_path_ui = text.get("1.0", tkinter.END).strip() - master.configuration_path_ui = text2.get("1.0", tkinter.END).strip() - master.destroy() + file_save_dir = filedialog.askdirectory( + initialdir=init_dir, + title="Save new projects to", + ) - b3 = tkinter.Button(master, text="Ok", width=40, command=callback) - b3.grid(row=25, column=1, pady=10, padx=10) + for file_cfg_path in cfg_files: + fname = Path(project_file).stem + "_" + generate_unique_name(Path(file_cfg_path).stem) + if file_cfg_path.endswith(".json") or file_cfg_path.endswith(".toml"): + if self.selected_app_option.get() == "SIwave": + file_save_path = os.path.join(Path(file_save_dir), fname + ".siw") + self._execute["siwave_load"].append( + {"project_file": project_file, "file_cfg_path": file_cfg_path, "file_save_path": file_save_path} + ) + elif self.selected_app_option.get() == "HFSS 3D Layout": + file_save_path = os.path.join(Path(file_save_dir), fname + ".aedt") + self._execute["aedt_load"].append( + {"project_file": project_file, "file_cfg_path": file_cfg_path, "file_save_path": file_save_path} + ) + else: + file_save_path = os.path.join(file_save_dir, fname + ".aedt") + self._execute["active_load"].append( + {"project_file": project_file, "file_cfg_path": file_cfg_path, "file_save_path": file_save_path} + ) + self.execute_load() + + def call_export_cfg(self): + """Export configuration file.""" + init_dir = Path(self.selected_project_file_path).parent + file_path_save = filedialog.asksaveasfilename( + initialdir=init_dir, + title="Select Configuration File", + filetypes=(("json file", "*.json"), ("toml", "*.toml")), + defaultextension=".json", + ) + if not file_path_save: + return + + if self.selected_app_option.get() == "SIwave": + self._execute["siwave_export"].append( + {"project_file": self.selected_project_file_path, "file_path_save": file_path_save} + ) + elif self.selected_app_option.get() == "HFSS 3D Layout": + self._execute["aedt_export"].append( + {"project_file": self.selected_project_file_path, "file_path_save": file_path_save} + ) + elif self.selected_app_option.get() == "Active Design": + data = self.get_active_project_info() + if data: + project_file = data + self._execute["active_export"].append({"project_file": project_file, "file_path_save": file_path_save}) + else: + return + + self.execute_export(file_path_save) + + def execute(self): + ConfigureEdbBackend(self._execute) + self._execute = { + "active_load": [], + "siwave_load": [], + "aedt_load": [], + "active_export": [], + "siwave_export": [], + "aedt_export": [], + } + + def execute_load(self): + desktop = self.desktop + self.execute() + desktop.release_desktop(False, False) + messagebox.showinfo("Information", "Done!") + + def execute_export(self, file_path): + ConfigureEdbBackend(self._execute) + self._execute = { + "active_load": [], + "siwave_load": [], + "aedt_load": [], + "active_export": [], + "siwave_export": [], + "aedt_export": [], + } + messagebox.showinfo("Information", f"Configuration file saved to {file_path}.") + + +class ConfigureEdbBackend: + def __init__(self, args, is_test=False): + if len(args["siwave_load"]): # pragma: no cover + for i in args["siwave_load"]: + self.execute_load_cfg_siw(**i) + + if len(args["aedt_load"]): + for i in args["aedt_load"]: + self.execute_load_cfg_aedt(**i) + + if len(args["active_load"]): + for i in args["active_load"]: + self.execute_load_cfg_aedt(**i) + + if len(args["siwave_export"]): # pragma: no cover + for i in args["siwave_export"]: + self.execute_export_cfg_siw(**i) + + if len(args["aedt_export"]): + for i in args["aedt_export"]: + self.execute_export_cfg_aedt(**i) + + if len(args["active_export"]): + for i in args["active_export"]: + self.execute_export_cfg_aedt(**i) + + @staticmethod + def execute_load_cfg_siw(project_file, file_cfg_path, file_save_path): # pragma: no cover + """Load configuration file.""" + fdir = Path(file_save_path).parent + fname = Path(file_save_path).stem + siw = Siwave(specified_version=version) + siw.open_project(str(project_file)) + siw.load_configuration(file_cfg_path) + siw.save_project(fdir, fname) + siw.quit_application() + + @staticmethod + def execute_load_cfg_aedt(project_file, file_cfg_path, file_save_path): + fedb = Path(project_file).with_suffix(".aedb") + edbapp = Edb(str(fedb), edbversion=version) + edbapp.configuration.load(file_cfg_path) + edbapp.configuration.run() + edbapp.save_as(str(Path(file_save_path).with_suffix(".aedb"))) + edbapp.close() - tkinter.mainloop() + h3d = Hfss3dLayout(str(Path(file_save_path).with_suffix(".aedb"))) + h3d.save_project() - aedb_path_ui = getattr(master, "aedb_path_ui", extension_arguments["aedb_path"]) + @staticmethod + def execute_export_cfg_siw(project_file, file_path_save): # pragma: no cover + siw = Siwave(specified_version=version) + siw.open_project(str(project_file)) + siw.export_configuration(file_path_save) + siw.quit_application() + + @staticmethod + def execute_export_cfg_aedt(project_file, file_path_save): + fedb = Path(project_file).with_suffix(".aedb") + edbapp = Edb(str(fedb), edbversion=version) + edbapp.configuration.export(file_path_save) + edbapp.close() - configuration_path_ui = getattr(master, "configuration_path_ui", extension_arguments["configuration_path"]) - output_dict = { - "configuration_path": configuration_path_ui, - "aedb_path": aedb_path_ui, - } - return output_dict - - -def main(extension_args): - aedb_path = extension_args["aedb_path"] - config = extension_args["configuration_path"] - if os.path.isdir(config): - configs = search_files(config, "*.json") - configs += search_files(config, "*.toml") - else: - configs = [config] - app = ansys.aedt.core.Desktop( - new_desktop_session=False, - specified_version=version, - port=port, - aedt_process_id=aedt_process_id, - student_version=is_student, - ) - if aedb_path == "": - project_name = app.active_project().GetName() - aedb_path = os.path.join(app.active_project().GetPath(), project_name + ".aedb") - else: - project_name = os.path.splitext(os.path.split(aedb_path)[-1])[0] - if project_name in app.project_list(): - app.odesktop.CloseProject(project_name) - for config in configs: - edbapp = Edb(aedb_path, edbversion=version) - config_name = os.path.splitext(os.path.split(config)[-1])[0] - output_path = aedb_path[:-5] + f"_{config_name}.aedb" - if os.path.exists(output_path): - new_name = generate_unique_name(config_name, n=2) - output_path = aedb_path[:-5] + f"_{new_name}.aedb" - edbapp.configuration.load(config_file=config) - edbapp.configuration.run() - edbapp.save_edb_as(output_path) - edbapp.close() - h3d = Hfss3dLayout(output_path) - h3d.save_project() - if not extension_args["is_test"]: # pragma: no cover - app.release_desktop(False, False) - return True +def main(is_test=False, execute=""): + if is_test: + ConfigureEdbBackend(execute) + else: # pragma: no cover + app = ConfigureEdbFrontend() + app.mainloop() -if __name__ == "__main__": # pragma: no cover - args = get_arguments(extension_arguments, extension_description) +if __name__ == "__main__": # Open UI - if not args["is_batch"]: # pragma: no cover - output = frontend() - if output: - for output_name, output_value in output.items(): - if output_name in extension_arguments: - args[output_name] = output_value - - main(args) + main() diff --git a/src/pyaedt/workflows/installer/pyaedt_installer.py b/src/pyaedt/workflows/installer/pyaedt_installer.py index 8148869f681..0178052ab05 100644 --- a/src/pyaedt/workflows/installer/pyaedt_installer.py +++ b/src/pyaedt/workflows/installer/pyaedt_installer.py @@ -1 +1 @@ -from ansys.aedt.core.workflows.installeraedt_installer import * +from ansys.aedt.core.workflows.installer.pyaedt_installer import *