From 025f89396f5401d500031a3fd1c295d3c83879e9 Mon Sep 17 00:00:00 2001 From: gmalinve <103059376+gmalinve@users.noreply.github.com> Date: Fri, 30 Aug 2024 16:15:20 +0200 Subject: [PATCH 01/29] DOCS: Fix release_1_0.rst (#5108) --- doc/source/release_1_0.rst | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) 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 `_ . From f108a0f11197616293d3f268e69fc0e49f5cfb9a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 31 Aug 2024 07:44:21 +0200 Subject: [PATCH 02/29] BUILD: Update ipython requirement from <8.27,>=7.30.0 to >=7.30.0,<8.28 (#5113) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 300d7f76f59..c85a20cf1e4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -72,7 +72,7 @@ dotnet = [ ] 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", From a982f6fd18bd029ffe7df2687d15e492511c6dd4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 31 Aug 2024 09:48:09 +0200 Subject: [PATCH 03/29] BUILD: Update scikit-rf requirement from <1.3,>=0.30.0 to >=0.30.0,<1.4 (#5112) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Sébastien Morais <146729917+SMoraisAnsys@users.noreply.github.com> --- pyproject.toml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c85a20cf1e4..9ed691ebe2f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,7 +59,7 @@ 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", ] @@ -84,7 +84,7 @@ 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'", @@ -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,7 +137,7 @@ 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", From accdcba8d1e8fab301f5a276093763df77a4a492 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Morais?= <146729917+SMoraisAnsys@users.noreply.github.com> Date: Mon, 2 Sep 2024 15:05:03 +0200 Subject: [PATCH 04/29] DOCS: Add aedt log file in settings (#5115) --- doc/source/User_guide/settings.rst | 2 ++ 1 file changed, 2 insertions(+) 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: From a318a470b00203a590f26b3dc9548c7292f67702 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Sep 2024 09:01:24 +0200 Subject: [PATCH 05/29] BUILD: Update ipython requirement from <8.27,>=7.30.0 to >=7.30.0,<8.28 (#5119) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 9ed691ebe2f..f65ad48195d 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", @@ -141,7 +141,7 @@ installer = [ "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", ] From beadd4e47c93320b71c31134c624b8d1cade0df2 Mon Sep 17 00:00:00 2001 From: Samuel Lopez <85613111+Samuelopez-ansys@users.noreply.github.com> Date: Tue, 3 Sep 2024 10:42:08 +0200 Subject: [PATCH 06/29] FIX: Update jupyter_template.ipynb (#5121) --- .../aedt/core/workflows/installer/jupyter_template.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ansys/aedt/core/workflows/installer/jupyter_template.ipynb b/src/ansys/aedt/core/workflows/installer/jupyter_template.ipynb index 16545246b28..f135f2e725c 100644 --- a/src/ansys/aedt/core/workflows/installer/jupyter_template.ipynb +++ b/src/ansys/aedt/core/workflows/installer/jupyter_template.ipynb @@ -14,7 +14,7 @@ "import sys\n", "import atexit\n", "from ansys.aedt.core import *\n", - "import pyaedt\n", + "import ansys.aedt.core\n", "ansys.aedt.core.settings.use_grpc_api=False" ] }, @@ -77,4 +77,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} From ee5b2a6bc51c4e6809d34424ad251273a59db3c4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 4 Sep 2024 11:26:05 +0200 Subject: [PATCH 07/29] BUILD: Bump sphinx-autobuild from 2021.3.14 to 2024.9.3 (#5129) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index f65ad48195d..e4bce897341 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -87,7 +87,7 @@ doc = [ "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-autodoc-typehints", "sphinx-copybutton>=0.5.0,<0.6", "sphinx-gallery>=0.14.0,<0.18", @@ -103,7 +103,7 @@ doc-no-examples = [ "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-autodoc-typehints", "sphinx-copybutton>=0.5.0,<0.6", "sphinx-gallery>=0.14.0,<0.18", From 064f0023becaea761b19ac0c16e32792aaeeb4c2 Mon Sep 17 00:00:00 2001 From: Massimo Capodiferro <77293250+maxcapodi78@users.noreply.github.com> Date: Wed, 4 Sep 2024 15:43:01 +0200 Subject: [PATCH 08/29] FEAT: added method to enable matrix convergence (#5126) Co-authored-by: maxcapodi78 --- _unittest/test_11_Setup.py | 34 +++++ _unittest/test_41_3dlayout_modeler.py | 33 ++++ examples/07-Circuit/Reports.py | 2 +- src/ansys/aedt/core/modules/solve_setup.py | 170 +++++++++++++++++++++ 4 files changed, 238 insertions(+), 1 deletion(-) 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_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/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/src/ansys/aedt/core/modules/solve_setup.py b/src/ansys/aedt/core/modules/solve_setup.py index c70979c3cfa..d939e859053 100644 --- a/src/ansys/aedt/core/modules/solve_setup.py +++ b/src/ansys/aedt/core/modules/solve_setup.py @@ -2320,6 +2320,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 +3031,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. From 855f8f7303426ff8a72a7067f76318f5f764947a Mon Sep 17 00:00:00 2001 From: Massimo Capodiferro <77293250+maxcapodi78@users.noreply.github.com> Date: Thu, 5 Sep 2024 08:53:16 +0200 Subject: [PATCH 09/29] REFACTOR: removed all OrderedDict (#5127) Co-authored-by: maxcapodi78 --- _unittest/test_27_Maxwell2D.py | 3 +- doc/source/conf.py | 2 +- examples/04-Icepak/Icepak_CSV_Import.py | 1 - src/ansys/aedt/core/application/analysis.py | 7 +- src/ansys/aedt/core/application/design.py | 11 +- src/ansys/aedt/core/generic/configurations.py | 33 +- src/ansys/aedt/core/generic/data_handlers.py | 11 +- .../core/generic/farfield_visualization.py | 3 +- .../aedt/core/generic/general_methods.py | 19 +- src/ansys/aedt/core/generic/spisim.py | 3 +- src/ansys/aedt/core/hfss.py | 154 ++++----- src/ansys/aedt/core/hfss3dlayout.py | 3 +- src/ansys/aedt/core/icepak.py | 316 ++++++++---------- src/ansys/aedt/core/maxwell.py | 117 +++---- src/ansys/aedt/core/mechanical.py | 58 ++-- .../core/modeler/advanced_cad/stackup_3d.py | 9 +- .../aedt/core/modeler/cad/component_array.py | 18 +- .../aedt/core/modeler/cad/components_3d.py | 91 +++-- .../aedt/core/modeler/cad/elements_3d.py | 16 +- src/ansys/aedt/core/modeler/cad/modeler.py | 76 ++--- src/ansys/aedt/core/modeler/cad/primitives.py | 27 +- .../modeler/circuits/object_3d_circuit.py | 7 +- src/ansys/aedt/core/modules/boundary.py | 151 ++++----- .../aedt/core/modules/design_xploration.py | 144 ++++---- src/ansys/aedt/core/modules/layer_stackup.py | 4 +- src/ansys/aedt/core/modules/material.py | 162 +++++---- src/ansys/aedt/core/modules/material_lib.py | 33 +- src/ansys/aedt/core/modules/mesh.py | 49 ++- src/ansys/aedt/core/modules/mesh_3d_layout.py | 32 +- src/ansys/aedt/core/modules/mesh_icepak.py | 19 +- .../core/modules/optimetrics_templates.py | 89 +++-- src/ansys/aedt/core/modules/post_processor.py | 9 +- .../aedt/core/modules/report_templates.py | 6 +- .../aedt/core/modules/setup_templates.py | 207 ++++++------ src/ansys/aedt/core/modules/solutions.py | 15 +- src/ansys/aedt/core/modules/solve_setup.py | 31 +- src/ansys/aedt/core/modules/solve_sweeps.py | 21 +- src/ansys/aedt/core/q3d.py | 25 +- 38 files changed, 919 insertions(+), 1063 deletions(-) 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/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/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/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/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/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/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..75af5af6700 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 @@ -1240,11 +1232,11 @@ def create_sbr_linked_antenna( design_name = assignment.design_name if not setup: setup = assignment.nominal_adaptive - params = OrderedDict({}) + params = {} pars = assignment.available_variations.nominal_w_values_dict for el in pars: params[el] = pars[el] - native_props = OrderedDict( + native_props = dict( { "Type": "Linked Antenna", "Unit": self.modeler.model_units, @@ -1259,7 +1251,7 @@ def create_sbr_linked_antenna( "PathRelativeTo": "TargetProject", "FieldType": field_type, "UseCompositePort": use_composite_ports, - "SourceBlockageStructure": OrderedDict({"NonModelObject": []}), + "SourceBlockageStructure": dict({"NonModelObject": []}), } ) if field_type == "nearfield": @@ -1287,9 +1279,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 +1335,7 @@ class SbrAntennas: ) class SBRAntennaDefaults: - _conical = OrderedDict( + _conical = dict( { "Is Parametric Array": False, "MatchedPortImpedance": "50ohm", @@ -1355,7 +1345,7 @@ class SBRAntennaDefaults: "Flare Half Angle": "20deg", } ) - _cross = OrderedDict( + _cross = dict( { "Is Parametric Array": False, "MatchedPortImpedance": "50ohm", @@ -1368,7 +1358,7 @@ class SBRAntennaDefaults: "Mode": 0, } ) - _horizontal = OrderedDict( + _horizontal = dict( { "Is Parametric Array": False, "MatchedPortImpedance": "50ohm", @@ -1382,7 +1372,7 @@ class SBRAntennaDefaults: "Use Default Height": True, } ) - _parametricbeam = OrderedDict( + _parametricbeam = dict( { "Is Parametric Array": False, "Size": "0.1meter", @@ -1393,7 +1383,7 @@ class SBRAntennaDefaults: "Horizontal BeamWidth": "60deg", } ) - _slot = OrderedDict( + _slot = dict( { "Is Parametric Array": False, "MatchedPortImpedance": "50ohm", @@ -1402,7 +1392,7 @@ class SBRAntennaDefaults: "Slot Length": "499.654096666667mm", } ) - _horn = OrderedDict( + _horn = dict( { "Is Parametric Array": False, "MatchedPortImpedance": "50ohm", @@ -1414,7 +1404,7 @@ class SBRAntennaDefaults: "Height Flare Half Angle": "35deg", } ) - _dipole = OrderedDict( + _dipole = dict( { "Is Parametric Array": False, "Size": "1mm", @@ -1422,7 +1412,7 @@ class SBRAntennaDefaults: "Representation": "Far Field", } ) - _smallloop = OrderedDict( + _smallloop = dict( { "Is Parametric Array": False, "MatchedPortImpedance": "50ohm", @@ -1437,7 +1427,7 @@ class SBRAntennaDefaults: "Flare Half Angle": "20deg", } ) - _wiredipole = OrderedDict( + _wiredipole = dict( { "Is Parametric Array": False, "MatchedPortImpedance": "50ohm", @@ -1645,7 +1635,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, @@ -1681,9 +1671,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 +1999,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 +2061,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 +2075,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 +2091,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 +2154,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 +2268,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 +2276,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 +2327,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 +2335,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 +2708,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 +2804,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 +3203,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 +3270,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 +3362,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 +4885,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 +4977,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 +5054,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 +5123,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 +5178,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 +5293,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 +5756,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..aa84bfc6568 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") 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/primitives.py b/src/ansys/aedt/core/modeler/cad/primitives.py index ad48d2dad2e..880ace5e725 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 @@ -863,7 +862,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 +875,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 +1164,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 +1186,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 +1201,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 +1234,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 +1252,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 +1290,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 +6568,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 +6618,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: @@ -8788,7 +8787,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/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/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/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..0729588d2b3 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) 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..aadd24db36f 100644 --- a/src/ansys/aedt/core/modules/solutions.py +++ b/src/ansys/aedt/core/modules/solutions.py @@ -21,7 +21,6 @@ # 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 collections import defaultdict import csv import itertools @@ -489,7 +488,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 +550,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 +583,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 +704,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 +732,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 +1007,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] diff --git a/src/ansys/aedt/core/modules/solve_setup.py b/src/ansys/aedt/core/modules/solve_setup.py index d939e859053..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 @@ -3522,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..83f1735b86c 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 @@ -1496,7 +1495,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 +1542,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 +1638,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 +1707,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 +1755,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 +2060,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 +2463,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 +2506,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 +2531,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 From d03dd0af18d6d357bf22bebb326e7dd81d1b6f3e Mon Sep 17 00:00:00 2001 From: gmalinve <103059376+gmalinve@users.noreply.github.com> Date: Thu, 5 Sep 2024 13:50:31 +0200 Subject: [PATCH 10/29] REFACTOR: Check if material is a parametric design var (#5117) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: maxcapodi78 Co-authored-by: Sébastien Morais <146729917+SMoraisAnsys@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- _unittest/test_02_2D_modeler.py | 25 +++++++- src/ansys/aedt/core/modeler/cad/object_3d.py | 3 +- src/ansys/aedt/core/modeler/cad/polylines.py | 2 +- src/ansys/aedt/core/modeler/cad/primitives.py | 60 ++++++++++++------- .../aedt/core/modeler/cad/primitives_2d.py | 8 +-- .../aedt/core/modeler/cad/primitives_3d.py | 20 +++---- 6 files changed, 81 insertions(+), 37 deletions(-) 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/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 880ace5e725..c48bbc99cdc 100644 --- a/src/ansys/aedt/core/modeler/cad/primitives.py +++ b/src/ansys/aedt/core/modeler/cad/primitives.py @@ -36,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 @@ -8411,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 @@ -8420,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``. @@ -8437,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): @@ -8595,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 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..0702b77af0a 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) @@ -427,7 +427,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 +490,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 +567,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 +716,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 +773,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 +852,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 +948,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) From 906f3244363ff81883100bf098f6d3c13a11f43e Mon Sep 17 00:00:00 2001 From: Ramin Aghajafari <153928265+ramin4667@users.noreply.github.com> Date: Thu, 5 Sep 2024 08:48:35 -0400 Subject: [PATCH 11/29] FEAT: FilterSolutions export (#4935) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .gitignore | 1 + .../test_filter/test_attributes.py | 2 +- .../test_filter/test_dll_interface.py | 2 +- .../test_filter/test_graph_setup.py | 2 +- .../test_lumped_export/test_export_to_aedt.py | 154 ++++++ .../test_optimization_goals_table.py | 148 +++++ .../test_lumped_nodes_and_leads.py | 2 - ...est_lumped_termination_impedance_table.py} | 4 +- .../Lumped_Element_Response.py | 2 +- src/ansys/aedt/core/filtersolutions.py | 8 +- .../core/filtersolutions_core/attributes.py | 266 ++++++++- .../filtersolutions_core/export_to_aedt.py | 515 ++++++++++++++++++ ... => lumped_termination_impedance_table.py} | 0 .../optimization_goals_table.py | 342 ++++++++++++ .../transmission_zeros.py | 4 +- 15 files changed, 1423 insertions(+), 29 deletions(-) create mode 100644 _unittest/test_45_FilterSolutions/test_lumped_export/test_export_to_aedt.py create mode 100644 _unittest/test_45_FilterSolutions/test_lumped_export/test_optimization_goals_table.py rename _unittest/test_45_FilterSolutions/test_lumped_filter/{test_lumped_termination_impedance.py => test_lumped_termination_impedance_table.py} (99%) create mode 100644 src/ansys/aedt/core/filtersolutions_core/export_to_aedt.py rename src/ansys/aedt/core/filtersolutions_core/{lumped_termination_impedance.py => lumped_termination_impedance_table.py} (100%) create mode 100644 src/ansys/aedt/core/filtersolutions_core/optimization_goals_table.py diff --git a/.gitignore b/.gitignore index 24c53893698..7d23ec21bfd 100644 --- a/.gitignore +++ b/.gitignore @@ -400,3 +400,4 @@ model.index\+ # test coverage output /.cov/ +/pyaedt.code-workspace 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/test_export_to_aedt.py b/_unittest/test_45_FilterSolutions/test_lumped_export/test_export_to_aedt.py new file mode 100644 index 00000000000..8e28035d6bf --- /dev/null +++ b/_unittest/test_45_FilterSolutions/test_lumped_export/test_export_to_aedt.py @@ -0,0 +1,154 @@ +# -*- 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 pyaedt +from pyaedt.filtersolutions_core.attributes import FilterImplementation +from pyaedt.generic.general_methods import is_linux + +# from ..filtersolutions_resources import resource_path +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_schematic_name(self): + lumpdesign = pyaedt.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 = pyaedt.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 = pyaedt.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 = pyaedt.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 = pyaedt.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 = pyaedt.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 = pyaedt.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 = pyaedt.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 = pyaedt.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 = pyaedt.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 = pyaedt.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 = pyaedt.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 = pyaedt.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 = pyaedt.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 = pyaedt.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 = pyaedt.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 = pyaedt.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 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..a728b75d77b --- /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.set_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.set_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.set_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.set_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.set_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.set_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.set_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/examples/08-FilterSolutions/Lumped_Element_Response.py b/examples/08-FilterSolutions/Lumped_Element_Response.py index acb4a07e124..1e0bb85cd20 100644 --- a/examples/08-FilterSolutions/Lumped_Element_Response.py +++ b/examples/08-FilterSolutions/Lumped_Element_Response.py @@ -21,12 +21,12 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~ # 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.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/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..24e7ce7dbf4 --- /dev/null +++ b/src/ansys/aedt/core/filtersolutions_core/export_to_aedt.py @@ -0,0 +1,515 @@ +# -*- 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 enum import Enum +import os + +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 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() + + 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 + + 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) + + @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 option 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: ExportFormat.DIRECT_TO_AEDT, 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 ``DIRECT_TO_AEDT``. + 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_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 import_tuned_variables(self): + """Imported ``AEDT`` tuned parameter variables back into the ``FilterSolutions`` project.""" + status = self._dll.importTunedVariables() + ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) 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..68e613cae65 --- /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 set_design_goals(self): + """Configure the optimization goal table according to the recommended goals for the current design.""" + status = self._dll.designGoals() + 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 From 5d8ef37efcea151acff1233f939d29de14ec08ad Mon Sep 17 00:00:00 2001 From: Matthew Young <86373761+myoung301@users.noreply.github.com> Date: Thu, 5 Sep 2024 07:53:55 -0500 Subject: [PATCH 12/29] Generalize .code-workspace in .gitignore A specific filename was mentioned before. Make it a general ignore for this extension. --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 7d23ec21bfd..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/ @@ -400,4 +401,3 @@ model.index\+ # test coverage output /.cov/ -/pyaedt.code-workspace From b39bf82f156840a744b689c25d90bccca471ff90 Mon Sep 17 00:00:00 2001 From: Lorenzo Vecchietti <58366962+lorenzovecchietti@users.noreply.github.com> Date: Fri, 6 Sep 2024 16:42:38 +0200 Subject: [PATCH 13/29] FEAT: Fieldplot folder settings class (#5124) --- _unittest/test_98_Icepak.py | 101 ++ src/ansys/aedt/core/generic/constants.py | 1149 +++++++++++++++++ src/ansys/aedt/core/modules/post_processor.py | 3 + src/ansys/aedt/core/modules/solutions.py | 899 +++++++++++++ 4 files changed, 2152 insertions(+) diff --git a/_unittest/test_98_Icepak.py b/_unittest/test_98_Icepak.py index cdfd42ae05a..0d5c4e5ec78 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" @@ -1874,3 +1876,102 @@ def test_81_transient_fs(self, add_app): 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) + 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/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/modules/post_processor.py b/src/ansys/aedt/core/modules/post_processor.py index 0729588d2b3..9ce93d343fe 100644 --- a/src/ansys/aedt/core/modules/post_processor.py +++ b/src/ansys/aedt/core/modules/post_processor.py @@ -3265,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/solutions.py b/src/ansys/aedt/core/modules/solutions.py index aadd24db36f..4d4eac87d47 100644 --- a/src/ansys/aedt/core/modules/solutions.py +++ b/src/ansys/aedt/core/modules/solutions.py @@ -21,6 +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 abc import abstractmethod from collections import defaultdict import csv import itertools @@ -32,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 @@ -1526,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. @@ -1612,6 +2457,57 @@ 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") + 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): @@ -2190,6 +3086,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 From a90d95802c0f7bc079990b9940858a8065e66969 Mon Sep 17 00:00:00 2001 From: gmalinve <103059376+gmalinve@users.noreply.github.com> Date: Fri, 6 Sep 2024 17:57:38 +0200 Subject: [PATCH 14/29] DOCS: Extensions (#5138) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sébastien Morais <146729917+SMoraisAnsys@users.noreply.github.com> --- doc/source/Getting_started/Installation.rst | 8 +- doc/source/Resources/my_custom_extension.png | Bin 0 -> 69537 bytes .../Resources/my_custom_extension_1.png | Bin 0 -> 47134 bytes doc/source/Resources/toolkit_manager_1.png | Bin 29023 -> 86957 bytes doc/source/User_guide/extensions.rst | 93 +++++++++++++++--- 5 files changed, 87 insertions(+), 14 deletions(-) create mode 100644 doc/source/Resources/my_custom_extension.png create mode 100644 doc/source/Resources/my_custom_extension_1.png 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 0000000000000000000000000000000000000000..90ece84f848735537a8c3572392b271492bad002 GIT binary patch literal 69537 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

ebe|fYn-TbQ06e86BRz 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

D5vjJMzNYKG8#oK6H%+MP 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 g-N_dGl*f`_. +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 @@ -53,8 +58,74 @@ Project extension apply to all extensions that are applicable for all AEDT appli pyaedt_extensions_doc/project HFSS extensions -=============== +--------------- HFSS 3D Layout extensions -========================= +------------------------- + + +Open source toolkits +~~~~~~~~~~~~~~~~~~~~ + +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) From f9465db1710010f2796dfb18ab973e3d7e325aeb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 7 Sep 2024 15:14:49 +0000 Subject: [PATCH 15/29] BUILD: Bump cffi from 1.17.0 to 1.17.1 (#5133) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Sébastien Morais <146729917+SMoraisAnsys@users.noreply.github.com> --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index e4bce897341..0e706a1f68c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -65,7 +65,7 @@ tests = [ ] 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'", From bf6c25c4c8795a049bd5192c11015d1357d76c2a Mon Sep 17 00:00:00 2001 From: gmalinve <103059376+gmalinve@users.noreply.github.com> Date: Sun, 8 Sep 2024 11:41:24 +0200 Subject: [PATCH 16/29] FIX: Allow scale_min and max to be set if not log scale (#5131) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sébastien Morais <146729917+SMoraisAnsys@users.noreply.github.com> --- _unittest/test_12_1_PostProcessing.py | 89 +++++++++++++++++++ .../core/modules/advanced_post_processing.py | 8 +- 2 files changed, 96 insertions(+), 1 deletion(-) 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/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: From 3efb82f8f709a7a7e9901403feb3ba8cb915b5c0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Sep 2024 14:36:57 +0200 Subject: [PATCH 17/29] BUILD: Bump sphinx-autobuild from 2021.3.14 to 2024.9.3 (#5134) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 0e706a1f68c..0ab078c63fa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -86,7 +86,7 @@ doc = [ "recommonmark", "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.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", @@ -102,7 +102,7 @@ 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.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", From c098962e49448358744a88dd01f3dc80be56918f Mon Sep 17 00:00:00 2001 From: Hui Zhou Date: Mon, 9 Sep 2024 14:51:13 +0200 Subject: [PATCH 18/29] REFACTOR: configure edb extension (#5128) Co-authored-by: ring630 <@gmail.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- _unittest_solvers/test_45_workflows.py | 43 +- .../project/configure_edb.rst | 72 ++- .../_static/extensions/configure_edb.png | Bin 38876 -> 8391 bytes .../core/workflows/project/configure_edb.py | 485 +++++++++++++----- 4 files changed, 447 insertions(+), 153 deletions(-) diff --git a/_unittest_solvers/test_45_workflows.py b/_unittest_solvers/test_45_workflows.py index e6c5bf61f10..355c99c6cb7 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"], } @@ -383,4 +409,3 @@ def test_15_import_asc(self, local_scratch, add_app): from ansys.aedt.core.workflows.circuit.import_schematic import main assert main({"is_test": True, "asc_file": file_path}) aedtapp.close_project() - 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/_static/extensions/configure_edb.png b/doc/source/_static/extensions/configure_edb.png index c233b5284096d30d6cf6a524c074cab86e23f083..8dfdf2d83e93e00f18ea689daa0a95bac7059637 100644 GIT binary patch literal 8391 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 Date: Tue, 10 Sep 2024 09:03:43 +0200 Subject: [PATCH 19/29] FEAT: Arbitrary wave port extension (#5122) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Samuelopez-ansys --- .../example_models/T45/waveport.aedb/edb.def | Bin 0 -> 1566322 bytes _unittest_solvers/test_45_workflows.py | 23 ++ doc/source/User_guide/extensions.rst | 23 +- .../hfss3dlayout/arbitrary_wave_port.rst | 33 +++ .../project/kernel_convert.rst | 2 +- .../config/vocabularies/ANSYS/accept.txt | 2 + examples/04-Icepak/Icepak_ECAD_Import.py | 12 +- .../generate_arbitrary_wave_ports.py | 259 ++++++++++++++++++ .../images/large/arbitrary_wave_port.png | Bin 0 -> 2631 bytes .../hfss3dlayout/toolkits_catalog.toml | 7 + 10 files changed, 341 insertions(+), 20 deletions(-) create mode 100644 _unittest_solvers/example_models/T45/waveport.aedb/edb.def create mode 100644 doc/source/User_guide/pyaedt_extensions_doc/hfss3dlayout/arbitrary_wave_port.rst create mode 100644 src/ansys/aedt/core/workflows/hfss3dlayout/generate_arbitrary_wave_ports.py create mode 100644 src/ansys/aedt/core/workflows/hfss3dlayout/images/large/arbitrary_wave_port.png 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 0000000000000000000000000000000000000000..50886518f67b9eff24fb5608314d968c31579711 GIT binary patch literal 1566322 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%0ABf7Hh{B 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

    (4)!?2}yY9=Q%Xd5I&q-o5JW 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 z zL4L}8F4K-LP$p=8+9YEj&C}alD&z$PsCl}XD@E>hnP1WvimNDxVwZIcxOsY;E5$C0 zHh}ZAGhd%_&&zaRC`{)3w97{U=sdm6P~^Us>A+B2Mg60YbqwTrdYi9Lx%Xu{Fceo& zuTI_-L7%6$8w$x7`17IxrOGpz>4x>62;4mBOUaPq`mv+A$O+kbcTdEYptfPv*Gt zQ*L9Kc6@&_q4bkHPXMLo-_OiYgjE+6uGTsIxrL_qkii0M+#8t>20nQxwU0F zFcjv_)=ym)9+2w!cVIIWa;`wt)6IN+$_*~lf!`@iTKzO6W5CtZ`y(OcyEr$wOb3R- zoMwI+vhV;|Pw$U})T@)1J3#AcXNDsG7R+>DC`@ksl$%|q9ajpITt5xH?-&XbUO(lA zmq{@ArNSI*ej1W7@aySqrb6C40kEf=xl-h|m+8Qj!erP_x$$M%F%;%x^HXkpnRZ+$ zOpg7Ow`Q4ke0?%!o1b#~%d}%COqTtW8(^j#Lt)bFr~Fem(~hAq=bN8$6U-bFXDD2x zoi}Njc6@&_C!C*hBh0kpQelobKS^RS;XJL)l_EF8Ob3R-#oDWZ5{^6c!$56OzJ2%EG699g);}GRVJ8#@F?GTC(b-TP& z%)dahI&-PW?J=`DEEOTD)m`%2*!(jGi~A6Dw+yuAw?*1{uTPix(fyB)|NQ^_zyJL| z|JVQh*F0IIB7{+%o-SfB-+%u7e>42@pBCrio#*=@48Q#PIg>%Z4`KM__s@9&;b(H~ z`FZ3od2{y;`gt!=(=Y!yVD8^RKQ9~8FTaA$9X#mgEg92KvP-r-H}v?ox$$}AC2j8F z!TQ{M$n8wHy_j(OGH;F?H{$KZ#M{$P>tj4jzCHaUZUo$m3Am@9#Epb|F$wqdleiIa zFDBxieiAn_?!{!>7rlIB+>6P$FMqjuTsut0efi79V>V32efi6^$5Fx044H8TVo`?#n9ACo=BEWZakhn?m!W;BsLy z?u#_dEQH)4>eo&(M##OGkozJ{GYcVih;ntZl96#QCgZ+H)67D~9im>Gya$kRFDB!@ zNYl(h#vP(wonAYx6ei=oNYl(h#vP(won(xRdodaJMVe+7GVT!d>g0u+kb5y9_eGj! z7DDb2_3C6DBjjF8$bFHACmHu*GVY5s%`9ZxA zafhf^rym7Z3X^ePq-ka$;|@`;PQKL=axW(2zDU!|LdYGWUY)FCgxre>xi5LsnE9=f z?@uP=zR1&#jC(P+=e|hO%tFQ;qI~J3X=Wkg4pFz0jFE9KCgZ+H)67D~9im>HWQ>e^ zF&Xzonr0R$5FuTIu6GVaA>+!yJ=S;)9U)T@(+F(LP2Lhg(7 z;4FmPA?nr1yCNa?VnXhV^x!On+#$-t6MtjV}9(u1>*afhfECx7!G<6cb0eUToV zm5e(?y}JB2kClu&MBOfDY$f9kQMb$M*h{K(_UfW->A_h^wnNmblZ=sUuP)in8`Mk`i=`q&y*fz+=eAdqYd`B< zjHZv(q}tB{@mE6a5Y=;?c9K~_?bU?Z(@##9PA_hExkJ>e zlXn3^?$sRRewH4bm5@6`xjI?N$hcQ?j{8}9a8}N7ho~1P?*U}ot2xL0EIl|Y8Fz?! zb#m>A_jaxI@&7lXZ-Ydo>yNvus?ml5vNqS10Qj8TV>3?q}J!W+meeQLj!u zSu*a`WZciPam~s>?hy6rBou_)t2xO1EF0IXgxn#@)yeaOjC(a1_p>z3tYq9F>cvSY z$hcRNaX-t(H7gl+h7t)}GpY7GT}dse_GVJ;=_gAgN4GZ9O9mS5;sn9ZzkcMeiAn#?#&$Io_-QHGVaY}+%J0h$hbFi zj{8Ng9vSy$GVYhZTs-W9vzeQfzx?IeVLWd$8TX4c&1_`cA?i_+2NfarWelgAVx_hv%w7fCG{_h!yGya$kRZzkh@k*1lAj5|cVI=yyWDNM%wB26B+vRm^C*%%Mw#$#Fos2s~-7T}ros2s~-7aTrC*uxLx6A9;PR1Rg zZkIE*bEonUb-TQd?PS~`>UKF}I~jL~x}Dr8gxvd8)a@i=gxtG1$o(QcI6EPCh;afc|Mt884elW~Wr+eyaAxOa1o`$aac*~z#=)T@(> zk#XHWQ=3ny9v2pWaFBhkUK=ZI$6gExp#Aj`$aac*$KHrl&jO? z0P}Wpg8M}_uGz`BL)43tb&QOAH|Musqz7jw;|@`;PS!Cp?%kZ;evuxWos2s~y*gRP z$hdcNc>6_qaCSoO5cTTh*-ps4o1@z=(u1>;afhf^C+ipow|5tDs~f&(?=Ik$9-N(g zJ4E?hr3Ysx-VRZ>lXZ-Adw1!!^x*7-+ac=J$vQ^1y}N8%dT@54?GW|qWE~^f-d(aS zJvckbc8Gd)vQ!Xk?=IMu9-N(AJ4Cg*S6L}YwRe+hzY4_P3AIDii<2IlolrZ3;U}j{ zsJ)v|d!DYOmQ;H;srK}frIA>BH?j8gliYH4dpEiE^pnMr!`r(Fwx^#Ymt=c4w5cTThWq^=-HwU?2SIHP5_kI=i>f}{`kb5^F_p96| zWZb*CS^2B<;Ov~^4pBbWO)^Htyk#X-P<9^*F zV`SX>Rn)7Kb&QaEHzD`yCK)5--mjuwon(xVdp9BX>n0f^}1>_>cvUMILE!4jQe%Z8Ea(RA?nrTj5RXu5Our!Q8Y5{5Ouqpu|~!nqHdQn)(E*n z)a`P{8X6Qr;%}os27(r*2uU+)a@i= zWZcbU+^_QEQH_i{M7=u67#Vjn2f1J6$DLe6| z+|3;1e${hjC``uvDjU}{GVT!NbCq9vYGm9Y>UI(eGVW&1algv1JvB1!5cTRL6lC1Z z+^PJv%j1rWyP1spRW`0^WZWU@Co2mN2f3RGxnHGerV(<7s8=T$Bjj!-*-afhheNyf;yo5{FerD>*-afhf^CmAE-ZYJY?m8O|S#vP(w zoji=mxSPqiU!`fLaf&-cy*hchBjj%85cjJz%``&p5asHmI5O^LGVWJtnrUR*A?n4+ z%N-eaGa2`*G|euTcQYCHt2E6tGVT!d>SP@w<8CJ7ewC(~M#deYUY$JK z3AvjKxut2Q5psv9S10Qj8Fw=Ww_nw5`Op9O=ih(-*T3dZNPmcOandx?2)IMk?IdI5 z+s)tYd+s(z>(lpaZw?ouVR@O1X?dHO5X_{$d+ac=J$vQ@~-CVRSO*4&TJ4C%Y zSt>}jn>n}rDorzuU^_&$x*u{E6KgjUYyS}H-bl4W)Qgj*nMSG|!tm46ML&5nsrEcw zNiC^%GpY9UlckZP+s(w<(@%2C+3jX>?dd0rBZs$}3AU%7B$s5nnPhwV$?{0F-AuGS z{Up0&+wCfh`%jiM!tG|l?H|&V(g?Rh)XUTO5^pyXZ_n~1ZsgnTDvbIhZUo%T1l+Se zi5m%by9%Q|i5n4jGZFW!PvS<#-Au;)Lwb%H8Fz^K>B`k3<8J04_YY~BX=L0X>ecDB z!#+68WZXYwHJg5k{n+dsp$i_8|kUK=ZI(bYHayJul|B%#@aW|83|B$Ac zM#deYe6F%_O(WwDQMZ$mCF5=;oGDgPTO~(C0nr1o~cZhm*k})#w zZZhs4yM7dyS?%Tza{rKxYdRTsi2BJ&#yH5`P00O2Hm>P}+#%}KNyZ4dyE(}HLpHAI zgxn#@)ydP2jJun2+&`pgrjv1ps23+0BjfHSHezNHN=qBU-Asg3p4swU6S10QjA$KGVTy{J9$?mlw4xjXp}>A~q_+#%}KNya$F-A%~- zLwayJA$N#+b@HxA$lXoI{X=?iIw5z6a&=l9U|u&TxPM3wPAB6IQ7=y370I}}Iluiw zdT=@!cZhm*@~%k6-OcIkAJT)<$+$z*tCM#{GVX2;Z~u@UoKDCcqF$Xm+X=b5IlBEr zdT=@!cZhm*vW{_ZySs>6-S|b@1>Dku)5*6(l+RT*uIa?vA?kLrj*)J6mu^cBPAA+B zQLj$cF|zIMvTfeb0QMzY;qvMoJ0on$*iy*gPc2)4TmwxtKBlWT{lR`*j@ z3R3NEQth7t@jIb*hezG(YYj+cCPd~{m zxpp^ax2K;hjvU_ZCfJ^Sl3bGQZccAcKUp4$w!4Y8r=Mh(Y`dGAlutid(g?S^3AcYr zk4q=r4pEPX#+P`zn#XbEbZbaPOMBLL) z;zq{Z%{lI$f4O{op)wiw&%azf403mKko)IfE*}3#YclSif4O#;MCvBv{wX~;gOEE! zJ!<(uH3+#w)a~+fY7laVsN3bo)F9*zQMSve9h~D1QFqIml@BuR5Our!j2dLzA?kK| zvIxbv0`IzAenJg0?htjm{D2x{+#%|A`S~=+xI@(K^4q{5%74mzLdHEz#{E-za0chNLzK@|Hm(_D+#%|Ak})#wVKVNYvT@BI z;|@`;PBKQuJxs>^Q#P&{WZWU@)k($(xrYh4f6B%+gOEE!y*gRP2)Ty|xqr&WHG_~l zM7cWsVDb7iOve3FdT<6AcZhm%vW{_%dzg&-r}W?qGVT!d>g4%E#yw2N{Zo2y1{rsV zdUdjnk#P@`asS*UV}#tpgxo)+2WJp+hp3;dWQ>q|Tt(eZ)-givVM6Yo`bqHh$=s~` zr}W?qGVT!Nb8V6_GVXB|bvs$d$he2exPQvVHG_;hM7=tB+>vn)bCCO|Y+N(QxI@&d zlZr!>tBLhcat>Le6|+`}B?{;B86P?(JSr!>tBGVT!NbCsr8D!ic>eWdo$he2OQ~6J6ni*u=A?nr1jY7sf%t7v-(lj$T$Q`0yoh&?r z+`}B?{@EpCgxte~+&|^ZA{qBE=eU1L)65{_4pF{z(lj&3xI@(KBx7XU!(`k)rD{Ir_b?gvPidMNoZ=2quTC;X$UV#eb0QM#eqN!R?>oM#4Q@!YxfR zgMd3k`CO%GW{_`(sN2apM!Y>-ye&;LgLFGYy*gRP2)Bm|x20)jkZp&kS10Qj(e`lB zwlvKQlI;-n>SU=P*&gQH_D^Y=83fxQs@1*8NA9w}VsMAq>A9w}Xf~gyEOtc93z0sQby~BjY}A^Y3xI@&dlXpc9ZXYhgL4pX zhp5}hI!3yExO7{3a1O%l5cTTvI(Cw6hp5}-jGaW=A?kK{9Xm<3L)7hZ#!iy$5Ouq} zRGb9cA?kKH6({GmLsad4<(1+j)ecd2%Mkx0)DB_TsUPs&Y5oBBujPxLF1}TqSHf-7 zms5L^YKJiV^3r$`YlkrWB)8<+r#ZVlub%{$VEZ(|_VknFl5C&m^!D_V=n`$8Cfc5U zl3lXx)7+$d`bl^Rw@(vp|B{ViPEK%#sNXKqLU$5xhcNskZsgmiIm10qSK>y%eVTxK z`bpeKxKDG6d-_S-h`3J^aZf*q8yWX$&T;?x%jLrh)p-Tp^^aGt9tOEjlX3t0%f-VV zY0oS0u2-kmj!TEhxPM6x&Pm7}qF$Xms0g`FbCCO&^x&L?+#%}K$zzI;`!pf{Y!dqPBQKg_3GpSMaF%ajQf}L;GAUK zA?nr1+W;Z=X+rK_^5an_A$N#+b@DDi$bFiS``0QNBji5K&B}ktvzUzgG#U3V>A^Y4 zxI>gLo%GM7=tB+>vpgCgc7k8`qp<+#%}K$vQ^JeVUN_mo&|sgxn$O)k!D_xla>v z|I%}1C``uvOPXd*GVT!NbCsr2)R#lko%W3&76eXAeb219U1p&4s!n*k})#w(`4Mgq-o|P;|@_j zS;-g~_h~ZjU(z&la*8`dy*kMlA@^wxasQI0nUjz^M7cUGj(?Ih8TT(~nmNh1L)42) z8C$=AasLr@yR?o?hvh&2@aq=@q;4k}1KFN-9|@`3Nh$!gr=6FI-*OiNYp-8S zto=Jv_vyfu!lc^MPBIIsJo0JK+r=7$Nczc?AuTs-b;s(Aw{oHuuu8(QKmnn0j@>!q64O86H+>J-> z`XAm)6R{CJg5MA=;(gxtUL#x>LKBL^Qhin&?&@7y#q?YLH$ko&hhi@~_3wYgH{ zrkUx$P?(JScW#_?J?+euA~(%U2fjs_gWSJ2$ru>-^fp(D+%z*C zK63DJ+g(Nd+DXR1xTm+dQskzY>A+B!ko)&0>lh&S^fs4@+%z*CxKvz4`P%6R%TSn% z`*&`dS-*gB{}J`#!MW_1WfhQUp~xH8%<32llX3q(^7pZYj5|d6KFJ%` z%<32llX3q(@;bJVafhf^CmAE;UR=n1NX7`c7Z-BpjceA0j5|dAWF=!5+@9X%QlV}P zg$uaz#x=7ZhQj6BdE=UC$56O<`;>KzbbE2>w)EgEgxev?AFTA?EM(gu>UNSbqV2^T z+x~q@#z?jomu%-Bk6IU!?GW{om8F7UdvU>b{_&_;9aCX)?RQxzNVOM}YQGD_UkJ5B zR4?7M%S{0bp>_zvPfwR?g$cE1eUe&I?Zu?p(@&O0V(rDm+S5luAlX1UG56(iy9im>HWQ>e^F&X!} z^x!On+#%}K$-5#U_hLfscj>`d2)RSltCM#{Lhi+c-0%8H@b$@L-0#wZvygFzD4(nJ z;4Ea^A?kMWu87Ub*TrPq@6v;_ka35oSC=1mbL{mKB88~iObDD5Pm- zvIg3jp^&DTm5@6`{gcfL&-{}Nt20xP7uorJlWt}xq-ka);|@_iS81AA$+$z*?efAi z7aN|e8478dS;@FV)T@()hm3nh0g5WZdt0G_#U%hp5|0#>lu=lX1UG z)67c79im>HWQ>e^HK(`VrD7;39CEpHFx08$!Z?7)imZq7NbUQ@7I>{K}_Ugjz zQ`RxE?bT)5(loOYZHK6zth_&wY_BfaJ|$x$+p9UZ{Vq*2E5UY%;>q5~7amgW)uY-s z!rWIf?GWYCq+@0!(hgC#lZ26IuO88!=PKXE2((uZXiqyy7>Bl34`@$2Nf?K=R}W}U zJBb8`wpR~mPdkYOhqhM_Xiqy?C=5PKPD4SSyF`(yvqO~cISD^m_Uf_h8|m*@iLyhKYm?}cWUn5{zL9K^W3S$@_Kh@mtmN1s zswXNNqO8Q&AJ4SzNJ@#TS8pWy zMp*hvS{B zBc~2gcFQ;KMot}~?3UkBH)84#RX5owVk4yvQFhb&4S!|bydTuQk&PWTGU^cJ+T`vf zqTW12eIrPDBcTpau1)SY0_x2h!oCrpypd0bsMe;X0mN=dDi2G7>CGFyz7e*%kxPdt*CvlQ zV(HDp(l_$tC6wMgD19Sfbt97wQ9V)FJzyh}4pDZ?FP0mLbcnK>JS#bMy?I3X=Fr=X zQSf#YzY%J=kw=FppQ+p-#L=6Fqi^KiC5+y@f$JM#j2l^Wi0X+7V%&(LLzLa*SxFMT zc_jKq#^^VK=n&=F%YHeR-H6?`J zydmqGufi%eLg*0n;)LLBq|hM@KRsP^@ogT4{^xWh66DaE$D#l6lP5Ys^ybZ2|Klgm zbdu=JBhml(Nz90%HxEVs<0q>GS@h-&S^wiFQ6rAtOdLJ^WThaG-n=2}f9jLPf<$`r zhODQb+|DG@n@OanUG9e7h@?Z*@OLh0!zaU+%9Oe#J7ByPmg zn~9~TpTvz^dNaB7*S}mow7PEIp!K}_H>zY1vG2&hBUtCQyw3H9bpTHkz?-<{Zqs6*7NlZ=s3 zZziMuD!)6i5mJY!S0@=GrQS?R{Z;Q1e%#p{Z(e(H{$9L_3Gq( zo4k56dG%KT)*FF!h;nuM!SeOVB-URAS#LzvA?n4+cL6f%&1BYJW#)Y&v<^|PPBKPn zy?MKd-+UDaz7bo8s8=WJ7`gT4O2-*@UC!7}d>x{0m)EhK{5nM4E@x~fzz$Kj%a6OA z1Up3CPCr?+yY5$>UAM~_+sUv))a~-S;?7Cy5Ouqpv7Hn?p((T>bOnka!_^}gjhbW(` zjL`4o+ac<9k}(4A-2~iUWrThw;SN!+PBKQsy_<;ptBla^WZWU@)k($(xpxiC*KZHzI4*xvJ-EIsM|@#NVj*F zZp#S$PPiSSUY%r&Y5Op_M#|X7|6Kc=lX!XNn>25;p=_gt zdHp2T-c77M{Uo>K+PlfMr=NVuBiPgkmpoSk?(gyAP~Bj4W5;p=(25;p?w-2~jzPvSDo3q%uFTqa89im>HJf;Y_cN22U&ICIdcZhOv(u1>;afhhe z$uo+Kd-rw|zqygE4t6r`5cTTh2}Q=ed%KCx>Lg=i+`GxRZ{&9;b~5e|^^=vi0gh$w zCgj%L6Lv!G5cTThU4W2#HzD_p{O-g~$Q`0wo!lp6+`GxRbw7rkj5|cVILR0p_ii%o z8~NRdos2s~y*j;iTq(@)Y~A5uC*uxLuTIu6GVa}E+`7j@BjgTIuP(1+jgUJ;-7aUW z5psv9+vRnv5pstp+vSI6BjXNHcgx>x8yRUKF}jf^`) z-A+FWv_rKk@UGkCj5RXu5Ouq}jx|E=5Oq7r7$J8vhqZ6ycPAPlcZhm*k}*Q=W8zYWZWU@Co35v<8CJ7zG;#% zGVW$F?i=~tiAKmBqJFZn@DOr0b8!1ces`h~a)&5aC(jcy?q)LX8)=$pWZWU@#Yrg0 zxSPqiZ=`9ak#UEpS0@V(8Fw=o_l^ASL?h!4QLj!yLB`$80dCzSq>*uls8=To4hSlct$Q#vP(=CmAE-ZYJZtk?mF*8Fz?!b&@eM?q)LXn?qji$hez1 zy?rB1GmVTpMEzvtg@=s0nX}uvgG(di4pFa8-W3VCn+v(6X{K>-J4CrUNh}F>a|yRJ z%`^h;5cT3DW8~Y-<=dyMW5nCd#oN*}(@3{N)K6A2M!4NvxGhaHjchway*kMl(ROpu zwlvK&lI;-n>Lg<%+s&NY){Sc#!FGshb>H+Z=3k#oto==>dn45jQ7=xKW*Vt>2*XcK zmsGo%RC}JTq?S~>nN)lF$G zJ50v?O)nl9ce{%E%`DfBjJuhP`UKF}osc_3*-q~hG=B6e@UFXM zpx?>3L)7i^dqC$LcZj-O&R8eo4pFz0Ye&Z2%|Y&OvT;o(;|@`;PBKQu-OWMnZ}P(^ zos2s~y*kMlA$Pxux}9W5ps7Ea(|PJYdRr!h;nuMN#OOVn~eLLG|hA}?hy6jBx7XU-DKR~q-my;afhf^ zCmAE-?k3~@*5q+V#@)?*%D+j|OefVREwdd)|%E-y> zZc^>(C$Z(|b~my1^pmxbT)UfGd-_Rm3AVclwx^%0jwIXtDvZxpqD!>hO|(7hlkAdh z_p31KlO>ICyPI(PyY#qp((MrS@-)80+ua=Dp5;m0$hW(>Px_y zWZWU@)yeaTjC+`j`@8hu3^MKz_3GqZk&JtogWTWc$D;-zcZhm*vW^jQkE^KLNyZ4d zhY7jAOApQ<^U7BVF8Fz?!brK3P?qM?S@6t3gILIBMUY&%3jC+`a+~1{X zW{`1*s8=To4w-A=whk#Uc!sM|@#$he2exWCJH+;@cB z!-U-5rDUNSbGVWnA z?(fnxGsw6@)T@*4vSi%DWZd7SX=addhp1O4FFa)2!<^mzE=@CokUK=ZI=PJrxraHq z{au=71{rsVa&?kej%^Q@a7)w7Am9#BFHYVS$+w5gx20)j5O0U5S10Qj>Gp8xwlvKQ z!tD_C>SP@w+a504mZq6Ov>l>eovdRd+ruT>(lj$jwnNmblT;9F4-;(P%3VyXJxr{9 zE7X0EYKN$v>$J-Qvggi)Wwjez?whqz~b5;sn9A12|ReiAn#?!z48o_-QHGVa4<+_%zmbdYg} zsDB)K^{@}lVGeTN{^jCf=Hf6J_pM$#GVa41w`CMh=nuClxMBPqLmZ7);@4B62jEws* z8TYOH+S5VC9im>HJfFz850i15po|U z6TnuCx#M7=u67$NszLhf5>nmGu$LzJu2PlB&cCgZ-9rkR6`J4C%W z$ru^;VKVMpX_`66xI@&dlZ=sZA133zm8O}4j5|cVI{9SDxDS(Y-%8WW!9ng2_3C6D zBji4=qHZS{Bji5JLGD}W!8r)ILzJtN#}gU%VKVMp>A^Y3xI@&7lZ=sZA133zl^&df zj5|cVI>{Ir_hB;bTj{|$$hbq)tCNh8aUUk*zLg%FgOEE!y*kMlA@^Ypa^Ff1&Oyi> zqF$Z6D-v=aCgi@Ab0y0z4Ama{EuTC;X$bGnwTY7K~Lhcat>hf)Tl5vNq+vSX%MBE|DcIvi%PBNcY+Ff_c zfbk^X4pFzu?}{h!c8I!N&e%!19incR-xW{7?GSaloUxN^J4D?szbl?Z+ac<9Ib$cu zc8I!Net$YiwnNnIBx3~Irwg`aFPJ4Cg*JGqNVwNI03-$@V7NvIv7UYzvcoP^pT z3_m?x>}GJ9PL}2Cp|bP8Fz^KXCY52LhjRq+;@vSs0g`FbCCN^dT>rc?hy5pmB$nz z_h~}zJ4r1W_i1icekVORCmDB$^0`V6&Pm1{qHd=ryWvZV$++)iFLgX+rKh*|_E;rM?hy6r^pnMi#c49`JL$nW3AsbmtCLU=a-ZfP_nkD& zoP^vV%GJr5O~!qijQdWSW==Bh5cT3D6lC0|$++*NY33y34pFa8LP5rTnvDBSnr2Qi z?hy6rBot)ar^&eQq-o|P;|@`;P8J?Q?$dTU_>Plr#K_ea$2(mFOBK1VG6h`L?M*mU^pCjTSqc4-}(4xg`2e?;9bWo-Kb z#{Eas?b13n9T*Ceao-)1F);4w{gIG*b&@ea?rHatkh-1R#(><@?js>}JINRr_p~!p zp>7O?OStpKHM1Uu!Uf!?WDIA;o3q}tO?))6ZKjrk?~C!`su(i^lYm)e&TS`gse+^pofUZBM_Cq!^!vtdC&Z)6b5F zENOt-)6ZKp?sL=3bl{?4!tH4%aRc7ozL`bpftx2K;QkKFY!E%*(?+^BrkCvn3R z_cV9ok^4TT1;1mMW8AYoi5nRAG!(`m|f4O$d zhB?T6pEs`AzJPK65%njFJg5MLg=;+|%0(MQ)mz4*ZsJ74_;QV}RV#+f0SrCt%#u&0HyR)68^W zC``tEpPOc;9YbNxao=x}F);4wZH6K@%}fV|!W`tj-{hSejC=cHGVc4_G&3C-3X^f) zZ}P?s#y!2wP~@hW>A+B!ko!JwTr=(X0(BMTjOC`8X~(6)gxvS~!7>!)X65&}X=WD3 zP?(JSK5twz?fCk173E8pn`WjRLt!%R`(2(-VBFgmbCCN!H_c23hQegr_q(iPVBFK& z3`K65nGOtv3Ayj{#x>K9p}30rCoAuYfZWsDTq<(Y%yeKXuA*F>ei96Y$++)x)66W6 zp}2~Aaq@i@jC*>2B&2R9>lhgK_QjmzzHgE-Fz#t*ey7MyGt=QC2mk!~?jKPc19L)6bTXKW$k4pFzu8Jm9sW_9LDk$Z5qg^W8yy}F#S z`3GQD_aW+b`9_(4|D~N7ik>qz|NKikGZeW8XI?uj6(Q;;n=>{iCRv@C3O!eZVz~nE za&fr_XPbYjMRDd1<@dP71!i3!SdE=UC$5fb*`#vwS z3mJEa@@_j%)*d9n*Yay*gRP2)7p(Zc7i&Lbe^EUY)!v5^XOo+Lj)ig=9NK zy*kMl$@b!sZRx>T2)0AitCLiaYcD3(evrGERC_V0_JctDg-|<0^<1Z2ZVFfkwL=(w zdb)gpGNJaYPgX`!?Zu?p(@$cH(d}(9vG(+nwGp%1)6e^2G5sXC7~Y1%Lr=P@)ha_#sn!(`kK(u1=Qa)+o#O&(N)+=~ghAM(aE+d{}4qF$Xm zrU*afhhe$;py&FDB!D$Q##e3mJEadUf)E zBI906#{G~tu9?;Gb;@Mi57L9PV32!ydw-;T$Q##82mU?Egxn9(gR>BFhp2xPk}*Q= z#f01svXYT;FDB!DkRF_cj5|d6T%`wRA>$5Fx08&KaW5w0evlrVg^W8yy*kMl8TVo` z?g#0?S;)9U)T@&>ZVYm7iwU_Oqz7jqHJfFz87n5;6NDt0J#vP(woxEq0aW5w0 zevlrVg^)W$y*hbUB;;O9$o;VAjID&+A?nrTb!;W%4pFwtpTtVW9ir}*|9-TRafhhe z<&3Rl+#%|Ac^zBHxI@(Ka>iCN?htjm{J2}mxI@(K^pge7Td%;oZkN}wm4nUI(e zLhjXs+z)x3?uWc_&9;(php1O4 z3lAChYBKHzX_{F%#~q?xoji=mxL0$G`$3v!RzmI&_39*Jgxsq+#Qh*mGbKS=iQ1_KoJ4C%WX_{F{wL=(w zdb<2pVN&gRx{_K_?bW2((@&O0V(rz$+S5;RORl||TzmS-;z+Q)nqYhSNpd;8y_#fu z`pNQ0w7r`1+tW|7OSZk5YByL39t2xF!{UmN=+^fmBAOCXs_(Eke?#I7eJ+zmv zCgXnm%f$oZUQNdR_?K(PKhm0m+>g>UvyyR#s7Fm6RD|5C3ArDoX=Wwl4pFa89#e$e zt2xO1D5)jmUQNdRC`~gf8Fz^Cxk}T_O2!?cZl@>9P?&SvkJ2==l5vNqS0@iBGVawJ zelXn3^?)56_c9Jnd?$w0ckFt`Haj)ha z_oFn;tYq9F%I7LgGblu=lW{*v)6Cr3`EyV* zM7_G4vAIJo?Y!L$9;In!?j}k*Z)WvTHm;dlG1AVPS$&kInYlY3?LI{L+T{;+Zu>>I z4^el^K!0wSL_4oV@KH9dnOn`!?nBh8%Nd*da?s8jw|JC|Yv%R_wDYDd9;In!POZbv zWZaLkam}2lrJWfHX_}dXm$WlOAsg4sSwz~Ip^&DTIqX6^Hxzjto5KsVGgFbj@yzyb zx|yMnjcaD(EbYutwETT`b{W#n3`PF6r)?wS4pEM*Y+SREafhhe$>WZUd-C{ypLyL* zK3OvE$yrT1S;siYy_t~vQ8upG2)RSlPd2|RZiL(+>UNSbLhj9k+>d(c7z%T<@<-{x z*~qv=7Aorv6;A~{vA?hb986)G~%t7u) z>A~4J$Q`0yUH+TLM#vqaZYLQdyHTq#V({U|*+8yRV`SW$IlTQSJvbX7cZhm*@@yyM-ptYMN9n=Y z$hbq)tCM#{4sLHQ;ubdo?#%_<(u1>+Z-*$KtMuS(#M>e2cCwCl>eovdRd+nY!PL>LS?ac+-(u1>+Ylo;-_arL? zsrF`4?I(fw8=-cHdU4W&vk_{CF#Pm%`S&LiYR}V^)N*orGpY9UlckZP+nb5Cr=R4O zv)h}=wWpsfjvU_JOt3xuB)KHpn>oEb{bYG0+TKjGJ^duRWZRp$N%{1XC5>=Z{{}Tvpk6#`Sxbca8Eyp8;7_z6L3#Ii5m&`W=?TWKZzR=_husQ z=_hd`3xE~NA2cjHWQ>e^HwU?&qz7jw;|@`;PBKQwy_BS0@=Gj}J4C%Yc|MVG@8)LZPtt?4lW~Wr zS10Qj8TW27?kDNN**VA^qF$Y>V}#thImrDaJvcidcZhm*vW^jQ?nw^Y0M7=s$c*wYSlW{*u)67oB9im>Hgo2EFHyQVnG|lW}+#%}K$-=`y?%jmk zPx5O|J0W+7dUdk!5OVJ(-c82+ zBuz6r8Fz?!b+Yh~aqlMMev+n{os2s~y*haqlX34R<9?E+nVpb3M7=s$#|XK1bBOy% znr3!F?hxhbv^X@A?lhjLZVqlgsT&CQ z?hHtYd`Ry9>9aX=W$e4pFa8 z)-j^(-9_8dG_#Xzhp1O4O9jdHZq98#Nz=?uupOdW-9=UkV(s0;+83ejJE?YvdU4V; zvy*CvF#Pm%(NDgcRC}JTq?S~BH>vjYlckYZdpEK6^po6@Ywsr4o_?}85^V1#*q(lp zT$1hGB-_(ZmPexP-JIW^ev)0X?cHSC(@&N(!tMPk>i4tU&V<{$3AZovXMF$1#}v;0 z`G5cWfBvuk`>$;$-VR}ur}Yu#nKRt8z8tqkz#YP8T$E}fZ zhp7AM<--eAy8`dJonAeRthOuguG{Iw!^~>C0`Iz=UOW7ewq1dD-7Y_=8X0$px?O%y zH4buzsN3b|R3qdLQMb#FsYb{hqHHI(9T|5s8TUn+W*QlHhlvv$+$18WQ>fvT}8b*$ru@TGa2_qe(kA|afhf^CmAE;ZYJcu$ge#$Lhcat z>Lg=?+|7jC7r9T!xSKi0eUYY_M#deYe6F%_O(WwDQMZ$fk#RSZabKiqrjc=ns8=T$ zBjau+S{i!{wNLhcat>SP@wBjgTIuTIu6Lhfd6R(_EloJPnUqFkL`I)2eMH!HtL4^AWF4pA>o)-f{fb`^Cy z$ru@TGa2_qHm+%8+#%}KNyf;yo5{E@U7ns~+|Asl{31O#jf31F>L)Af7$J8vcPYO} z4^AWG4pFa8)-givX6{jb(R1ZrpG?Mmksh2z#vP)3uF`|k$hbq)?IdGl+|Asd{31O# zjf^`)y*kMl8Fw>xC%;G!P9x(EQLj!O#@w5{nUMP;Jvfb!J4C%YS;q*un>oaNksh2z z$Q`0wofZd}*USm-i}c_$GVT!d;$$5o<8J2s_CSP_`;C6Enx4MDgH5YJ8 z4^AWB4pBZ=>A`8l+ac<9vW}5%HA?nr1I!3bH zT(T`aIE`dGM7=s$DhRflIk$b09-PLx?GV-Ko)>9z>EzlW48OegbaL$whF=awC)W;P z_~q57lWT`C{Bkrphqpr*etG@roZb#$_~mePj&FxB{PGIaIlmpk@XPV&gxetuzr1R6 z((Mp+Kj};9#M>bZKgkFAcE1Y4Px3*+-A%&%ted%XBJL1IeUc9{?rzR;&-x@E9OUjM z1pa1Ue~qh73AFAoaKHN3g5}OLzJr%3g5}OL)7hLtsv*_Cg*+@3g5}OL)5F2wSt_xo1FVu zD10a94pFa8)(Ud&ZgTGDCJ%RV?rsiqKMOYR9Oe#DK3M_XouE5J-A*3v1l`>P-OsYw zL?`GDQLj!O?gZW4+_C&wHk;@K-687L$-|wXyPKfeb1^ous>) z)7;O3raMV@hHtQ92P-Q2JISQFn-Xb+T3vb$1hWKMPFmMBO3k)yY~x)ZI}#J5hItx}B^Q9OmvO>wXse+sV2^ z)T@)Vf~>onqukGee>+)shkeV~<8T z=XQ{FhcNu|ayH1iLl}NJxr3}bgyEMLv_aM#!tl%49c0}h48Odj4YKYKbw9nG(I7R< z-O68d3x+||9l|J2>LcnNChDH`N!*CKhl#qUpTv!*dt8Naz7jX0?qQsC$^G z`{gf}53?7;oacV|%hf}h`7lxUi~MfMAnFcL|1k90F&kIzUAL1b6;byvQTNLt4=SSW zaTWFIea~uillp7Mcqy^M$$b@()}V^FbtCJ5cTRLVli`zFz2~nq`_hkbcd){C+iqN_b}(VU!=ie5OjwqSEnB= zU!ShfyY801+YWN>5Oq7r7&-Sa=eb{`U1N}Qhp1O4&nI&3VRG&lY1bI!+#%}K$vQ^P zJxtF1BJCQ3oI6ClI$6iaxrfQQU!+}QkaLHqS10QjIrlIJx?l8@;OmpQXZedXe+**o z5an}~=8r+l9inb0>liWjFfsRwG=B_Y?hy6rMc#EcS;t7Zhe^3#x~yZQ+{2vb zev!_ULCPJXezLNTk#Y}np8G{QQwAw_hSP@wlh*TFd_Gg^tlW|?hy6rW%pl_qQ7=x`F*5F9&U3#=*UTW}4pFa8)-f{fVa{{ENY~6D z;|@`;PS!Cp?qSYzzev~2Amk2FuTGxrgxtf0+|o5O$hbq)tIO-yLBt)RY^QF^$1d&v z{a^pujw|i1yXAMqgM2$g-7aVBAl?p9x6A9;LAo8HZkIE55N?O4+vRoaAlnX6x62tj zh_*x2?eaQykZgyj+vSWM9O4d9x64b#L9iX7ZYQZA*FH?H{VI1csrF$~?N{l+IS92w zRL^zVNoEPP4-;xnKRsRSvU!+Ld-_RgIlz6GRQvx^cJ8{71WS^Y@BGNBo$m&cI zbD#3?li+fOyP04+{3N*~+s!1~;V020+HNM=4nN5**>*G8cKAtn3AdXGw_hf?oJqHv zNw>pJ;zqpPuA&~_Z|VcJXyzn$)F*M{D0edfclb%%NVuE1V|n;V+=#fFiMYd0;zq{Z zOve49r;m)gT}A!pm9t02-Au;)q9>1xyIn=SIz4yz=1Vgf_sb-ADnjmNLhcvo!D)ot zDe4C+_bEc|WA`7)+$qY{NovWsn>oz=B0V^bj5|fWIJt+CaW`|A`(>7cCF5=; z<9?AIoJPi-qJFS)gCgT@CgXmQZAls#cZzy-k}(c*HxqKd$hIVnkUK@aI>{IzcQYaP zi)>5M2)R>~tCM>%8Fw=o_lxx4G&1fK_2MLBWZcbU+%M9D)5y3})T`5T$Cbil+%Jn{ zjEuXPv)nJzgVV^kQ`8SuGR9f%WA`7)+$rkSNyZ4do4INEi}c_$Lhcmh>g0zd z<8J1jn2h^nm1jjV z?q+UU{vtg%jicNt>IW+?wS?TwgxoLEgVPAPQ`D=IS6V{uW{z^d$S*<0-Au;)B0V^b zj5|g7SfvN2k#VP}+eyaAxSKi2{USX$jf^`*y*kMl8F#yix}E;A==^9V<9^v>9pfZ- zGa>hjY{1e8xl_~+Rzg9@-L9f+C&x<0-Au;)BHOt%GVT=h;$-0=<8CJ7evzh`M#i0@ zUY#sFWZcbU+%M8J)5y3})T@(Fka0JYalc5@Oe5n?QLj!G9zyPBLhcu7nrVdGDeBcp z#t6Ba3AtbNSQo%XbB_B(nr0dqcZ%|{O4Cdu<4#exlZA(jyP1spMVe+B8Fz|$b+Yh~ zaW|83zev+eBjZj{uWq~zv|FQMVgkpgJLUin`sHu};XHqHL$d;YGWf zpW%LyrkPI0ouXdcxQ=x)?i6*qF=L&KJ4M}YT*o>YcZ#~*n6XaAouY0xu4A2yJ4M}2 zGDgPTUB=xcV}#t@h1}9K(+Rm#)DKoNM#kM;#;tB3+}$PIvT;o(;7(CKR@u0wlW(V} z+eyZVx4VnCW#gJox}Bn4on(w~ySs2(Hm>Pp+bQbRNydn_yNkAE>qn{fM8no>I9c8YpDG`_^!-Nf5bp2UrOyPGrI;U{q;;O-{i4nK(-33oRM zclb%%h`77CUwQaR+{n1Q$+%y?IemPfGB+%L{pRd}Ty&FhzkYM_Ftggt4a;A@Id}LY zZ8sVBt2E7YGVT=hsL73rkh`0Z`&GWa(+Rm#)T@)*6d`vvA@{4KmW;b!MY%X>n(3V5 zPEog$dlVUWHyQV zalcB_Oef<`QLj$V9ajo-ko#4dW;z*nih6bO3_!-+%|Y(hMKVUl-A%^*Dorz;kUK^F zU?pRO+}+%+{8gG}Iw5z8a&>a^B;)QT<9?NnhKR zgxviq%GK#F!FLLialcB_Oef<`Q7=w1M#kMu#{Ig5W<*%}FO()|{QLj$cF%EKf6LP=G#xUDm#Etf>sUDa9pwHJb-N*B;V^%-YJ7>h z-Ej8|hrgX4U!ra|Tqxo27jl1zy4|pjg~Q)JKYfY1-H@?x_`6hmiMrjej)lYDRD6lD zogVAocZzWP6m_>@nlT*ya*Hofw;M9H{s80t5_LPt7#MfheI}%CCm93d4!h5U)a@i= zVBBH%nUK1jWDJZu>^>7xx08%vZ}PDFOi0~Mt~)^Pu=`9%-A*zF$Q^c{38~vj#sIm) z&P;_C$55CP+^=H~&iVt4`%9FMwMoXnxWmp2#kg@zIB=yf8TV_GjDc~7w;76Ys}`orYfXIUvgwZqL@ zDb6Fr4+n#PD|bc@I(HC&>lb4nHp&;U|xvK-=pN6K#i|WEX5Z{Oov0cmcP=&wIT% zk3BBo@R^8z#MW+KqPpIOox}}zJN&%&i|~`Ufp3SO8;`MxBrLdYm>ZQxeG)ei?l5=b zF}9I}1y>FeaYua;H!$uncjF;4_$ZZOcJM7F{=w-)Ln2h^8_TWT4pE>xv>6vrf z=keoF>klyQFHydSjy*Wxz_$#Oai7PHYr>8XROTS}dF;UnJ1!U|<35i)IAO=fDRZ;( z^Z4fBIB#sIm)+kBLgl?;qK+{~3? z?7>-ofN_6`awryg4glj0J9DKNdvL;mp)d!z&*R6V!j7RZ8TWbY!3jHt!erd%apRh> zV<=33adVbgae^v? zCgVPj8`s3SV<=3#8TVu|?(?{D zO&lvjVKVOXxN%L`F%%}_J|D91ka15Y<35iY*F<$(DNM$FJ|tsg+>^<;&*R25Q5{2J zGVb#sH)AsH$zIva86)GKT*fU; zGZP_qih6Z&8543(F65S`nTd=$MY%djEXKCi$tB#GYvFHq#$lgqcIX=Wnc zPEoH;o)t;ACzozZ)67J;ouXcyJS&oIPcGY*rkROoJ4L-Zd43|XcH$++LXId}XctvSg3 zHf~(APGsCE>QR#$6(RRzLhiS5;5p-z2qU+>^<;-=t|~BI8a` zK2~X(naH?P)a~?O848neze&@~M8=(>UY*>a$haqyalc8^%tXeWqF$Xm4Uln9CgXmS zrkRP5J4L-Zc@`k#o=nL7Hf~(APK4Yk%GJqAM#epvjQdTRW+pQ36!qfdIe?6NG8y-q zG|fz8+$rkS>AB-dVKVMFX_}eHxKq@tlV<=j?#X1_Z_+d~lX0i0S2wO>Ga+}1y4{$u znUFh0-ELgRWNVF8Jo$t zQ`GJBrvT%gufV%*H)d=m<4#ex8`rU!kUK@)PBKQwJ)48vZ_+d~6LP1hS0@=Glv5 zbF=cdapRhGCgV;~KX;NbLhjjw+;8K?HBlXSUW$5kvW^jQ&nD!48#k_r>X-@>a=+=R z!;AK8GVV9&!I{apQr(t|UTai^$PCmAE-p3On-H|fEd z$+%P0tCI_bgWR(Tx!UNSbGVa-A+;7r@Gm~+rs8=T$BjcV;#{DKeI5Qb{ih6aDF+%Ry zgxqh^gEJFyr>Iva86)JLP00OrNX7`cXLE-8O^XA}n@z_3COtSa8Fz~EsgoX@nT$I{ z-A*z_#yy+k+i%i?Gm~+rs8=T$BjcXUy~*FC2WKYZPEoH;GDgTfyO3LYaArd86!q%l zGA84m&B^UI>A{&fxSgV0og|ikdv*c0^x(|o+bQbB$=^JPw`Uh`OApRWx}Bn4o&3#% zaC>&)w)Ei4WZNm~)ybPS(e~`3ZRx?8Nw!netCQy^lI__X+kTTCoS9%dMZG#n1-bTY za_x&;#iZJ^NwqHm@n=Hq6xCx5JNY{$q4sP-?eNpX<*T*{wZl(VMowsi7} zxILS2`yxFqGwF7UdU+aO;_cZS;g0eoZsgmuIl~=(5;qQU&nDmwKZzR&_iRpaho8ia zhclb%%$hc>7j{EY>>Ej=1O~!rEvq#1~n}ggJJ$Yo@v&pzGdhW=$XLFGIB0V@W zA$N*;)Z|7*$UU2b+!yJ=nF+a5)T@)*6e0I)4su^4wVdOgO~!qZ9-NtsJ4N|er3Ysw z<4#ex8xM9N<4#ex8}CpH8Fz}h-FSmq$hcF~?Z*4lLdKnULws7DDb6 zb-VFdU?JpAQMVg2wh(fsDBJ0Eg1<*C=4Ry=>A_hz$DN{H-1r=@ka4G|+eyaAxEFJf z`yw0HEM(j%>eWfc$ha4CkozJV*DPe*DeBcp#yH5mn2`G-8`ms^+$rkSNyZ4d7juyN zGJZU2T?n~Tl&jMp7LQMh$+$1Fam_-;ouXcxWQ>e^G3U51vT@Bq#+{;Go!peb0QM#jCEjQb)R*DM_5PEoH;)-giv#T?|mNDt0J$ep5IovdSo+=~gh zFY-%}aWCd(gU$H=%BlW||92WKJUPEoH;Zg*tdi^;ez z(u1>*ai^$PC+ip?_hLfsi)>u85OSxeS0|w$_3Gr|j*NRT8TUmtu35;qQ`D=IM+!3T#bn$U*|=sQ<4#epPOm$@RG5(aA{*B% zgxo3W)yXNV>I!4C5n2h@(O*0D_ zcZzy-vW}5)FDB!@NYl(h#+{;GovdSI+>6V&rDd9?FHY7m^6kat+tM_%5O1fbS10Qj>GtB%ZE2cW2)9$ztCMw% zYLe8e+lvXd-{mSM)?Q4k{VvpfA=OS% zJ=U-rn`RbL?G%Qe9xmT1OsXCA$;wEoy_i%x{3Ny<-Cj(r9e%Pll4~y}*A71kF2VL< zg6;5=)sbX-G0ArLNpy*}7ju3){A7J3+g?nz9exsC!tKSJ;C`2;l!b6RMLixGU*he> z#M@Dx#EpD=G50ACKZzRw_hJrlhu;{t_;~T(eUDQZ=WmQ#d_|Ui-nPt9-x#;}VkZ5( zeVO0o^u@OZY4<7WhpT4~`{2a4+Wzfbx6_k{>Ad*1m1(Ev4&!<8i6GN%yi>&|RCw+_ zMg3sM8&!OJf_9&xZa3biVhexTeTur>c$#^>&pj5|fWxbZn) zCF4#}x04$R8TV>3?ssXLS;@Fl)T@(qjEs9V8TY$1&8%eHDeBe9I!4C5nvDBhnr2o) z?iBUvWE~^qj-D6uGM0=HanU#z?Mfudp*Pd1~?i6)9$ru^; zYR+-L%h#S(GVT=h>h!1JN?~qR{w`m8TFJOm)T@(>5pu64*Rx(D$y_$^sU7BWAGVT=h>Lg=?+^Y$>-(};Pm5@6{y*kMlA@^!R?swU^W+miK zQLau;9bdFf#{DimI4c=f{N9jC(cb zxZkA*XC>rLQLj#}J3{W&oZ^0$9-NhsJ4L-Zc^@O>UdoKQMZ$4MKbQy9N&JI9-NhoJ4L-ZS;xq@S95Rjcj>`d$+%P0tCMw%kb89@ zxAfqwgxo3W)yZW{#=V-8+wanYvvP1dMY%djECKiG0&eNSS;@Ck)QgjKjCgx>@wW8f ztfbp1>eb0QM!3DYa9etCRdUdjnk!-K#*!H{h;H(7O zDeBcpD#*20lWTwIRZLD{Qtc0c_#2^iit4e3-N*tqLhTfW-*~tip>_(xZ(JESQtcFm z-x%ACquVJAzj1BcIJ=#~@Ee1>ad>i_P4u{NtOmhqYrf2f07= zeWfc2)Q>Ca(~FiH5(y!igI=O!}9UT+^qaVdT=%}?iBUnBx7XU z+f~%A~5^xKq@NlZ=sZZ{{5LhxFiVWZWt0 z)yX`qc$?`6!q%lmnGxg%t7vtO)^Hvy_t~vLpHA22)R?#4_02F2)Q>C za)0Qt@}0t*gU$H=%hlW~7Y)67Q3ouXcytYc){o5{F8q-ka&<4#epPS!Cp?#*S~(loPi zbUQ`8y74mJ3At0$?Z%AlWZWsrcIpO%w_kC0-EAa-I{|l!y4|>r?d01j>ULwscH-?6 zb-QsL+ex=m)a}NM?S$JY>UQHgwv%nAsN0Ph+ljVQ)a}M~Y$w@HQMZ$fk!PW0iyvXzw1-4m(L0 zhqiYQXosC7j6>VI2eiXZB0-?Ndq6wvBoYMLyEn8Qb`l8!?cD>~x3b&HPM)2jeA#Iz z$g}sWsN2a^OrE`aJUfn6u3`f1-2>WTCs#3n_U;XBhn-x-1ls#ml+T?WEB^Mhdp!GA z50yB3_x2^f)gvX%-aVRqE1xFX3A0m_&zppwEPMA@_O0}H>_piq%C$-KNwRm3WZz1* z$gy{CSo>C*J9cvH6x9Qj4N-Pt>=b1;i2^D1?osSp*$!nV#7DP-%97i zPK2GJT$?OhB-p#R75T0F2;|qh$FFat&tWINPEkG3MIH=EuXm4L-%6LmPI#T7T$?O1 z9MIl9czr8P2|L+!igImo@e*C{9=g6=gq-aT@CD=h>&!F7u2k;;!iY`uHf`c@hU zc2esU<PpO2X>hgVnb}(s#1z6y@6FawDqVJyd-wn@{W{ z)hWug$-R=GdiQo5zm=^gc5>+IdIK6vt`c~-gPBxvQT$@~OMAN&6rf&~fvPh8bysz6gJ9%`9@{!6FLL9w&IQmwuUBc+y+e-Xa2J?5a z=oHlh?Q*Xqir&3_#BXIRe^5F+2Pt%ls@u(Yg&c&?De7(`B0mVBQy6yYhkcR{Z}afmo9TxhF4l(Q%A}3@ z#{2m}4xPgA8~>tr5Jaai{Kk+SB+)4hKZzMp^x>iCfBha3G_vT!WYOU#Q6r8%OdK74 z<4SQ5NT)E)pM;l0`tXLVqA4|VKV9PleiH|A10Iz zKZzTu^kGuz@RPU^OCKhd4nK(-x%6Rj=^H(L1k;B%XdPFdo;_@_f0$tU=9`m;?Jy4$ zOy7KS?znWAVERUg=s_@@qJAfk8x_IyVS?!!VWJ0j6HigEPHs~~(}#(sZzQ!u(}#(s zZv=}TWYa0i$0{@L2jO&zx}6>@Lvcmbbvwxz@$_Nh=^Fv92LW}8dUbMtBB4IKN$cAi z`R>F)M4h5uon(xR`Y;*wjeK|FAf!%FuTC;XN`07=`bMr3QtHDSw7$I&7JLv>rzjt* zz~FGf%S0}Wjpy{Nvsc(Sl=gCtWE~^JKCYr}CmAEeK1_&xBO~+&DRzo_b&@e+ z?8C&^H+t&$qHSXA8|fxE$gxwDk5xwK4}$CzbvwxzQTAb?>>FuMILNY7)T@(>5oRAI z%)XHk`hzq(MZG$?P>8b+6KCH@!^1(IouXcy{B4#%`|u{MZ*OFT{vgp#QLawzCnVa3 zNwjaIh2r3#b&7g%vW^jIAKsw#?Ts{19HiPQ>eb1!BC+=24O&Nak}-1a!{pjG(v@)# zY^SIntYnO2`?!j_om_WB+lPs^Z)Al2Alyz-uTIu6((S{Ww7$KO8vyC{Vbbjz>GU{= zw^NjlRYvF!4qB(E+l}j3Bj8R^w;MCoNVrqf?Z%8XBJLD*yYVfck#VP}+l?7(gxo3W zc4NjGA$N+p-FO){PFkm^+l?7(oU~3+wo^B}XtyivuDgwZv5{}5sN0R}SR>v}QMZ$f zk#0AaZgb#Fq2c&BWT_Cu<`IuA9lV!%u?CiR)&9?eLS;kz~7>BiG?4(Iwh$CfW`^Ss%%^ zn>lqIeiB~7?PkL5pVH&fNVikeX%o*(Plem#_H>xGVY(!gVV^k zQmyHQ@%UV$hcF~tCObzLhfcl z?w_)ILL=l(QLj#(1qivD3AumDcPAPlcZza#vXYT;Hz;N#O3c-P(J??+_Z&1Bp^r3a^xai^$PCmAE-ZYJaYDLpuij5|fW zI>{IrcQYCHPwByFWZWt0)ycCWA$Kz&_fKh>X@uM<>eb1@L&)7s$o*4~m7y>vw|`30 zOe5n?Q9f2_nrUR*De86-3Nr3y4sZXIrkO^@ouXcygo2E_nT-3VG|eO`bTaM~_39*JWZd0k+&^W% zl}^T;qF$Y3jEuXRjQgj2ccPPVr>Iva86)HFF5{LRTslX$Q`D=I%b1Y6o0Ho=n`DfP zySt2A-SFLs?hOl+Nydn`yNkD_X{M8Ir>Iva86({8F5H%F zW;)q+ih6aDF{176qU|p07|C{b$+k4jbdv29^@EjE5Nvl7Y|DoyIIw_=Z-6dImmr0 zO*5U0J4L-ZS;xq@yUDn3rD>*0SdWZWt0#Yx715m~>eWfc$hf=7 zxbeWfc2)VmC$gSUl>4e-V>eWfc2)Vlnxo_o{Ami@l9JhX8rjv1}C?Bgd z&2%#E6m>g!RwU!@CgZ-9rkPI0ouXcy-0sM@yUDoqn>C$`J4L;^;aPF}0m%I&>UKlM z!eRRSOXh$5=Rdzh-EMeR42Qqy;!D)+hKz;7!s+7$A4pxuKAZ0dj|(nF>8thQi#TT)zDi^)M7B za*iMpL+42(PM%utNq z6AA~e6ei@pJ>0a8QLj$cF);41Gea@<;DiH1;WF;= zBT8Y%$0u`kTfU+cb_|6%x_#T^GREX~c)OvHi~(_notX-C<4WNI?y(0a>fuV^^6jw) zC+zt6WamxN%L`F%&M@ z9(!=Yj?Yi#*!Jz%gA;aqesaNfmsEgjhqt#>oMfc{)ebjrr8tccKO7he6KaQ@tc!r! z+Yb|Jho2lSpmz9qYeo3U$_T0*e%@A$7RFh+fkpy4S+l9bK@~~k%R>o4s)yWs88Ys#2w~tJjNcJu;9{R zZdQK!=JfG_%4FQ9Z_XaWVGeSizBzeZJ50uX(sKvKz5Or;xliN9HQ~SqDid;_Cb>}o za)-COaL98!Aa~fg!I0Y&Aa~fA%Z8*DbKK!(ref^D2?vJ4oZ~)?8`p##Lt!%R)2s)} zP?(#QpT-`XsE(m98TV=Yc+~a-jQdNJ7mTq7Cma|GlX0KMk4J?amkSeepT>=A!j5kl zS5ZG$$rvDac)OvHi~(|ootX-Ga0KHHH}gSi+_)wj7>cVXpStnmQDMhWn2h^0Zd?;~ z423z!eOlz)fpKp?OvZg0dvL;mp)fZqKaC%c3Ok0vWZb8*2PfV<@ho zeCoy?oGsqP|6<=1b-OWR@hVQcPf@oUe~Ne$r=9uuw2rT}@ghz;^YLlixF*gWLXo0= zu;a60yoR$nbEOzJu8HdK{FI_z-I%d>31@X?D)g5?C}Jk&-`3^g#*atEu_6>H>UQIw zkK&CP$9ffYyYX2uhE`~2hGOi&+2Vbfc4jCx$ru@T%&(X~h5WK)-0|vc+KqoXih&g# ztQm@N8TV=2xMrKkxKorvu}dh( zxF?fwpT>=AqB@4cWZb7+LP5qonT-21Zd?=9aiuUB_i2|4g^YVL8TV=2xF)J&C``zG z+Q%2DiI6)*{X&t95pqu^*R<1itaYw1<eWfc2)QQ{a-ZY|K*l|p6WpiqYfsxm#+{;ktmDQtVaJuiWZb7F86)GKOvZhZrkRP1 zJ4O9qC1YgVlgYSG(lj%Xai^$PC+ip)_vA9}apRi!W%>N%LT+iAnFzU4)DKoNM#eq4 zj9cCKPT>-6X_}b`xKosmRhnid^6eCLJINUF_T=JiX_}cxw^P)slZ+8=PcGb+rkROs zJ4L-Z$r#c0am91Nbx69?G%Qe9xflCOsXCANoq;8CzEQ2pZskRqucRwc#lxwC%MJ!cKCUJg9< z`p=>9CElJ)ydC99+{m{llW&Kg#EpP^G68q^N!&2Sy-g9y4{$unUFh0-ELgRW7j{8oUW@a+(6!q#PV`SX3$++*vuRU!u8Fz|$b^22P=glVLzLTbz znT$I{y*kMl2f1exa^J0zF+%Rygxq)1G&2)&r>GySWQ>q|HX-+&-0jG?XOnT?Nz=?s z#+{;ktmDQt+f2rtqHZS{BjcV;#(gJEGcy@?ih6aDF*5Gi9OS+mzxEX84&)+5y*kMl zA@^)T?z>GgM#w#zo0Z>556(=;ouYoQk}*Q=*@WD8a_Y#qXLFAGPI_==GVT=RW0fA9 znT$I{-A*z_#yy*J+;`H0Gm~+rs8=T$BjcXULGC;0!I{apQ`D=I3x$w-HX-+&^x({d z+$rkS$+IFM_iRG$yYb^u+f2xvqFkNaPsq4ubB_B?dT?ek?iBUnIva8RHoDY(nlk*|=sV@U6YKFanB~>zLOrDnT$I{{a__ygxs?WxupkZCge_0uTCywGVa-&+`bz>9<|LJ z+)h!hPM$moxMvq|OApRWzMZ08oMeo6dv@`*Y+N&wZl|bMCmAE$o?W;t8`sQa+bQbR z$(uIO_Uxi<*|=sV*-lZfPM)7gwr6u}`%X5lnF+R2)T@(JkZaE-*S?plm{fZJN#sIB-x(L>Fw~7=n`$uCfW`^Ss%%^XLEo%{3N`D+p`I`@1@6OCf!a^ zkDJDqczZTSxT8FY8~OHZ&TxmH#EpP^HUW3|N!&=dXLE`>{3LEf+_QM)_As(Kn}gi<-<&-Dk=A6~_urg5jOWefAosoW;4FmPDe6%hZ&V8* zcZ#~*c%NDbxl`2b#@p0F$ep5WH>P&s9CwPk+xSedka4G|+l}|Ag^W8z-A)e{p;)fK zyKXn$p%yak6m`4t2DOlJr>NVF_os!7J4M}Yd>U8?xl`2bBx8i!iwU{!XUP~L_hJrm z-%Ah9Ldcz>e6VtzkZ~{OX65&?am~Ux?iBUnBx7XUi#f-AFB{h^WZWt0)#_39*JWZa9%xbJ1-nuU-%MZG%77$Ns!4szei#x)BecZzy-vW^jQFDB%^ zmzyUU_hQa*-^<1|3mJEc^07(}&O*kWqHZVa7#a6sGVXin!CA<-Q`D=IpMs2gF*hr} zmmZvjj5|fWI$6gExfc_1-%Ah9Ldcz>UY)FCgxrfc$bG*`#t69=6LR0n-HwcVG3U7N zr3Ysr<4#dNb<%^gka4G|+eyaAxEGUg-%Ah9LdKneWfc z2)P#%a^FkS%tFYWqF$YZf{=SLA@{u=E8i(h#(ghMGYc7ait@2a)67D~ouY0hp&;X4 z%sK9RX_{HcxKq@tlTeUxFXm3=_tG@8ka4G|S0@(=8TVoia^FkS%)&wL6!q$4;UVN+ z%t7vZX_{FGxl@#@lLuKc?!}zrzL%z%g^W8zy*PP+BI906#(ghMGYc7aih6bO0!7BX zn2h^gzV@_`ai^$PCyx|l+>6P$?`7kfg^W8zy*jz>2)P#%a^K6wH47nkih6ajjuCP% zCgi@C8vq&iVoq@1OVi9k#+{;ktg>;Iva>lhjL;xcY&npp_BQ`D=I%b1XRF(7nf~I)67D& zouXcytYakGi%YhpX=WkWPEoH;QbDl2m|**tT*buNi;1;=33XpcwNq4&HS7eCk!mj{ z)eb*BT+FC0Ce;oV9(i$hcQ?v+`fkG_#U%r>Iva zCy$JKH5vCWX_{HdxKq@t8}C#r8Fz}ho!qDhxmOc%|B{VsRzmI+_3Gp{MaaFHko%Wj zcIbv$%{lI0vT@DIIqnqYW0j3-Rx<7sbvrp&GVax6+`nYwnw5+@MZG%77#a6!GVWip zam`A`ouXcyWQ>e^H5vCW*|=sUyNFKL=t$+%P0tCME{GVax6+`pu0 zW+mfJQLj$cF+%RugxtTRX=WwlPEoH;)-giv)!eN7m)tzbxL1>L|B|Mem5e(@`BLGIOr+`pu0 zW+miKQLj$cF+%Ru9OV8bO*1PYcZza#a)67c7ouYoQk})#w)nweiq-ka)<4#epPBKQwy_%5wmuy_K5^|@gS0@=G zs3r>Iva&x(ZHt2xO1OFka85^|@gS0~Sk zgxsqMxqs=g;`@=SxkLFc>A_jaxKosmRX!fIl5wY~+sQgc#=V-1`8miR}*sol8tLtLhcmx>SP@wlX3r&jcZmi?iBUvWE~^pUQNdROE#`q$+%P0tCMw% zjC*w%caw|}a<4ArmL8mykUK^FVC6C<<6d3HEj>6Z2e(s{tCLlcfO~ZTxAfqwTV;%-w3r+7?#*P}zoiE!_9Y-HRi>UMgt423zz z{abo)HZtxM_39*JWZav%S^012!P&^TQ`D=Ij1h8gCglDtJvbX7cZzy-@+?5ey_tjD zzoiFfBjip|u1;1mGVaZs6J8Fz|$b$agjl3{+3 z`?vJqY-HRi>eb03HyQV44s!pN9-NJkJ4L-ZS;q*uC za{rc_CmHu)r3YstV`SW$$+&-Sk})#w?JDZk$uCRBy_t;r z_a+(RAopfM?%%R;%|^(bqJFTl@DOruS5dapW92)A$+&+@)67Q3ouXcxgo2EFGa2`9 zX`0!{xKq@tlTeUxZzkjZElo2U8Fz|$brK3P?#*P}zoltrBjZj{uTCEBILN)3ko&hZ z&1{6+DeBcp#t6AL6LSC7W946;%q_})OVi9o#+{;ktkN{Ik#VP}+sVTn8TV!~?%&ch zvypM9s8=To4;lAnZcqMOnr1dK?iBUvC%Au0)67Q3ouXdcxQ^{)+$rjIW5#we?i6*qaUI*qxKq^a#*FP` z+$rjI<2tsJai^%;jTzg?xKq^a#(Vot$ep5YH(tg&A$N+p-MEhJ9NbP(wo^9{?){3p z>uw_v+zGf-)a@i=D7_Vq)#x#M*ykjRJ4N+a!%i|w zs=b?3JN)!;(NDgcR6G16wWQknRT#%Bu_e~tO{^XD$=XP+y_*}9ho1zO!`r(Fw!=?W zN0RORDva|d(Iwj6O|%{L$@)mPy_;-1{3N`D+q*fz{YSp0v=eTpsGmNKFY)$n;_WC; z;zqu`UxiVh#EpP^H;1^RK8YKrxObCqho8iahDe6Cm zoINt`-DKQ<^yHCo?^jW;PR<<}_ii%oKk~Jwos2t0y*jy35pwS)}1?2>ea~& zii~?V8TTJ)n%T*?Q`D=IrvWnV-DKQIva>lh*TZbI%qa`PnP-p$R*|47r! zPR5<0e5}$mvy*YBsN2apM#jCHjQfu?&Fo~{DeBe9PeI1Lo12yYk*1lQj5|fWI$6g! z$i178`;Rou?1bDY>eb0QM##OJko%7`&FqBSDazH!-HwcVHyQUIX`0!|xKq@NlXZ-Y zdp8;PA8DG|$+%P0tCMw%jC(g3_aAAR*~z$5)T`597M&lv$+-VW)6C96?iBUvWE~^q z-pxVoKhlG<6LP1hS10QjA@^=V?mu#SBIDl8IqpBwgR_%yrzjt*d^~C=<4#exlXZ-Y zdp8;PANhFHPR5<0UY)FCWZb*Sxc|tx-EPd-!7=U>bvwE42)Pe)iu;dzJnA6iPEoH;GDgUKn2`IA z+yKb950i2Kksh3bj5|g7SmonU2N`#Yx}9WOjiC+isT_Tl1f*|_E)-A+-jPS!EP?ZbuJ(t~r5ZKtSLC+ir|_Ti#!>A^Wjwo}xr zlXZ+_`!L70|40wcL9m^oUY(?ZT>CJ&_Jdr-q}qo`wI2lHAB5T|s>d33^6W{deV9-? z{Pb|~R&kh6JN#s2B-K95-O0mGVoR)jm{>dfWNjqZK1{A1eiB@Q?ZX7y;U}vj$@XDx zQ67F0U83#7MBCvf>m%9rVQx|$eiB~7?ZbrI57OgukZz}_$4%o)ynUD>+)(lem#^ALdr&;U{q;;yz5o9exrwGVa6Nto-4d(}#U<4wG>|d~^1& zga2U;azA`?^6*F6!(`kK-<&&4A{|%YUC)NxsR+3b6LLSu#x(~acZzy-a-SmPK1|5{ zFv)F-ko&lba&?kgGVa4<+z--&bC7YTs23;qC^GKDWZVz49xOv~1>W`QcvUM$hZ%4j{8A+a1Ju=6!q%#+;OG20`Iz=WQ>gaFd6s5 zA{is&KCYr(on(xV`!FH*!y*sdgxtqf)T@(>5po|U{IF!)hsn4f zqzC69<4#d8PBO+h?!#o<538(WWZZ{2$o(KaI0qSbiu%FoPl55g;|jd%c9JnN?!#o< z536L1kozzp_k;A{9E98{>IW+sBji5J&B`C72j?KY*7ouY0xEq-my+ai^#kH-@5-ai^%;jSEjB<4#ex8$;2^ zxKq^a#)YSmai^%;Nhrv;n>on+ARE^-GVT=h>c)q=M#!C_ZYLQd0e$j&VQ8#x;$QJ4O9qC1Zr#%^c!>kd12^A$N*$by^%=w3|7> z{UA*<4#epPBKQu-OS`nGr{(wUd8z9Q!}ylqfqxos-2>GtYJ4c%`{T&6o#K1E~$1isdm&S zPoJdP&7|7lC$Z(|b~CYd_{sApXSbWlwZl(>%i-;2g6;5=Cs0mrHg8#CiMN}Hx1&6X8~Jv-3Zp)W8v%DS0e93V zapM$sGYNP2N!*CIn~Au?PvS<#-Au;)C`~hsj5|gB=g_mqwZmlGk9zXRxSP3I`Jok*C`~hs zbKEJ)$0{4wG&1fKbvr#+hQegrkFs%1BjZj{uTE}IWZcbU+>f$xO(Ww@QLj#(2FSRZ z$+#b-X{Hf!r>Iva&jN(p?JDYak}*Q=WYcZ#~* zn6XaAouY0x{uG^zJ4M}Y%vdMmPEofT*Rjq)?i6*qF=L&OJ4M}YT*o>gcZ#~*n6XaC zouX`~zXTqiy17~TqcqKQGVT=h;>LBXlX0i0+eyaAxVt&W{kTcS$hf;X$o(iyGo6e( zMg3sqmnGxwCgXmTjcYmwxl`1ulZ+8^cXPAyN7=Zh6LP1hS0@=GY)A>-~Q<9?JLoKD7_qF$V= zV`SXjWZaL3WQ>fvn{(Wc(u32*Rx(D$-A%^*C?AjNWZWt0)k($(xw{FuAEgJU z6LP1hS0@=GA~q_+$rkS$+IFEcQ+aLqx9f(GVT=h>f~9GjJvyxTY7LhXSY+-tCM>>A$K=N zw;!bkr;~A~s8=V?ibUMqMcnF!FTHdZa7zzPC*Mv{KGrT7Bi`;V-j*JmPP(0;M0b&@fn?e3y&>A~qF+bQbRNybRFyE(S~C_OlxU^_*~Suv4-8)gVPDMQy6}FxO}THp?1_KPoJdP-JIMGKZz|zx4Vh8 z!%v<+$+f%5wZl(>OR(KdupNH#1WK~q%`M8qPohh--A%L|e)5<{w%yH5%EM2>OSs)l zxcwwOE}e8cMLixGU*hd15m~%Eu}_IGv0; zMcqyhmZ2~=D}Rz6oKD7_qF$Zcpvbtpxmo#>^x$+d?iBUvu)Qvqj z;lNOsbKFm34^G%I6ei<-8aJ*9JBGp>N2|KP7CgXnE<>3yDJG?&=QoaL>O*7%ZP?(JSX_tiuj61wP6H>2ELIK9T|1cT% z)3|X>I4~6EKIKni(@fYg6ei?;+GXJZ+ces5fr2NB#;-kv9bYQUA?~NKX(sHrRG5(aNp1jO++l4#K8;N? z;lNOsjQeT)+EdtZr7-8WpT?${u;b&C$+(}!uRZNQz_`CeIkIEZOgJzUCgXk@zxEV% z423zo{WLbsgdIcSGVbwfPhrPUxR85nnh86G!kpZG8aJ*9J1!OG;P#WOiWu7tYxD7G zY?=uNhQbBhW7AC7F%&M}9-C(NAHdsRq8y4Y>lo;E*nK9XZYS#);C9%3CZujB&x&B% zVP`%*jZHJ*z)-koyUX(v$aZ*}&rf61OgJzU=G^vEms9|3hqsrCXZbS#uy(k4k5A7d zbq@!I!lc?^Cx5&L)!u)YR6G3Sa6z@h&x=L)$#{ z*fbM%2t|tWbuxbKDeMr66m`4tfgqL;9;~@wj9+`&vol<{UY-21WZaX<@Q9zJ(-OAS$c3LGVT=RW0fA9iHti%-A>jqGVaM_+|Sa3 zGm&wps8=WJ7#a6uGVbSbUm@@MJ6naH?Pluw=X;7nxPDe88TF*5GSWZci=#x?sy#+{;G zon(xRdomgKv-IFhWZWt0)k($(xhE5HKT8kJM97_@UY%r&kb5#A_p|iiOoZGi%GF76 zWZaX6BA$N*;b#iYf6B8Fz|$b@Hr8#67u)Tiy8ACl_!_56(osouYiK z(t|S*Z>Ol+$vQ^5J-KvSdT=Jf?G*LuWE~^ho?N!wC1XU}lZ&>c2WKMLPEkKt$r#D@ zWR7h=OApROu$`h_oumSD+xuj4?H5@oNVO-EYQG4?p9r;6RF5_6;so-A-ZHjd7caw^JB?S|3o}e1+YH-x#-< zfIEfZH^yxy;Z9-rjd7caxKkK@5;rpL*<{==(t|UTai^%4Cufh0do~&Oi}c{kWZWt0 z)#@6y;-;9-NtsJ4M}24;GAjHW~NJxN*%slX0i0S0^_pGVa+NA{%^xl`1ulV<@!?%5pVewig>gxs?UxnJa7OvXK%bKEb|gENzH zrzoE~>A{)FxKq^aBx7XUv&pz$qz7jv<4#epPBKQuJ)4aCMS5^%GVT=h>Lg=?+_O2z z{USX$Ga+}1dUcX9Lhjjw+%K|m%}mIhqFkN)uw>k`$+%yn2WKYZPEjvTp0&xiXOnTi z$i_7@8Fz|$b#i|qeb1!A{qB=GVT}IxMn8gPEoH;o)rnXXLFGI zMK-RP3At0$tCMw%kb5>E_lx`zWZbhk$NeH3*UV(xDaywx8`sQa+$rjIvW}5)&nDx3 zk&SC+GVT=h>g0Au#yy*i`$aacnaQ|Q)T@(qjF5XaA@_?k&CG<{DeBcpCa`$d{& zW-{&+_3Gq8A>*FSeac^?X=WzmPEoH;9_|RaXLFGIMVe-2Lhcmh>SU26&{URIJ%!J%2>eb0QM#w#zGu$t710ds`O~(BqO*1nYcZ%|{ z%EmP_8Fz}hovdSI+_TBJUu5H&nT$I{y*gRP$hc>dalgpMH8UA^ih6ajj*)TCF5{Ms zYi2_36!q%lGA87n&B^T-*|=sV<4#eoP7=$p?b#*V(lj#@aHpsjC+isb_U!U)*|=sV z-cC`kZd}I}((M#=yD?)6;dY9;-MEe|WZNm~c4NjCqU{uQyKx;`NVZed?Z%8PB-<(K zc4I0Qg6$MlyVvn5UO2X$qV6_Q_k~nDg<+?D=q6vx4{*O~)67Duox-SZTp1Tq?G%Qe z#FkilF-N!KcqO;w+Kb7x!%u=su)UbW+uXAX{qmEZw}p5+h2bZ67xL}J+^0MaSK>y%y_iGX;U{t96!&5h z?(mbi5pgf(7gk^S;)9k)T@)H0W$8z z+^qannr0S4?iBUv_3GpqfQ)-FH!FXYjcXP%?iBUvWE~^q zUQEdSDjU}&R_uTFjnGVaCPto&6ru35;qQ`D=Ib&P}DiwU`3W#gKKkUK@aI$6gE zxfgSg`&BlsSqQmPl&h1w9U1px&T+p=)67D~ouXcxtYc){i#f;rDjU}+^@26%|gbVqF$Z+vSi$gImrDg8`ms^+$rkS$vQ^Jy_kdCuhN6F5OSxeS10Qj zA@^bqa=*&$iHv(O8TYI7;4Ea^DaywxJva*)cZ#~5tYc){i#f;rDm^$08Fz|$b+V3; zaWCdZ<*(9%vygG8s8=T!3L*DmLhe`T!C45oQ`D=Ib&QaEF$cL{r3Ysr5zG`K$EcEM(j%>cz=AM#jCE8sDm^$08Fz|$b+V3; zaWCc^_p9{aEQH)C>eb10N65XHQ{1o8gR>BFr>Iva>lh*TV$N{CjyHgnj5|fSIO)Mz z$+%P0?Z%9)WZWt0cH=s>l5wY~+l?7p$+%P0?Z$O%CF4#}w;MCIl5wY~+l}kkO30m} zZZ~FZCFD*~x6{iQe|}nB#w|TKD-m~!a&=>3R|4)7b+?h{ujJb)>UNSb;_cPN+tP!x zl5VG{S0@=G++JO{-6dmW+pEjAW#gKaXgfvyU?pQD+p9~q<>OH+$##l*b&@fH?bV#y zewB|$t>oG%s@0w4DkjxlO{#qsh`$nQr>GYv8`rFa+9?b_JzVT&u$oXi4p&x2PHwLz z)eb+2El0Ok6KjW`wyuDt9;U{q;-(Jlb?l@eD8;7`86L5#0#Epb| zHK(}4PvSbb=jC(Z)xzBp?$hcRNai70AclfNu zY7TOrr3Ysv;Dcz=AM#jCGbKGa?!CA?;Q`D=Ib&QOAy^6Y> zWQ>e^H5vC=Hm+I8xKq@tlZ+8^uO{R^OVi9s$ep5Ioh&?r+^Y$>&vL9}+^adqeU_$~ zm5e(@`Bzxp6!q#P6lC11$+*wbG_#U%r>Iw_7YcEn z$+*wbG_w(Mr>IvqE<76{cZ#~*n6ZtJJ4M-Ue30G9xKq^KM%cKKai^%;jSJ64#+{;W zH)d=j<4#ex8yB99j5|f$Zp_$5#+{;WH$GBq+?_l{-EPd-M#i0@ZYS3rA@^qPO@5Z9 znT?P;MZG%77$Ns&LhiHN0LZvEbAtOUO*0!AcZ%|{%EmPt8Fz}hon(xRdo#zk&$4mN zM#i0@UY%r&jC(V;CO^x@H5(asih6aDF*5GWoZUXl#x)xucZzy-av2kHZ|3CoS(;`x zGVT=R>Ljro+umHlEgRQt1l%d=#mPEGzP-78TbgDz;_Vdm>SP@w-QHZfElo2U;dY98 zb+V3;ZEr5ymajc+MB6Fq)yXx1R>am8MJbRLAZzk0aKRsN$Rct2J4nJ8LNwqhVYKNc1mRNf;v3B^$+DNXwnOr;k zB)A0In+dkVPgX}xZ*L~q4nK)5(e`G}Z-<|(k7V1M$+p8!!b`ZlnG@V^(loOXZl|cn zP2)?vy_tAB%9FT}Z*S&4<>4oBBjDc5A@1;#xRG#gCgBc0i5n63W{z=(pTv!fdovmL z+c&2VErXjm$Nl!r*#o)QOve58&B?=-AKMjp*Dq#0ci0DKGa2`rG|g;e+$rkS$&HGT zdov;Tn>5XAgxo3W)yZv&kb5&B_nV}ajC(WZxZk8{X5$=pit@3}S{*}S&T+pE5H*=8tZI<IW;UEgAP_GVV9Ixs!2kCgXmSK9Y@$ zJ4N|eR;X z8TXrfVrV1dPEoE-ZU98wn~AvJq*G%f;!aU7PA)q#?#*P}Z_-+^k#VP}SEuI=-B6p! zxZmU>J{uW#ih6bO2tdZYnT-2QKH{^Hai=I(Cy6EE-pswq-=ukABjQd`FHYVoh`2X% zuktr(Uf77ZQ`D=I%Z`kDGa2`rbQ^4B+$rkS$s+(6_h#-@{UQJ3cqigc zQMc2p7=NMN%`xsb*|lOP;!aVoZd?|3BJLD*JGqL9xOa1(@;4#oI}vw^dUfN?b0_0Y zQMQvz5OMG3826hH^PPx0MZGw=?1;E`6LG%@;@*k4Q`D=InMnAfkZ|wj@b*PG&rZUfqF$U}+MS3yh2f`%i@(Y4CgYC7mAgAB_ij?|@RMg_ zV(#4>-VQ$r8Zq~7V(##hq;YtAH!*kk$$~-5y_=Xj{3L6{+`Ean!%vnBV(#6<+~FsS z1~K<;V(yDz(4CY!MLixGUsCSfq})-S#Eq1DHz{}cN!&=ecaw65pTv!rdpBpe!%yNy z%)OhKJNzVW#N4}yxi5P9NV#{Da$of95pwS)R^iOTxXITa{k~)9xhPDaywxn06=O zPEog$TM7wxytG)4wwGD%C`8=5iMTILZQMZ$fk#O%O;l2o_-HEtU)T@(qjEH-`in^UVH4<^} z=2qnw8K~chxKq@tlba_I_ik=gevumh3HNRi?u%gBorF6@`B+!I>;NuylW<=I)9xhP zDeBe9xg+AOuG|tr>IvaH%}t&-9+3M!L&OOcZza#l2}f0?gR5}iVq_06lJ?{p*TpmQ`Fr?OnZ=Ur>NVF_u_+u zJ4M}Ye4;o=xKq^a#>?*D6nBcc-MB0sMBFLrcH>oi5OJrd+v#P8P#h-Wz8vGt^C03* zQLavkBjG;GA?}M{+Jl5UMZGw=>`1r|bBOyQnD!vyPEoH;u3{qY!$jN{!L$bvcZzy- za(^P?K1{@YX?mgH@#!#kD!=GO%uJYs`y!b3AmL6?K6PDgo+R9dImCStOnZ=Ur>Iva zmmLxJVIuB}>}Y=wai^$PCpS+b?!!df7unJNAmUC@uTHKzBJRUP-0ymwFcT)>eizPj zkZ`A{9&6aiBLxxnVIuDElfxzBKFl%h@RPecDfeMg?(iF*jSph(6vp|Jpb>K)S7G?c zV+u#P4-<38@k-Q)xepU_ho7t%#N3C8xx-JE3}WuX#N6R0;U(riOw9c*81x|JPEr4P zHNK?Whe^4kJc%1A_hC}*@RPWaavvt;4nK(-G528(bBCYAjhOo|F?aY$+=#gk6LY_R zbNT=-4wG`fe{=S@c9@X+{hO1=2P%_szw5ap;yz5o{VtgHAmUC@kDA=5h`0|EalZ?u zJ&3qd)T@)*6sNck6LG&wYDu^cbBOz0FzrFYouYiKf@u#D?i6)9xuuYBA12{`7fgE) zai^$PC+jT{_hAlkzsof3LByS+UY)GAMBImoxZmZMAmKht!u>9o_8{R-Q9f3|vj?}BL$BJLFB>Ljrw+=ofH-v!eiB-|E|~Tp;Z9L6PVU7d+=ofH-(~OagM>Rpy*dd6hqwW=YV+(@`n)a}NrxRG$DsN0Q~T_fU7 zQMVhH#YV)PqHZ_dP#O_;in`r+*)<~W6m`4tuK_3Gp*CgN@;;(ixQ+laVR)TMcqy=6e8|sZdCp* z7cmKUGYR**VA@8)ouYiKf@vEGcZ#~5T*VyXZYJS=mpzmlhqzPJtCO225qC3(xZh=( zwh?iss8=UfF%fq&hq&Kmnzj*fr>Iutce{$Zo7_A}xSL71KNQn8BJLDMd3v~9 zD@?{6^+_%`$K6cI9e(4V78@~l3gdX?{!Yx@Ow1kiNz#b9n~Ax@Po7hVxtoc(!%wnC z%-ziW%EM2V3}WtPV(##hMT3~TnV9=SFlZy?PEo&H1k*NB?i7Zf#Eq1@nUp&YSK>y> z-Au|IeiAog?q&{iho8ian7f&nJNzVW#N5rq+#h=SNV%Iyxj()+duT3iCglG3=Hy|g zgJv@Bk8jQ${zltO#QhSVno;%?>;_lIEGM#P<> zUY)GAMBL3p+#mW&@XgyC;{Fg!+eo-ml#f*~Z6o1MQMZ$fk#IMYaDNDeb0Q zM#SB&qHZTwF%fq&hqymvnzj*fr>IvaH%}t&W=?T`$Rh;_cQXn1hhW-9!kwagtTIj8 zNVrqf?If}!+|Asl{9~1KN5tJs#QhGYv?-eB6%_Q6(f@vEGcZzy-a@i4aHxqGx2&QdB+$rkS$<339yP1gl zLojV4;!aVoP96b>xSNT%KLpb@BJLFB>h#p{mBJ+4AA)Hc33rNmaq%5qC2Y_lIEGM#P<>T%8uj_iU4Je+Z^+B-|ob&af~;VPQ;y}Ufp=}>_prt z>UQIUY$xJQQMS|KmcLu$_ABnLyN#rwlW?b~+l`l9C*e*}w;La1I|+A+y4`s5>>T1w zQMc2}4t*c}%Dd}!t!re{6{UMmPlW?b~7dPHKI|+A+ zx}99bB;4I3+#iBzI}vw^dUfN?vlDTrsN2a^OvK&IA?^>ErtL)BDeBefb%(z`b#IFM zB$o*RclQAINhnVz-%e3H(r}YIG5L1)_;%RIHB7$Uy%FxPlRGg1clQ8y*vXxkfV+Eu zJM1J9OY0ti8;dEJ-i*&$(@*VyL)sy>?9I|+x;ra2P>H%+U_3OK1~`5lI`x1 z?XZ)pm|(kmU_0#ODkj(N9@h>#xr&LkyN9*IPOf57?e0KS8x9skXZlAt6RCIiF zZ*cqc&5`oS$phLaVTzqNJ4HDV5`Mz$?!oMn5XDZEouXWuM4uqLdm#HH*&@d79>zWi zPV5}jPEkEjp^2S?+9}Fz5_^tmcaLG8ge7(&>=fnN+a#}lVHS7dYz(rph6Kl;dP3#n*@vOx_j*UBn+_=U8gA5CTk4Ib@#~i zNd`ST!F7sqZF;$JRq(j=Nya=oC$m#jYm=3p)Vh0f*(afgozOZ(xiq=l$gI1^tWPrH z*@>)Elxx%ThQGOXk653C9CiZh6y@4vp(n5I-bnUIxM3%*PEoB*Qc7CgJz9MdYS;;@ zQJ;VLga?jET=2{G&h)hWug$wE&~-91iy5?^DHQFjkfpJb=pPC}icT$@~P z1k~LF)F;^|x06q&DAy*}8}W4a@bpRUsCy`E3u1!{Y0_pC}T%Tm%vXe)rDAzXJkYX3{A76;} zOO)M)DY`b(7EhI?fg{EfnwD7y_8 zZy5X?gZL6{U;{Wo~!(|{m4E--Z zi3B)w6#JPEqWu~A|2*#KIC!+kq*1htki#w5jBPd<6$D{8`%su{J3J6 zOgj7|Zh+EZ{+SiycqMM2(&6XEV?=sk!F9vL(s8^JH*o1NcjFg6~J`ZxeJFp(PG>>?A&0;Z3@%Y zVQ1z-FFU5fMAJ7T7L9uNIOUC6pKeAj8eiGrtAz=tZ)OPv=yZ6Sp%}?%IPmSl#M3w9 zH%r5g&r>F#z8TqQ*m1q^=B(qVkgFJoI=szL=r6%%DHBoOjCeHa;TwjxllbXoQjCN&z7@q#n3(!zk$W*fb$FYh7#V3eFcjWS;_*|+Wd~Fp-sVa% zQqpi>C`?v;Bda1^Gfr8C9ajo( z&iZsSveNkC8AD+b>zh>`0f4N-+YH4>OT&SoFq!p@Bo@p%tj$b}yfhq`2@_i1Z1Ua% zY8~EYC`Mu$4h)5ft#3AoEVy-en@>+8GYtoZ!X(!>n>@$@U5B^1QjF9zzT3x8nC$vy zlY24Xb$FYh7`bUUFcc=ezL8T0dL7ngC`Jq$4h)5fuW!b0mWJJD4nF@7eHG<<@i=7} zb_|6Hux~~Z8+KeNuA*L@{uB&_H)nmi8Ch&p$Cbil*f-;pWqf^-p)eu#jVu&^*kNsE zV#KlGz)YAF`)1q>H|+RIaTVnscAT;dJBGsK*f%4Q4LgRyB-uBIEQ>(d;r*GA`oYRo z43-^s=1OtM%@Z&?>^>7xuTK670Gb_k=1L*Ofo8||R6he!E^g$q;qaM*&%2$8vu~Qb zKY?e5_h&-t)ycajfOgoKD@Bth3hX2vcAp8US0|Spn0DBik55hRPk`ECXNF?@W@$KZ zrSRsgPd9QAgKCGhnTc`AG90*2cw^R4-1s0H#Op8DPEr10$8VM%0la8ut`y^xW!Pb* zNKvnDym`h59IG=!F>Zz%)nTPbQLk>iiem(h)tR9fH^YtU@c5LXTHQ~*PLPTJPubn; zHWCC`o3`h>k#)bytY2e{7MqeFQUW392kkCqjWKqO1@`_oIbw9bm4`;0_Kp*XqB66J zdOAvtz5b`ue6^lw+dv(!)!P&g%Crr-SkJptw0d&6H10ML=U#4qx;L3Zf2MM`{`%v+ z$rS5(cZ*i9Ki}I}9qV~Jqt%n0hH2}i4cWP$Uw^}BGR6M9z0vxUy+-C9Oy+L&`e%!Q z%pJkl9{o*YAah5^*VE<9?O`hSgG_|BztGORhN;}Gp7clM9!%wK^<=wIxd&6ZTRqus zWbVOa?p9B>8<~4BnY-1K?MCJvOy+*L^YQW4VJi2-ollSV4imW_?tFN>cbLZgaObn* z-Y|*#p&wjb1`>CK{LYnwio`vb#Qo5ZuD0%Y-!O^$VUS~r#66hA{UE!R!abP6{UA&` zP`D$ce-gs91BE+6zMLE>6z;(k?gwGo0k0EpKV|cQN|<&aaYx8stgK=Z_h1tDgD~wt z;*OB+PJR*;?!gr92VvTQ!W|*soZK2I+=D6H55lwqg*!sNJGqfz3VRt$;(idO9Z1{} z^4-Z(BZ+%3iTgpAb|7&_$ag1)Cy9G7iTgo*5)|&i6z&IM+JV9yA$_gFv;&1ZLcW}A zSqk@H3ipFB?Lgv=knc{G9f^A|iTgpAb|7&_$ag1SRY=@}N!$N62?4KME4}U=sI(FzrC%j*#z89sx+)gGt;E z!n6a4J3_uYIg3f$gGt;EasW`c2UEBoglPu~cZBq{3eyf0?g;sEau!p#2UEBoglPv7 zcZ7U*@}nSe4<>Ox2-6NE?g;trOx$QGk;52kQG2-6N2(q1B@uT_|Kpm0aX zmy@%Y!abP6{UA&`khmk{yOXn+#66hA{m_rjE(3`>LcTj$b|mh>B<_cPc(!%NU(TAu z{h-b9mrtf}KM2zf6z&M=k4~6&pm0aXmy^Sj!abP6{UA&`khmk{yOYC{#66hA{UA&` zkhmk{yOV`N;vP)mevl^s3in_N_k%F)K;e#%zE)*g3in_N_k%Jmg?liC`$3tO#66hA z{jka5N#Y(%;(idOEhO#;`5#4pmn|gj2>EjTx+^5^2-$Ln{5sZ5MFL?@?JAzTK-)V)+9l@yA z-!KZ9JAzS9_8OVHnA6+`W!ggKj$rgBo0rU8Oy)iagBB`xgnWB4Oe0Oq8af-W` z#C?!mOW`i&5cfftwoteuq_0(&woteuub}5z^)KCxQR=QB2`J2-6k{cZ7U%a%-e;7gM+o!nB3L9U7Fl`}mN62?4tC+-HOyWKW(-snUgnV~$c#^n_N!$nhN#OrN6?2IDAWT~*+!4~( zDok4_+!6BSWXn>xiz(a(VcJ6Cj*#z8mK}+^m_ytLVcJ6Cj*#z84o?zyF^T&iPo5O+ zVh(X1glP+fJ3{(eg=q_gJ3_vkJfKjxiz(a(VcJ6Cj*#z8eiS6`Vh(X1glP+jJ3_uY zd5|S>7n8UT!nB3N9U`2_jB<_PSZ6R?- zNOz~r;eV1BQ@9Vpw1vVQA>W)VI|_F(h5OLI=Xfa;?g;tr)VG4Kq z^O66@&oJcw^Z)(d|L6bp|NiGvDcljV*V@WyJxr_Cn|B-a`d^M!8g~SvUcWCYl{R!{rGFn2ZIS>Ec&cB67vQ@L9`*=}U+YQD3) z)syW;=C0;2cdIAcjm%w5=Kg)>2alSN62?4n}Wn$P2&D7)3lYu9UZ%%HF6z*!iru?@sZKZHW$akm9j&}-^xPJ@NRuXrFe0Opd zlenu%+`olsD~UTozB@TQN!-;W?%(p0pm107HRbZhVV6qbj*z}qVcJUJj*u@WTb9CI zP2v76Oj|j`9U=HkhrT!+`ols zD~UTozB@UKN!-;W?%#3%P`Io4n)2Vmw3WggA$_gFw3WggAzx0;VhVRPg{3bG z5%S&XkAj=R9O9NgK-;EuXZKZHW$d{7`SqgVG zUsL{DUV2<9+!6BK$>S4=yPCxPTV8rxN!$_g-N`B@aaZ#_<-g^n$Cbn#A>W-Go+R#S zPI3R1Jwf5Frf|z2qg^V6J3{(eWtz59xFh7t$>B-iuI78nf6Fv&X#L)^b*5mUIUDcrw>X)A?0Li$>TX)A?0LcW|l$a09gn!^2C zn6{F*Bjmf22U!w#HHWx=3)5B-cZ7U*@*qp%t|oE+mX{t^5_g1bcSpI&Qn;%r+(&gD z3U@VyyOk3+B5_x9io4a*%jGw1)3{qb*%wsqYAScD*B|dAnL9%Mhbu2V9y!S!!Kl~o zw2{mm!Kl~YFh(+W1fyQR*G4jT1fyPm%NWVr5sZ5MO=Bc;N66Rfm-9&Fj$oAQx7$eN zj$qW&{_q83H2*61QJHq6az`-wlkG<49!=(M{qz&xFh7dlXHs1J(|RQ zl$RclB<=|5?)sbLNa2o^)Q@D>ZO*>M!Bc!iY{x(k+?^5i2Epin|35|N62?4%Z|i7n(rw;%HO6P`JVC!>F(r_ zg2FxCLcW?Do)qrU6z-!i?MUH{knc{mEQNbCh5IN>JCe8~W;>ViNag68BMdEQNbChq#Y2O*?XkJ3{(eg=t3$cZ7U7IXo%cqbb}+VcLI^hK1SjmP2xVz@}nSekLD2fQKo4}5_g3B#mZSs z;vP-nKFSuOaF6B?_feR3W;x#U$?0 z9O6F8H0?;@j*#z8mK}+EG>5p4GEF;@xFe*y)8_C$$w%`wpG@LD3e%1x?g-iL9%Y?SxJOgCABAa03U`EjbHcPEi93Q(PcN7E3iD0n?Q-RG zr*e;`a<_W&dkQl5Xfk)JCmW5-J(|qj>d9jY-&Q`F%-!nARwHwdCUduX{a%~M+!2iR z(mz{FWbOz?z5b>#k+~z}>-EcdqH;$t%Jsj*o2c9ojC$H1Aa63?S^lU@J5jkK82$Cz zZ6b3=FzWT&Z6b3=FzWT&ZQ?L@gnYgJw3?{g5%T5a(<5?ECUQRt(@r$*2>I^hvm$u4*xf5GKKq5rfDY% zcZBq{3e!#$?g;sEvMDIsllh+VM`7BD#2q2uU4OrwNZb+fH<&QE=JCV2} zq`T9f1peE{Wd0@YM`7BD!W|*soZK2I+><%P{V3D46Nk7Xp)ImG=a)3g(bJ3_uYIXp?+lR3rxs6PolLYcz-C@(#pDBKa!*D6dqQMe=I z%gL6da8KqC_oFcFMBi3~MB$#yA?`3DZs#?g;sEvWh9(llh+VM`7BD!W|*s zo!rMr+>=S%kHWMQi915RJ6*;29qnWi_v0*QF^PLJhqxc5ISTh=3iqQh?L^^@kpAd| zX(tMIgnT(!#T4$z6z)f1+KI#+A>W;x#U$>@9O8ZyrkzOK5%S&Xvg4h?B<@FH+KI#+ zA>ExcN8z4K;eHgRohaN9^3BPzqi|2Aa6byuP89A4`R?TKN04Us(Dcq03v=fCpLcTfqEdYgkGKKq5n0BIYN62?4%Z|i7 znZ*4lOgoXdBjmf2r!f-uWD@tIy!3b?aYx8^C+m*HJ(dEEOxF_>X<*lBa?o{r{RPI(!eosN>o^HYT{A8n%xhHdyyY(lJ zDIDdVOy+L&WUG<6CzH8bJ-K6$xhIpkTRnNUAahS9bGLf3dCA<9$=px!QsIfp9U;G5 zWc$uk?g&P`e!I<7?g&P`e!I<7?g&P`e!IGEH}KAv)6Wjyyk~Qg`$?E~CUHl|ch?_OGl@GwzFdD! z%_Qy!`Eva+HIuj_q|3>&qj1mWtID5*X=e&|gnV<_9XEwJ#Qh{MJ)SAt5%S&1rr;3w zY!dgAy!3b`aYx8^C##smJ)1+^Pr|e_i915NJ2~7b+_U+b@+V>1nZg|*-<;eUDcrLu z+)u)^Gle@szB^fV9O9l$;(ijQok`pg^4;}MjWdZmLcW|Fo+R$s9O8bGY1)~@9UJ)1+^Pr|e_i915RJ9z{kanB}kKMB*$B<=|L?&Lw1Q{1yj+)r`Zd&-}LX=e&|gnV~$A0u(kCUHLr)6OLB2>I@06_dDUlenLR zX=f65gmib>9DYYTo5KAhOgmG!BjlTt2U)(Rd^UyqNnUz9Q@A7KyOU){;+{?7ev+3S z&m`^$`R?REA#u;QkS`~X03`0&B1A>Exe$M4yua6bvt&J^wl`R3&CIb|!I0$ag2_6N!5^iTg>Ib|!I0NOvbs02J=o6z(Ts z+L^)~A>W)Fo)qrc6z(Ts+L^)~A>W-YJN`!2B1A>W-Go+R$sB1 zA>W;>I}-P768E#L6AJfizNY+Horl6bo5J17$!`@%+_U+f@>WkTm-hy=h1Jsh0GlxU$6i87Akjye7XM9TZr5d^5yiy!1T&Aq{W=%eio)(ILI9#-(7!DEhO#;`Eva^wQ!6(LcUyoOf8(^j*u=V%Z|dm+(N!u ze@HD9?g;sE+Fkiy|8f2I-~aWW%VPdL?q^}zg~A;n-<@m<68B;f_p>nVLgJ2)?@m@R zhqxD$xSxe-7ZP`bba!$*QMeaVxSxe-7YcWTd~^M+aiMTW$d{8G4A1 zj*#z8&SDbxV!o&RSzda)khmk{yOYC{#J!mBDSsBGT}a#!(%s1cK;d4@*OWiYH0?s+ zj*xFommU5u)M5(vvoP&K;f|2+PCh#l_hJ(F^Vok`X@6uLcM5Ze`&pQ_{k3bB`w97r zl~qjQZhwRLe`=@8$&RIPw?8dwR+D=+g}eQ+MYEh7o)qr(XX?yyvWh9(iz(dC!n6yC zJ3{^^AwLQd_hJrlKMT_?B<=|L?&J}G#J!lr{VYtokhmk{yORf568B;f_p=-T6z=5~ z(#;9eE)?zv`Es&~DcpW;x#U$>W;>ViNaa68Ez( z?Ly*?knT>KQw4skCgaX$;wE+p;< z`R?REA#pDzaX-u7rd>$f5%S&1;Ys3NOyYi)=MxI|V!o#QS(tXAa7RdAtNd-+g~A;n zUrxSzQn(lMJ>}2xw`ms+aYx8^C(Dk+z1%{+oSaW2?!_eTXJOif#2q2soh)Js_hJh7 zvoLM@4blHRZ2tVV=oa$L$>B-iUQFSB7N%V&+!6BK$>B-jUQFVC7N%WD+!6BK$toss zFD7w63)3zn?g;trblrit7n8VObe-^f_Kmx<&Ao{8EEMhtMmhONAPmXso_hK@4t0x6W z+>6QFt)4tvkhvF=xm!KiykzdhWbPMX(1pq!A-_Fz`%<|VQ@LAvvfZfMi>chLo@_TN z_hKq{t0&uy%)OYy+^wE$H!}BPGIy&d+l|bA(g5%S&Xj{^U-d^L&tMVNLa zaYx8^Cl9hD?$spj7h&3!#2q2uot(ua?$spj7dZeZ-0Ll*n-iv8DclkA(k+@frxL<^6R}y!Ge0Q>nN!+VR+%LkkD~UTox;t$S-?LX!xL<^6 zR|`C2>bccPERO!o8Y9+%LkkD}_5kzBxHODcq|m+%Lkk zD}_5kzB^fVB<|HD?iXR&mBbw(-<=$uB<|HD?iXR&mBbw(-<_;G68CBn_es_Xg?qh) zY;z}Zo|VEK!6+xck|lAkw_wzh)0l56Urpm~mn*+l;2igADtD_V8-vWfnuFY}o_xh4 zbFU_Iw|a6Slet%uxm!KCcaynSlet?x*&Jl<)nx9IFyl()j*wq|x;?1etEt?rJz36F z?$uQ8R!^2Qm3uXnyVcX>%r6+Ga<_W2oT=QasoW?1_^8~gIm><0PmjpGn#g_950A#Z zn#O&)^Vwlobv23mB-5oUg*!riYskSu;9gDOKFQx|UFq8q^4-a?!YS_6^zD=ETF!8< zCU2kQCBPebJ3{(eTK{OaaezBQzFhwxx{Unpcy9FV2-uEjLbZN625S{wVOJVlyYWPr{ZP zc{@VBJ6Xl_?alPW;x#pLbHHq`TAR@K%G(9N<0) zTW;j-2>IsZEGBPn<^cCe*m5IpN62?4%Z|LgneQk+30rRD?FjkqBZ{|D7Pr{ZP zC%7ZzyOYC{zP;T-x|}?pkheFJw@<>B8+kiIzBxHO$=jRB+b3bmjl3Np-<_;t^7dx( z_DR@sBX38@cPHl)d3!T?`y_0+(YGU{yVFI?rzdlO`y_0+k+&n{o0G$nyuFzN+$Ukn zjl3Np-<>Qw^7dxFqx>XnxskUcW;>JNou!PH>-fo$!0M z$=hdfnT@<1A$zT@ocwN#zP*{g-Rj9{OyJ(k8SYk3eicaJ-b~?c^<-m^xVKv{K0o=2 zN8{d1<8J-QiA?3*OyzF%W+^s!X z&Q$KrRPI(!mNS)mGnKp5ljTh1-c03g^<+6yxi?d}&v!mPNZw{5_xaAJhu6+-<|z01 z&WFce(3-}5zVq2pEllD*3tMg!?g;sI@06_d9& zlef?EQrwNc9UzFPNa)++pa9nRm7FV{VYwhI4#7xg#f%XNFK zRrvSfw7(%=u3L7k!oNGk-;giY-N#yme|L(%Az!Zh!qO`IyHorP`EuPuS*!5xPVqP7 z%XNomtMKnD#@~=Gr$32*U%OkipOCL6s~Ei9UP17)L-OTh*@3rPxt|@9FDF|Tyxq$E z?2vpp`Ru^kt(^DT*>lg9tpYcN`GWFuKW*8{aZ}tv{$gbnV|=^S{@EevaYZ zJzKU4yi=IGeV)2UfL4y1;uiADPF68|yVdqy#(bXSEQW8la^|Lx`wn=!RWmn5&z7wM zH-$O9eeT(^mE)!`dHdY6WqSh*H-$O9eV*kk25-08=AEKv%T|GpPv#5C&$Fyz@OG zyvq3m-fpkvGQU&wY}qRC@yYb8WSSR)KrMbz@OGUtY}qPsQ<%Pe-eldux7!=$ zyiM^c>jb>rs(Ckx*WP7X1>Pvk>FrideyafAZpFRFr&dpXtpMO|^}KD->dEgFAl$8< z_pPGUlZ^r5ZuPv4(dx-pJQ#PY=RHHUdU7ITh`ZJEwnnQb_iiwEtM{`}vRkdylg$C< zZtqKUH;3#FD0eI8?hf4^Q0`XGyJx%#TecFsX_(60>dA73a<}5{_UPrUmEdi|RPNTF zEN3WpEADO&ISqi^t(?0%^wZZ zECB9S&fOVuuE4ijIrqLH#|nnHTRC%I$g;x>cdKUJG z+OuUV$4y}laKH9!*~)QKn7sYkvt@f}?aw~A{wa#TA$|YpUlQ9Y@EeB7+pj%awsL%$ zGJX41jwkSTD{bzH{w1-k!p}CieRSrYsB)_XZ@1d!rl_*Vz}u~yd8g=K65A?pQKpQaz7zmu7C0z$lDR})nwU`x7#0+_@7Sm<@&?3eKWwdn!Nog zY}vjTu$;Lmge}{DXJk3^P9bdBz80{YxhaG#2l94={Ewo4kR9mT5%T3^71Or|)3;xR zEeHB`gmiau0Fbu_leb@mEeG;;gnV=TBfvo3j*u@WXEAwuFnRk`*m59mN62@lKMHON zleb@mEeG;;gnW0his{>f>D#Ze#mL)($=k2OmIHY^Li$>TEeG;;gnT(!#pLb5WwwlFskhde`tI2~bd3!K<`&HO-Aa6&=cPFcuygit_{VHrZkhde`yOYC{ygit_{VHrZ zkhde`yOUK+-yTfgeigPH=-Uyp-Mz^d9`g2J^7fm!%s}3bkZ(@da-eTVFzU%VCU6fX zaJS2qXITpOUQ@ICIxm!KCcaymXlet?xIh4uV zgUQ@){j_EK6I=YkZ7O#wCx<+hdoY!|)sy8+&)e^Y}6S?2?VrkriY20u9cx3zgZv0)8N!)LPoCFl^!4&Sd zemt^u$FJQcaK8<54$!v;)3@Jbn~}E%legc*83)X8w+r`vKl>)mIADakmGgc-`zFpf zkhdeGZ@J=(19>|_zMTAehP*wPy!|H5IFPp^1};e+ZN}3X`|r)EUX!gUQ=({aamIcl=$H$=h%0jO6XX zZj~vL`5z@;}oUxF%Bjn5VtGJN2Bc#jqJGPLwBjl^~Pws`h9U)(?|Jq&1+Y$2R z`opu3w5l@NqL^%Tx1j&DcEmy_d;zFo}m?KhFZLf?*%?oOM-e}pQgZ@-BQ7W#ICd~eEUsgu+X<7zKk_OyO>q+yC;e zkhmil{mFSu<1VIgxBg^j5V?yv!`dB!@=q@I7Uql8A zp*uqU$E(|e&|SW;Rv88Vp)3+}ogN42w zA>WNx!g!HwF3>Nx!gnT*KWAyD}`u0U+u+X<7N0qEPs^zDntV4-hE$Tug;j=o*Y z@$HMqV4-hE$aklo9iN}f@$HMqV4-hE$ag1?0QBu*j&EQ3zxTKn`gVkLcd}#2+r{MV zi@Z3s(6=Mxo0G5I^zCB$_C+QT3w=96zB^fV^zCB$_C+QT3w=96zB_pYpl=s*eET9V zPObFq2>I^%v$)c?Bjn5V53-fO9U)y#WUvyrBjn5Vr)MQ_N644!A9yN(J3_u(zl#oeLF(FyZ%O2>Dv+VaDD5z^NxGFa)`5%T5a@T6~7)3+}ogO$D= zA>W-Gp7iZ%`u0U+u+q09&+3w!^uPBwi9U)(>_w7pGj$oA2 zdiY--)qFqsyT0nQ;_q*-5sd!iI3{sd^9|*#KY5s?aaYs0TRqtsMDA+7qrBCVwM^x% zrgFD>awLdCQ8=&mMox69S#%&!;b ztIAtFS#-_zl#i3PH{)bcPHO4=-btt;(iwytn}>&`R?R)M&GXH4EMYKBrt1HP2PSN8Laf} z2Eid$LQPDoZo&I8Laf}2>I^h#zWt(=KS`%$Y7;!N62?4%Z|QX&H3$j zk-hB?3eE;3l@+Y$2J$!AC3uIB5>-$e#1 zeLF(FJ9z}4Z&!1E`(0$P(zhd|yOSMD-md2O_PfYnrEf>bHz!}a>D$$OJ^8!HV5M(I z$akm9j+?@q-+mVvteoGDknc_&0qEP+oZo&|8KiGl)3@IzIg9Dr)tujcmzlvz;Es^~ z>{JE`+|?Z5ewROjSP9$_^4-Y;4}rUy1KjWOHqlDpj*#z8*By6-Il%ocZxgKq?g;tr z`gJ!FxFe*?^+)?i-;R*4*8duBq;E&am+Mc@k-i-vU#@=!80p&)^5y!|bEI!a$d~JH zWFvh$LcUzTibwi(gnT(&cGwi-4ZHK@`tR){2e>1o%Sm(e?a}n@cag!7z8xXooGd%~ z_GrGJ{9R@SNBVYze0Q>n>D%KiJq{Pw%Z;7H$&knc_x3chKN=KS`%EMoHZ zX!7>E$lyrdj*z}qk-?F^9U)&%Rxy2hH0QV9MFvOuc7%L)a(L3WM{|DrU1V^iZ%4>? zCwE!;_GrGJ{9R;lq;E&acK0DSS^D;9`u2y=$4K9fkZ(?A21f#S1f!m;V+!|Z3U|BQ z{#kY;aYr!vlk=FyJ(|Yd`jeeO2ikTjpitK>ra+5p?fr;yVaBBOz0j>=x+67ITN}^ z6S_a{TrMbYG@bk7&eekQMw7We?p!S1n>L!t{UI_qQn@4K*PfgNMDFnx^5x_ppmC3; zaev6$L`TkYM@V-k+l;_Hn!x=bGC0z=BjlUY?(i3oM$@-H<>DwRjR|`k_c7$|yavGDjN0YZdLkLLXL zhy2yTk-i-v-<>Qw`u1r0_J{n{!jZlmA>W;RPo{5=rf+}9Uo9Nz+Y$2J$wL%Io#gPOZ;$5t$v;E}N6v3Y$ag1O zmcBij^V=UHgCl)ALcTj$#q{mboZtQs864@`5%S&1DyDCb=KS`D$lyrej*#w7WN;*K zN643xM^6IxXae_#yiIf@a7V~@C(D=v+@lHHAM!TQk-!}x-<>>q61YbbxIg4=q9cJj zLb^L`j^8Ov-~N!9!I8clA>W*wp7ia}^z9FMo9Ia2j*#z8mK}Y2G=2L+-X=QIwEjTvYY7J5%T5w^J$`QN644cg#zE6OyB;{MU3CdPUiUbhsfYW z-;R*JR*}Jpz8xW7PF68}doq3dLu7EGZ%4>?*MAF`=-UzUv#^zF%< z-~JF8oH)N7A$zf({Y`eFZ%4>ilf#p~J(=^{pM%KYMBt8Kv?uGB!abS7-TIT`n8ZDq zBiyZ?oX0fo$u#a(Pj&{8doqW(TRmCJRPM=C?p9BZWHR?;j&ZkoawrqJClk6qWoB?9 zbVtZ9KY{a!&>g|3C(D`8J(DM>FBUHooJ{5Z6d9bT+!6BK$w@%up3G_PPnj8D^eS0$Jw?9P&C(dt2$ag1q z9{ToV&ToH;3{Ldz2>I@071Ot;TgaD_rzraNWcv1}%nVNS?Fi}a^e4e@-KKAUiVRNl z?FjkiKZ%?Lgf6C0@MBk2( z?oOVb$lH_2+n*wX6JJjrA>W)Fp7ia>d_Vc8$lyfZj*#z8mK}Y2GJX3~WN@NyN62?4 zhbMh|GJX3~WN@NyN62?4XEA+yGJX3~WN;#IM@V-kGB^>qBjn4;=}F+8OyK?$8Jq~* z5%S&XGUoG>3EZC|gA;)}LcTjWJqg^C3EZC|gA;)}Lb^L`4*zF%GJX3~WN@NyN60rP zrzd@TGG9>sDKa?GwFV`QQGkrTkzFhw;V5VjZmZ zHhud`=wqgDN621lE7wcoOyG`S)RT2g;hs(5ZvFMg@l4{5VDu*&gT_6ZGu*8|*%?Ic z*+lMEPu4P(dp4E3)$5Psnamx*`21vZ5V~h`ko!wya3*v|$hW84gU~(Sf>BSFGogDn zp}SqKEN4RZY(jUdC(D`8J)6+o>dA5@bk8Pqf8DuUOy$j{bAR2rT2S6>GWXY=i^Z_T zY%2Gc$ly%nj*wq_auN`^=Ud2^lY@Z9J)6e;B{PFFi915NJK1Ig?%4$HFOk8Sz8xXo zoOTD_o=xBWl9|Doz8xXoog4w2;+{?4{*sx&nZ6w%-<_;t`u1%4_Ls=uOy7=>?oLi) z^7d@<_Ls=uOy7=>Z%&>Z>D#k8zx^dLIMcTyI^hA&R~|oAcXW`jg-{4AZy2L?CtH@jJ>NpUoct*0+q3E0Uz4n2`u2Pa`R?QqfWAGOzWpU{ z6P@YX5%S&1Sxn%bP2m0#8Jr2+5z^hs+eBvqcZ7U7IXwy7^DX4d$ucHz&n9qxi44vJ z?g;trWZeBjlTt)04hEn=dH;5*eK7+Y$2J z>9XT5Xw4Ute~Apv9N>&Dl$0JwB-gp3V8~FOk8Sz8xXooi00W3Uhw@OJs1SZ%4>?CkutX zJ)85}U$ThF+q22rUn+z2?b-D0FPRyf>Dv*~AKfOueWGvA=KS`T%nZ)-?FjkqD#k8zx^dMgEQy1BV@b#?r*XSeLF(FS}%DEeLI3tPV3>V z2Fp#mje7k$UMSoVjC%cXypXsf81?$6iiO4yw_x-q%bC!< zn9$w&ljTh4UQFozzH_;tyv20xZ;`=;%pD>B>FLGdVQMjz`&(pip>jvacPA$Sk$W+b z`&(uP7aDhje0OpVkhm9Ehy25^jfF@5`6 zW(F5daYx8^*MGxU=-UzU<#ZK;Ef&+azeNTY`gVkLck+`UZ!hKq_qWL4Lf?*%Z%*!w z^zFr*-~JXET=<^y2>I^h&O_f`%-58EiwrLG?FjkqWEIo57xOLU-y(wxeLF(FJ2^b* z+l%>*@^AS`(6<-Ux4%UO7y5RD^tFl%F7)jP`Es&l>D!C>e)4aT!G*pZA>W-WJNouw zzMuSCWN@KxN62?4-v#K~i#fmjEl*G6?ZxEnZ;`=;uP2X?zE*jg=tAF)kS`|>DD>^c zoZtSQWXsaG7t^=DWoB@pZ%4>qtgK@C_G0?>x6BMK^z8`w?qn6yw-?j5zh!1{A#g`X zcPBEq5V#}c%jvq~IdXcPFPOeS5iud^tJp=-Z3w+uw^kdeXO-TS#}O&B3=9)3?7x1{eBvgnV;yc+$5Q z)3?9n?+h;V?FjkqWEFFMdog|cd(~yfO<~S&e~Sz*^z8`wiV+1zP*^f{YQqP7W#ICd~-50xDdD_81-ZwQ@9sXxZCB* zZvsf%i#fvG>dARb<6cbTZuMkm5V;p~h`ZI3wM^w+OyzF%q1Rw8$Ve7XK0SZUl5^5x_l zAaSoIasQERM&Mpe;Qk{rxYD;Hq_0(EaOE6#gnT*K6!h)&7V_m}Q*erVHGTV!%nYvd z?FjkqWEIo5SJSuuhzzdu?Fi}afd z8C>bx5%SH+(N5o9P2c__ZxdbV+Y$2J>1T&u(5|L$|B<(euJr8)`R?TKq;IdLZ~u|E ziLUhR29RAPjYWnsc znHgN^+Y$23$>~YoUdQw`u1wRp!|=>;7Z?)knc`TPx|(14sidG znZcF59UFc7%L)vh3*Ft2w{@M`UoNZ%4>?CkutXy_&xLM;0-8do_9ckI3N4_mf9RU#rOA zO5cu%hI=3bAJ1e$lyxf zj*#r`DECv8wzkIBoZntuB5>vNVZ+g3xlcSity?VTTlvjwZ)a?lAWv82h zxV_#&zMQOL+V<+%cDq(t#iZ@kqwQ8sRxxFJ^<=x1lT}REUOm`8-nmxFoyXe8JD18W z;i2|Xu5=@5M@X-d{yA);Xh%p_>o@;K&yJ9;*6;m|njIlst>5|^EjvQCTEDk8LUx37 zvHrgSY-H>R>1x^=6npa&`zWsr-8icqA>CWQ>o*#9gmg7oyd><+8`M4)S-ceN?H1C# z$>JqoZ{Cphu|In^@^yr4YXW~8`8qIms-a#j+nH}7TRM^V0wRvjVTn`~23_2#{5{3yn^aS}U1x;I(8gzC+E z(fCn>Z=+L3NcSd-mrT8RuNgmz?`>r22-)6*_ckhZgmg8zHxsEh52=qb_P5cfBcywi z)k~t@Jfc1d?QIn52*xTsS5wg8$Yy7U@>GV-pZzE1eNVg`3C2e~1 zUM_wV)Z0kY5z@WMa-&Rdo=hKw^ftnDgmiCmSkk4pTS!-v!T3fMu?7( z?oA%=>Cl@uXMGgF+sM!n(!I&zr9yAsl=V^gZX-fR$oBS2?xsZO%|qzpFR_Y^2pu8c zoCw}Vg^pmC=1p2(>&a3kMQSD3aYHxs3Q>BSPIHxs3Q$tyoMs&s_> z+LM!jD!rL1{Yzf?xlyGf9PeXSffh4&KiR!+7ooVwNi*&*p4Y;S$70yl*T z)xY||zE+N#!W*(~7b}M+hOArdpB<9FSXsre>h_<6%uOLX7FOM=nR}uKzgB^J!qnF|mxv#K_2k#eaZ`9h)~%duS%7t`{j)>TKiD4qS_R%Iydmq>ogAJZ>sI?` zhvd7HRSdIk<$iWZzMQUN-YHD9{?)@@`|oXhe7c2ncfI_za(sO9rmT;@`acHP%5hhi zaQ&;dzgCXB!ke;g-N`ZrUANjlTO|M4$-0AGw{qsLm}T7ouUk3uR?+)ktH4`@H)VbN zrOok9Ve0j-UI1Hj+!WrFb!$!@J>l2wzigU!irxTQ1#SuxuzxMG>>${!_RkJUFS}j= zTLo?kldyj+vWj8Yt+u%-`oX?dfzMASV*lzPu$AMj;ug}Mot(uOvTmi#J4H`{tpYcN z_ZIQvuYRzvmE)!`A^TU4f$e`A^G@LnS-0+F6@#){ZS(o5=fGBhcM5OFx^*Y#6EM5g zHosK#AlNGK`N`DmU)?XCS~c#8TSzbBo&;Mt?g`VgfAuEV%JD{V3;FKkdpktC)ixiW zdKGLHxGB7sh#!A#@+|rPfNRJ+wS?-acZwhFvcn5_LE zH(9uLEA8DV9(wv{6}Tz9A?sr+C%?@CZMWjy<5R0A>lnD*>UsByR!@Et0N!r(ynWH? z$$1RmZuNe4Np{<|da^S>+-(}f+ZnB%tYsi~tLNP>T0OaUgSlHhZ*R1Eawr43TRrcN z@zBd)tH3*k_crmioOOEux?6GY%SEdv%Nfw!>bcvar?OUpcMTJ|TYs{g0o|>*yFGd= zYbAK!FroWFFBi_;rkmW|Ay*6LZspv~A$u3f-O9OpL%tF~xm!7RYsg6ekrTNn9FkJoua=hwuf9+Gj9|kgY6lY<;+bXGC0t;Bcwk% zk-_%F%|^KLWJpTa+_>`=Nj3XB)c4*X{`E?)s;v z_OQ(6%%>-j!S=uCSkBxNB7^NwndQt)Au`zh4;{;yn?hu8pl?UW|0MKB!A)WM_Jhda zK;Mp#?@m`SH-+ij50jk5^zFg)?FW&;fxsOheX$~g1A#k2zFhxcJP^1eBEJp90=SI(%oru+!Us7KZpzt^z8`w z=K4p^fxaCfUrtsreS0u{`$1%Ipl?UWcPFPOeS0u{`$1%Ipl?UWcPGakeS0u{`$1%I zpl?S=cc;zq@yYb<2a&;nz8xXooGd%~_F($jnw+GX=A2waZyi=II{U9

    r@4HWJO zMm<@1B<{f^?smEI^hx6$Oyh3#TAda{K;t$ZuMk2le!0! zx(|2S<9)-F?t^wm=pIbyJ_s}pbnXcG#Uj7&C36oZa~}rTxm51KRPIARmDgU4$6rR7 z%6%AQ-x9e86S)tvElAvhN!$mqw}HYPA^n3Ddm9Mc5%T3^&(gOC)3*;|Zv%ZhLcTj$ z#q{mL^zDP#+d$urknc`zKlJUv^zDQEB*@!?$=e69w}HGJA$_f4Zv%NdLcW~rG5Ypk z`u0KWZJ=*Q$ag2tJ@oCt^zDP%8-05)ef!YAd$YZ}lWJl5_Ccod2Ksh{^k*mcZ1VPC z^7cXPjl4aWynRr6qi+wUZy(g&=-Y$o+XuBb`u1S@_Cf89zCD<}eUPcVfxaCfzfStY zv(UFAq|5a?wve|YMR?x&9HL(6=Mx%k>Ykg}xmjUrtvszEhMNcIV6W53+^69U)y#?5)tZBjn4;x+8EG zbAJ0EQ+b8J9U(AEV$N?L z#NG<$w?C(Dk$UCaUQgG}WW`gVkTcXE2tw~INzeUPcV zLf?*%?@o?8`gSn~xDRp`lede>+Xu0?Lf(#$zE+vaD|qR6dn^6VZ6jZ<|F&4@+Y$2R zWEIo5i#fl25PK{1?Fjkq;$s#6i7ju03AofB-f zF6Q|5LF}#I?c?pQA$b2i@F4b9=-UzU7b}mR^zCB$_Cf5e(6=MxyOUK+-!7(aAH?1Y zeLF(3yGL0j)a~Nw_M<>WA#O)Vwa~)!i^tlJdZ|S1 z;-U7VUMWetc%=QL zT|CHs6aXw_>F}j{<*%d>tWsq2hjpdL1EMO*R(sx_HyskD`8sb{!$zo7`ha z*ToyneiZX7l5c-J9I#3D(5}>qnWgEA;9J+1_NAQmczMjr}My zc7<9UA>EpMi6&MT533(#!miM&BcywiP!kIzqZPxzQ7rBX*oSL+YUN~DgEuGT-(R2p@JbhUo< zRuXlDbhUoHRZd_>NLT9*%Sxb*kgnF>=_`FYLbjT=hOJONoqiP7tHkLD>DKzgveKp_ zq^rr|B~4e4rXOXVu2QBWqJZ|wR} zb^?d4tB2B$qIs1j9U*(6f_arB9U)y!&Ps}O^R zW+g{QNcScygc@DFY3oN>yR_))S@feQUZq7x$X=+tTCEtYO{vh;Q|L$GyGn$PknHVAZl*No>KXKtNJS+m2{SBcOO(#uXa1rfS>Bi5}sS;a)?>LGM1C##qUT|If4B6Rf-`bn>q23DbNwpOIS8P z0lIns{Um%>>CX|;y~)-mKUa^RpJZot~r9)wAa(;k!zEj*xCmmK*K4dhZ5*627an=LqTE^mF4Ak~cT~Bz#wC&k@qS z$&H@&T)nC3C*iwFdybIpO?D~ixq2hhPr`SV_8cMIntX|-Jy-9A;7`JLmG&GV-J2{o z+H>{hrJscFD#xWGqEstytL=)%}PJXt1&C_IYPEKY0nYT)%q{tBkegtwwktvoiKX#{3Lug(w-xvTa)ERdme8gU9CSW zN7{3QbTwJLwCC{_($!?S(VjZTwj1v)}{3CrduK#v|kKMUWD^ydia-el{OpGS|MpJi`x z0($iD`C0gGq&-K-Ua0WhNPCWut|r@__B?v_{49Joa{4(!x;OdeKzklj?KwiaHF+?kJ&)ep^RxWHyOH)BA>EtYWN6Q$ zXV1^_=k7+@bA)tnvUq9Fqi4_0^1{uL_8cMIo1B%j=h3t0XZ<0-o=4A~pM~#6+H-{L zh04n|N7{3QbT!$gwCB;Y=Vy7<=16;vknT;E8|``Y?D<(?GJx9o1sQiJuk@g%RT}>WBXwRc(&(HGb?MB*jgmiEEQ{cA+&z_&< zkK2v3=LqTE9zA=0mg&2Z_8cMIo1DDF=h4IGXW_e%_#7eIoABL8e2$Q=CWj^Q zdGrRKpM~#6;&X&_Z*o`?pGR--`C0gGBtAz-_a=uW@p<$HpPywb(4I%no}ZQPXwRcJ z`24)cgC*^G^z8XrUa2|Ko+D&`2r_*)(w-xvtI1(Wdmg>P=V$p_b|dXMLb^9yZg>a4 z=nXzU%U`k^IrtnQ+gsn-M0<{qF4n(Kd!ju@NLTCc%@gf8Lb_UiR!+3%24qy`W>Pk zxpSp>k>2D9^o#J_M1hWwUURbf3DA=V&@aMw6a6_tx;NSSoPnM^etwa?MSPw-e0~wW zn`qAwvKK0RH_@IWq^rrc=lJvF+4GC=-NfnV2-9oyWEMD64} z(w-;po!c+McN6V7Lb^9uZnWpgd*}9x@ZCgvj*#w69`b3=llRW;7kLsSJx?AzzX;z= zeC2k8?1c*7O|<6->1y&2LVKQWAze+jDeZak?D<8e?AQ*e93k7A@ZCgwj*zY<>y7w4-9oyW9G1lA$;0Ot;k$|W93kDC zt~Y*l_VD>d_--OTM@aW3>y7w4dHDPy&%Ctf$$RJai}2k1zFhuu)TbA)8IQ~z62k=aSj*$QCWJ?gCXKw)dBz!j$p(CW56TX{?&=KRAVj}eHA@u3awF2B`&!A7jcQXk(Li&@_E5$Iw>{^M@aW3 zo1XwZ-$J^Y?0vq1d-nYKG|1K`KhGXNpJZgzskBbA)tnvUq9FvuDpI;k%jk93kDC zoRzfa*?aHyNq-3V4n2GJd=kE!Y0nX|7b<)=)1D)wtI0N{JM z%V9};o^K)Bo3@7kr#gG~d=kE!Y0nYTt;vHW?RoZIx_y%AyP5VJA>Eri)6kx0&z?_< z9G0}_`4-Z>>Eh*=1<#&O^0)71+H-_-Z*siRo@dXVPqGte&$DOGC*ix9_8cL5q4Kxy zX4-RvbTv6EY0tA~&nMx#nf4qZ-J2{o+Vkw$^GWz_raebU_ogd^TfwvEldN6R^X!d1 zpOo)t&$DOGC*?cZ^X$z%pEh~0q&?4`J)dOyZl*m)$o@z-IV)+;v-i&Jle|20raebU z_a=8!+VkwabNeLIcQfC)9UIqAz!UW=!FO!Azw~bF%f$45c;fqw-BKtL`8h(i zH`!an=f%V4v+&(QdybH9O?!hqFP=T0i`=|u&x<$yd=|c2IQ<+UeWm?3hlTbWAze)t zFYS5p?D;Hwx6qy=WP6hz0_l12==m&sx6qy=q+64lAnkea=AO^OcMI(~Lb^9Od1=p! zXU}KhyM^`~A>ErSUfT2G+4EWWZlOI#NcSd>Nwnw1d++vHe+c*vy?FL~7QS0(&k?d0 zDtx!lo+G5I$u^}uFWx)1&%$>L?KwiaH(749=f!*H_F4FDp*=@P_a--b+VkSgJ)h-C zko3HG^n4b+TlmWD2-yo2zFTO|5z^JUc9;Iv+&(QdybIqO-^3o^Wx$2S@>=tK1ay*CVaOLpChEJ$ze%+UOaq0 z3*Rlo=LqTEE3j?;eY2Xo;{z1 z@0J@k|Ib`cgmiDRLTJy+Eo7_7+9f?N9zCCh?-tr~gmi22C7kxWc<&x?o8t(@HIsn3h2&#jyszU1e{8+~r&WINEG7tfztIr*YRfL^@e=T=T0 z2r1BuC(x~&9Ka;##T$QaraxE{2U=&tv^Us>T`r_HCb-7=hd_4SHZxQ z_8cMIn)b%6;Mw!5VBpH>=LqTEy<~`BgA*r9DT;UZ`N;N_&owt|r@* z_Pl!b{3;l@(w-xvdz0lxdtN3bg0dv*%aAz?JqKA>EtY=xNWZXV0&K zfh+MjLb^9Od5O=fH~9Q2d!F{Z-a@uDk;Rqv93fpz7BB62_2!;mXE}Lk&#Pz8uOf>p z?KwjFO68|OdtNEoTH+b9X(etak*K;L3M@aW3Pxqwf)uZRvRnAJ%^XiQ~ zzltobq~{3fE0q;OdtN3O|{Y-=KmE9p5xx|)2WCq1toJ->=9uB7J(>E3j? zaVvQA{3^1zlAa@^dy~aWdR{$xeid03O|{ zW-mJMeElubw}*?&N`x z0=;?y-O9-UOoCoLf^OwxOOT*fkD%XF7AerHC(x~$tYQlE>Irl!C##qOy?O%O%E>CG zK(C%aw{o(IDbTAY(5;-TVhZ%?3G~~YkB;8v0rZ=EavK3ULVCmYAKXTNj*za_e{LK3 zIYPQxe>dEy&k@qq`lDncK1WDb>rax6_8cKytv^UM&Ob-UR_k}_#_8t>>0E7h5q&;t*J-<~sD{0T0_s;D%+4H35%^Q1u6It9y&k?d8o5m^ z5waI5vbd3+Bc!XzSxI`{ZXsPwmK*7L^XU0a{>a}(dXA9pO%^ZddGqM`P5#K=MthEs z?oAdi?RmR}bTv77Y0sPY&h0n(*htTtN6&8}iyP@VLiR#sW^p4uM@Uzblb7_od9U1l z6It9y&k@qS=}!UwO?C6;p5H_kH_~&2bZ@$Nc~|i4`Ar_6Nza=%_WUNYxRIVCWG_@? zaU(rPNLQ1Sm-M`OuiSnUS=>m^5z@WM{g3p#d9U1l6It9y&k@qS$#SDTZ=OBBi7alk z=Lp%}v^DMoZ|eC?WU>9_tN-;M*MHZ)f)yd%nk+Zc^X5%Gzlkhvq~{3f-sG`?^t^df z&u=1&8|gVhx;HtHNY9)1%I&vRRtU$QH_x8mHCH&38jIXQqy(3?llt(+XeBS1~t*C(x~&tYQlE<_UBwC##qOy?FwC(T|P*y?FqA(NB&5y?FqA zx%0u{jgp(^&zC!&+k}T!kDo6xv)CScS?wpJH-sD|#OKY!=gS}`3GI3F?D--uFx@!( z93gw9-A--)QwH|@FQvvc={TH)WXm;R+}y*odSf9h~8_mk4) z?kvB5w~A}MpOmiGJ$kkZ@aTUjT~C)YMEY9qXS1a1>GFd~U+a0>qn~EHR@iM1kEJiY zI$rDTwud(qed#9}ul07@I!+R_DrPs%6d%Nx70rjQ# z$7{Xa_VC`!eHnH8!l+wy52-KxbmO(c?(X3+^`%$HYrWmw!-MKe?~vDeyY1mo^<~u4 z6j*(&{-y}L(0 z?Rc%Q+a4ZUUwV~n_2Ab3Qu@cM4+oIzYd!Do(aYqu!ftzbdVT4q9a3t<+Y*R_V5t<(i`Qq-fnx`QugEP=O3^2c6SdCvM;?;UhD0) zhc`xjnf2!Z%Wl;@%)azid9AR!dw86E>Hk3Dwcc)fc%psLM{$VuwfN6o$^LkIvAkB; zJzIJ6)R*2Yul07@!(;7B|A!K<^>*9Co2kC^Zh5V@+a4ZmU;4MLUhD0)hc{P!>Fx4b zZ?`=>-oEs2Ty6CL-2YN~z36EQ;=b1N?jHK=0^`1x^S*lYhIy^9yLoubed*u4dabwH z9^Q=grFYD0z1{ZksQc2tef3&zw>`W$>q~E$*Lu6{;c@q+pOd`S+ij0q$}Yd&Gq3e_ z+ru;Oi>_vvcPsAATVHz9yjIxVJUsTk^s0HSx4U_GGuM}XV)9yVw>>=izVxzrt+(4A z-rV)2pPIbZ+ieezzc0ORUhD0)hX>%7esc0!Z?`=>1Hbgbd9AnG9^L@>#&P=A{P z6TcR;zJ9cV`u!X%el7U3WAZ-~eWV19UkmSoyV{xlitVg1dW(H?aMF?*rW3OFS=szxVm=?j;_WzxNh;{ls>UTArA{ z4|>c%%v*Jj%-?$ty;j(55zoxudl9|X+dXS}YW}Xv4{Clb?%hcGH@RLb>>jl|IDap9 z`rAEfd365X&s<*n+ieeTbo;&k`Y^?e~86 za%e{Q@4w&vOWAvzoK~#_$U9QHoIJU;XRlp7@BYzGU|uhfw~t8a{$x3~C$C+9-rb|0 z!o2p!?GY*6pWNMs9ic}`*OOm+w*R@dyI$`ZOHH)>*R@?e?-8q?#=L%h+#Zp#*DFua z?L8K3@0QZ#bUE(`eeekVT}`w-!tMI=wuhQ%dxG25^X?vMqU}Gh?do~kLrt_jzwPRI z4_9iU!;a7+rGLKi6=cAKcUz2}p}*_y-4XiW5&FBD=&&R7NZHF(6CHMh9w}WjJ!41Mqn{e6-z z)WgouBW3&3o6(NY2anL-)kKFKp+`!$r^|Uq=!5s#@pm=RVMpkZ(*5b(ZAa*XN9gZr zqQj2RBc=P(<-8;G!6Wo{HPHc6;BE7HhW>u1J%05VJVJk06CHMh9x40rsfi9dLXVWL zcV{{8o~=AWe^(P7c7z@&-JhP$J3=2kLVs5i9d?8sDczr*raMC)JVSr)XFA&g-WhtN zY=3v!+dW%(g#NB3I_wBNQo21|emg=RJVJk06CHMh9x2_Qo~AoOA3Q>TR}&p}gdQo~ zpB`5`LLWRre^(P7c7`4)+n+ug>o46bl4Gkq;z}o%llzR=#kR(bUE(`eeekV zT}^b@5qhL_e|nnk2z~Gf{asCT*b#c9bbq>>cZNQAhW@T5I_wNRQnJ4fT`oI9A3Q?; zQ0f_WgdQo~UO)TU?jAcskCZQ{3wnp>gNNwtiuHGiJ4GKnMQ;W5gx)dw;4ykDsC#7R z=!56zt>B$Sy?ey+B)t{XoBEE@2XCgl71U#TN9lt{=^ybl-Z`rt`=E2!&wC+UMH>8+ry>z$+zo}_==`v`Zx<@F%_1{;4%7#n&_}o^hoJVqQ}e*(FYIFKh#8rouNlc_os)< z&d>+X&_8qsW8l1CaD=bJ-Dkq;x%5er0Fq zk<#_#G%Y(rkCd$^Pa9=N=#kRp#6-)E&?BYm$?_{ZLXVWLC)>B|2t87|-kr~ngkHQq z#{HotT6TmUDczqu9F!fQM@rYz<-9ZW;u-pfJe!ssp-0NLrzTovKXgvC>yUe`scmRZ}*#C zkI_Gsfy-_lJyLqt>AAI=M=u_ue<}l)9ivA|_ot`Uj?s(9=%2cScZy!TS@ch3;IdQn zNZHF(1}-~AkCd*b2h2{K(H%D`pE=#kR>>3w*|=*467Pi5e;WAsSr{`4-qWAx%p zqJQd-W2flF8$|z91}-~AkCeS!W#FQ2!krR(W(-YI(Z6#Y{fxb7G|Qo29=dF&XydM|VTR0gg)Mvs*4 zPnYwK(W}SkpUS{>$LNvL{mHX#-A$rL%GT4_cZ?n>+uxn`_|3d} zFLVD?2Cln7^hoLU^mN`Sdi7rB{;97Et~*7KlkI_H%b-{JV=#kR>>G85- z^y+ieeT68%$O7hHFY9x2_Qu9qF7S8o#iQ&;m&(W|HE zpUS{>r|6Ngm#eP}t~*7Kl&+@_2RlWt-X!{`j>gsg%t4Harpl-U|JbLvgy%p4($d1yhN9nDg zZo3_&SC7(LLA{OaD7|`=-U{lCWJl@Mqx3ID*1D7QNa>AoXDja{y?T<~8q}S)ll1CI zdMl_qZzt*1lk`?lcixWDt2dP13hK_=QF`?#y%p4*x1;pxQTo@Nk8mgH)sytEJD=bV z(yIsQUw1yhougOJ(ZB9|emh359;1IL1J~U^dZhHO({pP#k6t}S|5667yK(eL>HhT8 z+D)TZkI}z$2k#WUdc){n%D{D}=#jFQs|;LsiXJIlPY;-#qE}DRzm$RNj?p8f`_udI zj?t?(jQ*tzTz8BfDczsmg?EfzJx2e!^W)%uGO6A$`j;|r-6?vc?Byy0*PWtAO4rlv zwo~-#Df*W(aNRL_r2oIYvk#K2st)*|sLZ+wN-%yR~ zGtTUE(`1(3p6)j@z4UZ9-95W3VzDVOF<2-@jZh{5)GC7|xRzS3hO#$_mVx}Cn3Tbk zmL@8(Vu&adQi*|_^WHme-s#i5eJ?vKRTgh+X5YE*-t*4=IQQ!}x7*l0Il3{7K4f=p>oiCubXsq7T_o^i&%R%qaSh-C^{U{DkBo zM$t(!&aQM{M$w1t4x^{!CnOIsj82lVeWEv245O1|tWQi16vOBw8S4|xSuu=GlBqu7 zy^2wEl8n^}46GPMC&^f!Sbr!+(MdAaCwf!GC^|{T`h@!`hS5nf*4L&!qJQwN?7kB{ zB{8sK7@Z_z`($%w7+u+6^pwQFieYq;jO`P1UBxguNv8T_Z@?(J3M6B7(mfbOS9TOV zB~Jq@M$t(!womlVicxfujP*(PU>IH5Vf2*5z=~mXl8o(Z)10FqMA>2Vl*GV_VRVvA z?UUv)imvP^dP-to#V9&S#^%Z1nNf6QN6}Lf11m<+Niw!iHa~V4UD;vul*GV_VRVv= z?UUUL!|2Kmqo*VWRt%$)WNe@8P1$L5WrxvIa_+(?y0ZH`_msrIicxfuOtUL7uwoRQ zBx8NDH)RxE*-`YA#K4MSbdrqilg*D|bY=H>?kS0Z6~pKx8Qa&Uy+qG{C_9XvlC7Ch zbY*uKJtZ-)Vu#U5GR>~Uz=~0Hl8p7qxh|vV%8sI^BnDOtqmyK8pPcJ5jIQiH&pjnE zuwodUBxC#J=*uv=vcu>piGdZv=p-51mzIMsqv*hP!1vt zr7Js>4hp5)F_fB_~dLT?w+;mK{h>w<|!lm1W1#)9uQSt<~)?dRk&&#V|Ta#$G4;Er!vR9Y#+}46GPN zC&}18*=sS3uIw;+T6!>}=*sRedRk&&#V9&SrrDJkSTTxDlCeJ7!7z%h>?nF#VqnEE zI!VU%$#IxrbY*uKJuNY?Vi=tyWBcSN%rLsL!{}*Q9gLzYyTj;diGdZP=p>nDS7Knr zC^|{T`lP!timvP^dRk&&#SWvBWNe=t-55q!c8Af^5(6uS(MdA4uTAq~qlXpjIQhsqo|Pi~*LD~^EitfW7@Z_z z`($s*FuJzG=xOO4jG}A1k91E<46GSNC&@Is5(8^S(MdAaCwo&y(X|~#PfHA}8Ad0` z*go0(7)IB2htbm#18auSNiw!iwikxcwH-!J%ht>&y0$xvo|YI`Gm1`g3#%QFLwhk?xr`9}2A*MkmSKz&1IKf)8!?sqSE*^bkhUwH-+Z zg|f$IC|%oqt~)4{6KICgwcUwyP$->_p>%DB(m|mdL>Nlfb|@VbO1EPuUE85_P$-8H zhSIeiN(Y5^UlCJGYI^3IyLYr8|~pip`qL+RQMrGrB0c?_j%JCvSjQ-qA9YdeyjX;Xp>q-#5no@rNr(a&zs zb{sv^uKc1qz1j|=XCwyJ>_9q6#!e#pEp{GV+hO#K#K4*zM<>bHKG|!r)9Bg`qi3WC zGm5V54x?uz2G)$ClVqA*iGekv=p-5IlN}7B=-Q5=XCwyJ45O1|Y@Zy58AjK3htV?< z18auSNiw!ij=~J1YdegdX;U51KQhsFhtV?<18YXnNixl@#K4+SbdrqqNq1uuUE5Lg zjKsj2VRVv=?USP$!|2-XFnUH}V9hW(Nyhfc=EpF)w!`QdiGel4=p>oiCubXsqH8;f zo{<<>Gm1`oFW)xl9QS^-bP-x9C zI!VUWA?m|n7@Z_zePVLpFpN%;u|Cn99fr|KGS(-0XNO^Ql8p6EQ%S-B_L2YI7JxC&^f!XwD9!=p-5I6O${4QFM}w^@-luVTaL4GS(;SgJE>X?l5{r zemAhgFgi)b_Q~eVFuG&+neG|sZH%Hjb`(7$F|flZI!UJ4l^EDz6rChveX=<-itgA^ z^o+#74m*ralCgcVcV-yf2_$2EZJKj*a^=_^M$bqL>@bW@lCgcVH)R;zu{({Pk>0^5 zx?@MtGZF(kjG~idnq7&39Y)bfGS(-1Q%2DpJBpr>7}#MLog`!XWbX zVHlkxWBb~)7v>&z7(F9fGo$E^-C^{M#J~=t=p>nDS7Km?QFM}w^~v6pQFOwr&=h6F7*67==3|#Kzv{m9LUgro}c@ie(xC=96t4iV(2{nlGChWt z_|wMn&|n4W73z?$!AlCg6fQnlVf$-Nc#pR%9fWP}(b4Wp&vvEIeIe?l(wk8MElOUj z3V?5SV1?PTgnywcprsVdDxgiGURwuf(eYvxf0xO~3tapyg#e}RZ)J&HE9#ZrxpQ*o zgo>1Pw8CJ6E4N;1U{HtZ2x4GiufiVGU_8FQwit`-5^bpP4Qcm2W{cirTekP%R@rF0 z;I5#ROCSvSLN_a0EFmlRx%t&{rBqot5|%Cx+SuVN;4bH$+zn%mMs0Tii!m0DB|Hci z8-N=O7>p%=$oqwZ`2u{HOjwwk_T@d5f?L|VzP3cEr`%FCe427=^BG~Bu$I94iE4(}`! z8;RvysqTU$UdU{&UO!x^6=2J@&Yq%hl^YndyFOjayXCrD2vetEFSJtI$k$}4!~|y1 z?D|rvm=D#3;+3#f?3?GS!xGqCfQ{$ka*^`6PY)MAz>POU?A_&t zTPx>E_&Un#oLepB@-D^;HTX?$qmH~CZ@=pNN3ek&+j2%vPY?dQ0)AcwKU?5uxl(CV zYsGRSPETGAq0?vf^iZRLnl2U+@h!atsFQ5{$l6k+bS0(AE)NeD2H|_ev%~S_LVU#A zC0|-1W9wCK|9VSru3AAA^<@gE=lzybT2CM#$*m{ws7|q(r=->LI^7l&2BaHYASSw!lxzgw#z}XSITmTQ- z`@DU39{!Ga$M9{`S9p5K+^J<~wl_4O#h`Cdn;V3CKXl)bDm1Y1rOFK(vBqf=?p}1JC1uZM5}+#zYLWuAx(&EUx+00lDj)s+21= zXuma79W;U7-Q|2~z2FW_QnmH&tF4#wV~t(q4PP89)}|^o&`jE4D&3+SqRdw6*MxBf z+eFywuAC&o{E>1VACqM>Rku6`Osi7%3wbUFaHatw)&yh&ZK~8ou872K2w{)hjDCwC2iOKD20l4Loc$ zc%R>TS^J7aue-Y^(GPm}R1Uf0@P@;=S|RKzdV?f>PQfJ( zy7@*V3{7v*4ZT*UG~HwnhMAPIlwTe@MCFUPiEpYlrh!RuB2f9(JJp*y0N!Ye#a zj!oy*ie>2kA%LD$BaZ6dL!al?`u8Scd)!=oy#{03_CClyOrQ59Vrv^=6F}79doJJ; znMUDJE#ZK7&H{6Th^gfSO!%PLhPvi=AI=?e`}`&mXoUEnv0lU{tKh2jO6ibWt9h*k zqu>ih;2T_r2k_lpUNDz~D)S751rn&O86X^qAQhT&`7n4xW}V`jZkDwbVeAuQ=ZAxu$%Ag|n&Gcr8FEsScS z<}+Q%U+3b?s~2VgcpvsVenSnPQ-b^&PJaA{-aR#FY{NK=!Z;aTDC6}){Qn$Wo^l+e z@xp-C@f0yRjN_=)I-YyGOxM6tt==Esw!IJLGm#a3wTi3zMVk36#)3bAg1-;JVE7jUAO#yC z6Ek}!7bf=2%mwlB?|OJ_uiILT`5I&Jrup@y>HdAI-rQZSt%0S}J4@~%XgHUQ4h(vI zUwqIDpMyB-7-2lTn-A~yjjMMp2K(Gtl4j!+xzDB6kuCmYQ2^_ z0ulG3f=jfgb_ym!#ftZ0?F@FOSwiB_-#_KikgJpo-I?bfvHe5bpJX}uh+B^BH{4eo|cVW@toS2fmHVCIx zCnm%DvfCKQR=;~G#`CY%lvwb1wM|)m-`^kfAH(m~l;;FbqA4*8@Xl=YWX9sKg;z9T zVC-PFyg1=M#ow*3e0}h!P0FEc_4Y46942i|dG5(lmjCbYjU7||PUn;=TYdWGzwMav zypyFY|Ki^L9aFxcO-iq58#-J4;}8D4W5VBUlQ1Y+oh|p@`KKLIzOi#kCtF<@Ug((e zO(#oPe&o*2i)kCR)~Yw$?}Bd zgn8;aR4Ep+0~j4MgO|t{>hUs$1#%JmV8)h?PM+Jplxy~U=9k~uvvi>Osp70U`#`RF z$4$NGoqz3t=3{e<3s3LQHBY$bIWJ#4&^(@b*Y=kswkA>gbI<+a=5xOD=3DljwZD1d zydTa!Q-c4GziRtup8c=O>G>D``?338`;|=d#Ql$E56xWLJaG3n`@i+zbn}WI&fNa7 z@=|m0laIdQ_`ke0N%8;sYfrxa^-t|;_I>K>4?O<(a&zR<|M7#XXQ!I?T=+jXedKj3 z&Ep>(o4e>(Zy0~;7e2Q3>HFW+?78{igN+ZbHt%@m;KOIep9tT7+5R7V{?Q8;nkUX3 z`-?w0ceQ!^wr^CnykkTD{`I$g;3vPzHmjHZ@58q|RcKy)cWwF&zuu6q_}K>@`tF@) zhwuB(w|;L?e=FBKcE#UJ+;+xNv+wKw*89Mhe;&TCwW52WjJs7dju&{DSM(r8x2xzo zw*KUMKmEg*Bvtg$l`q2H`b?54`sm-?`p9QXGfArGJ6bCG8Fk=}r-}i|-fB3{>=Ud1SAYI{#~+?ZcJk<+@+Z%D@D<}p^5~wyh4@AHy*>HQpJ?yVM{j@k zlW)0jN9fTvyW0%{lqG*-oKQjF`DE~9(~RQzc~NlS+}c4 zACK%t>1idThqIb{JPldy5F3nAWTp98w;GM`6g`@ z&Bn{b{BS0TOX8^cG&*>if}zp7kNmPXA7?<_Tn*Poc$t_V&W~_)9W_5%`h5?*_1@(v zcN0n<>$RKtIOE65#Qbp7$2ES`{AlUZ4Aj#a`DI`FI9hcxAN>R`6Z6Bd3^y90=0{8a zo?s#1X^s4{Hy``pZswzV;$>of*hAxPN7Vf4($wAy%L|@cQs3ffjr_7VANMG_nUAiH zmx=kq7!i9LbgHQNv?j;rG}-a)Bfsp;N7K5QPy1>n=8vE?)LBN&rv-p#?WT2{Xj(V( zu?xq`#Qaf=h~{ItM9shRQ-j|)|IGbfZ?k!g2Tki{KJ74`%zPZ$ykRTc1jA+-wLe`_. - Maxwell 3D: `Magnet Segmentation Wizard `_. + Custom extensions ~~~~~~~~~~~~~~~~~ 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/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/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_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/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 0000000000000000000000000000000000000000..22c807605b9a74cd105d311a1db14b4f7b07d493 GIT binary patch literal 2631 zcmV-N3b^%&P)EX>4Tx04R}tkv&MmKpe$iQ?*(u4t5Z6$WWc^q9Tr^ibb$c+6t{Ym|Xe=O&XFE z7e~Rh;NZt%)xpJCR|i)?5c~jfc5qU3krMxx6k5c1aNLh~_a1le0HIlBs@W3*RLwHd ziMW`{uZn?J44@A|L=lmgsV6gwS$K}Gd-(Wz7v)*r=l&dnO2K4+Pb7{p-LQx^h-Wt~ zo%23%n3W}k_?&pspbHW|a$R=$jdRIifoFz|YZ<~c6ccIMk9+t>9e;{kGPx>X zDYDGy0}HFnkLH*WBLP`#607veeb`4RCM> zOq3{l-Q(T;-M#&LrrqBU#%yxP?7mM800006VoOIv0RI600RN!9r;`8x010qNS#tmY z5_A9n5_AFHW*>L}000McNliru=m`c2G#4w@{R99202y>eSad^gZEa<4bO1wgWnpw> zWFU8GbZ8()Nlj2!fese{00_ZzNY0#(%fEs_W6!4?ns+_IPZM2PdA% zBqW0nlMpFEB9Q`$M0f~^6&u8kEq?$j#EJzHD>m6i0SOR65f70OBq14%CuEYDkQqP6 zcDvjCs_L$;s;J5&%^rhhkNnCkjcA(T&Eu?8S=?NtVpk~T zE&4MBO0QlcUo>%QW!e=B(Hro@+S6kIX04Vd9+}`r_G|kGHv9zZahm zM?~%bX&OY~h>B67ViqatHf6)6HdP~cg7UjnSV5^I$ljA9(aUhi0#Z8}td}2wSsQon4|@nvOjY1ffiXB#Lwg zJvh?Nri?CKoh}!81SI6&3>;=Z+Dxb>yd9eXpJtRGvMIpkPBDVX5Dve?$TIr6h*1uvC{ADZ*c6k zS$=zi#=V*Z@ypSeiY>2ql5JTP^ns$gpcimJt`S?0pU1pL8{O>|9X>h38x}HNGTbOB8L7D+bpC5GfvyQ zs*^(@h(hka`ekZcONjn3?uO|ilsq?f@31?lqxC(e-`-&B=025z%EDu_45tbVOBUWt zk!Hmtkb=vzt30`UCBqTYIFJ&C;gHSNF82>MQ51!|$fpTO7S+RW$UnDk((-%gszww= z1b#r^`^=aXig}xoVNPCf>kn{-4o#zB#cIws?Kz= z!s#B7rD3thwi~-_w)W^W53r6}7{@)d;~r)|qW{@0%9M@&!c`jUi>Q&p*Vn#^uIXa~ z)xW&|XWYX*N`XWPBK%sJZmoiW#*1Hg7E3ozc%VGhgan^AwzzfpDbw{XOMiNY1Mfa) zWor3Lv|AlM|KKjiW{#Ili`JE8A|$=OgI?Ch-d302yn!kd{u3mD;Tba z=MUL8@<>g^R!wZpWF}|w%%2-gEVP`P))~&zGvQeaBm9g>`MbpAI?MLFB zNv{dZ8kg<3fGL^zAaQe=hMm6m6epa-*!3LTU_jp=&~(~#I!%VnIwBeoR4Yg=&%7Da z@0^m$oJ}}Fy6c^8RAUdEo{Z|f1|RNxgm-jE^}!Lj!wyqUfF4Nxz1L;G>+}2to6h&I zX`)CvWfQ8N9{tn_5f${k0q^bKMyP@(-ujrI{eGLhy?~#7d!EN@ z1-u}l<&E$nP^3f=f@l;yQsvSHrCWG#Rob~5nBjVQ*){{Z2yyt?iPla~Mh002ovPDHLkV1lz+<1GLH literal 0 HcmV?d00001 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 From 0fa774009688d707b319b55f18b16a206d9442f7 Mon Sep 17 00:00:00 2001 From: Samuel Lopez <85613111+Samuelopez-ansys@users.noreply.github.com> Date: Tue, 10 Sep 2024 09:31:35 +0200 Subject: [PATCH 20/29] FIX: Create cone with same inner and outer radius (#5149) --- _unittest/test_08_Primitives3D.py | 1 - src/ansys/aedt/core/modeler/cad/primitives_3d.py | 9 +++------ 2 files changed, 3 insertions(+), 7 deletions(-) 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/src/ansys/aedt/core/modeler/cad/primitives_3d.py b/src/ansys/aedt/core/modeler/cad/primitives_3d.py index 0702b77af0a..aed255fb1cc 100644 --- a/src/ansys/aedt/core/modeler/cad/primitives_3d.py +++ b/src/ansys/aedt/core/modeler/cad/primitives_3d.py @@ -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 From 1b966c4103b4490dc208ffe6a312cf6deb33626f Mon Sep 17 00:00:00 2001 From: gmalinve <103059376+gmalinve@users.noreply.github.com> Date: Tue, 10 Sep 2024 13:48:35 +0200 Subject: [PATCH 21/29] DOCS: Improve advanced fields calc doc (#5146) --- .../aedt/core/modules/fields_calculator.py | 107 +++++++++++++++++- 1 file changed, 103 insertions(+), 4 deletions(-) diff --git a/src/ansys/aedt/core/modules/fields_calculator.py b/src/ansys/aedt/core/modules/fields_calculator.py index 117a18b6a01..9c8c83b7eb8 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.") From 8560e9c5d3c581c51309f83c66c41dbc9d11aec1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Morais?= <146729917+SMoraisAnsys@users.noreply.github.com> Date: Tue, 10 Sep 2024 17:43:20 +0200 Subject: [PATCH 22/29] DOCS: Fix pypi landing page (#5154) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 |
    中文 From 761a7badd1ad9ecd0e1ce5c5c2c3fbbef4ba1dbb Mon Sep 17 00:00:00 2001 From: Samuel Lopez <85613111+Samuelopez-ansys@users.noreply.github.com> Date: Tue, 10 Sep 2024 21:19:04 +0200 Subject: [PATCH 23/29] FIX: Add missed parameter "pass" (#5151) Co-authored-by: gmalinve <103059376+gmalinve@users.noreply.github.com> --- src/ansys/aedt/core/q3d.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ansys/aedt/core/q3d.py b/src/ansys/aedt/core/q3d.py index 83f1735b86c..8882632d3d9 100644 --- a/src/ansys/aedt/core/q3d.py +++ b/src/ansys/aedt/core/q3d.py @@ -725,7 +725,7 @@ def export_matrix_data( length_setting, length, matrix_type, - export_ac_dc_res, + 0, precision, field_width, use_sci_notation, @@ -748,6 +748,7 @@ def export_matrix_data( g_unit, freq, matrix_type, + 0, export_ac_dc_res, precision, field_width, From 618cfec19ad303ade584e1e7e83cad13a9cca6b2 Mon Sep 17 00:00:00 2001 From: Samuel Lopez <85613111+Samuelopez-ansys@users.noreply.github.com> Date: Tue, 10 Sep 2024 23:30:34 +0200 Subject: [PATCH 24/29] FEAT: Assign two way coupling in Mechanical (#5145) --- _unittest/test_29_Mechanical.py | 4 +++ src/ansys/aedt/core/mechanical.py | 47 +++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) 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/src/ansys/aedt/core/mechanical.py b/src/ansys/aedt/core/mechanical.py index aa84bfc6568..2f212fa4862 100644 --- a/src/ansys/aedt/core/mechanical.py +++ b/src/ansys/aedt/core/mechanical.py @@ -675,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. From 634988a3a65fdb13a136c9c4fd2991448ab7ac4c Mon Sep 17 00:00:00 2001 From: gmalinve <103059376+gmalinve@users.noreply.github.com> Date: Wed, 11 Sep 2024 13:30:54 +0200 Subject: [PATCH 25/29] DOCS: add advanced fields calc API (#5155) --- doc/source/API/Post.rst | 27 ++++++++++++++++--- .../aedt/core/modules/fields_calculator.py | 2 +- 2 files changed, 24 insertions(+), 5 deletions(-) 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/src/ansys/aedt/core/modules/fields_calculator.py b/src/ansys/aedt/core/modules/fields_calculator.py index 9c8c83b7eb8..d4084b27121 100644 --- a/src/ansys/aedt/core/modules/fields_calculator.py +++ b/src/ansys/aedt/core/modules/fields_calculator.py @@ -44,7 +44,7 @@ class FieldsCalculator: Parameters ---------- - app: + app : Inherited parent object. Examples From 3f781019e6b147fc019f87d4abe214f29a43f042 Mon Sep 17 00:00:00 2001 From: Lorenzo Vecchietti <58366962+lorenzovecchietti@users.noreply.github.com> Date: Wed, 11 Sep 2024 13:38:34 +0200 Subject: [PATCH 26/29] FIX: Get scale settings with multiple designs in the same project (#5144) --- .../example_models/T98/transient_fs.aedtz | Bin 2196354 -> 2194661 bytes _unittest/test_98_Icepak.py | 8 ++++++-- src/ansys/aedt/core/generic/load_aedt_file.py | 2 +- src/ansys/aedt/core/modules/solutions.py | 6 +++++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/_unittest/example_models/T98/transient_fs.aedtz b/_unittest/example_models/T98/transient_fs.aedtz index e73de4a0dc7fbde12345d50a77d846bdd1ff7529..1c35dfb9aeb599ee3493bf8036593e6d1d262ba7 100644 GIT binary patch delta 44377 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 NhX(;64kklD{12wJLLUGC delta 46803 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 Date: Wed, 11 Sep 2024 15:43:29 +0200 Subject: [PATCH 27/29] FIX: PyAEDT installer compatible from 2022R2 (#5159) --- _unittest/conftest.py | 5 ++-- _unittest/test_01_3dlayout_edb.py | 1 + _unittest/test_01_Design.py | 2 +- _unittest/test_02_3D_modeler.py | 15 ++++++++--- .../Resources/pyaedt_installer_from_aedt.py | 20 +++++++++----- .../core/workflows/installer/console_setup.py | 27 +++++++++++-------- .../installer/jupyter_template.ipynb | 24 ++++++++++++++--- .../workflows/installer/pyaedt_installer.py | 2 +- 8 files changed, 67 insertions(+), 29 deletions(-) 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/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_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/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/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 f135f2e725c..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 ansys.aedt.core\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, 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 * From 91482d448f2be3b569684c930acfcfda71522fca Mon Sep 17 00:00:00 2001 From: Ramin Aghajafari <153928265+ramin4667@users.noreply.github.com> Date: Wed, 11 Sep 2024 09:48:07 -0400 Subject: [PATCH 28/29] FEAT: Filtersolutions Export Modelithics (#5101) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .../resources/__init__.py | 1 + .../resources/import_tuned_variables.ckt | 17 + .../resources/imported_netlist.ckt | 17 + .../resources/library_parts.cfg | 45 + .../resources/library_parts_test.cfg | 0 .../test_lumped_export/__init__.py | 23 + .../test_lumped_export/test_export_to_aedt.py | 506 ++++++- .../test_optimization_goals_table.py | 14 +- .../Lumped_Element_Response.py | 4 +- .../filtersolutions_core/export_to_aedt.py | 1252 ++++++++++++++++- .../optimization_goals_table.py | 4 +- 11 files changed, 1846 insertions(+), 37 deletions(-) create mode 100644 _unittest/test_45_FilterSolutions/resources/import_tuned_variables.ckt create mode 100644 _unittest/test_45_FilterSolutions/resources/imported_netlist.ckt create mode 100644 _unittest/test_45_FilterSolutions/resources/library_parts.cfg create mode 100644 _unittest/test_45_FilterSolutions/resources/library_parts_test.cfg create mode 100644 _unittest/test_45_FilterSolutions/test_lumped_export/__init__.py 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_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 index 8e28035d6bf..9ca433a806f 100644 --- 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 @@ -23,132 +23,594 @@ # SOFTWARE. from _unittest.conftest import config -import pyaedt -from pyaedt.filtersolutions_core.attributes import FilterImplementation -from pyaedt.generic.general_methods import is_linux - -# from ..filtersolutions_resources import resource_path +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 = pyaedt.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + 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 = pyaedt.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + 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 = pyaedt.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + 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 = pyaedt.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + 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 = pyaedt.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + 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 = pyaedt.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + 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 = pyaedt.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + 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 = pyaedt.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + 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 = pyaedt.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + 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 = pyaedt.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + 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 = pyaedt.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + 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 = pyaedt.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + 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 = pyaedt.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + 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 = pyaedt.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + 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 = pyaedt.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + 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 = pyaedt.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + 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 = pyaedt.FilterSolutions(implementation_type=FilterImplementation.LUMPED) + 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 index a728b75d77b..09d87471f80 100644 --- 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 @@ -37,13 +37,13 @@ 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.set_design_goals() + 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.set_design_goals() + lumpdesign.optimization_goals_table.restore_design_goals() assert lumpdesign.optimization_goals_table.row(0) == [ "200 MHz", "1 GHz", @@ -71,7 +71,7 @@ def test_row(self): 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.set_design_goals() + 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" ) @@ -88,7 +88,7 @@ def test_update_row(self): 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.set_design_goals() + 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", @@ -103,7 +103,7 @@ def test_append_row(self): 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.set_design_goals() + 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" ) @@ -120,7 +120,7 @@ def test_insert_row(self): 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.set_design_goals() + 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) == [ @@ -136,7 +136,7 @@ def test_remove_row(self): 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.set_design_goals() + 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" diff --git a/examples/08-FilterSolutions/Lumped_Element_Response.py b/examples/08-FilterSolutions/Lumped_Element_Response.py index 1e0bb85cd20..971463f3195 100644 --- a/examples/08-FilterSolutions/Lumped_Element_Response.py +++ b/examples/08-FilterSolutions/Lumped_Element_Response.py @@ -14,14 +14,14 @@ 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" diff --git a/src/ansys/aedt/core/filtersolutions_core/export_to_aedt.py b/src/ansys/aedt/core/filtersolutions_core/export_to_aedt.py index 24e7ce7dbf4..31241b1a7dc 100644 --- a/src/ansys/aedt/core/filtersolutions_core/export_to_aedt.py +++ b/src/ansys/aedt/core/filtersolutions_core/export_to_aedt.py @@ -27,8 +27,10 @@ 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 @@ -59,6 +61,116 @@ class ExportCreationMode(Enum): 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 . @@ -69,6 +181,7 @@ 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.""" @@ -158,16 +271,235 @@ def _define_export_to_desktop_dll_functions(self): 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 @@ -464,7 +796,7 @@ def optimitrics_enabled(self, optimitrics_enabled: bool): @property def optimize_after_export_enabled(self) -> bool: - """Flag indicating if the optimization option after exporting to ``AEDT`` is enabled. + """Flag indicating if the optimization after exporting to ``AEDT`` is enabled. Returns ------- @@ -480,7 +812,7 @@ 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: ExportFormat.DIRECT_TO_AEDT, export_creation_mode=None, export_path=None): + 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. @@ -489,7 +821,7 @@ def export_design(self, export_format: ExportFormat.DIRECT_TO_AEDT, export_creat ---------- export_format : `ExportFormat` The export format type. - The default is ``DIRECT_TO_AEDT``. + The default is ``None``. design_creation_mode : `ExportCreationMode` The design creation mode. The default is ``None``. @@ -497,6 +829,8 @@ def export_design(self, export_format: ExportFormat.DIRECT_TO_AEDT, export_creat 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: @@ -509,7 +843,917 @@ def export_design(self, export_format: ExportFormat.DIRECT_TO_AEDT, export_creat 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.""" - status = self._dll.importTunedVariables() + 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/optimization_goals_table.py b/src/ansys/aedt/core/filtersolutions_core/optimization_goals_table.py index 68e613cae65..79852ae2753 100644 --- a/src/ansys/aedt/core/filtersolutions_core/optimization_goals_table.py +++ b/src/ansys/aedt/core/filtersolutions_core/optimization_goals_table.py @@ -291,9 +291,9 @@ def remove_row(self, row_index): status = self._dll.removeOptimizationGoalDefinitionRow(row_index) ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) - def set_design_goals(self): + def restore_design_goals(self): """Configure the optimization goal table according to the recommended goals for the current design.""" - status = self._dll.designGoals() + status = self._dll.setDesignGoals() ansys.aedt.core.filtersolutions_core._dll_interface().raise_error(status) def save_goals(self, design, file_path) -> str: From ce3b625a77a55bac50c9104219db4a63a6a6d1a6 Mon Sep 17 00:00:00 2001 From: Samuel Lopez <85613111+Samuelopez-ansys@users.noreply.github.com> Date: Wed, 11 Sep 2024 15:48:36 +0200 Subject: [PATCH 29/29] FEAT: Create custom array file (.sarr) (#5156) --- _unittest/test_04_SBR.py | 22 +++ src/ansys/aedt/core/hfss.py | 360 ++++++++++++++++++++++++------------ 2 files changed, 268 insertions(+), 114 deletions(-) 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/src/ansys/aedt/core/hfss.py b/src/ansys/aedt/core/hfss.py index 75af5af6700..589ad5d3f0f 100644 --- a/src/ansys/aedt/core/hfss.py +++ b/src/ansys/aedt/core/hfss.py @@ -1154,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 = {} - 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_native_component( self, antenna_type, target_cs=None, model_units=None, parameters_dict=None, antenna_name=None @@ -1648,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.