diff --git a/.github/workflows/ci_cd.yml b/.github/workflows/ci_cd.yml index ebe924c3c71..3072d972192 100644 --- a/.github/workflows/ci_cd.yml +++ b/.github/workflows/ci_cd.yml @@ -54,7 +54,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest] - python-version: ['3.7', '3.8', '3.9', '3.10', '3.11'] + python-version: ['3.7', '3.8', '3.9', '3.10', '3.11', '3.12'] target: ['all', 'installer'] exclude: - python-version: '3.7' @@ -205,11 +205,11 @@ jobs: .venv\Scripts\Activate.ps1 .\doc\make.bat pdf - - name: Add assets to HTML docs - run: | - zip -r documentation-html.zip ./doc/_build/html - mv documentation-html.zip ./doc/_build/html/_static/assets/download/ - cp doc/_build/latex/PyAEDT-Documentation-*.pdf ./doc/_build/html/_static/assets/download/pyaedt.pdf + # - name: Add assets to HTML docs + # run: | + # zip -r documentation-html.zip ./doc/_build/html + # mv documentation-html.zip ./doc/_build/html/_static/assets/download/ + # cp doc/_build/latex/PyAEDT-Documentation-*.pdf ./doc/_build/html/_static/assets/download/pyaedt.pdf - name: Upload HTML documentation with examples artifact uses: actions/upload-artifact@v3 @@ -458,7 +458,7 @@ jobs: command: | export LD_LIBRARY_PATH=${{ env.ANSYSEM_ROOT241 }}/common/mono/Linux64/lib64:${{ env.ANSYSEM_ROOT241 }}/Delcross:$LD_LIBRARY_PATH source .venv/bin/activate - pytest -n 4 --dist loadfile --durations=50 -v --cov=pyaedt --cov-report=xml --cov-report=html --junitxml=junit/test-results.xml _unittest + pytest -n 2 --dist loadfile --durations=50 -v --cov=pyaedt --cov-report=xml --cov-report=html --junitxml=junit/test-results.xml _unittest - uses: codecov/codecov-action@v4 with: diff --git a/.github/workflows/nightly-docs.yml b/.github/workflows/nightly-docs.yml index 463dbf16f16..4443fed81e1 100644 --- a/.github/workflows/nightly-docs.yml +++ b/.github/workflows/nightly-docs.yml @@ -10,6 +10,7 @@ env: MAIN_PYTHON_VERSION: '3.10' DOCUMENTATION_CNAME: 'aedt.docs.pyansys.com' MEILISEARCH_API_KEY: ${{ secrets.MEILISEARCH_API_KEY }} + MEILISEARCH_HOST_URL: ${{ vars.MEILISEARCH_HOST_URL }} MEILISEARCH_PUBLIC_API_KEY: ${{ secrets.MEILISEARCH_PUBLIC_API_KEY }} concurrency: @@ -83,11 +84,11 @@ jobs: .venv\Scripts\Activate.ps1 .\doc\make.bat pdf - - name: Add assets to HTML docs - run: | - zip -r documentation-html.zip ./doc/_build/html - mv documentation-html.zip ./doc/_build/html/_static/assets/download/ - cp doc/_build/latex/PyAEDT-Documentation-*.pdf ./doc/_build/html/_static/assets/download/pyaedt.pdf + # - name: Add assets to HTML docs + # run: | + # zip -r documentation-html.zip ./doc/_build/html + # mv documentation-html.zip ./doc/_build/html/_static/assets/download/ + # cp doc/_build/latex/PyAEDT-Documentation-*.pdf ./doc/_build/html/_static/assets/download/pyaedt.pdf - name: Upload HTML documentation with examples artifact uses: actions/upload-artifact@v3 @@ -103,72 +104,6 @@ jobs: path: doc/_build/latex/PyAEDT-Documentation-*.pdf retention-days: 7 - # doc-build-without-examples: - # name: Documentation build without examples - # runs-on: ubuntu-latest - # steps: - # - name: Install Git and checkout project - # uses: actions/checkout@v4 - - # - name: Setup Python - # uses: actions/setup-python@v5 - # with: - # python-version: ${{ env.MAIN_PYTHON_VERSION }} - - # - name: Update pip - # run: | - # pip install --upgrade pip - - # - name: Install pyaedt and documentation dependencies - # run: | - # pip install .[doc-no-examples] - - # - name: Retrieve PyAEDT version - # id: version - # run: | - # echo "PYAEDT_VERSION=$(python -c 'from pyaedt import __version__; print(__version__)')" >> $GITHUB_OUTPUT - # echo "PyAEDT version is: $(python -c "from pyaedt import __version__; print(__version__)")" - - # - name: Install doc build requirements - # run: | - # sudo apt update - # sudo apt install graphviz texlive-latex-extra latexmk texlive-xetex texlive-fonts-extra -y - - # # TODO: Update this step once pyaedt-examples is ready - # - name: Build HTML documentation without examples - # run: | - # make -C doc clean - # make -C doc html-no-examples - - # # Verify that sphinx generates no warnings - # - name: Check for warnings - # run: | - # python doc/print_errors.py - - # - name: Build PDF documentation without examples - # run: | - # make -C doc pdf-no-examples - - # - name: Add assets to HTML docs - # run: | - # zip -r documentation-html.zip ./doc/_build/html - # mv documentation-html.zip ./doc/_build/html/_static/assets/download/ - # cp doc/_build/latex/PyAEDT-Documentation-*.pdf ./doc/_build/html/_static/assets/download/pyaedt.pdf - - # - name: Upload HTML documentation without examples artifact - # uses: actions/upload-artifact@v3 - # with: - # name: documentation-no-examples-html - # path: doc/_build/html - # retention-days: 7 - - # - name: Upload PDF documentation without examples artifact - # uses: actions/upload-artifact@v3 - # with: - # name: documentation-pdf - # path: doc/_build/latex/PyAEDT-Documentation-*.pdf - # retention-days: 7 - upload-dev-doc: name: Upload dev documentation runs-on: ubuntu-latest diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d368033e733..a15b8612131 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -27,7 +27,7 @@ repos: args: ['--force-single-line-imports', '--profile', 'black'] - repo: https://github.com/PyCQA/flake8 - rev: 7.0.0 + rev: 7.1.0 hooks: - id: flake8 args: @@ -48,7 +48,7 @@ repos: # validate GitHub workflow files - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.28.4 + rev: 0.28.6 hooks: - id: check-github-workflows @@ -64,6 +64,14 @@ repos: hooks: - id: check-pre-commit-ci-config +- repo: https://github.com/ansys/pre-commit-hooks + rev: v0.3.1 + hooks: + - id: add-license-headers + files: '(pyaedt|examples|_unittest|_unittest_ironpython|_unittest_solvers)/.*\.(py)' + args: + - --custom_template=mit_license.jinja2 + - --start_year=2021 # - repo: https://github.com/numpy/numpydoc # rev: v1.6.0 diff --git a/.reuse/templates/mit_license.jinja2 b/.reuse/templates/mit_license.jinja2 new file mode 100644 index 00000000000..06fc58439b5 --- /dev/null +++ b/.reuse/templates/mit_license.jinja2 @@ -0,0 +1,29 @@ +-*- coding: utf-8 -*- + +{% for copyright_line in copyright_lines %} +{{ copyright_line }} +{% endfor %} +{% for expression in spdx_expressions %} +SPDX-License-Identifier: {{ expression }} +{% endfor %} + + +{% if "MIT" in spdx_expressions %} +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. +{% endif %} diff --git a/LICENSE b/LICENSE index a9d9a2ef7eb..6a949e7fd8c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,13 +1,13 @@ MIT License -Copyright (c) 2021 ANSYS, Inc. All rights reserved. +Copyright (c) 2021 - 2024 ANSYS, Inc. and/or its affiliates. -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: +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. diff --git a/README.md b/README.md index 8cee89d3b48..e8a9e292391 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,7 @@ *** PyAEDT README --> - -# PyAEDT +[![PyAEDT logo](https://github.com/ansys/pyaedt/blob/main/doc/source/_static/logo.png)](https://aedt.docs.pyansys.com)


English | 中文 diff --git a/_unittest/__init__.py b/_unittest/__init__.py index e69de29bb2d..9c4476773da 100644 --- a/_unittest/__init__.py +++ b/_unittest/__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/conftest.py b/_unittest/conftest.py index c65f120585c..aa4dbb3f73a 100644 --- a/_unittest/conftest.py +++ b/_unittest/conftest.py @@ -1,3 +1,27 @@ +# -*- 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. + """ Unit Test Configuration Module ------------------------------- @@ -175,10 +199,10 @@ def _method( if not application: application = Hfss return application( - projectname=test_project, - designname=design_name, + project=test_project, + design=design_name, solution_type=solution_type, - specified_version=desktop_version, + version=desktop_version, non_graphical=NONGRAPHICAL, ) diff --git a/_unittest/example_models/T98/cylinder_mesh.msh b/_unittest/example_models/T98/cylinder_mesh.msh new file mode 100644 index 00000000000..3481636c14e Binary files /dev/null and b/_unittest/example_models/T98/cylinder_mesh.msh differ diff --git a/_unittest/test_01_3dlayout_edb.py b/_unittest/test_01_3dlayout_edb.py index 3bcab9a0c07..3feb99fe27c 100644 --- a/_unittest/test_01_3dlayout_edb.py +++ b/_unittest/test_01_3dlayout_edb.py @@ -1,3 +1,27 @@ +# -*- 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 from _unittest.conftest import config @@ -5,7 +29,7 @@ import pytest from pyaedt import Hfss3dLayout -from pyaedt import is_linux +from pyaedt.generic.settings import is_linux test_subfolder = "T40" original_project_name = "ANSYS-HSD_V1" diff --git a/_unittest/test_01_Design.py b/_unittest/test_01_Design.py index 6e72a2e8f4c..68a06aa48da 100644 --- a/_unittest/test_01_Design.py +++ b/_unittest/test_01_Design.py @@ -1,3 +1,27 @@ +# -*- 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 tempfile @@ -172,17 +196,17 @@ def test_15a_duplicate_design(self): def test_15b_copy_design_from(self): origin = os.path.join(self.local_scratch.path, "origin.aedt") destin = os.path.join(self.local_scratch.path, "destin.aedt") - self.aedtapp.save_project(project_file=origin) + self.aedtapp.save_project(file_name=origin) self.aedtapp.duplicate_design("myduplicateddesign") - self.aedtapp.save_project(project_file=origin, refresh_obj_ids_after_save=True) + self.aedtapp.save_project(file_name=origin, refresh_ids=True) - self.aedtapp.save_project(project_file=destin) + self.aedtapp.save_project(file_name=destin) new_design = self.aedtapp.copy_design_from(origin, "myduplicateddesign") assert new_design in self.aedtapp.design_list def test_16_renamedesign(self, add_app, test_project_file): prj_file = test_project_file(test_project_name) - self.aedtapp.load_project(project_file=prj_file, close_active_proj=True, design_name="myname") + self.aedtapp.load_project(file_name=prj_file, design="myname", close_active=True) assert "myname" in [ design["Name"] for design in self.aedtapp.project_properties["AnsoftProject"][model_names[self.aedtapp.design_type]] @@ -221,6 +245,8 @@ def test_19_create_project_dataset(self): assert self.aedtapp.dataset_exists("Test_DataSet", is_project_dataset=True) assert ds2.delete() assert not self.aedtapp.dataset_exists("Test_DataSet", is_project_dataset=True) + ds3 = self.aedtapp.create_dataset1d_project("Test_DataSet2", x, y, sort=False) + assert ds3.name == "$Test_DataSet2" def test_19_create_3dproject_dataset(self): x = [1, 100] @@ -228,11 +254,14 @@ def test_19_create_3dproject_dataset(self): z = [800, 200] v = [10, 20] vunits = "cel" - ds3 = self.aedtapp.create_dataset3d("Test_DataSet3D", x, y, z, v, vunit=vunits) + ds3 = self.aedtapp.create_dataset3d("Test_DataSet3D", x, y, z, v, v_unit=vunits) assert ds3.name == "$Test_DataSet3D" - ds30 = self.aedtapp.create_dataset3d("Test_DataSet3D1", x, y, z, v, vunit=vunits, is_project_dataset=False) + ds3.sort = False + ds3.v = [50, 200] + assert ds3.update() + ds30 = self.aedtapp.create_dataset3d("Test_DataSet3D1", x, y, z, v, v_unit=vunits, is_project_dataset=False) assert ds30.name == "$Test_DataSet3D1" - ds31 = self.aedtapp.create_dataset3d("$Test_DataSet3D2", x, y, z, v, vunit=vunits, is_project_dataset=False) + ds31 = self.aedtapp.create_dataset3d("$Test_DataSet3D2", x, y, z, v, v_unit=vunits, is_project_dataset=False) assert ds31.name == "$Test_DataSet3D2" def test_19_edit_existing_dataset(self): @@ -245,9 +274,9 @@ def test_19_import_dataset1d(self): filename = os.path.join(local_path, "example_models", test_subfolder, "ds_1d.tab") ds4 = self.aedtapp.import_dataset1d(filename) assert ds4.name == "$ds_1d" - ds5 = self.aedtapp.import_dataset1d(filename, dsname="dataset_test", is_project_dataset=False) + ds5 = self.aedtapp.import_dataset1d(filename, name="dataset_test", is_project_dataset=False) assert ds5.name == "dataset_test" - ds6 = self.aedtapp.import_dataset1d(filename, dsname="$dataset_test2") + ds6 = self.aedtapp.import_dataset1d(filename, name="$dataset_test2") assert ds6.name == "$dataset_test2" ds7 = self.aedtapp.import_dataset1d(filename) assert not ds7 @@ -260,18 +289,18 @@ def test_19a_import_dataset3d(self): ds8 = self.aedtapp.import_dataset3d(filename) assert ds8.name == "$Dataset_3D" filename = os.path.join(local_path, "example_models", test_subfolder, "Dataset_3D.csv") - ds8 = self.aedtapp.import_dataset3d(filename, dsname="dataset_csv") + ds8 = self.aedtapp.import_dataset3d(filename, name="dataset_csv") assert ds8.name == "$dataset_csv" assert ds8.delete() - ds10 = self.aedtapp.import_dataset3d(filename, dsname="$dataset_test") + ds10 = self.aedtapp.import_dataset3d(filename, name="$dataset_test") assert ds10.zunit == "mm" filename = os.path.join(local_path, "example_models", test_subfolder, "Dataset_3D.csv") - ds8 = self.aedtapp.import_dataset3d(filename, encoding="utf-8-sig", dsname="dataset_csv") + ds8 = self.aedtapp.import_dataset3d(filename, name="dataset_csv", encoding="utf-8-sig") assert ds8.name == "$dataset_csv" def test_19b_import_dataset3d_xlsx(self): filename = os.path.join(local_path, "example_models", test_subfolder, "Dataset_3D.xlsx") - ds9 = self.aedtapp.import_dataset3d(filename, dsname="myExcel") + ds9 = self.aedtapp.import_dataset3d(filename, name="myExcel") assert ds9.name == "$myExcel" def test_20_get_3dComponents_properties(self): @@ -361,7 +390,7 @@ def test_34_force_project_path_disable(self): e = None exception_raised = False try: - h = Hfss("c:/dummy/test.aedt", specified_version=desktop_version) + h = Hfss("c:/dummy/test.aedt", version=desktop_version) except Exception as e: exception_raised = True assert e.args[0] == "Project doesn't exist. Check it and retry." @@ -397,7 +426,7 @@ def test_36_test_load(self, add_app): with open(file_name2_lock, "w") as f: f.write(" ") try: - hfss = Hfss(projectname=file_name2, specified_version=desktop_version) + hfss = Hfss(project=file_name2, version=desktop_version) except Exception: assert True try: @@ -405,7 +434,7 @@ def test_36_test_load(self, add_app): file_name3 = os.path.join(self.local_scratch.path, "test_36_2.aedb", "edb.def") with open(file_name3, "w") as f: f.write(" ") - hfss = Hfss3dLayout(projectname=file_name3, specified_version=desktop_version) + hfss = Hfss3dLayout(project=file_name3, version=desktop_version) except Exception: assert True @@ -432,7 +461,7 @@ def test_38_toolkit(self, desktop): def test_39_load_project(self, desktop): new_project = os.path.join(self.local_scratch.path, "new.aedt") - self.aedtapp.save_project(project_file=new_project) + self.aedtapp.save_project(file_name=new_project) self.aedtapp.close_project(name="new") aedtapp = desktop.load_project(new_project) assert aedtapp diff --git a/_unittest/test_01_GeometryOperators.py b/_unittest/test_01_GeometryOperators.py index cd1e88f3ec9..9ec435b2464 100644 --- a/_unittest/test_01_GeometryOperators.py +++ b/_unittest/test_01_GeometryOperators.py @@ -1,3 +1,27 @@ +# -*- 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 math import pytest diff --git a/_unittest/test_01_configuration_files.py b/_unittest/test_01_configuration_files.py index 33e19fe4f6f..b2cbcf3e2d2 100644 --- a/_unittest/test_01_configuration_files.py +++ b/_unittest/test_01_configuration_files.py @@ -1,3 +1,27 @@ +# -*- 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. + # standard imports import json import os @@ -79,12 +103,12 @@ def test_01_hfss_export(self, aedtapp, add_app): file_path = os.path.join(aedtapp.working_directory, filename + ".x_b") aedtapp.export_3d_model(filename, aedtapp.working_directory, ".x_b", [], []) app = add_app(project_name="new_proj", solution_type=aedtapp.solution_type, just_open=True) - app.modeler.import_3d_cad(file_path) + app.import_3d_cad(file_path) out = app.configurations.import_config(conf_file) assert isinstance(out, dict) assert app.configurations.validate(out) assert app.configurations.results.global_import_success - app.close_project(save_project=False) + app.close_project(save=False) def test_02_q3d_export(self, q3dtest, add_app): q3dtest.modeler.create_coordinate_system() @@ -101,7 +125,7 @@ def test_02_q3d_export(self, q3dtest, add_app): assert isinstance(out, dict) assert app.configurations.validate(out) assert app.configurations.results.global_import_success - app.close_project(save_project=False) + app.close_project(save=False) def test_03_q2d_export(self, q2dtest, add_app): conf_file = q2dtest.configurations.export_config() @@ -153,7 +177,7 @@ def test_03_q2d_export(self, q2dtest, add_app): assert q2dtest.configurations.options.import_mesh_operations assert q2dtest.configurations.options.import_object_properties assert q2dtest.configurations.options.import_parametrics - app.close_project(save_project=False) + app.close_project(save=False) def test_04a_icepak(self, icepak_a, aedtapp, add_app): box1 = icepak_a.modeler.create_box([0, 0, 0], [10, 10, 10]) @@ -184,13 +208,12 @@ def test_04a_icepak(self, icepak_a, aedtapp, add_app): "test_dataset", [1, 2, 3, 4], [1, 2, 3, 4], - zlist=None, - vlist=None, + z=None, + v=None, is_project_dataset=False, - xunit="cel", - yunit="W", - zunit="", - vunit="", + x_unit="cel", + y_unit="W", + v_unit="", ) filename = icepak_a.design_name icepak_a.export_3d_model(filename, icepak_a.working_directory, ".x_b", [], []) @@ -235,7 +258,7 @@ def test_04a_icepak(self, icepak_a, aedtapp, add_app): out = app.configurations.import_config(old_conf_file) assert isinstance(out, dict) assert app.configurations.results.global_import_success - app.close_project(save_project=False) + app.close_project(save=False) @pytest.mark.skipif( config["desktopVersion"] < "2023.1" and config["use_grpc"], @@ -269,13 +292,12 @@ def test_04b_icepak(self, icepak_b, add_app): "test_dataset", [1, 2, 3, 4], [1, 2, 3, 4], - zlist=None, - vlist=None, + z=None, + v=None, is_project_dataset=False, - xunit="cel", - yunit="W", - zunit="", - vunit="", + x_unit="cel", + y_unit="W", + v_unit="", ) filename = icepak_b.design_name icepak_b.export_3d_model(filename, icepak_b.working_directory, ".x_b", [], []) diff --git a/_unittest/test_01_downloads.py b/_unittest/test_01_downloads.py index f8d1b71a447..66f89601a2c 100644 --- a/_unittest/test_01_downloads.py +++ b/_unittest/test_01_downloads.py @@ -1,11 +1,35 @@ +# -*- 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 tempfile import pytest from pyaedt import downloads -from pyaedt import is_linux from pyaedt.generic.general_methods import generate_unique_name +from pyaedt.generic.settings import is_linux @pytest.fixture(scope="module", autouse=True) diff --git a/_unittest/test_01_general_methods.py b/_unittest/test_01_general_methods.py index 6b53e40f0ca..d8e3e5ab8f8 100644 --- a/_unittest/test_01_general_methods.py +++ b/_unittest/test_01_general_methods.py @@ -1,3 +1,27 @@ +# -*- 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 pytest from pyaedt.generic.DataHandlers import str_to_bool diff --git a/_unittest/test_01_report_file_parser.py b/_unittest/test_01_report_file_parser.py index 5241f2f1c29..aa046f0f63e 100644 --- a/_unittest/test_01_report_file_parser.py +++ b/_unittest/test_01_report_file_parser.py @@ -1,3 +1,27 @@ +# -*- 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 pytest diff --git a/_unittest/test_01_toolkit_icons.py b/_unittest/test_01_toolkit_icons.py index 99922aa102d..303eb3c23a8 100644 --- a/_unittest/test_01_toolkit_icons.py +++ b/_unittest/test_01_toolkit_icons.py @@ -1,3 +1,27 @@ +# -*- 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 defusedxml.ElementTree as ET diff --git a/_unittest/test_02_2D_modeler.py b/_unittest/test_02_2D_modeler.py index ce1a6d1a416..49cb7175fb6 100644 --- a/_unittest/test_02_2D_modeler.py +++ b/_unittest/test_02_2D_modeler.py @@ -1,3 +1,27 @@ +# -*- 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. + # standard imports import filecmp import math diff --git a/_unittest/test_02_3D_modeler.py b/_unittest/test_02_3D_modeler.py index e5004ff86a7..e9e4ef510ec 100644 --- a/_unittest/test_02_3D_modeler.py +++ b/_unittest/test_02_3D_modeler.py @@ -1,3 +1,27 @@ +# -*- 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 random from _unittest.conftest import config diff --git a/_unittest/test_03_Materials.py b/_unittest/test_03_Materials.py index 6cece448949..3779bdae18d 100644 --- a/_unittest/test_03_Materials.py +++ b/_unittest/test_03_Materials.py @@ -1,3 +1,27 @@ +# -*- 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 from _unittest.conftest import config diff --git a/_unittest/test_04_SBR.py b/_unittest/test_04_SBR.py index 0bdf8a10593..7ef95e00347 100644 --- a/_unittest/test_04_SBR.py +++ b/_unittest/test_04_SBR.py @@ -1,7 +1,37 @@ +# -*- 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 builtins import os +import sys +from unittest.mock import mock_open +from mock import patch import pytest +from pyaedt.sbrplus.hdm_parser import Parser + try: import osmnx except ImportError: @@ -10,7 +40,7 @@ from _unittest.conftest import desktop_version from _unittest.conftest import local_path -from pyaedt import is_linux +from pyaedt.generic.settings import is_linux if desktop_version > "2022.2": test_project_name = "Cassegrain_231" @@ -28,6 +58,28 @@ test_subfolder = "T17" +CORRECT_HDM_HEADER = b""" +# The binary data starts immediately after the '#header end' line. +{ + 'types': + { + 'Int32': {'type': 'int', 'size' : 4, }, + 'Bundle': {'type': 'object', 'layout' : ( + {'type': 'Int32', 'field_names': ('version', ), }, + ), + }, + }, +'message': {'type': 'Bundle'} +} +#header end +""" +INCORRECT_HDM_HEADER = b""" +# The binary data starts immediately after the '#header end' line. +{ + 12 +#header end +""" + @pytest.fixture(scope="class") def aedtapp(add_app): @@ -202,6 +254,7 @@ def test_12_import_map(self): for part in parts_dict["parts"]: assert os.path.exists(parts_dict["parts"][part]["file_name"]) + @pytest.mark.skipif(sys.version_info > (3, 8), reason="Bug in VTK with 3.12") @pytest.mark.skipif(is_linux, reason="feature supported in Cpython") def test_16_read_hdm(self): self.aedtapp.insert_design("hdm") @@ -217,3 +270,24 @@ def test_16_read_hdm(self): assert plotter plotter.plot_rays(os.path.join(self.local_scratch.path, "bounce2.jpg")) assert os.path.exists(os.path.join(self.local_scratch.path, "bounce2.jpg")) + + @patch.object(builtins, "open", new_callable=mock_open, read_data=CORRECT_HDM_HEADER) + def test_hdm_parser_header_loading_success(self, mock_file_open): + """Test that HDM parser loads header correctly.""" + expected_result = { + "message": {"type": "Bundle"}, + "types": { + "Bundle": {"layout": ({"field_names": ("version",), "type": "Int32"},), "type": "object"}, + "Int32": {"size": 4, "type": "int"}, + }, + } + hdm_parser = Parser("some path") + + assert expected_result == hdm_parser.header + + @patch.object(builtins, "open", new_callable=mock_open, read_data=INCORRECT_HDM_HEADER) + def test_hdm_parser_header_loading_failure(self, mock_file_open): + """Test that HDM parser fails to load header.""" + + with pytest.raises(SyntaxError): + Parser("some path") diff --git a/_unittest/test_05_Mesh.py b/_unittest/test_05_Mesh.py index fe73eb8ebce..03c6399ce62 100644 --- a/_unittest/test_05_Mesh.py +++ b/_unittest/test_05_Mesh.py @@ -1,3 +1,27 @@ +# -*- 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 from _unittest.conftest import desktop_version import pytest diff --git a/_unittest/test_06_MessageManager.py b/_unittest/test_06_MessageManager.py index dbe9fda245d..c85d7c41082 100644 --- a/_unittest/test_06_MessageManager.py +++ b/_unittest/test_06_MessageManager.py @@ -1,3 +1,27 @@ +# -*- 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 logging import os.path diff --git a/_unittest/test_07_Object3D.py b/_unittest/test_07_Object3D.py index 13d2e6a3011..1fe9aada249 100644 --- a/_unittest/test_07_Object3D.py +++ b/_unittest/test_07_Object3D.py @@ -1,3 +1,27 @@ +# -*- 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 math import pytest @@ -595,7 +619,7 @@ def test_27_get_object_history_properties(self): assert box_clone_history.children["Rotate:1"].command == "Rotate" assert box_clone_history.children["SplitEdit:1"].command == "SplitEdit" project_path = self.aedtapp.project_file - self.aedtapp.close_project(save_project=True) + self.aedtapp.close_project(save=True) self.aedtapp.load_project(project_path) subtract = self.aedtapp.modeler["box_history1"].history().children["Subtract:1"].children assert len(subtract) == 1 diff --git a/_unittest/test_08_Primitives3D.py b/_unittest/test_08_Primitives3D.py index d8c8dedb945..3d34aabf3fa 100644 --- a/_unittest/test_08_Primitives3D.py +++ b/_unittest/test_08_Primitives3D.py @@ -1,3 +1,27 @@ +# -*- 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 sys import time @@ -9,8 +33,8 @@ from pyaedt import Icepak from pyaedt import Q2d from pyaedt import generate_unique_name -from pyaedt import is_linux from pyaedt.generic.constants import AXIS +from pyaedt.generic.settings import is_linux from pyaedt.modeler.cad.Primitives import PolylineSegment from pyaedt.modeler.cad.components_3d import UserDefinedComponent from pyaedt.modeler.cad.object3d import Object3d @@ -1065,7 +1089,7 @@ def test_54b_open_and_load_a_polyline(self, add_app): assert len(p3) == 3 assert len(s3) == 1 - aedtapp.close_project(save_project=False) + aedtapp.close_project(save=False) def test_55_create_bond_wires(self): self.aedtapp["$Ox"] = 0 @@ -1142,7 +1166,7 @@ def test_59_lines(self): @pytest.mark.skipif("UNITTEST_CURRENT_TEST" in os.environ, reason="Issue in IronPython") def test_60_get_edges_on_bounding_box(self): - self.aedtapp.close_project(name=self.aedtapp.project_name, save_project=False) + self.aedtapp.close_project(name=self.aedtapp.project_name, save=False) self.aedtapp.load_project(self.test_99_project) edges = self.aedtapp.modeler.get_edges_on_bounding_box(["Port1", "Port2"], return_colinear=True, tolerance=1e-6) assert len(edges) == 2 diff --git a/_unittest/test_09_Primitives2D.py b/_unittest/test_09_Primitives2D.py index e448859e878..b688ede2849 100644 --- a/_unittest/test_09_Primitives2D.py +++ b/_unittest/test_09_Primitives2D.py @@ -1,4 +1,29 @@ #!/ekm/software/anaconda3/bin/python + +# -*- 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 pytest from pyaedt import Maxwell2d diff --git a/_unittest/test_09_VariableManager.py b/_unittest/test_09_VariableManager.py index 7f934255478..23844f3a5c1 100644 --- a/_unittest/test_09_VariableManager.py +++ b/_unittest/test_09_VariableManager.py @@ -1,3 +1,27 @@ +# -*- 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 __future__ import division # noreorder import math @@ -156,9 +180,9 @@ def test_04_set_variable(self): assert self.aedtapp.variable_manager.set_variable("p1", expression="30mm") assert self.aedtapp["p1"] == "30mm" assert self.aedtapp.variable_manager.set_variable( - variable_name="p2", + name="p2", expression="10mm", - readonly=True, + read_only=True, hidden=True, description="This is a description of this variable", ) @@ -409,10 +433,10 @@ def test_12_decompose_variable_value(self): assert decompose_variable_value("3.123456kgm2") == (3.123456, "kgm2") def test_13_postprocessing(self): - v1 = self.aedtapp.variable_manager.set_variable("test_post1", 10, postprocessing=True) + v1 = self.aedtapp.variable_manager.set_variable("test_post1", 10, is_post_processing=True) assert v1 assert not self.aedtapp.variable_manager.set_variable("test2", "v1+1") - assert self.aedtapp.variable_manager.set_variable("test2", "test_post1+1", postprocessing=True) + assert self.aedtapp.variable_manager.set_variable("test2", "test_post1+1", is_post_processing=True) x1 = GeometryOperators.parse_dim_arg( self.aedtapp.variable_manager["test2"].evaluated_value, variable_manager=self.aedtapp.variable_manager ) @@ -435,7 +459,7 @@ def test_15_arrays(self): assert self.aedtapp.variable_manager["getvalue2"].numeric_value == 1.0 def test_16_maxwell_circuit_variables(self): - mc = MaxwellCircuit(specified_version=desktop_version) + mc = MaxwellCircuit(version=desktop_version) mc["var2"] = "10mm" assert mc["var2"] == "10mm" v_circuit = mc.variable_manager diff --git a/_unittest/test_11_Setup.py b/_unittest/test_11_Setup.py index b97a6c8a584..5ac553f8e5f 100644 --- a/_unittest/test_11_Setup.py +++ b/_unittest/test_11_Setup.py @@ -1,3 +1,27 @@ +# -*- 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 from _unittest.conftest import desktop_version @@ -77,7 +101,7 @@ def test_01c_create_hfss_setup_auto_open(self): assert setup1.props["SolveType"] == "MultiFrequency" def test_02_create_circuit_setup(self): - circuit = Circuit(specified_version=desktop_version) + circuit = Circuit(version=desktop_version) setup1 = circuit.create_setup("circuit", self.aedtapp.SETUPS.NexximLNA) assert setup1.name == "circuit" setup1.props["SweepDefinition"]["Data"] = "LINC 0GHz 4GHz 501" diff --git a/_unittest/test_12_1_PostProcessing.py b/_unittest/test_12_1_PostProcessing.py index 45382124944..6efb2d9ba49 100644 --- a/_unittest/test_12_1_PostProcessing.py +++ b/_unittest/test_12_1_PostProcessing.py @@ -1,3 +1,27 @@ +# -*- 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 sys import uuid diff --git a/_unittest/test_12_PostProcessing.py b/_unittest/test_12_PostProcessing.py index c3539714afc..0dfebc86637 100644 --- a/_unittest/test_12_PostProcessing.py +++ b/_unittest/test_12_PostProcessing.py @@ -1,3 +1,27 @@ +# -*- 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 sys @@ -194,10 +218,12 @@ def test_09_manipulate_report_C(self, field_test): report_category="Far Fields", context="3D", ) - assert data.plot(snapshot_path=os.path.join(self.local_scratch.path, "reportC.jpg")) - assert data.plot_3d(snapshot_path=os.path.join(self.local_scratch.path, "reportC_3D.jpg")) + assert data.plot(snapshot_path=os.path.join(self.local_scratch.path, "reportC.jpg"), show=False) + assert data.plot_3d(snapshot_path=os.path.join(self.local_scratch.path, "reportC_3D.jpg"), show=False) assert field_test.post.create_3d_plot( - data, snapshot_path=os.path.join(self.local_scratch.path, "reportC_3D_2.jpg") + data, + snapshot_path=os.path.join(self.local_scratch.path, "reportC_3D_2.jpg"), + show=False, ) def test_09_manipulate_report_D(self, field_test): @@ -215,7 +241,7 @@ def test_09_manipulate_report_D(self, field_test): context=context, ) assert field_test.post.create_3d_plot( - data, snapshot_path=os.path.join(self.local_scratch.path, "reportD_3D_2.jpg") + data, snapshot_path=os.path.join(self.local_scratch.path, "reportD_3D_2.jpg"), show=False ) assert data.primary_sweep == "Theta" assert len(data.data_magnitude("GainTotal")) > 0 @@ -250,11 +276,12 @@ def test_09_manipulate_report_E(self, field_test): assert field_test.post.get_far_field_data( expressions="RealizedGainTotal", setup_sweep_name=field_test.nominal_adaptive, domain="3D" ) - field_test.post.get_far_field_data( + data_farfield2 = field_test.post.get_far_field_data( expressions="RealizedGainTotal", setup_sweep_name=field_test.nominal_adaptive, domain={"Context": "3D", "SourceContext": "1:1"}, ) + assert data_farfield2.plot(formula="db20", is_polar=True, show=False) assert field_test.post.reports_by_category.terminal_solution() @@ -380,7 +407,9 @@ def test_18_diff_plot(self, diff_test): data1.primary_sweep = "l1" assert data1.primary_sweep == "l1" assert len(data1.data_magnitude()) == 5 - assert data1.plot("S(Diff1, Diff1)", snapshot_path=os.path.join(self.local_scratch.path, "diff_pairs.jpg")) + assert data1.plot( + "S(Diff1, Diff1)", snapshot_path=os.path.join(self.local_scratch.path, "diff_pairs.jpg"), show=False + ) assert diff_test.create_touchstone_report( name="Diff_plot", curves=["dB(S(Diff1, Diff1))"], solution="LinearFrequency", differential_pairs=True @@ -621,6 +650,7 @@ def test_70_far_field_data(self): ) assert isinstance(data_pyvista, Plotter) + @pytest.mark.skipif(sys.version_info > (3, 11), reason="Issues with VTK in Python 3.12") @pytest.mark.skipif(is_linux or sys.version_info < (3, 8), reason="FarFieldSolution not supported by IronPython") def test_71_antenna_plot(self, field_test): ffdata = field_test.get_antenna_ffd_solution_data(frequencies=30e9, sphere="3D") @@ -643,6 +673,7 @@ def test_71_antenna_plot(self, field_test): secondary_sweep_value=[-180, -75, 75], title="Azimuth at {}Hz".format(ffdata.frequency), image_path=os.path.join(self.local_scratch.path, "2d1.jpg"), + show=False, ) assert os.path.exists(os.path.join(self.local_scratch.path, "2d1.jpg")) ffdata.plot_2d_cut( @@ -651,12 +682,16 @@ def test_71_antenna_plot(self, field_test): secondary_sweep_value=30, title="Azimuth at {}Hz".format(ffdata.frequency), image_path=os.path.join(self.local_scratch.path, "2d2.jpg"), + show=False, ) assert os.path.exists(os.path.join(self.local_scratch.path, "2d2.jpg")) ffdata.polar_plot_3d( - quantity="RealizedGain", image_path=os.path.join(self.local_scratch.path, "3d1.jpg"), convert_to_db=True + quantity="RealizedGain", + image_path=os.path.join(self.local_scratch.path, "3d1.jpg"), + convert_to_db=True, + show=False, ) assert os.path.exists(os.path.join(self.local_scratch.path, "3d1.jpg")) @@ -708,7 +743,10 @@ def test_72_antenna_plot(self, array_test): assert os.path.exists(os.path.join(self.local_scratch.path, "2d2.jpg")) ffdata.polar_plot_3d( - quantity="RealizedGain", image_path=os.path.join(self.local_scratch.path, "3d1.jpg"), convert_to_db=True + quantity="RealizedGain", + image_path=os.path.join(self.local_scratch.path, "3d1.jpg"), + convert_to_db=True, + show=False, ) assert os.path.exists(os.path.join(self.local_scratch.path, "3d1.jpg")) diff --git a/_unittest/test_13_LoadAEDTFile.py b/_unittest/test_13_LoadAEDTFile.py index 32dae828262..256260eb42f 100644 --- a/_unittest/test_13_LoadAEDTFile.py +++ b/_unittest/test_13_LoadAEDTFile.py @@ -1,3 +1,27 @@ +# -*- 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 base64 import filecmp import os diff --git a/_unittest/test_14_AedtLogger.py b/_unittest/test_14_AedtLogger.py index 09f246b13ec..ba8900b741a 100644 --- a/_unittest/test_14_AedtLogger.py +++ b/_unittest/test_14_AedtLogger.py @@ -1,3 +1,27 @@ +# -*- 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 io import logging import os @@ -230,10 +254,10 @@ def test_log_when_accessing_non_existing_object(self, caplog): from pyaedt import Hfss app = Hfss( - projectname="log_project", - designname="log_design", - specified_version=desktop_version, - new_desktop_session=True, + project="log_project", + design="log_design", + version=desktop_version, + new_desktop=True, ) with pytest.raises(AttributeError): app.get_object_material_properties("MS1", "conductivity") diff --git a/_unittest/test_15_ibs_reader.py b/_unittest/test_15_ibs_reader.py index e1d5453dacb..0fa6de41c51 100644 --- a/_unittest/test_15_ibs_reader.py +++ b/_unittest/test_15_ibs_reader.py @@ -1,3 +1,27 @@ +# -*- 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 from _unittest.conftest import local_path diff --git a/_unittest/test_16_3d_stackup.py b/_unittest/test_16_3d_stackup.py index 0a503983b66..9250fdd7dea 100644 --- a/_unittest/test_16_3d_stackup.py +++ b/_unittest/test_16_3d_stackup.py @@ -1,3 +1,27 @@ +# -*- 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 pytest diff --git a/_unittest/test_20_HFSS.py b/_unittest/test_20_HFSS.py index f70f81b9117..48ffe2c4f37 100644 --- a/_unittest/test_20_HFSS.py +++ b/_unittest/test_20_HFSS.py @@ -1,3 +1,27 @@ +# -*- 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 math import os import shutil @@ -943,7 +967,7 @@ def test_33_copy_solid_bodies(self, add_app): design_name = "HfssCopiedBodies" new_design = add_app(project_name=project_name, design_name=design_name) num_orig_bodies = len(self.aedtapp.modeler.solid_names) - assert new_design.copy_solid_bodies_from(self.aedtapp, vacuum=False, pec=False) + assert new_design.copy_solid_bodies_from(self.aedtapp, no_vacuum=False, no_pec=False) assert len(new_design.modeler.solid_bodies) == num_orig_bodies new_design.delete_design(design_name) new_design.close_project(project_name) @@ -1296,7 +1320,7 @@ def test_52_crate_setup_hybrid_sbr(self, add_app): assert bound.props["Type"] == "IE" bound.props["Type"] = "PO" assert bound.props["Type"] == "PO" - aedtapp.close_project(save_project=False) + aedtapp.close_project(save=False) def test_53_import_source_excitation(self, add_app): aedtapp = add_app(solution_type="Modal", project_name="test_53") @@ -1310,7 +1334,7 @@ def test_53_import_source_excitation(self, add_app): assert aedtapp.edit_source_from_file( aedtapp.excitations[0], time_domain, is_time_domain=True, x_scale=1e-6, y_scale=1e-3, data_format="Voltage" ) - aedtapp.close_project(save_project=False) + aedtapp.close_project(save=False) def test_54_assign_symmetry(self, add_app): aedtapp = add_app(project_name="test_54", solution_type="Modal") @@ -1330,7 +1354,7 @@ def test_54_assign_symmetry(self, add_app): assert not aedtapp.assign_symmetry(ids[0]) assert not aedtapp.assign_symmetry("test") assert aedtapp.set_impedance_multiplier(2) - aedtapp.close_project(save_project=False) + aedtapp.close_project(save=False) def test_55_create_near_field_sphere(self): air = self.aedtapp.modeler.create_box([0, 0, 0], [20, 20, 20], name="rad", material="vacuum") @@ -1630,13 +1654,13 @@ def test_66_assign_febi(self, add_app): aedtapp.hybrid = True assert aedtapp.assign_febi(["inner"]) assert len(aedtapp.boundaries) == 1 - aedtapp.close_project(save_project=False) + aedtapp.close_project(save=False) def test_67_transient_composite(self, add_app): aedtapp = add_app(project_name="test_66") aedtapp.solution_type = "Transient Composite" assert aedtapp.solution_type == "Transient Composite" - aedtapp.close_project(save_project=False) + aedtapp.close_project(save=False) @pytest.mark.skipif(config["NonGraphical"], reason="Test fails on build machine") def test_68_import_gds_3d(self): diff --git a/_unittest/test_21_Circuit.py b/_unittest/test_21_Circuit.py index 23b44ed622e..f342e63d75d 100644 --- a/_unittest/test_21_Circuit.py +++ b/_unittest/test_21_Circuit.py @@ -1,3 +1,27 @@ +# -*- 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 @@ -6,7 +30,7 @@ import pytest from pyaedt import Circuit -from pyaedt import is_linux +from pyaedt.generic.settings import is_linux test_subfolder = "T21" diff --git a/_unittest/test_22_Circuit_DynamicLink.py b/_unittest/test_22_Circuit_DynamicLink.py index 4756805a3b9..37891b77d86 100644 --- a/_unittest/test_22_Circuit_DynamicLink.py +++ b/_unittest/test_22_Circuit_DynamicLink.py @@ -1,3 +1,27 @@ +# -*- 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 from _unittest.conftest import config @@ -7,8 +31,8 @@ from pyaedt import Circuit from pyaedt import Q2d from pyaedt import Q3d -from pyaedt import is_ironpython -from pyaedt import is_linux +from pyaedt.generic.general_methods import is_ironpython +from pyaedt.generic.settings import is_linux test_subfloder = "T22" test_project_name = "Dynamic_Link" diff --git a/_unittest/test_27_Maxwell2D.py b/_unittest/test_27_Maxwell2D.py index 39f36dae04a..d19bd64ce6b 100644 --- a/_unittest/test_27_Maxwell2D.py +++ b/_unittest/test_27_Maxwell2D.py @@ -1,4 +1,29 @@ #!/ekm/software/anaconda3/bin/python + +# -*- 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 collections import OrderedDict import os import shutil diff --git a/_unittest/test_28_Maxwell3D.py b/_unittest/test_28_Maxwell3D.py index d60dbd56748..5cb4110b245 100644 --- a/_unittest/test_28_Maxwell3D.py +++ b/_unittest/test_28_Maxwell3D.py @@ -1,3 +1,27 @@ +# -*- 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 shutil @@ -480,7 +504,7 @@ def test_32_matrix(self, add_app): L = m3d.assign_matrix(assignment="Current1") assert not L - def test_32B_matrix(self, add_app): + def test_32a_matrix(self, add_app): m3d = add_app(application=Maxwell3d, design_name="Matrix2") m3d.solution_type = SOLUTIONS.Maxwell3d.EddyCurrent m3d.modeler.create_box([0, 1.5, 0], [1, 2.5, 5], name="Coil_1", material="aluminum") @@ -493,22 +517,24 @@ def test_32B_matrix(self, add_app): rectangle3 = m3d.modeler.create_rectangle(0, [16.5, 1.5, 0], [2.5, 5], name="Sheet3") rectangle4 = m3d.modeler.create_rectangle(0, [32.5, 1.5, 0], [2.5, 5], name="Sheet4") + m3d.modeler.create_polyline(points=[[1, 2.75, 2.5], [8.5, 2.75, 2.5]], name="line_test") + m3d.assign_current(rectangle1.faces[0], amplitude=1, name="Cur1") m3d.assign_current(rectangle2.faces[0], amplitude=1, name="Cur2") m3d.assign_current(rectangle3.faces[0], amplitude=1, name="Cur3") m3d.assign_current(rectangle4.faces[0], amplitude=1, name="Cur4") - L = m3d.assign_matrix(assignment=["Cur1", "Cur2", "Cur3"]) - out = L.join_series(["Cur1", "Cur2"]) + L = m3d.assign_matrix(assignment=["Cur1", "Cur2", "Cur3"], matrix_name="Matrix1") + out = L.join_series(sources=["Cur1", "Cur2"], matrix_name="ReducedMatrix1") assert isinstance(out[0], str) assert isinstance(out[1], str) - out = L.join_parallel(["Cur1", "Cur3"]) + out = L.join_parallel(["Cur1", "Cur3"], matrix_name="ReducedMatrix2") assert isinstance(out[0], str) assert isinstance(out[1], str) out = L.join_parallel(["Cur5"]) assert not out[0] - def test_32a_export_rl_matrix(self): + def test_32b_export_rl_matrix(self): self.aedtapp.set_active_design("Matrix2") L = self.aedtapp.assign_matrix(assignment=["Cur1", "Cur2", "Cur3"], matrix_name="matrix_export_test") L.join_series(["Cur1", "Cur2"], matrix_name="reduced_matrix_export_test") @@ -527,6 +553,75 @@ def test_32a_export_rl_matrix(self): assert self.aedtapp.export_rl_matrix("matrix_export_test", export_path_2, False, 10, 3, True) assert os.path.exists(export_path_2) + def test_32c_post_processing(self): + expressions = self.aedtapp.post.available_report_quantities( + report_category="EddyCurrent", display_type="Data Table", context={"Matrix1": "ReducedMatrix1"} + ) + assert isinstance(expressions, list) + categories = self.aedtapp.post.available_quantities_categories( + report_category="EddyCurrent", display_type="Data Table", context={"Matrix1": "ReducedMatrix1"} + ) + assert isinstance(categories, list) + assert "R" in categories + assert "L" in categories + categories = self.aedtapp.post.available_quantities_categories( + report_category="EddyCurrent", display_type="Data Table", context="Matrix1" + ) + assert isinstance(categories, list) + assert "R" in categories + assert "L" in categories + assert "Z" in categories + categories = self.aedtapp.post.available_quantities_categories( + report_category="EddyCurrent", display_type="Data Table" + ) + assert isinstance(categories, list) + assert "R" in categories + assert "L" in categories + assert "Z" in categories + report = self.aedtapp.post.create_report( + expressions=expressions, + context={"Matrix1": "ReducedMatrix1"}, + plot_type="Data Table", + plot_name="reduced_matrix", + ) + assert report.expressions == expressions + assert report.matrix == "Matrix1" + assert report.reduced_matrix == "ReducedMatrix1" + data = self.aedtapp.post.get_solution_data(expressions=expressions, context={"Matrix1": "ReducedMatrix1"}) + assert data + expressions = self.aedtapp.post.available_report_quantities( + report_category="EddyCurrent", display_type="Data Table" + ) + assert isinstance(expressions, list) + expressions = self.aedtapp.post.available_report_quantities( + report_category="EddyCurrent", display_type="Data Table", context="Matrix1" + ) + assert isinstance(expressions, list) + report = self.aedtapp.post.create_report( + expressions=expressions, + context="Matrix1", + plot_type="Data Table", + plot_name="reduced_matrix", + ) + assert report.expressions == expressions + assert report.matrix == "Matrix1" + assert not report.reduced_matrix + data = self.aedtapp.post.get_solution_data(expressions=expressions, context="Matrix1") + assert data + + report = self.aedtapp.post.create_report( + expressions="Mag_H", context="line_test", primary_sweep_variable="Distance", report_category="Fields" + ) + assert report.expressions == ["Mag_H"] + assert report.polyline == "line_test" + data = self.aedtapp.post.get_solution_data( + expressions=["Mag_H"], + context="line_test", + report_category="Fields", + primary_sweep_variable="Distance", + ) + assert data + def test_33_mesh_settings(self): assert self.aedtapp.mesh.initial_mesh_settings assert self.aedtapp.mesh.initial_mesh_settings.props diff --git a/_unittest/test_29_Mechanical.py b/_unittest/test_29_Mechanical.py index c353a1d505d..d00903202b2 100644 --- a/_unittest/test_29_Mechanical.py +++ b/_unittest/test_29_Mechanical.py @@ -1,3 +1,27 @@ +# -*- 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 shutil diff --git a/_unittest/test_30_Q2D.py b/_unittest/test_30_Q2D.py index ec88160bca7..53a4e41c8f9 100644 --- a/_unittest/test_30_Q2D.py +++ b/_unittest/test_30_Q2D.py @@ -1,3 +1,27 @@ +# -*- 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 from _unittest.conftest import config @@ -102,7 +126,7 @@ def test_11_matrix_reduction(self, add_app): assert q2d.matrices[4].name == "Test4" assert q2d.insert_reduced_matrix(q2d.MATRIXOPERATIONS.DiffPair, ["Circle2", "Circle3"], "Test5", "New_net") assert q2d.matrices[5].name == "Test5" - self.aedtapp.close_project(q2d.project_name, save_project=False) + self.aedtapp.close_project(q2d.project_name, save=False) def test_12_edit_sources(self, add_app): q2d = add_app(application=Q2d, project_name=self.test_matrix, just_open=True) @@ -119,7 +143,7 @@ def test_12_edit_sources(self, add_app): sources_ac = {"Circle5": "40A"} assert not q2d.edit_sources(sources_cg, sources_ac) - self.aedtapp.close_project(q2d.project_name, save_project=False) + self.aedtapp.close_project(q2d.project_name, save=False) def test_13_get_all_conductors(self): self.aedtapp.insert_design("condcutors") @@ -189,7 +213,7 @@ def test_14_export_matrix_data(self, add_app): assert not q2d.export_matrix_data(os.path.join(self.local_scratch.path, "test_2d.txt"), c_unit="H") assert q2d.export_matrix_data(os.path.join(self.local_scratch.path, "test_2d.txt"), g_unit="fSie") assert not q2d.export_matrix_data(os.path.join(self.local_scratch.path, "test_2d.txt"), g_unit="A") - self.aedtapp.close_project(q2d.project_name, save_project=True) + self.aedtapp.close_project(q2d.project_name, save=True) def test_15_export_equivalent_circuit(self, add_app): q2d = add_app(application=Q2d, project_name=self.test_matrix, just_open=True) @@ -274,13 +298,13 @@ def test_15_export_equivalent_circuit(self, add_app): assert not q2d.export_equivalent_circuit( output_file=os.path.join(self.local_scratch.path, "test_export_circuit.cir"), model="test" ) - self.aedtapp.close_project(q2d.project_name, save_project=False) + self.aedtapp.close_project(q2d.project_name, save=False) def test_16_export_results_q2d(self, add_app): q2d = add_app(application=Q2d, project_name=self.test_matrix, just_open=True) exported_files = q2d.export_results(analyze=True) assert len(exported_files) > 0 - self.aedtapp.close_project(q2d.project_name, save_project=False) + self.aedtapp.close_project(q2d.project_name, save=False) def test_17_set_variable(self): self.aedtapp.variable_manager.set_variable("var_test", expression="123") diff --git a/_unittest/test_32_RMxprt.py b/_unittest/test_32_RMxprt.py index 97ffb03a56d..a6883dcd807 100644 --- a/_unittest/test_32_RMxprt.py +++ b/_unittest/test_32_RMxprt.py @@ -1,3 +1,27 @@ +# -*- 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 pytest diff --git a/_unittest/test_34_TwinBuilder.py b/_unittest/test_34_TwinBuilder.py index b7714db35ef..27103b11947 100644 --- a/_unittest/test_34_TwinBuilder.py +++ b/_unittest/test_34_TwinBuilder.py @@ -1,3 +1,27 @@ +# -*- 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 from _unittest.conftest import NONGRAPHICAL diff --git a/_unittest/test_35_MaxwellCircuit.py b/_unittest/test_35_MaxwellCircuit.py index 1e4b627bb86..a13e7bd1360 100644 --- a/_unittest/test_35_MaxwellCircuit.py +++ b/_unittest/test_35_MaxwellCircuit.py @@ -1,3 +1,27 @@ +# -*- 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 from _unittest.conftest import local_path diff --git a/_unittest/test_36_Q2D_PostProcessing.py b/_unittest/test_36_Q2D_PostProcessing.py index 6a50e6feb4e..7c0e58d8076 100644 --- a/_unittest/test_36_Q2D_PostProcessing.py +++ b/_unittest/test_36_Q2D_PostProcessing.py @@ -1,3 +1,27 @@ +# -*- 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 from _unittest.conftest import config diff --git a/_unittest/test_37_Genetic_Algorithm.py b/_unittest/test_37_Genetic_Algorithm.py index a0b382abc80..323eed56c4a 100644 --- a/_unittest/test_37_Genetic_Algorithm.py +++ b/_unittest/test_37_Genetic_Algorithm.py @@ -1,3 +1,27 @@ +# -*- 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 random import time diff --git a/_unittest/test_41_3dlayout_modeler.py b/_unittest/test_41_3dlayout_modeler.py index b72b7761d77..bbc425e938e 100644 --- a/_unittest/test_41_3dlayout_modeler.py +++ b/_unittest/test_41_3dlayout_modeler.py @@ -1,3 +1,27 @@ +# -*- 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 tempfile import time @@ -299,6 +323,8 @@ def test_12_create_line(self): line.center_line = {"Pt0": ["0mm", "0mm"]} assert line.remove("Pt1") assert line.add([1, 2], 1) + assert line.set_property_value("Pt0", "10mm ,10mm") + assert line.get_property_value("Pt0") == "10 ,10" def test_13a_create_edge_port(self): port_wave = self.aedtapp.create_edge_port("line1", 3, False, True, 6, 4, "2mm") diff --git a/_unittest/test_43_CableModeling.py b/_unittest/test_43_CableModeling.py index ea2430f4cb0..a200d51ce64 100644 --- a/_unittest/test_43_CableModeling.py +++ b/_unittest/test_43_CableModeling.py @@ -1,3 +1,27 @@ +# -*- 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 from _unittest.conftest import config diff --git a/_unittest/test_44_TouchstoneParser.py b/_unittest/test_44_TouchstoneParser.py index a7ed22c3ff8..45fb945c164 100644 --- a/_unittest/test_44_TouchstoneParser.py +++ b/_unittest/test_44_TouchstoneParser.py @@ -1,3 +1,27 @@ +# -*- 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 from _unittest.conftest import local_path diff --git a/_unittest/test_98_Icepak.py b/_unittest/test_98_Icepak.py index 89f220e914a..f9983fc56a2 100644 --- a/_unittest/test_98_Icepak.py +++ b/_unittest/test_98_Icepak.py @@ -1,3 +1,27 @@ +# -*- 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 from _unittest.conftest import config @@ -70,20 +94,34 @@ def test_02_ImportPCB(self): assert len(self.aedtapp.native_components) == 1 assert len(self.aedtapp.modeler.user_defined_component_names) == 1 - def test_02b_PCB_filters(self): + def test_02b_PCB_filters(self, local_scratch): new_component = os.path.join(local_path, "example_models", "T40", "Package.aedt") + new_component_edb = os.path.join(local_path, "example_models", "T40", "Package.aedb") + new_component_dest = os.path.join(local_scratch.path, "Package.aedt") + local_scratch.copyfolder(new_component_edb, os.path.join(local_scratch.path, "Package.aedb")) + local_scratch.copyfile(new_component, new_component_dest) cmp2 = self.aedtapp.create_ipk_3dcomponent_pcb( "Board_w_cmp", - [new_component, "FlipChip_TopBot", "HFSS PI Setup 1", en_ForceSimulation, en_PreserveResults], + [new_component_dest, "FlipChip_TopBot", "HFSS PI Setup 1", en_ForceSimulation, en_PreserveResults], solution_freq, resolution, custom_x_resolution=400, custom_y_resolution=500, extent_type="Polygon", ) - assert cmp2.set_parts("Package Parts", True, "Steel-mild-surface") - assert cmp2.set_parts("Device Parts", True, "Steel-mild-surface") + assert cmp2.set_device_parts(True, "Steel-mild-surface") + assert cmp2.disable_device_parts() + assert cmp2.set_package_parts(solderballs="Boxes", connector="Solderbump", solderbumps_modeling="Lumped") + assert cmp2.set_package_parts( + solderballs="Lumped", connector="Bondwire", bondwire_material="Al-Extruded", bondwire_diameter="0.5mm" + ) + assert not cmp2.set_package_parts(solderballs="Error1") # invalid input + assert not cmp2.set_package_parts(connector="Error2") # invalid input + assert not cmp2.set_package_parts(solderbumps_modeling="Error3") # invalid input + assert not cmp2.set_package_parts(bondwire_material="Error4") # material does not exist assert not bool(cmp2.overridden_components) + assert not cmp2.override_component("FCHIP", True) # invalid part import selection + assert cmp2.set_device_parts() assert cmp2.override_component("FCHIP", True) assert "Board_w_cmp_FCHIP_device" not in self.aedtapp.modeler.object_names assert cmp2.override_component("FCHIP", False) @@ -93,15 +131,27 @@ def test_02b_PCB_filters(self): assert cmp2.set_board_settings("Polygon") assert cmp2.set_board_settings("Bounding Box") assert cmp2.set_board_settings("Polygon", "outline:poly_0") + cmp2.disable_device_parts() + cmp2.footprint_filter = "1mm2" + assert cmp2.footprint_filter is None + cmp2.power_filter = "1W" + assert cmp2.power_filter is None + cmp2.type_filters = "Resistors" + assert cmp2.type_filters is None + cmp2.height_filter = "1mm" + assert cmp2.height_filter is None + cmp2.objects_2d_filter = True + assert cmp2.objects_2d_filter is None + component_name = "RadioBoard2" cmp = self.aedtapp.create_ipk_3dcomponent_pcb( component_name, link_data, solution_freq, resolution, custom_x_resolution=400, custom_y_resolution=500 ) + assert not cmp.filters + assert cmp.set_device_parts() f = cmp.filters assert len(f.keys()) == 1 assert all(not v for v in f["Type"].values()) - assert not cmp.set_parts("Device Pt") - assert cmp.set_parts("Device Parts", True, "Steel-mild-surface") assert cmp.height_filter is None assert cmp.footprint_filter is None assert cmp.power_filter is None @@ -297,8 +347,11 @@ def test_12a_AssignMeshOperation(self): mesh_level_Filter = "2" component_name = ["RadioBoard1_1"] mesh_level_RadioPCB = "1" - test = self.aedtapp.mesh.assign_mesh_level_to_group(mesh_level_Filter, group_name) + assert self.aedtapp.mesh.assign_mesh_level_to_group(mesh_level_Filter, group_name) + test = self.aedtapp.mesh.assign_mesh_level_to_group(mesh_level_Filter, group_name, name="Test") assert test + test2 = self.aedtapp.mesh.assign_mesh_level_to_group(mesh_level_Filter, group_name, name="Test") + assert test.name != test2.name # assert self.aedtapp.mesh.assignMeshLevel2Component(mesh_level_RadioPCB, component_name) test = self.aedtapp.mesh.assign_mesh_region(component_name, mesh_level_RadioPCB, is_submodel=True) assert test @@ -773,13 +826,12 @@ def test_50_advanced3dcomp_export(self): "test_dataset", [1, 2, 3, 4], [1, 2, 3, 4], - zlist=None, - vlist=None, + z=None, + v=None, is_project_dataset=False, - xunit="cel", - yunit="W", - zunit="", - vunit="", + x_unit="cel", + y_unit="W", + v_unit="", ) file_path = self.local_scratch.path file_name = "Advanced3DComp.a3dcomp" @@ -804,13 +856,12 @@ def test_50_advanced3dcomp_export(self): "test_ignore", [1, 2, 3, 4], [1, 2, 3, 4], - zlist=None, - vlist=None, + z=None, + v=None, is_project_dataset=False, - xunit="cel", - yunit="W", - zunit="", - vunit="", + x_unit="cel", + y_unit="W", + v_unit="", ) file_name = "Advanced3DComp1.a3dcomp" mon_list = list(self.aedtapp.monitor.all_monitors.keys()) @@ -859,13 +910,12 @@ def test_51_advanced3dcomp_import(self): "test_dataset", [1, 2, 3, 4], [1, 2, 3, 4], - zlist=None, - vlist=None, + z=None, + v=None, is_project_dataset=False, - xunit="cel", - yunit="W", - zunit="", - vunit="", + x_unit="cel", + y_unit="W", + v_unit="", ) file_path = self.local_scratch.path file_name = "Advanced3DComp_T51.a3dcomp" @@ -884,13 +934,12 @@ def test_51_advanced3dcomp_import(self): "test_ignore", [1, 2, 3, 4], [1, 2, 3, 4], - zlist=None, - vlist=None, + z=None, + v=None, is_project_dataset=False, - xunit="cel", - yunit="W", - zunit="", - vunit="", + x_unit="cel", + y_unit="W", + v_unit="", ) mon_list = list(self.aedtapp.monitor.all_monitors.keys()) self.aedtapp.monitor.assign_point_monitor([0, 0, 0]) @@ -1429,7 +1478,7 @@ def test_68_mesh_priority_3d_comp(self, add_app): assert app.mesh.add_priority(entity_type=2, component="all_3d_objects1", priority=2) - app.close_project(name="3d_comp_mesh_prio_test", save_project=False) + app.close_project(name="3d_comp_mesh_prio_test", save=False) def test_69_recirculation_boundary(self): box = self.aedtapp.modeler.create_box([5, 5, 5], [1, 2, 3], "BlockBoxEmpty", "copper") @@ -1584,7 +1633,7 @@ def test_73_conducting_plate(self): def test_74_boundary_conditions_dictionaries(self): box1 = self.aedtapp.modeler.create_box([5, 5, 5], [1, 2, 3]) ds_temp = self.aedtapp.create_dataset( - "ds_temp3", [1, 2, 3], [3, 2, 1], is_project_dataset=False, xunit="cel", yunit="W" + "ds_temp3", [1, 2, 3], [3, 2, 1], is_project_dataset=False, x_unit="cel", y_unit="W" ) bc1 = self.aedtapp.create_temp_dep_assignment(ds_temp.name) assert bc1 @@ -1594,7 +1643,7 @@ def test_74_boundary_conditions_dictionaries(self): self.aedtapp.solution_type = "Transient" ds_time = self.aedtapp.create_dataset( - "ds_time3", [1, 2, 3], [3, 2, 1], is_project_dataset=False, xunit="s", yunit="W" + "ds_time3", [1, 2, 3], [3, 2, 1], is_project_dataset=False, x_unit="s", y_unit="W" ) bc2 = self.aedtapp.create_dataset_transient_assignment(ds_time.name) rect = self.aedtapp.modeler.create_rectangle(self.aedtapp.PLANE.XY, [0, 0, 0], [20, 10]) @@ -1641,7 +1690,7 @@ def test_74_boundary_conditions_dictionaries(self): ) ds1_temp = self.aedtapp.create_dataset( - "ds_temp3", [1, 2, 3], [3, 2, 1], is_project_dataset=True, xunit="cel", yunit="W" + "ds_temp3", [1, 2, 3], [3, 2, 1], is_project_dataset=True, x_unit="cel", y_unit="W" ) assert not self.aedtapp.create_temp_dep_assignment(ds1_temp.name) assert not self.aedtapp.create_temp_dep_assignment("nods") @@ -1671,3 +1720,49 @@ def test_76_design_settings(self): assert d["GravityDir"] == "Positive" d["GravityVec"] = "Global::Y" assert d["GravityVec"] == "Global::Y" + + def test_78_restart_solution(self): + self.aedtapp.insert_design("test_78-1") + self.aedtapp.insert_design("test_78-2") + self.aedtapp.set_active_design("test_78-1") + self.aedtapp["a"] = "1mm" + self.aedtapp.modeler.create_box([0, 0, 0], ["a", "1", "2"]) + s1 = self.aedtapp.create_setup() + self.aedtapp.set_active_design("test_78-2") + self.aedtapp["b"] = "1mm" + self.aedtapp.modeler.create_box([0, 0, 0], ["b", "1", "2"]) + s2 = self.aedtapp.create_setup() + assert s2.start_continue_from_previous_setup( + "test_78-1", "{} : SteadyState".format(s1.name), parameters={"a": "1mm"} + ) + s2.delete() + s2 = self.aedtapp.create_setup() + assert s2.start_continue_from_previous_setup("test_78-1", "{} : SteadyState".format(s1.name), parameters=None) + s2.delete() + s2 = self.aedtapp.create_setup() + assert not s2.start_continue_from_previous_setup( + "test_78-1", "{} : SteadyState".format(s1.name), project="FakeFolder123" + ) + assert not s2.start_continue_from_previous_setup("test_78-12", "{} : SteadyState".format(s1.name)) + + def test_79_mesh_reuse(self): + self.aedtapp.insert_design("test_79") + self.aedtapp.set_active_design("test_79") + cylinder = self.aedtapp.modeler.create_cylinder(1, [0, 0, 0], 5, 30) + assert not self.aedtapp.mesh.assign_mesh_reuse( + cylinder.name, + os.path.join(local_path, "../_unittest/example_models", test_subfolder, "nonexistent_cylinder_mesh.msh"), + ) + assert self.aedtapp.mesh.assign_mesh_reuse( + cylinder.name, os.path.join(local_path, "../_unittest/example_models", test_subfolder, "cylinder_mesh.msh") + ) + assert self.aedtapp.mesh.assign_mesh_reuse( + cylinder.name, + os.path.join(local_path, "../_unittest/example_models", test_subfolder, "cylinder_mesh.msh"), + "name_reuse", + ) + assert self.aedtapp.mesh.assign_mesh_reuse( + cylinder.name, + os.path.join(local_path, "../_unittest/example_models", test_subfolder, "cylinder_mesh.msh"), + "name_reuse", + ) diff --git a/_unittest/test_launch_desktop.py b/_unittest/test_launch_desktop.py index 37e928cbdf6..6f1e464321c 100644 --- a/_unittest/test_launch_desktop.py +++ b/_unittest/test_launch_desktop.py @@ -1,3 +1,27 @@ +# -*- 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 pytest diff --git a/_unittest/test_utils.py b/_unittest/test_utils.py index a87c0010036..397d493630d 100644 --- a/_unittest/test_utils.py +++ b/_unittest/test_utils.py @@ -1,3 +1,27 @@ +# -*- 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. + """Test utility functions of PyAEDT. """ @@ -7,8 +31,8 @@ import pytest -from pyaedt import settings from pyaedt.generic.general_methods import pyaedt_function_handler +from pyaedt.generic.settings import settings SETTINGS_RELEASE_ON_EXCEPTION = settings.release_on_exception SETTINGS_ENABLE_ERROR_HANDLER = settings.enable_error_handler diff --git a/_unittest/test_warnings.py b/_unittest/test_warnings.py index 7a2c7b1bec4..a1ba7badbb7 100644 --- a/_unittest/test_warnings.py +++ b/_unittest/test_warnings.py @@ -1,3 +1,27 @@ +# -*- 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 sys from unittest.mock import patch import warnings diff --git a/_unittest_solvers/conftest.py b/_unittest_solvers/conftest.py index 6d581605884..29a6b3b864f 100644 --- a/_unittest_solvers/conftest.py +++ b/_unittest_solvers/conftest.py @@ -164,10 +164,10 @@ def _method( if not application: application = Hfss return application( - projectname=test_project, - designname=design_name, + project=test_project, + design=design_name, solution_type=solution_type, - specified_version=desktop_version, + version=desktop_version, ) return _method diff --git a/_unittest_solvers/example_models/T01/compliance/ANSYS-HSD_V1_0_test.aedtz b/_unittest_solvers/example_models/T01/compliance/ANSYS-HSD_V1_0_test.aedtz index be4ebe5c0cc..dc1da4afdb6 100644 Binary files a/_unittest_solvers/example_models/T01/compliance/ANSYS-HSD_V1_0_test.aedtz and b/_unittest_solvers/example_models/T01/compliance/ANSYS-HSD_V1_0_test.aedtz differ diff --git a/_unittest_solvers/example_models/T01/compliance/general_compliance_template.json b/_unittest_solvers/example_models/T01/compliance/general_compliance_template.json index 1f51d87e736..08af8bae72d 100644 --- a/_unittest_solvers/example_models/T01/compliance/general_compliance_template.json +++ b/_unittest_solvers/example_models/T01/compliance/general_compliance_template.json @@ -46,7 +46,7 @@ "type": "statistical eye", "config": "StatisticalEyeDiagram_Custom.json", "quantity_type": 3, - "traces": ["b_input_67"], + "traces": ["b_input_67", "b_input_119"], "pass_fail": true }, {"name": "eye3", @@ -54,7 +54,7 @@ "type": "contour eye diagram", "config": "ContourEyeDiagram_Custom.json", "quantity_type": 3, - "traces": ["b_input_67"], + "traces": ["b_input_67", "b_input_119"], "pass_fail": true }, {"name": "eye2", diff --git a/_unittest_solvers/example_models/T45/ANSYS-HSD_V1.aedb/edb.def b/_unittest_solvers/example_models/T45/ANSYS-HSD_V1.aedb/edb.def new file mode 100644 index 00000000000..51fcd27e22a Binary files /dev/null and b/_unittest_solvers/example_models/T45/ANSYS-HSD_V1.aedb/edb.def differ diff --git a/_unittest_solvers/example_models/T45/ANSYS-HSD_V1.aedt b/_unittest_solvers/example_models/T45/ANSYS-HSD_V1.aedt new file mode 100644 index 00000000000..f6b1505d130 --- /dev/null +++ b/_unittest_solvers/example_models/T45/ANSYS-HSD_V1.aedt @@ -0,0 +1,5431 @@ +$begin 'AnsoftProject' + Created='Fri Jun 21 09:25:15 2024' + Product='ElectronicsDesktop' + FileOwnedByWorkbench=false + $begin 'Desktop' + Version(2024, 1) + InfrastructureVersion(1, 0) + $begin 'FactoryHeader' + $begin 'geometry3deditor' + KernelVersion(2, 0) + ProjectContainsGeometry3D='0' + $end 'geometry3deditor' + $end 'FactoryHeader' + $end 'Desktop' + UsesAdvancedFeatures=false + NextUniqueID=0 + MoveBackwards=false + $begin 'HFSSEnvironment' + Version(1, 0) + $end 'HFSSEnvironment' + $begin 'PlanarEMEnvironment' + Version(1, 0) + $end 'PlanarEMEnvironment' + $begin 'Q3DEnvironment' + Version(1, 0) + $end 'Q3DEnvironment' + $begin '2DExtractorEnvironment' + Version(1, 0) + $end '2DExtractorEnvironment' + $begin 'NexximEnvironment' + Version(1, 0) + $end 'NexximEnvironment' + $begin 'NexximNetlistEnvironment' + Version(1, 0) + $end 'NexximNetlistEnvironment' + $begin 'EmitEnvironment' + Version(1, 0) + $end 'EmitEnvironment' + $begin 'Maxwell3DEnvironment' + Version(1, 0) + $end 'Maxwell3DEnvironment' + $begin 'Maxwell2DEnvironment' + Version(1, 0) + $end 'Maxwell2DEnvironment' + $begin 'RMxprtEnvironment' + Version(1, 0) + $end 'RMxprtEnvironment' + $begin 'MaxCirEnvironment' + Version(1, 0) + $end 'MaxCirEnvironment' + $begin 'SimplorerEnvironment' + Version(1, 0) + $end 'SimplorerEnvironment' + $begin 'IcepakEnvironment' + Version(1, 0) + $end 'IcepakEnvironment' + $begin 'MechanicalEnvironment' + Version(1, 0) + $end 'MechanicalEnvironment' + $begin 'SchematicEnvironment' + Version(1, 0) + $end 'SchematicEnvironment' + $begin 'geometry3deditor' + Version(1, 0) + $end 'geometry3deditor' + ReadVersion=11 + $begin 'EDB' + Path='' + LastUpdateTimeStamp=1718954715 + $end 'EDB' + $begin 'DesignMgrEnvironment' + CompInstCounter=1 + GPortCounter=0 + NetCounter=0 + Alias('Ieee;Simplorer Elements\\Ieee', 'Std;Simplorer Elements\\Std', 'Basic_VHDLAMS;Simplorer Elements\\Basic Elements VHDLAMS\\Basic Elements VHDLAMS', 'Digital_Elements;Simplorer Elements\\Digital Elements\\Digital Elements', 'Transformations;Simplorer Elements\\Tools\\Transformations\\Transformations', 'HEV_VHDLAMS;Simplorer Elements\\HEV VHDLAMS\\HEV VHDLAMS', 'automotive_vda;Simplorer Elements\\VDALibs VHDLAMS\\automotive_vda', 'example_boardnet;Simplorer Elements\\VDALibs VHDLAMS\\example_boardnet', 'example_ecar;Simplorer Elements\\VDALibs VHDLAMS\\example_ecar', 'fundamentals_vda;Simplorer Elements\\VDALibs VHDLAMS\\fundamentals_vda', 'hybrid_emc_vda;Simplorer Elements\\VDALibs VHDLAMS\\hybrid_emc_vda', 'megma;Simplorer Elements\\VDALibs VHDLAMS\\megma', 'modelica_rotational;Simplorer Elements\\VDALibs VHDLAMS\\modelica_rotational', 'modelica_thermal;Simplorer Elements\\VDALibs VHDLAMS\\modelica_thermal', 'modelica_translational;Simplorer Elements\\VDALibs VHDLAMS\\modelica_translational', 'spice2vhd;Simplorer Elements\\VDALibs VHDLAMS\\spice2vhd', 'spice2vhd_devices;Simplorer Elements\\VDALibs VHDLAMS\\spice2vhd_devices', 'aircraft_electrical_vhdlams;Simplorer Elements\\Aircraft Electrical VHDLAMS\\Aircraft Electrical VHDLAMS', 'power_system_vhdlams;Simplorer Elements\\Power System VHDLAMS\\Power System VHDLAMS') + $end 'DesignMgrEnvironment' + $begin 'ProjectDatasets' + NextUniqueID=0 + MoveBackwards=false + DatasetType='ProjectDatasetType' + $begin 'DatasetDefinitions' + $end 'DatasetDefinitions' + $end 'ProjectDatasets' + VariableOrders[0:] + $begin 'Definitions' + $begin 'Materials' + $begin 'copper' + CoordinateSystemType='Cartesian' + BulkOrSurfaceType=1 + $begin 'PhysicsTypes' + set('Electromagnetic') + $end 'PhysicsTypes' + conductivity='58000000' + ModTime=1677073156 + Library='' + LibLocation='Project' + ModSinceLib=false + $end 'copper' + $begin 'Megtron4' + CoordinateSystemType='Cartesian' + BulkOrSurfaceType=1 + $begin 'PhysicsTypes' + set('Electromagnetic') + $end 'PhysicsTypes' + permittivity='3.77' + dielectric_loss_tangent='0.005' + ModTime=1677073156 + Library='' + LibLocation='Project' + ModSinceLib=false + $end 'Megtron4' + $begin 'Megtron4_2' + CoordinateSystemType='Cartesian' + BulkOrSurfaceType=1 + $begin 'PhysicsTypes' + set('Electromagnetic') + $end 'PhysicsTypes' + permittivity='3.47' + dielectric_loss_tangent='0.006' + ModTime=1677073156 + Library='' + LibLocation='Project' + ModSinceLib=false + $end 'Megtron4_2' + $begin 'Megtron4_3' + CoordinateSystemType='Cartesian' + BulkOrSurfaceType=1 + $begin 'PhysicsTypes' + set('Electromagnetic') + $end 'PhysicsTypes' + permittivity='4.2' + dielectric_loss_tangent='0.005' + ModTime=1677073156 + Library='' + LibLocation='Project' + ModSinceLib=false + $end 'Megtron4_3' + $begin 'Solder Resist' + CoordinateSystemType='Cartesian' + BulkOrSurfaceType=1 + $begin 'PhysicsTypes' + set('Electromagnetic') + $end 'PhysicsTypes' + permittivity='3' + dielectric_loss_tangent='0' + ModTime=1677073156 + Library='' + LibLocation='Project' + ModSinceLib=false + $end 'Solder Resist' + $begin 'FR4_epoxy' + CoordinateSystemType='Cartesian' + BulkOrSurfaceType=1 + $begin 'PhysicsTypes' + set('Electromagnetic', 'Thermal', 'Structural') + $end 'PhysicsTypes' + $begin 'AttachedData' + $begin 'MatAppearanceData' + property_data='appearance_data' + Red=27 + Green=110 + Blue=76 + $end 'MatAppearanceData' + $end 'AttachedData' + permittivity='4.4' + dielectric_loss_tangent='0.02' + thermal_conductivity='0.294' + mass_density='1900' + specific_heat='1150' + youngs_modulus='11000000000' + poissons_ratio='0.28' + thermal_expansion_coefficient='1.5e-05' + ModTime=1499970477 + Library='Materials' + LibLocation='SysLibrary' + ModSinceLib=false + $end 'FR4_epoxy' + $end 'Materials' + $begin 'SurfaceMaterials' + $end 'SurfaceMaterials' + $begin 'Scripts' + $end 'Scripts' + $begin 'Symbols' + $begin 'CAPC0603X33X15LL03T05' + ModTime=1718954704 + CE=0 + Library='' + ModSinceLib=false + LibLocation='Project' + HighestLevel=1 + Normalize=false + InitialLevels(0, 1) + $begin 'PinDef' + Pin('1', -0.00508, 0, 0, 'N', 0, 0.00254, false, 0, true, '', true, false, '1', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(-0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '1', false, false, ExtentRect(0, 0, 0, 0, -0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'PinDef' + Pin('2', 0.00508, 0, 3.14159265358979, 'N', 0, 0.00254, false, 0, true, '', true, false, '2', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '2', false, false, ExtentRect(0, 0, 0, 0, 0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'Graphics' + Rect(0, 0, 0, 0, 0, 0, 0.00508, 0.00508, 0, 0, 0) + Rect(0, 1, 0, 0, -0.00211666666666667, 0, 0.000423333333333333, 0.000423333333333334, 0, 0, 0) + $end 'Graphics' + $end 'CAPC0603X33X15LL03T05' + $begin 'CAPC1005X05N' + ModTime=1718954704 + CE=0 + Library='' + ModSinceLib=false + LibLocation='Project' + HighestLevel=1 + Normalize=false + InitialLevels(0, 1) + $begin 'PinDef' + Pin('2', -0.00508, 0, 0, 'N', 0, 0.00254, false, 0, true, '', true, false, '2', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(-0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '2', false, false, ExtentRect(0, 0, 0, 0, -0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'PinDef' + Pin('1', 0.00508, 0, 3.14159265358979, 'N', 0, 0.00254, false, 0, true, '', true, false, '1', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '1', false, false, ExtentRect(0, 0, 0, 0, 0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'Graphics' + Rect(0, 0, 0, 0, 0, 0, 0.00508, 0.00508, 0, 0, 0) + Rect(0, 1, 0, 0, -0.00211666666666667, 0, 0.000423333333333333, 0.000423333333333334, 0, 0, 0) + $end 'Graphics' + $end 'CAPC1005X05N' + $begin 'CAPC1005X33X10LL5' + ModTime=1718954704 + CE=0 + Library='' + ModSinceLib=false + LibLocation='Project' + HighestLevel=1 + Normalize=false + InitialLevels(0, 1) + $begin 'PinDef' + Pin('1', -0.00508, 0, 0, 'N', 0, 0.00254, false, 0, true, '', true, false, '1', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(-0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '1', false, false, ExtentRect(0, 0, 0, 0, -0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'PinDef' + Pin('2', 0.00508, 0, 3.14159265358979, 'N', 0, 0.00254, false, 0, true, '', true, false, '2', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '2', false, false, ExtentRect(0, 0, 0, 0, 0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'Graphics' + Rect(0, 0, 0, 0, 0, 0, 0.00508, 0.00508, 0, 0, 0) + Rect(0, 1, 0, 0, -0.00211666666666667, 0, 0.000423333333333333, 0.000423333333333334, 0, 0, 0) + $end 'Graphics' + $end 'CAPC1005X33X10LL5' + $begin 'CAPC1005X55X10LL05' + ModTime=1718954704 + CE=0 + Library='' + ModSinceLib=false + LibLocation='Project' + HighestLevel=1 + Normalize=false + InitialLevels(0, 1) + $begin 'PinDef' + Pin('2', -0.00508, 0, 0, 'N', 0, 0.00254, false, 0, true, '', true, false, '2', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(-0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '2', false, false, ExtentRect(0, 0, 0, 0, -0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'PinDef' + Pin('1', 0.00508, 0, 3.14159265358979, 'N', 0, 0.00254, false, 0, true, '', true, false, '1', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '1', false, false, ExtentRect(0, 0, 0, 0, 0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'Graphics' + Rect(0, 0, 0, 0, 0, 0, 0.00508, 0.00508, 0, 0, 0) + Rect(0, 1, 0, 0, -0.00211666666666667, 0, 0.000423333333333333, 0.000423333333333334, 0, 0, 0) + $end 'Graphics' + $end 'CAPC1005X55X10LL05' + $begin 'CAPC1005X55X23ML05T8' + ModTime=1718954704 + CE=0 + Library='' + ModSinceLib=false + LibLocation='Project' + HighestLevel=1 + Normalize=false + InitialLevels(0, 1) + $begin 'PinDef' + Pin('2', -0.00508, 0, 0, 'N', 0, 0.00254, false, 0, true, '', true, false, '2', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(-0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '2', false, false, ExtentRect(0, 0, 0, 0, -0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'PinDef' + Pin('1', 0.00508, 0, 3.14159265358979, 'N', 0, 0.00254, false, 0, true, '', true, false, '1', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '1', false, false, ExtentRect(0, 0, 0, 0, 0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'Graphics' + Rect(0, 0, 0, 0, 0, 0, 0.00508, 0.00508, 0, 0, 0) + Rect(0, 1, 0, 0, -0.00211666666666667, 0, 0.000423333333333333, 0.000423333333333334, 0, 0, 0) + $end 'Graphics' + $end 'CAPC1005X55X23ML05T8' + $begin 'CAPC1005X55X25LL05T10' + ModTime=1718954704 + CE=0 + Library='' + ModSinceLib=false + LibLocation='Project' + HighestLevel=1 + Normalize=false + InitialLevels(0, 1) + $begin 'PinDef' + Pin('1', -0.00508, 0, 0, 'N', 0, 0.00254, false, 0, true, '', true, false, '1', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(-0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '1', false, false, ExtentRect(0, 0, 0, 0, -0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'PinDef' + Pin('2', 0.00508, 0, 3.14159265358979, 'N', 0, 0.00254, false, 0, true, '', true, false, '2', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '2', false, false, ExtentRect(0, 0, 0, 0, 0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'Graphics' + Rect(0, 0, 0, 0, 0, 0, 0.00508, 0.00508, 0, 0, 0) + Rect(0, 1, 0, 0, -0.00211666666666667, 0, 0.000423333333333333, 0.000423333333333334, 0, 0, 0) + $end 'Graphics' + $end 'CAPC1005X55X25LL05T10' + $begin 'CAPC1005X55X25ML05T10' + ModTime=1718954704 + CE=0 + Library='' + ModSinceLib=false + LibLocation='Project' + HighestLevel=1 + Normalize=false + InitialLevels(0, 1) + $begin 'PinDef' + Pin('1', -0.00508, 0, 0, 'N', 0, 0.00254, false, 0, true, '', true, false, '1', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(-0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '1', false, false, ExtentRect(0, 0, 0, 0, -0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'PinDef' + Pin('2', 0.00508, 0, 3.14159265358979, 'N', 0, 0.00254, false, 0, true, '', true, false, '2', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '2', false, false, ExtentRect(0, 0, 0, 0, 0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'Graphics' + Rect(0, 0, 0, 0, 0, 0, 0.00508, 0.00508, 0, 0, 0) + Rect(0, 1, 0, 0, -0.00211666666666667, 0, 0.000423333333333333, 0.000423333333333334, 0, 0, 0) + $end 'Graphics' + $end 'CAPC1005X55X25ML05T10' + $begin 'CAPC1005X55X25NL05T10' + ModTime=1718954704 + CE=0 + Library='' + ModSinceLib=false + LibLocation='Project' + HighestLevel=1 + Normalize=false + InitialLevels(0, 1) + $begin 'PinDef' + Pin('2', -0.00508, 0, 0, 'N', 0, 0.00254, false, 0, true, '', true, false, '2', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(-0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '2', false, false, ExtentRect(0, 0, 0, 0, -0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'PinDef' + Pin('1', 0.00508, 0, 3.14159265358979, 'N', 0, 0.00254, false, 0, true, '', true, false, '1', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '1', false, false, ExtentRect(0, 0, 0, 0, 0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'Graphics' + Rect(0, 0, 0, 0, 0, 0, 0.00508, 0.00508, 0, 0, 0) + Rect(0, 1, 0, 0, -0.00211666666666667, 0, 0.000423333333333333, 0.000423333333333334, 0, 0, 0) + $end 'Graphics' + $end 'CAPC1005X55X25NL05T10' + $begin 'CAPC1608X08N' + ModTime=1718954704 + CE=0 + Library='' + ModSinceLib=false + LibLocation='Project' + HighestLevel=1 + Normalize=false + InitialLevels(0, 1) + $begin 'PinDef' + Pin('2', -0.00508, 0, 0, 'N', 0, 0.00254, false, 0, true, '', true, false, '2', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(-0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '2', false, false, ExtentRect(0, 0, 0, 0, -0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'PinDef' + Pin('1', 0.00508, 0, 3.14159265358979, 'N', 0, 0.00254, false, 0, true, '', true, false, '1', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '1', false, false, ExtentRect(0, 0, 0, 0, 0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'Graphics' + Rect(0, 0, 0, 0, 0, 0, 0.00508, 0.00508, 0, 0, 0) + Rect(0, 1, 0, 0, -0.00211666666666667, 0, 0.000423333333333333, 0.000423333333333334, 0, 0, 0) + $end 'Graphics' + $end 'CAPC1608X08N' + $begin 'CAPC1608X90X35ML10T15' + ModTime=1718954704 + CE=0 + Library='' + ModSinceLib=false + LibLocation='Project' + HighestLevel=1 + Normalize=false + InitialLevels(0, 1) + $begin 'PinDef' + Pin('2', -0.00508, 0, 0, 'N', 0, 0.00254, false, 0, true, '', true, false, '2', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(-0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '2', false, false, ExtentRect(0, 0, 0, 0, -0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'PinDef' + Pin('1', 0.00508, 0, 3.14159265358979, 'N', 0, 0.00254, false, 0, true, '', true, false, '1', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '1', false, false, ExtentRect(0, 0, 0, 0, 0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'Graphics' + Rect(0, 0, 0, 0, 0, 0, 0.00508, 0.00508, 0, 0, 0) + Rect(0, 1, 0, 0, -0.00211666666666667, 0, 0.000423333333333333, 0.000423333333333334, 0, 0, 0) + $end 'Graphics' + $end 'CAPC1608X90X35ML10T15' + $begin 'CAPC2012X12N' + ModTime=1718954704 + CE=0 + Library='' + ModSinceLib=false + LibLocation='Project' + HighestLevel=1 + Normalize=false + InitialLevels(0, 1) + $begin 'PinDef' + Pin('1', -0.00508, 0, 0, 'N', 0, 0.00254, false, 0, true, '', true, false, '1', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(-0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '1', false, false, ExtentRect(0, 0, 0, 0, -0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'PinDef' + Pin('2', 0.00508, 0, 3.14159265358979, 'N', 0, 0.00254, false, 0, true, '', true, false, '2', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '2', false, false, ExtentRect(0, 0, 0, 0, 0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'Graphics' + Rect(0, 0, 0, 0, 0, 0, 0.00508, 0.00508, 0, 0, 0) + Rect(0, 1, 0, 0, -0.00211666666666667, 0, 0.000423333333333333, 0.000423333333333334, 0, 0, 0) + $end 'Graphics' + $end 'CAPC2012X12N' + $begin 'CAPC2013X100X20NL20' + ModTime=1718954704 + CE=0 + Library='' + ModSinceLib=false + LibLocation='Project' + HighestLevel=1 + Normalize=false + InitialLevels(0, 1) + $begin 'PinDef' + Pin('1', -0.00508, 0, 0, 'N', 0, 0.00254, false, 0, true, '', true, false, '1', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(-0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '1', false, false, ExtentRect(0, 0, 0, 0, -0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'PinDef' + Pin('2', 0.00508, 0, 3.14159265358979, 'N', 0, 0.00254, false, 0, true, '', true, false, '2', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '2', false, false, ExtentRect(0, 0, 0, 0, 0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'Graphics' + Rect(0, 0, 0, 0, 0, 0, 0.00508, 0.00508, 0, 0, 0) + Rect(0, 1, 0, 0, -0.00211666666666667, 0, 0.000423333333333333, 0.000423333333333334, 0, 0, 0) + $end 'Graphics' + $end 'CAPC2013X100X20NL20' + $begin 'CAPC3216X180X20ML20' + ModTime=1718954704 + CE=0 + Library='' + ModSinceLib=false + LibLocation='Project' + HighestLevel=1 + Normalize=false + InitialLevels(0, 1) + $begin 'PinDef' + Pin('2', -0.00508, 0, 0, 'N', 0, 0.00254, false, 0, true, '', true, false, '2', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(-0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '2', false, false, ExtentRect(0, 0, 0, 0, -0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'PinDef' + Pin('1', 0.00508, 0, 3.14159265358979, 'N', 0, 0.00254, false, 0, true, '', true, false, '1', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '1', false, false, ExtentRect(0, 0, 0, 0, 0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'Graphics' + Rect(0, 0, 0, 0, 0, 0, 0.00508, 0.00508, 0, 0, 0) + Rect(0, 1, 0, 0, -0.00211666666666667, 0, 0.000423333333333333, 0.000423333333333334, 0, 0, 0) + $end 'Graphics' + $end 'CAPC3216X180X20ML20' + $begin 'CAPC3216X180X55ML20T25' + ModTime=1718954704 + CE=0 + Library='' + ModSinceLib=false + LibLocation='Project' + HighestLevel=1 + Normalize=false + InitialLevels(0, 1) + $begin 'PinDef' + Pin('2', -0.00508, 0, 0, 'N', 0, 0.00254, false, 0, true, '', true, false, '2', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(-0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '2', false, false, ExtentRect(0, 0, 0, 0, -0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'PinDef' + Pin('1', 0.00508, 0, 3.14159265358979, 'N', 0, 0.00254, false, 0, true, '', true, false, '1', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '1', false, false, ExtentRect(0, 0, 0, 0, 0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'Graphics' + Rect(0, 0, 0, 0, 0, 0, 0.00508, 0.00508, 0, 0, 0) + Rect(0, 1, 0, 0, -0.00211666666666667, 0, 0.000423333333333333, 0.000423333333333334, 0, 0, 0) + $end 'Graphics' + $end 'CAPC3216X180X55ML20T25' + $begin 'CAPC3216X190X55ML30T25' + ModTime=1718954704 + CE=0 + Library='' + ModSinceLib=false + LibLocation='Project' + HighestLevel=1 + Normalize=false + InitialLevels(0, 1) + $begin 'PinDef' + Pin('1', -0.00508, 0, 0, 'N', 0, 0.00254, false, 0, true, '', true, false, '1', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(-0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '1', false, false, ExtentRect(0, 0, 0, 0, -0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'PinDef' + Pin('2', 0.00508, 0, 3.14159265358979, 'N', 0, 0.00254, false, 0, true, '', true, false, '2', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '2', false, false, ExtentRect(0, 0, 0, 0, 0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'Graphics' + Rect(0, 0, 0, 0, 0, 0, 0.00508, 0.00508, 0, 0, 0) + Rect(0, 1, 0, 0, -0.00211666666666667, 0, 0.000423333333333333, 0.000423333333333334, 0, 0, 0) + $end 'Graphics' + $end 'CAPC3216X190X55ML30T25' + $begin 'CAPMP7343X31N' + ModTime=1718954704 + CE=0 + Library='' + ModSinceLib=false + LibLocation='Project' + HighestLevel=1 + Normalize=false + InitialLevels(0, 1) + $begin 'PinDef' + Pin('1', -0.00508, 0, 0, 'N', 0, 0.00254, false, 0, true, '', true, false, '1', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(-0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '1', false, false, ExtentRect(0, 0, 0, 0, -0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'PinDef' + Pin('2', 0.00508, 0, 3.14159265358979, 'N', 0, 0.00254, false, 0, true, '', true, false, '2', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '2', false, false, ExtentRect(0, 0, 0, 0, 0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'Graphics' + Rect(0, 0, 0, 0, 0, 0, 0.00508, 0.00508, 0, 0, 0) + Rect(0, 1, 0, 0, -0.00211666666666667, 0, 0.000423333333333333, 0.000423333333333334, 0, 0, 0) + $end 'Graphics' + $end 'CAPMP7343X31N' + $begin 'COIL-1008CS_V' + ModTime=1718954704 + CE=0 + Library='' + ModSinceLib=false + LibLocation='Project' + HighestLevel=1 + Normalize=false + InitialLevels(0, 1) + $begin 'PinDef' + Pin('1', -0.00508, 0, 0, 'N', 0, 0.00254, false, 0, true, '', true, false, '1', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(-0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '1', false, false, ExtentRect(0, 0, 0, 0, -0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'PinDef' + Pin('2', 0.00508, 0, 3.14159265358979, 'N', 0, 0.00254, false, 0, true, '', true, false, '2', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '2', false, false, ExtentRect(0, 0, 0, 0, 0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'Graphics' + Rect(0, 0, 0, 0, 0, 0, 0.00508, 0.00508, 0, 0, 0) + Rect(0, 1, 0, 0, -0.00211666666666667, 0, 0.000423333333333333, 0.000423333333333334, 0, 0, 0) + $end 'Graphics' + $end 'COIL-1008CS_V' + $begin 'main' + ModTime=1718954704 + CE=0 + Library='' + ModSinceLib=false + LibLocation='Project' + HighestLevel=1 + Normalize=true + InitialLevels(0, 1) + $begin 'Graphics' + Rect(0, 0, 0, 0, 0.00254, 0.00254, 0.00508, 0.00508, 0, 0, 0) + Rect(0, 1, 0, 0, 0.000423333333333333, 0.00254, 0.000423333333333333, 0.000423333333333334, 0, 0, 0) + $end 'Graphics' + $end 'main' + $begin 'MURA-BLM15-CHIP-2_V' + ModTime=1718954704 + CE=0 + Library='' + ModSinceLib=false + LibLocation='Project' + HighestLevel=1 + Normalize=false + InitialLevels(0, 1) + $begin 'PinDef' + Pin('2', -0.00508, 0, 0, 'N', 0, 0.00254, false, 0, true, '', true, false, '2', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(-0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '2', false, false, ExtentRect(0, 0, 0, 0, -0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'PinDef' + Pin('1', 0.00508, 0, 3.14159265358979, 'N', 0, 0.00254, false, 0, true, '', true, false, '1', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '1', false, false, ExtentRect(0, 0, 0, 0, 0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'Graphics' + Rect(0, 0, 0, 0, 0, 0, 0.00508, 0.00508, 0, 0, 0) + Rect(0, 1, 0, 0, -0.00211666666666667, 0, 0.000423333333333333, 0.000423333333333334, 0, 0, 0) + $end 'Graphics' + $end 'MURA-BLM15-CHIP-2_V' + $begin 'MURA-BLM15AG221SN1x_V' + ModTime=1718954704 + CE=0 + Library='' + ModSinceLib=false + LibLocation='Project' + HighestLevel=1 + Normalize=false + InitialLevels(0, 1) + $begin 'PinDef' + Pin('2', -0.00508, 0, 0, 'N', 0, 0.00254, false, 0, true, '', true, false, '2', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(-0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '2', false, false, ExtentRect(0, 0, 0, 0, -0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'PinDef' + Pin('1', 0.00508, 0, 3.14159265358979, 'N', 0, 0.00254, false, 0, true, '', true, false, '1', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '1', false, false, ExtentRect(0, 0, 0, 0, 0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'Graphics' + Rect(0, 0, 0, 0, 0, 0, 0.00508, 0.00508, 0, 0, 0) + Rect(0, 1, 0, 0, -0.00211666666666667, 0, 0.000423333333333333, 0.000423333333333334, 0, 0, 0) + $end 'Graphics' + $end 'MURA-BLM15AG221SN1x_V' + $begin 'RESC1005X35X25NL8T10' + ModTime=1718954704 + CE=0 + Library='' + ModSinceLib=false + LibLocation='Project' + HighestLevel=1 + Normalize=false + InitialLevels(0, 1) + $begin 'PinDef' + Pin('1', -0.00508, 0, 0, 'N', 0, 0.00254, false, 0, true, '', true, false, '1', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(-0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '1', false, false, ExtentRect(0, 0, 0, 0, -0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'PinDef' + Pin('2', 0.00508, 0, 3.14159265358979, 'N', 0, 0.00254, false, 0, true, '', true, false, '2', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '2', false, false, ExtentRect(0, 0, 0, 0, 0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'Graphics' + Rect(0, 0, 0, 0, 0, 0, 0.00508, 0.00508, 0, 0, 0) + Rect(0, 1, 0, 0, -0.00211666666666667, 0, 0.000423333333333333, 0.000423333333333334, 0, 0, 0) + $end 'Graphics' + $end 'RESC1005X35X25NL8T10' + $begin 'RESC1005X40X25LL05T05' + ModTime=1718954704 + CE=0 + Library='' + ModSinceLib=false + LibLocation='Project' + HighestLevel=1 + Normalize=false + InitialLevels(0, 1) + $begin 'PinDef' + Pin('2', -0.00508, 0, 0, 'N', 0, 0.00254, false, 0, true, '', true, false, '2', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(-0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '2', false, false, ExtentRect(0, 0, 0, 0, -0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'PinDef' + Pin('1', 0.00508, 0, 3.14159265358979, 'N', 0, 0.00254, false, 0, true, '', true, false, '1', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '1', false, false, ExtentRect(0, 0, 0, 0, 0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'Graphics' + Rect(0, 0, 0, 0, 0, 0, 0.00508, 0.00508, 0, 0, 0) + Rect(0, 1, 0, 0, -0.00211666666666667, 0, 0.000423333333333333, 0.000423333333333334, 0, 0, 0) + $end 'Graphics' + $end 'RESC1005X40X25LL05T05' + $begin 'RESC1005X40X25ML05T05' + ModTime=1718954704 + CE=0 + Library='' + ModSinceLib=false + LibLocation='Project' + HighestLevel=1 + Normalize=false + InitialLevels(0, 1) + $begin 'PinDef' + Pin('1', -0.00508, 0, 0, 'N', 0, 0.00254, false, 0, true, '', true, false, '1', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(-0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '1', false, false, ExtentRect(0, 0, 0, 0, -0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'PinDef' + Pin('2', 0.00508, 0, 3.14159265358979, 'N', 0, 0.00254, false, 0, true, '', true, false, '2', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '2', false, false, ExtentRect(0, 0, 0, 0, 0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'Graphics' + Rect(0, 0, 0, 0, 0, 0, 0.00508, 0.00508, 0, 0, 0) + Rect(0, 1, 0, 0, -0.00211666666666667, 0, 0.000423333333333333, 0.000423333333333334, 0, 0, 0) + $end 'Graphics' + $end 'RESC1005X40X25ML05T05' + $begin 'RESC1005X40X25NL05T05' + ModTime=1718954704 + CE=0 + Library='' + ModSinceLib=false + LibLocation='Project' + HighestLevel=1 + Normalize=false + InitialLevels(0, 1) + $begin 'PinDef' + Pin('2', -0.00508, 0, 0, 'N', 0, 0.00254, false, 0, true, '', true, false, '2', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(-0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '2', false, false, ExtentRect(0, 0, 0, 0, -0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'PinDef' + Pin('1', 0.00508, 0, 3.14159265358979, 'N', 0, 0.00254, false, 0, true, '', true, false, '1', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '1', false, false, ExtentRect(0, 0, 0, 0, 0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'Graphics' + Rect(0, 0, 0, 0, 0, 0, 0.00508, 0.00508, 0, 0, 0) + Rect(0, 1, 0, 0, -0.00211666666666667, 0, 0.000423333333333333, 0.000423333333333334, 0, 0, 0) + $end 'Graphics' + $end 'RESC1005X40X25NL05T05' + $begin 'RESC1005X40X25NL5T10' + ModTime=1718954704 + CE=0 + Library='' + ModSinceLib=false + LibLocation='Project' + HighestLevel=1 + Normalize=false + InitialLevels(0, 1) + $begin 'PinDef' + Pin('2', -0.00508, 0, 0, 'N', 0, 0.00254, false, 0, true, '', true, false, '2', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(-0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '2', false, false, ExtentRect(0, 0, 0, 0, -0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'PinDef' + Pin('1', 0.00508, 0, 3.14159265358979, 'N', 0, 0.00254, false, 0, true, '', true, false, '1', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '1', false, false, ExtentRect(0, 0, 0, 0, 0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'Graphics' + Rect(0, 0, 0, 0, 0, 0, 0.00508, 0.00508, 0, 0, 0) + Rect(0, 1, 0, 0, -0.00211666666666667, 0, 0.000423333333333333, 0.000423333333333334, 0, 0, 0) + $end 'Graphics' + $end 'RESC1005X40X25NL5T10' + $begin 'RESC1608X05N' + ModTime=1718954704 + CE=0 + Library='' + ModSinceLib=false + LibLocation='Project' + HighestLevel=1 + Normalize=false + InitialLevels(0, 1) + $begin 'PinDef' + Pin('2', -0.00508, 0, 0, 'N', 0, 0.00254, false, 0, true, '', true, false, '2', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(-0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '2', false, false, ExtentRect(0, 0, 0, 0, -0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'PinDef' + Pin('1', 0.00508, 0, 3.14159265358979, 'N', 0, 0.00254, false, 0, true, '', true, false, '1', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '1', false, false, ExtentRect(0, 0, 0, 0, 0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'Graphics' + Rect(0, 0, 0, 0, 0, 0, 0.00508, 0.00508, 0, 0, 0) + Rect(0, 1, 0, 0, -0.00211666666666667, 0, 0.000423333333333333, 0.000423333333333334, 0, 0, 0) + $end 'Graphics' + $end 'RESC1608X05N' + $begin 'SMD-0603' + ModTime=1718954704 + CE=0 + Library='' + ModSinceLib=false + LibLocation='Project' + HighestLevel=1 + Normalize=false + InitialLevels(0, 1) + $begin 'PinDef' + Pin('1', -0.00508, 0, 0, 'N', 0, 0.00254, false, 0, true, '', true, false, '1', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(-0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '1', false, false, ExtentRect(0, 0, 0, 0, -0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'PinDef' + Pin('2', 0.00508, 0, 3.14159265358979, 'N', 0, 0.00254, false, 0, true, '', true, false, '2', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '2', false, false, ExtentRect(0, 0, 0, 0, 0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'Graphics' + Rect(0, 0, 0, 0, 0, 0, 0.00508, 0.00508, 0, 0, 0) + Rect(0, 1, 0, 0, -0.00211666666666667, 0, 0.000423333333333333, 0.000423333333333334, 0, 0, 0) + $end 'Graphics' + $end 'SMD-0603' + $begin 'WE-Coil-744301047' + ModTime=1718954704 + CE=0 + Library='' + ModSinceLib=false + LibLocation='Project' + HighestLevel=1 + Normalize=false + InitialLevels(0, 1) + $begin 'PinDef' + Pin('1', -0.00508, 0, 0, 'N', 0, 0.00254, false, 0, true, '', true, false, '1', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(-0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '1', false, false, ExtentRect(0, 0, 0, 0, -0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'PinDef' + Pin('2', 0.00508, 0, 3.14159265358979, 'N', 0, 0.00254, false, 0, true, '', true, false, '2', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '2', false, false, ExtentRect(0, 0, 0, 0, 0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'Graphics' + Rect(0, 0, 0, 0, 0, 0, 0.00508, 0.00508, 0, 0, 0) + Rect(0, 1, 0, 0, -0.00211666666666667, 0, 0.000423333333333333, 0.000423333333333334, 0, 0, 0) + $end 'Graphics' + $end 'WE-Coil-744301047' + $begin 'WE-Coil-PD4-S' + ModTime=1718954704 + CE=0 + Library='' + ModSinceLib=false + LibLocation='Project' + HighestLevel=1 + Normalize=false + InitialLevels(0, 1) + $begin 'PinDef' + Pin('1', -0.00508, 0, 0, 'N', 0, 0.00254, false, 0, true, '', true, false, '1', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(-0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '1', false, false, ExtentRect(0, 0, 0, 0, -0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'PinDef' + Pin('2', 0.00508, 0, 3.14159265358979, 'N', 0, 0.00254, false, 0, true, '', true, false, '2', true) + $begin 'PropDisplayMap' + PinName(2, 5, 1, Text(0.00508, 0.000635, 0, 4, 5, false, 'Arial', 0, '2', false, false, ExtentRect(0, 0, 0, 0, 0.00508, 0.00113792000000018, 0.000670560000000244, 0.00167640000000061, 0, 0, 0))) + $end 'PropDisplayMap' + $end 'PinDef' + $begin 'Graphics' + Rect(0, 0, 0, 0, 0, 0, 0.00508, 0.00508, 0, 0, 0) + Rect(0, 1, 0, 0, -0.00211666666666667, 0, 0.000423333333333333, 0.000423333333333334, 0, 0, 0) + $end 'Graphics' + $end 'WE-Coil-PD4-S' + $end 'Symbols' + $begin 'DefInfo' + CAPC0603X33X15LL03T05(1002, 0, 0, 2, '', 1718954704, '', 'CAPC0603X33X15LL03T05', '', '', '', '', '', '', '', 'Project', '', '', 1718954704, '', 0, 0) + CAPC1005X05N(1002, 0, 0, 2, '', 1718954704, '', 'CAPC1005X05N', '', '', '', '', '', '', '', 'Project', '', '', 1718954704, '', 0, 0) + CAPC1005X33X10LL5(1002, 0, 0, 2, '', 1718954704, '', 'CAPC1005X33X10LL5', '', '', '', '', '', '', '', 'Project', '', '', 1718954704, '', 0, 0) + CAPC1005X55X10LL05(1002, 0, 0, 2, '', 1718954704, '', 'CAPC1005X55X10LL05', '', '', '', '', '', '', '', 'Project', '', '', 1718954704, '', 0, 0) + CAPC1005X55X23ML05T8(1002, 0, 0, 2, '', 1718954704, '', 'CAPC1005X55X23ML05T8', '', '', '', '', '', '', '', 'Project', '', '', 1718954704, '', 0, 0) + CAPC1005X55X25LL05T10(1002, 0, 0, 2, '', 1718954704, '', 'CAPC1005X55X25LL05T10', '', '', '', '', '', '', '', 'Project', '', '', 1718954704, '', 0, 0) + CAPC1005X55X25ML05T10(1002, 0, 0, 2, '', 1718954704, '', 'CAPC1005X55X25ML05T10', '', '', '', '', '', '', '', 'Project', '', '', 1718954704, '', 0, 0) + CAPC1005X55X25NL05T10(1002, 0, 0, 2, '', 1718954704, '', 'CAPC1005X55X25NL05T10', '', '', '', '', '', '', '', 'Project', '', '', 1718954704, '', 0, 0) + CAPC1608X08N(1002, 0, 0, 2, '', 1718954704, '', 'CAPC1608X08N', '', '', '', '', '', '', '', 'Project', '', '', 1718954704, '', 0, 0) + CAPC1608X90X35ML10T15(1002, 0, 0, 2, '', 1718954704, '', 'CAPC1608X90X35ML10T15', '', '', '', '', '', '', '', 'Project', '', '', 1718954704, '', 0, 0) + CAPC2012X12N(1002, 0, 0, 2, '', 1718954704, '', 'CAPC2012X12N', '', '', '', '', '', '', '', 'Project', '', '', 1718954704, '', 0, 0) + CAPC2013X100X20NL20(1002, 0, 0, 2, '', 1718954704, '', 'CAPC2013X100X20NL20', '', '', '', '', '', '', '', 'Project', '', '', 1718954704, '', 0, 0) + CAPC3216X180X20ML20(1002, 0, 0, 2, '', 1718954704, '', 'CAPC3216X180X20ML20', '', '', '', '', '', '', '', 'Project', '', '', 1718954704, '', 0, 0) + CAPC3216X180X55ML20T25(1002, 0, 0, 2, '', 1718954704, '', 'CAPC3216X180X55ML20T25', '', '', '', '', '', '', '', 'Project', '', '', 1718954704, '', 0, 0) + CAPC3216X190X55ML30T25(1002, 0, 0, 2, '', 1718954704, '', 'CAPC3216X190X55ML30T25', '', '', '', '', '', '', '', 'Project', '', '', 1718954704, '', 0, 0) + CAPMP7343X31N(1002, 0, 0, 2, '', 1718954704, '', 'CAPMP7343X31N', '', '', '', '', '', '', '', 'Project', '', '', 1718954704, '', 0, 0) + 'COIL-1008CS_V'(1002, 0, 0, 2, '', 1718954704, '', 'COIL-1008CS_V', '', '', '', '', '', '', '', 'Project', '', '', 1718954704, '', 0, 0) + 'MURA-BLM15-CHIP-2_V'(1002, 0, 0, 2, '', 1718954704, '', 'MURA-BLM15-CHIP-2_V', '', '', '', '', '', '', '', 'Project', '', '', 1718954704, '', 0, 0) + 'MURA-BLM15AG221SN1x_V'(1002, 0, 0, 2, '', 1718954704, '', 'MURA-BLM15AG221SN1x_V', '', '', '', '', '', '', '', 'Project', '', '', 1718954704, '', 0, 0) + RESC1005X35X25NL8T10(1002, 0, 0, 2, '', 1718954704, '', 'RESC1005X35X25NL8T10', '', '', '', '', '', '', '', 'Project', '', '', 1718954704, '', 0, 0) + RESC1005X40X25LL05T05(1002, 0, 0, 2, '', 1718954704, '', 'RESC1005X40X25LL05T05', '', '', '', '', '', '', '', 'Project', '', '', 1718954704, '', 0, 0) + RESC1005X40X25ML05T05(1002, 0, 0, 2, '', 1718954704, '', 'RESC1005X40X25ML05T05', '', '', '', '', '', '', '', 'Project', '', '', 1718954704, '', 0, 0) + RESC1005X40X25NL05T05(1002, 0, 0, 2, '', 1718954704, '', 'RESC1005X40X25NL05T05', '', '', '', '', '', '', '', 'Project', '', '', 1718954704, '', 0, 0) + RESC1005X40X25NL5T10(1002, 0, 0, 2, '', 1718954704, '', 'RESC1005X40X25NL5T10', '', '', '', '', '', '', '', 'Project', '', '', 1718954704, '', 0, 0) + RESC1608X05N(1002, 0, 0, 2, '', 1718954704, '', 'RESC1608X05N', '', '', '', '', '', '', '', 'Project', '', '', 1718954704, '', 0, 0) + 'SMD-0603'(1002, 0, 0, 2, '', 1718954704, '', 'SMD-0603', '', '', '', '', '', '', '', 'Project', '', '', 1718954704, '', 0, 0) + 'WE-Coil-744301047'(1002, 0, 0, 2, '', 1718954704, '', 'WE-Coil-744301047', '', '', '', '', '', '', '', 'Project', '', '', 1718954704, '', 0, 0) + 'WE-Coil-PD4-S'(1002, 0, 0, 2, '', 1718954704, '', 'WE-Coil-PD4-S', '', '', '', '', '', '', '', 'Project', '', '', 1718954704, '', 0, 0) + main(1002, 0, 16, 0, '', 1718954704, '', 'main', '', '', '', '', '', '', '', 'Project', '', '', 1718954704, '', 0, 0) + $end 'DefInfo' + $begin 'Compdefs' + $begin 'CAPC0603X33X15LL03T05' + Library='' + CircuitEnv=0 + Refbase='U' + NumParts=1 + ModSinceLib=true + Terminal('1', '', 'A', false, 0, 1, '', 'Electrical', '0') + Terminal('2', '', 'A', false, 1, 1, '', 'Electrical', '0') + CompExtID=1 + $begin 'Parameters' + MenuProp('CoSimulator', 'D', '', 'DefaultNetlist', 0) + ButtonProp('CosimDefinition', 'D', '', 'Edit', 'Edit', 40501, ButtonPropClientData()) + $end 'Parameters' + $begin 'CosimDefinitions' + $begin 'CosimDefinition' + CosimulatorType=4 + CosimDefName='DefaultNetlist' + IsDefinition=true + Connect=true + Data() + GRef() + $end 'CosimDefinition' + DefaultCosim='DefaultNetlist' + $end 'CosimDefinitions' + $end 'CAPC0603X33X15LL03T05' + $begin 'CAPC1005X05N' + Library='' + CircuitEnv=0 + Refbase='U' + NumParts=1 + ModSinceLib=true + Terminal('2', '', 'A', false, 2, 1, '', 'Electrical', '0') + Terminal('1', '', 'A', false, 3, 1, '', 'Electrical', '0') + CompExtID=1 + $begin 'Parameters' + MenuProp('CoSimulator', 'D', '', 'DefaultNetlist', 0) + ButtonProp('CosimDefinition', 'D', '', 'Edit', 'Edit', 40501, ButtonPropClientData()) + $end 'Parameters' + $begin 'CosimDefinitions' + $begin 'CosimDefinition' + CosimulatorType=4 + CosimDefName='DefaultNetlist' + IsDefinition=true + Connect=true + Data() + GRef() + $end 'CosimDefinition' + DefaultCosim='DefaultNetlist' + $end 'CosimDefinitions' + $end 'CAPC1005X05N' + $begin 'CAPC1005X33X10LL5' + Library='' + CircuitEnv=0 + Refbase='U' + NumParts=1 + ModSinceLib=true + Terminal('1', '', 'A', false, 4, 1, '', 'Electrical', '0') + Terminal('2', '', 'A', false, 5, 1, '', 'Electrical', '0') + CompExtID=1 + $begin 'Parameters' + MenuProp('CoSimulator', 'D', '', 'DefaultNetlist', 0) + ButtonProp('CosimDefinition', 'D', '', 'Edit', 'Edit', 40501, ButtonPropClientData()) + $end 'Parameters' + $begin 'CosimDefinitions' + $begin 'CosimDefinition' + CosimulatorType=4 + CosimDefName='DefaultNetlist' + IsDefinition=true + Connect=true + Data() + GRef() + $end 'CosimDefinition' + DefaultCosim='DefaultNetlist' + $end 'CosimDefinitions' + $end 'CAPC1005X33X10LL5' + $begin 'CAPC1005X55X10LL05' + Library='' + CircuitEnv=0 + Refbase='U' + NumParts=1 + ModSinceLib=true + Terminal('2', '', 'A', false, 6, 1, '', 'Electrical', '0') + Terminal('1', '', 'A', false, 7, 1, '', 'Electrical', '0') + CompExtID=1 + $begin 'Parameters' + MenuProp('CoSimulator', 'D', '', 'DefaultNetlist', 0) + ButtonProp('CosimDefinition', 'D', '', 'Edit', 'Edit', 40501, ButtonPropClientData()) + $end 'Parameters' + $begin 'CosimDefinitions' + $begin 'CosimDefinition' + CosimulatorType=4 + CosimDefName='DefaultNetlist' + IsDefinition=true + Connect=true + Data() + GRef() + $end 'CosimDefinition' + DefaultCosim='DefaultNetlist' + $end 'CosimDefinitions' + $end 'CAPC1005X55X10LL05' + $begin 'CAPC1005X55X23ML05T8' + Library='' + CircuitEnv=0 + Refbase='U' + NumParts=1 + ModSinceLib=true + Terminal('2', '', 'A', false, 8, 1, '', 'Electrical', '0') + Terminal('1', '', 'A', false, 9, 1, '', 'Electrical', '0') + CompExtID=1 + $begin 'Parameters' + MenuProp('CoSimulator', 'D', '', 'DefaultNetlist', 0) + ButtonProp('CosimDefinition', 'D', '', 'Edit', 'Edit', 40501, ButtonPropClientData()) + $end 'Parameters' + $begin 'CosimDefinitions' + $begin 'CosimDefinition' + CosimulatorType=4 + CosimDefName='DefaultNetlist' + IsDefinition=true + Connect=true + Data() + GRef() + $end 'CosimDefinition' + DefaultCosim='DefaultNetlist' + $end 'CosimDefinitions' + $end 'CAPC1005X55X23ML05T8' + $begin 'CAPC1005X55X25LL05T10' + Library='' + CircuitEnv=0 + Refbase='U' + NumParts=1 + ModSinceLib=true + Terminal('1', '', 'A', false, 10, 1, '', 'Electrical', '0') + Terminal('2', '', 'A', false, 11, 1, '', 'Electrical', '0') + CompExtID=1 + $begin 'Parameters' + MenuProp('CoSimulator', 'D', '', 'DefaultNetlist', 0) + ButtonProp('CosimDefinition', 'D', '', 'Edit', 'Edit', 40501, ButtonPropClientData()) + $end 'Parameters' + $begin 'CosimDefinitions' + $begin 'CosimDefinition' + CosimulatorType=4 + CosimDefName='DefaultNetlist' + IsDefinition=true + Connect=true + Data() + GRef() + $end 'CosimDefinition' + DefaultCosim='DefaultNetlist' + $end 'CosimDefinitions' + $end 'CAPC1005X55X25LL05T10' + $begin 'CAPC1005X55X25ML05T10' + Library='' + CircuitEnv=0 + Refbase='U' + NumParts=1 + ModSinceLib=true + Terminal('1', '', 'A', false, 12, 1, '', 'Electrical', '0') + Terminal('2', '', 'A', false, 13, 1, '', 'Electrical', '0') + CompExtID=1 + $begin 'Parameters' + MenuProp('CoSimulator', 'D', '', 'DefaultNetlist', 0) + ButtonProp('CosimDefinition', 'D', '', 'Edit', 'Edit', 40501, ButtonPropClientData()) + $end 'Parameters' + $begin 'CosimDefinitions' + $begin 'CosimDefinition' + CosimulatorType=4 + CosimDefName='DefaultNetlist' + IsDefinition=true + Connect=true + Data() + GRef() + $end 'CosimDefinition' + DefaultCosim='DefaultNetlist' + $end 'CosimDefinitions' + $end 'CAPC1005X55X25ML05T10' + $begin 'CAPC1005X55X25NL05T10' + Library='' + CircuitEnv=0 + Refbase='U' + NumParts=1 + ModSinceLib=true + Terminal('2', '', 'A', false, 14, 1, '', 'Electrical', '0') + Terminal('1', '', 'A', false, 15, 1, '', 'Electrical', '0') + CompExtID=1 + $begin 'Parameters' + MenuProp('CoSimulator', 'D', '', 'DefaultNetlist', 0) + ButtonProp('CosimDefinition', 'D', '', 'Edit', 'Edit', 40501, ButtonPropClientData()) + $end 'Parameters' + $begin 'CosimDefinitions' + $begin 'CosimDefinition' + CosimulatorType=4 + CosimDefName='DefaultNetlist' + IsDefinition=true + Connect=true + Data() + GRef() + $end 'CosimDefinition' + DefaultCosim='DefaultNetlist' + $end 'CosimDefinitions' + $end 'CAPC1005X55X25NL05T10' + $begin 'CAPC1608X08N' + Library='' + CircuitEnv=0 + Refbase='U' + NumParts=1 + ModSinceLib=true + Terminal('2', '', 'A', false, 16, 1, '', 'Electrical', '0') + Terminal('1', '', 'A', false, 17, 1, '', 'Electrical', '0') + CompExtID=1 + $begin 'Parameters' + MenuProp('CoSimulator', 'D', '', 'DefaultNetlist', 0) + ButtonProp('CosimDefinition', 'D', '', 'Edit', 'Edit', 40501, ButtonPropClientData()) + $end 'Parameters' + $begin 'CosimDefinitions' + $begin 'CosimDefinition' + CosimulatorType=4 + CosimDefName='DefaultNetlist' + IsDefinition=true + Connect=true + Data() + GRef() + $end 'CosimDefinition' + DefaultCosim='DefaultNetlist' + $end 'CosimDefinitions' + $end 'CAPC1608X08N' + $begin 'CAPC1608X90X35ML10T15' + Library='' + CircuitEnv=0 + Refbase='U' + NumParts=1 + ModSinceLib=true + Terminal('2', '', 'A', false, 18, 1, '', 'Electrical', '0') + Terminal('1', '', 'A', false, 19, 1, '', 'Electrical', '0') + CompExtID=1 + $begin 'Parameters' + MenuProp('CoSimulator', 'D', '', 'DefaultNetlist', 0) + ButtonProp('CosimDefinition', 'D', '', 'Edit', 'Edit', 40501, ButtonPropClientData()) + $end 'Parameters' + $begin 'CosimDefinitions' + $begin 'CosimDefinition' + CosimulatorType=4 + CosimDefName='DefaultNetlist' + IsDefinition=true + Connect=true + Data() + GRef() + $end 'CosimDefinition' + DefaultCosim='DefaultNetlist' + $end 'CosimDefinitions' + $end 'CAPC1608X90X35ML10T15' + $begin 'CAPC2012X12N' + Library='' + CircuitEnv=0 + Refbase='U' + NumParts=1 + ModSinceLib=true + Terminal('1', '', 'A', false, 20, 1, '', 'Electrical', '0') + Terminal('2', '', 'A', false, 21, 1, '', 'Electrical', '0') + CompExtID=1 + $begin 'Parameters' + MenuProp('CoSimulator', 'D', '', 'DefaultNetlist', 0) + ButtonProp('CosimDefinition', 'D', '', 'Edit', 'Edit', 40501, ButtonPropClientData()) + $end 'Parameters' + $begin 'CosimDefinitions' + $begin 'CosimDefinition' + CosimulatorType=4 + CosimDefName='DefaultNetlist' + IsDefinition=true + Connect=true + Data() + GRef() + $end 'CosimDefinition' + DefaultCosim='DefaultNetlist' + $end 'CosimDefinitions' + $end 'CAPC2012X12N' + $begin 'CAPC2013X100X20NL20' + Library='' + CircuitEnv=0 + Refbase='U' + NumParts=1 + ModSinceLib=true + Terminal('1', '', 'A', false, 22, 1, '', 'Electrical', '0') + Terminal('2', '', 'A', false, 23, 1, '', 'Electrical', '0') + CompExtID=1 + $begin 'Parameters' + MenuProp('CoSimulator', 'D', '', 'DefaultNetlist', 0) + ButtonProp('CosimDefinition', 'D', '', 'Edit', 'Edit', 40501, ButtonPropClientData()) + $end 'Parameters' + $begin 'CosimDefinitions' + $begin 'CosimDefinition' + CosimulatorType=4 + CosimDefName='DefaultNetlist' + IsDefinition=true + Connect=true + Data() + GRef() + $end 'CosimDefinition' + DefaultCosim='DefaultNetlist' + $end 'CosimDefinitions' + $end 'CAPC2013X100X20NL20' + $begin 'CAPC3216X180X20ML20' + Library='' + CircuitEnv=0 + Refbase='U' + NumParts=1 + ModSinceLib=true + Terminal('2', '', 'A', false, 24, 1, '', 'Electrical', '0') + Terminal('1', '', 'A', false, 25, 1, '', 'Electrical', '0') + CompExtID=1 + $begin 'Parameters' + MenuProp('CoSimulator', 'D', '', 'DefaultNetlist', 0) + ButtonProp('CosimDefinition', 'D', '', 'Edit', 'Edit', 40501, ButtonPropClientData()) + $end 'Parameters' + $begin 'CosimDefinitions' + $begin 'CosimDefinition' + CosimulatorType=4 + CosimDefName='DefaultNetlist' + IsDefinition=true + Connect=true + Data() + GRef() + $end 'CosimDefinition' + DefaultCosim='DefaultNetlist' + $end 'CosimDefinitions' + $end 'CAPC3216X180X20ML20' + $begin 'CAPC3216X180X55ML20T25' + Library='' + CircuitEnv=0 + Refbase='U' + NumParts=1 + ModSinceLib=true + Terminal('2', '', 'A', false, 26, 1, '', 'Electrical', '0') + Terminal('1', '', 'A', false, 27, 1, '', 'Electrical', '0') + CompExtID=1 + $begin 'Parameters' + MenuProp('CoSimulator', 'D', '', 'DefaultNetlist', 0) + ButtonProp('CosimDefinition', 'D', '', 'Edit', 'Edit', 40501, ButtonPropClientData()) + $end 'Parameters' + $begin 'CosimDefinitions' + $begin 'CosimDefinition' + CosimulatorType=4 + CosimDefName='DefaultNetlist' + IsDefinition=true + Connect=true + Data() + GRef() + $end 'CosimDefinition' + DefaultCosim='DefaultNetlist' + $end 'CosimDefinitions' + $end 'CAPC3216X180X55ML20T25' + $begin 'CAPC3216X190X55ML30T25' + Library='' + CircuitEnv=0 + Refbase='U' + NumParts=1 + ModSinceLib=true + Terminal('1', '', 'A', false, 28, 1, '', 'Electrical', '0') + Terminal('2', '', 'A', false, 29, 1, '', 'Electrical', '0') + CompExtID=1 + $begin 'Parameters' + MenuProp('CoSimulator', 'D', '', 'DefaultNetlist', 0) + ButtonProp('CosimDefinition', 'D', '', 'Edit', 'Edit', 40501, ButtonPropClientData()) + $end 'Parameters' + $begin 'CosimDefinitions' + $begin 'CosimDefinition' + CosimulatorType=4 + CosimDefName='DefaultNetlist' + IsDefinition=true + Connect=true + Data() + GRef() + $end 'CosimDefinition' + DefaultCosim='DefaultNetlist' + $end 'CosimDefinitions' + $end 'CAPC3216X190X55ML30T25' + $begin 'CAPMP7343X31N' + Library='' + CircuitEnv=0 + Refbase='U' + NumParts=1 + ModSinceLib=true + Terminal('1', '', 'A', false, 30, 1, '', 'Electrical', '0') + Terminal('2', '', 'A', false, 31, 1, '', 'Electrical', '0') + CompExtID=1 + $begin 'Parameters' + MenuProp('CoSimulator', 'D', '', 'DefaultNetlist', 0) + ButtonProp('CosimDefinition', 'D', '', 'Edit', 'Edit', 40501, ButtonPropClientData()) + $end 'Parameters' + $begin 'CosimDefinitions' + $begin 'CosimDefinition' + CosimulatorType=4 + CosimDefName='DefaultNetlist' + IsDefinition=true + Connect=true + Data() + GRef() + $end 'CosimDefinition' + DefaultCosim='DefaultNetlist' + $end 'CosimDefinitions' + $end 'CAPMP7343X31N' + $begin 'COIL-1008CS_V' + Library='' + CircuitEnv=0 + Refbase='U' + NumParts=1 + ModSinceLib=true + Terminal('1', '', 'A', false, 32, 1, '', 'Electrical', '0') + Terminal('2', '', 'A', false, 33, 1, '', 'Electrical', '0') + CompExtID=1 + $begin 'Parameters' + MenuProp('CoSimulator', 'D', '', 'DefaultNetlist', 0) + ButtonProp('CosimDefinition', 'D', '', 'Edit', 'Edit', 40501, ButtonPropClientData()) + $end 'Parameters' + $begin 'CosimDefinitions' + $begin 'CosimDefinition' + CosimulatorType=4 + CosimDefName='DefaultNetlist' + IsDefinition=true + Connect=true + Data() + GRef() + $end 'CosimDefinition' + DefaultCosim='DefaultNetlist' + $end 'CosimDefinitions' + $end 'COIL-1008CS_V' + $begin 'MURA-BLM15-CHIP-2_V' + Library='' + CircuitEnv=0 + Refbase='U' + NumParts=1 + ModSinceLib=true + Terminal('2', '', 'A', false, 34, 1, '', 'Electrical', '0') + Terminal('1', '', 'A', false, 35, 1, '', 'Electrical', '0') + CompExtID=1 + $begin 'Parameters' + MenuProp('CoSimulator', 'D', '', 'DefaultNetlist', 0) + ButtonProp('CosimDefinition', 'D', '', 'Edit', 'Edit', 40501, ButtonPropClientData()) + $end 'Parameters' + $begin 'CosimDefinitions' + $begin 'CosimDefinition' + CosimulatorType=4 + CosimDefName='DefaultNetlist' + IsDefinition=true + Connect=true + Data() + GRef() + $end 'CosimDefinition' + DefaultCosim='DefaultNetlist' + $end 'CosimDefinitions' + $end 'MURA-BLM15-CHIP-2_V' + $begin 'MURA-BLM15AG221SN1x_V' + Library='' + CircuitEnv=0 + Refbase='U' + NumParts=1 + ModSinceLib=true + Terminal('2', '', 'A', false, 36, 1, '', 'Electrical', '0') + Terminal('1', '', 'A', false, 37, 1, '', 'Electrical', '0') + CompExtID=1 + $begin 'Parameters' + MenuProp('CoSimulator', 'D', '', 'DefaultNetlist', 0) + ButtonProp('CosimDefinition', 'D', '', 'Edit', 'Edit', 40501, ButtonPropClientData()) + $end 'Parameters' + $begin 'CosimDefinitions' + $begin 'CosimDefinition' + CosimulatorType=4 + CosimDefName='DefaultNetlist' + IsDefinition=true + Connect=true + Data() + GRef() + $end 'CosimDefinition' + DefaultCosim='DefaultNetlist' + $end 'CosimDefinitions' + $end 'MURA-BLM15AG221SN1x_V' + $begin 'RESC1005X35X25NL8T10' + Library='' + CircuitEnv=0 + Refbase='U' + NumParts=1 + ModSinceLib=true + Terminal('1', '', 'A', false, 38, 1, '', 'Electrical', '0') + Terminal('2', '', 'A', false, 39, 1, '', 'Electrical', '0') + CompExtID=1 + $begin 'Parameters' + MenuProp('CoSimulator', 'D', '', 'DefaultNetlist', 0) + ButtonProp('CosimDefinition', 'D', '', 'Edit', 'Edit', 40501, ButtonPropClientData()) + $end 'Parameters' + $begin 'CosimDefinitions' + $begin 'CosimDefinition' + CosimulatorType=4 + CosimDefName='DefaultNetlist' + IsDefinition=true + Connect=true + Data() + GRef() + $end 'CosimDefinition' + DefaultCosim='DefaultNetlist' + $end 'CosimDefinitions' + $end 'RESC1005X35X25NL8T10' + $begin 'RESC1005X40X25LL05T05' + Library='' + CircuitEnv=0 + Refbase='U' + NumParts=1 + ModSinceLib=true + Terminal('2', '', 'A', false, 40, 1, '', 'Electrical', '0') + Terminal('1', '', 'A', false, 41, 1, '', 'Electrical', '0') + CompExtID=1 + $begin 'Parameters' + MenuProp('CoSimulator', 'D', '', 'DefaultNetlist', 0) + ButtonProp('CosimDefinition', 'D', '', 'Edit', 'Edit', 40501, ButtonPropClientData()) + $end 'Parameters' + $begin 'CosimDefinitions' + $begin 'CosimDefinition' + CosimulatorType=4 + CosimDefName='DefaultNetlist' + IsDefinition=true + Connect=true + Data() + GRef() + $end 'CosimDefinition' + DefaultCosim='DefaultNetlist' + $end 'CosimDefinitions' + $end 'RESC1005X40X25LL05T05' + $begin 'RESC1005X40X25ML05T05' + Library='' + CircuitEnv=0 + Refbase='U' + NumParts=1 + ModSinceLib=true + Terminal('1', '', 'A', false, 42, 1, '', 'Electrical', '0') + Terminal('2', '', 'A', false, 43, 1, '', 'Electrical', '0') + CompExtID=1 + $begin 'Parameters' + MenuProp('CoSimulator', 'D', '', 'DefaultNetlist', 0) + ButtonProp('CosimDefinition', 'D', '', 'Edit', 'Edit', 40501, ButtonPropClientData()) + $end 'Parameters' + $begin 'CosimDefinitions' + $begin 'CosimDefinition' + CosimulatorType=4 + CosimDefName='DefaultNetlist' + IsDefinition=true + Connect=true + Data() + GRef() + $end 'CosimDefinition' + DefaultCosim='DefaultNetlist' + $end 'CosimDefinitions' + $end 'RESC1005X40X25ML05T05' + $begin 'RESC1005X40X25NL05T05' + Library='' + CircuitEnv=0 + Refbase='U' + NumParts=1 + ModSinceLib=true + Terminal('2', '', 'A', false, 44, 1, '', 'Electrical', '0') + Terminal('1', '', 'A', false, 45, 1, '', 'Electrical', '0') + CompExtID=1 + $begin 'Parameters' + MenuProp('CoSimulator', 'D', '', 'DefaultNetlist', 0) + ButtonProp('CosimDefinition', 'D', '', 'Edit', 'Edit', 40501, ButtonPropClientData()) + $end 'Parameters' + $begin 'CosimDefinitions' + $begin 'CosimDefinition' + CosimulatorType=4 + CosimDefName='DefaultNetlist' + IsDefinition=true + Connect=true + Data() + GRef() + $end 'CosimDefinition' + DefaultCosim='DefaultNetlist' + $end 'CosimDefinitions' + $end 'RESC1005X40X25NL05T05' + $begin 'RESC1005X40X25NL5T10' + Library='' + CircuitEnv=0 + Refbase='U' + NumParts=1 + ModSinceLib=true + Terminal('2', '', 'A', false, 46, 1, '', 'Electrical', '0') + Terminal('1', '', 'A', false, 47, 1, '', 'Electrical', '0') + CompExtID=1 + $begin 'Parameters' + MenuProp('CoSimulator', 'D', '', 'DefaultNetlist', 0) + ButtonProp('CosimDefinition', 'D', '', 'Edit', 'Edit', 40501, ButtonPropClientData()) + $end 'Parameters' + $begin 'CosimDefinitions' + $begin 'CosimDefinition' + CosimulatorType=4 + CosimDefName='DefaultNetlist' + IsDefinition=true + Connect=true + Data() + GRef() + $end 'CosimDefinition' + DefaultCosim='DefaultNetlist' + $end 'CosimDefinitions' + $end 'RESC1005X40X25NL5T10' + $begin 'RESC1608X05N' + Library='' + CircuitEnv=0 + Refbase='U' + NumParts=1 + ModSinceLib=true + Terminal('2', '', 'A', false, 48, 1, '', 'Electrical', '0') + Terminal('1', '', 'A', false, 49, 1, '', 'Electrical', '0') + CompExtID=1 + $begin 'Parameters' + MenuProp('CoSimulator', 'D', '', 'DefaultNetlist', 0) + ButtonProp('CosimDefinition', 'D', '', 'Edit', 'Edit', 40501, ButtonPropClientData()) + $end 'Parameters' + $begin 'CosimDefinitions' + $begin 'CosimDefinition' + CosimulatorType=4 + CosimDefName='DefaultNetlist' + IsDefinition=true + Connect=true + Data() + GRef() + $end 'CosimDefinition' + DefaultCosim='DefaultNetlist' + $end 'CosimDefinitions' + $end 'RESC1608X05N' + $begin 'SMD-0603' + Library='' + CircuitEnv=0 + Refbase='U' + NumParts=1 + ModSinceLib=true + Terminal('1', '', 'A', false, 50, 1, '', 'Electrical', '0') + Terminal('2', '', 'A', false, 51, 1, '', 'Electrical', '0') + CompExtID=1 + $begin 'Parameters' + MenuProp('CoSimulator', 'D', '', 'DefaultNetlist', 0) + ButtonProp('CosimDefinition', 'D', '', 'Edit', 'Edit', 40501, ButtonPropClientData()) + $end 'Parameters' + $begin 'CosimDefinitions' + $begin 'CosimDefinition' + CosimulatorType=4 + CosimDefName='DefaultNetlist' + IsDefinition=true + Connect=true + Data() + GRef() + $end 'CosimDefinition' + DefaultCosim='DefaultNetlist' + $end 'CosimDefinitions' + $end 'SMD-0603' + $begin 'WE-Coil-744301047' + Library='' + CircuitEnv=0 + Refbase='U' + NumParts=1 + ModSinceLib=true + Terminal('1', '', 'A', false, 52, 1, '', 'Electrical', '0') + Terminal('2', '', 'A', false, 53, 1, '', 'Electrical', '0') + CompExtID=1 + $begin 'Parameters' + MenuProp('CoSimulator', 'D', '', 'DefaultNetlist', 0) + ButtonProp('CosimDefinition', 'D', '', 'Edit', 'Edit', 40501, ButtonPropClientData()) + $end 'Parameters' + $begin 'CosimDefinitions' + $begin 'CosimDefinition' + CosimulatorType=4 + CosimDefName='DefaultNetlist' + IsDefinition=true + Connect=true + Data() + GRef() + $end 'CosimDefinition' + DefaultCosim='DefaultNetlist' + $end 'CosimDefinitions' + $end 'WE-Coil-744301047' + $begin 'WE-Coil-PD4-S' + Library='' + CircuitEnv=0 + Refbase='U' + NumParts=1 + ModSinceLib=true + Terminal('1', '', 'A', false, 54, 1, '', 'Electrical', '0') + Terminal('2', '', 'A', false, 55, 1, '', 'Electrical', '0') + CompExtID=1 + $begin 'Parameters' + MenuProp('CoSimulator', 'D', '', 'DefaultNetlist', 0) + ButtonProp('CosimDefinition', 'D', '', 'Edit', 'Edit', 40501, ButtonPropClientData()) + $end 'Parameters' + $begin 'CosimDefinitions' + $begin 'CosimDefinition' + CosimulatorType=4 + CosimDefName='DefaultNetlist' + IsDefinition=true + Connect=true + Data() + GRef() + $end 'CosimDefinition' + DefaultCosim='DefaultNetlist' + $end 'CosimDefinitions' + $end 'WE-Coil-PD4-S' + $begin 'main' + Library='' + CircuitEnv=0 + Refbase='U' + NumParts=1 + ModSinceLib=true + $begin 'Properties' + TextProp('Representation', 'D', '', 'main') + $end 'Properties' + CompExtID=1 + $begin 'Parameters' + MenuProp('CoSimulator', 'D', '', 'DefaultNetlist', 0) + ButtonProp('CosimDefinition', 'D', '', 'Edit', 'Edit', 40501, ButtonPropClientData()) + $end 'Parameters' + $begin 'CosimDefinitions' + $begin 'CosimDefinition' + CosimulatorType=4 + CosimDefName='DefaultNetlist' + IsDefinition=true + Connect=true + Data() + GRef() + $end 'CosimDefinition' + DefaultCosim='DefaultNetlist' + $end 'CosimDefinitions' + $end 'main' + $end 'Compdefs' + $end 'Definitions' + DesignIDServer=2 + MoveBackwards=false + $begin 'PlanarEMCircuit' + RepRewriteV2=true + Name='main' + DesignID=0 + $begin 'Circuit' + ComponentName='main' + AutoFP='' + $begin 'DesignDatasets' + NextUniqueID=0 + MoveBackwards=false + DatasetType='DesignDatasetType' + $begin 'DatasetDefinitions' + $end 'DatasetDefinitions' + $end 'DesignDatasets' + VariableOrders[0:] + $begin 'Net' + NetName='+VREFDDR4' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='1.2V_AVDDL' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='1.2V_AVDLL_PLL' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='1.2V_DVDDL' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='1.8V_DVDDH' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='12V-In' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='1V0' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='2V5' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='3.3V_AVDDH' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='5V' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='A10_GNDSENSE' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='AVCC_1V3' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='CLOCK_I2C_SCL' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='CLOCK_I2C_SDA' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_A0' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_A1' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_A10' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_A11' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_A12' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_A13' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_A2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_A3' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_A4' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_A5' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_A6' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_A7' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_A8' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_A9' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_ACT' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_ALERT0' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_ALERT1' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_ALERT2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_ALERT3' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_BA0' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_BA1' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_BG0' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_CAS' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_CKE' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_CLK_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_CLK_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_CSN' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DM0' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DM1' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DM2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DM3' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DM4' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DM5' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DM6' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DM7' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ0' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ1' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ10' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ11' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ12' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ13' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ14' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ15' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ16' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ17' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ18' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ19' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ20' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ21' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ22' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ23' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ24' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ25' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ26' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ27' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ28' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ29' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ3' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ30' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ31' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ32' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ33' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ34' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ35' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ36' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ37' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ38' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ39' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ4' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ40' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ41' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ42' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ43' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ44' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ45' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ46' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ47' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ48' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ49' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ5' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ50' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ51' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ52' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ53' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ54' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ55' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ56' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ57' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ58' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ59' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ6' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ60' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ61' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ62' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ63' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ7' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ8' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQ9' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQS0_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQS0_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQS1_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQS1_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQS2_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQS2_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQS3_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQS3_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQS4_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQS4_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQS5_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQS5_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQS6_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQS6_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQS7_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_DQS7_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_ODT' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_PAR' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_RAS' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_RESETN' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DDR4_WEN' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DP_3V3' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DP_ML_LANE0_C_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DP_ML_LANE0_C_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DP_ML_LANE0_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DP_ML_LANE0_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DP_ML_LANE1_C_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DP_ML_LANE1_C_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DP_ML_LANE1_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DP_ML_LANE1_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DP_ML_LANE2_C_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DP_ML_LANE2_C_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DP_ML_LANE2_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DP_ML_LANE2_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DP_ML_LANE3_C_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DP_ML_LANE3_C_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DP_ML_LANE3_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='DP_ML_LANE3_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='ENET_HPS_GTX_CLK' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='ENET_HPS_MDC' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='ENET_HPS_MDIO' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='ENET_HPS_RX_CLK' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='ENET_HPS_RX_DV' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='ENET_HPS_RXD0' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='ENET_HPS_RXD1' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='ENET_HPS_RXD2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='ENET_HPS_RXD3' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='ENET_HPS_TX_EN' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='ENET_HPS_TXD0' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='ENET_HPS_TXD1' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='ENET_HPS_TXD2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='ENET_HPS_TXD3' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='GND' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='GND_DP' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='JTAG_TCK' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='JTAG_TDI' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='JTAG_TDO' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='JTAG_TMS' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='JTAG_TRST' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='LVDS_CH01_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='LVDS_CH01_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='LVDS_CH02_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='LVDS_CH02_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='LVDS_CH03_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='LVDS_CH03_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='LVDS_CH04_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='LVDS_CH04_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='LVDS_CH05_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='LVDS_CH05_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='LVDS_CH06_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='LVDS_CH06_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='LVDS_CH07_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='LVDS_CH07_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='LVDS_CH08_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='LVDS_CH08_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='LVDS_CH09_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='LVDS_CH09_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='LVDS_CH10_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='LVDS_CH10_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='LVDS_CH11_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='LVDS_CH11_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='LVDS_CH12_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='LVDS_CH12_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetC10_1' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetC10_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetC177_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetC178_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetC179_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetC180_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetC18_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetC19_1' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetC19_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetC25_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetC26_1' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetC26_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetC271_1' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetC291_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetC33_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetC34_1' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetC34_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetC35_1' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetC42_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetC43_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetC50_1' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetC50_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetC9_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetD3_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetIC1_7' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetIC1_8' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetIC1_9' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetIC2_5' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetJ1_13' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetJ1_14' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetJ1_18' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetJ1_19' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetJ2_13' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetJ2_14' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetJ2_16' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetJ2_17' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetJ3_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetR100_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetR102_1' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetR104_1' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetR105_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetR106_1' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetR108_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetR113_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetR114_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetR115_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetR116_1' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetR116_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetR117_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetR119_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetR11_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetR120_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetR121_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetR122_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetR123_1' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetR124_1' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetR12_1' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetR13_1' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetR1_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetR22_1' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetR24_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetR25_1' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetR26_1' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetR34_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetR65_1' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetR66_1' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetR82_1' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetR83_1' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetR8_1' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetR99_1' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetSW1_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetSW1_3' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetSW1_4' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetU13_1' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetU13_2' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetU1_AP13' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetU1_AV11' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetU1_AW11' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetU1_AW13' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='NetU9_46' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_CLKREQ_L' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_REFCLK_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_REFCLK_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_RST_L' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_RX0_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_RX0_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_RX1_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_RX1_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_RX2_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_RX2_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_RX3_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_RX3_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_SMB_CLK' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_SMB_DATA' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_TX0_CAP_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_TX0_CAP_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_TX0_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_TX0_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_TX1_CAP_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_TX1_CAP_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_TX1_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_TX1_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_TX2_CAP_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_TX2_CAP_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_TX2_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_TX2_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_TX3_CAP_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_TX3_CAP_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_TX3_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_TX3_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_USB_D_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_USB_D_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_W_DISABLE_L' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PCIe_Gen4_WAKE_L' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PDEN' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='PLL_1V8' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='REFCLK0_FMCB_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='REFCLK0_FMCB_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='REFCLK_DP_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='REFCLK_DP_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='SFPA__Mod_ABS' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='SFPA_RS0' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='SFPA_RS1' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='SFPA_Rx_LOS' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='SFPA_RX_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='SFPA_RX_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='SFPA_SCL' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='SFPA_SDA' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='SFPA_Tx_Disable' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='SFPA_Tx_Fault' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='SFPA_TX_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='SFPA_TX_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='SFPA_VCCR' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='SFPA_VCCT' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='TRD1_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='TRD1_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='TRD2_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='TRD2_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='TRD3_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='TRD3_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='TRD4_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='TRD4_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='USB3_D_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='USB3_D_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='USB3_SSRX_C_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='USB3_SSRX_C_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='USB3_SSRX_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='USB3_SSRX_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='USB3_SSTX_N' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='USB3_SSTX_P' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='USB3_VBUS' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $begin 'Net' + NetName='VDD_DDR' + $begin 'Properties' + CheckboxProp('AlignMicrowavePorts', 'D', '', true) + $end 'Properties' + $end 'Net' + $end 'Circuit' + $begin 'Layout' + BlackBox=false + DefUnits='mm' + NIdx=5951 + ActLyr='1_Top' + Tol(1e-08, 1e-08, 1e-12) + $begin 'HfssExportInfo' + ScriptFileName='' + HfssFileName='' + Version=2 + ExtentType='PolygonExtent' + BasePolygon='' + BasePolygonEDBUId=5949 + DielExtentType='BboxExtent' + DielBasePolygon='' + DielBasePolygonEDBUId=-1 + DielExt(Ext='0', Dim=false) + HonorUserDiel=true + TruncAtGnd=false + AirHorExt(Ext='0.15', Dim=false) + AirPosZExt(Ext='0.15', Dim=false) + AirNegZExt(Ext='0.15', Dim=false) + SyncZExt=true + OpenRegionType='Radiation' + UseRadBound=true + PMLVisible=false + OperFreq='5GHz' + RadLvl=0 + UseStackupForZExtFact=false + Smooth=true + $end 'HfssExportInfo' + $end 'Layout' + $begin 'Rule Set' + $begin 'Data' + $end 'Data' + $begin 'DRCSolutionMgr' + $end 'DRCSolutionMgr' + $end 'Rule Set' + $begin 'Port' + $begin 'Data' + $end 'Data' + $begin 'CoupledPortsList' + $end 'CoupledPortsList' + $begin 'DiffPairs' + $end 'DiffPairs' + TotalVoltage=false + IncludePortPostProcess=true + $begin 'SortOrder' + $end 'SortOrder' + LegacySolverPinOrdering=false + $end 'Port' + $begin 'Boundary' + $begin 'Data' + $end 'Data' + $begin 'CoupledPortsList' + $end 'CoupledPortsList' + $begin 'DiffPairs' + $end 'DiffPairs' + TotalVoltage=false + IncludePortPostProcess=true + $begin 'SortOrder' + $end 'SortOrder' + LegacySolverPinOrdering=false + $end 'Boundary' + $begin 'Cavity' + $begin 'Data' + $end 'Data' + $end 'Cavity' + $begin 'Via' + $begin 'Data' + $end 'Data' + $end 'Via' + $begin 'LayoutVia' + $begin 'Data' + $end 'Data' + $end 'LayoutVia' + $begin 'Source' + $begin 'Data' + $end 'Data' + $end 'Source' + $begin 'Voltage Probe' + $begin 'Data' + $end 'Data' + $end 'Voltage Probe' + $begin 'DC Terminal' + $begin 'Data' + $end 'Data' + $end 'DC Terminal' + $begin 'CircuitSources' + $begin 'Data' + $end 'Data' + $end 'CircuitSources' + $begin 'NexximPorts' + $begin 'Data' + $end 'Data' + $begin 'DiffPairs' + $end 'DiffPairs' + $end 'NexximPorts' + $begin 'SortOrder' + $end 'SortOrder' + $begin 'NexximMultiComponentContainers' + $begin 'Data' + $end 'Data' + $end 'NexximMultiComponentContainers' + $begin 'ComponentConfigurationData' + $begin 'EnabledPorts' + $end 'EnabledPorts' + $begin 'EnabledMultipleComponents' + $end 'EnabledMultipleComponents' + $begin 'EnabledAnalyses' + $end 'EnabledAnalyses' + $end 'ComponentConfigurationData' + $begin 'Properties' + $end 'Properties' + $begin 'CustomSimSetups' + $begin 'Data' + $end 'Data' + $end 'CustomSimSetups' + $begin 'RadSetup' + $begin 'Data' + $end 'Data' + $end 'RadSetup' + $begin 'Setup' + $begin 'Data' + $end 'Data' + $end 'Setup' + $begin 'AnalysisOptionBlocks' + $end 'AnalysisOptionBlocks' + $begin 'EM properties' + $begin 'Data' + $end 'Data' + $end 'EM properties' + $begin 'OutputVariable' + NextUniqueID=0 + MoveBackwards=false + $end 'OutputVariable' + $begin 'Optimetrics' + $begin 'OptimetricsSetups' + NextUniqueID=0 + MoveBackwards=false + $end 'OptimetricsSetups' + $end 'Optimetrics' + $begin 'FieldsReporter' + $begin 'FieldsCalculator' + Line_Discretization=1000 + 'Show Stack'=true + $end 'FieldsCalculator' + $begin 'PlotDefaults' + Default_SolutionId=-1 + Default_PlotFolder='Automatic' + $end 'PlotDefaults' + $begin 'FieldsPlotManagerID' + NextUniqueID=0 + MoveBackwards=false + NumQuantityType=0 + NumPlots=0 + $end 'FieldsPlotManagerID' + $begin 'Report3dInGeomWnd' + Report3dNum=0 + $end 'Report3dInGeomWnd' + $begin 'Report2dInGeomWnd' + Report2dNum=0 + $end 'Report2dInGeomWnd' + $begin 'AntennaParametersInGeomWnd' + AntennaParametersNum=0 + $end 'AntennaParametersInGeomWnd' + AntennaParametersPlotTablesOrder() + $begin 'EntitySelectionCache' + $end 'EntitySelectionCache' + $end 'FieldsReporter' + $begin 'SolutionManager' + $begin 'SimDataExtractors' + $begin 'Version ID Map' + V=0 + $end 'Version ID Map' + $end 'SimDataExtractors' + $end 'SolutionManager' + $begin 'InterfaceOptions' + SchematicEnabled=false + SaveBeforeSolving=true + $end 'InterfaceOptions' + $begin 'AdvancedSettings' + ComputeBothEvenAndOddCPWModes=false + CausalMaterials=true + MeshingMethod='Phi' + EnableDesignIntersectionCheck=true + UseAlternativeMeshMethodsAsFallBack=true + CircuitSparamDefinition=false + CircuitIntegrationType='FFT' + BroadbandFreqOption='AutoMaxFreq' + BroadbandMaxNumFreq=5 + SaveADP=false + UseAdvancedDCExtrap=false + ModeOption='General mode' + PhiMesherDeltaZRatio=100000 + SpiceType='TouchStone1.0' + EnforcePassivity=false + EnforceCausality=false + UseCommonGround=true + ShowGammaComments=false + Renormalize=true + RenormImpedance=50 + FittingError=0.5 + MaxPoles=10000 + PassivityType='IteratedFittingOfPV' + ColumnFittingType='Matrix' + SSFittingType='FastFit' + RelativeErrorToleranc=false + EnsureAccurateZfit=true + TouchstoneFormat='MA' + TouchstoneUnits='GHz' + TouchStonePrecision=15 + ExportAfterSolve=false + ExportDir='' + $end 'AdvancedSettings' + $begin 'CoSimOptions' + Override=false + Setup='' + OverrideSweep=false + Sweep='' + FrequencySweepType=0 + Interpolate=false + YMatrix=true + AutoAlignPorts=false + Simulator=1 + InterpAlg='auto' + Renormalize=false + RenormImpedance=50 + $end 'CoSimOptions' + $begin 'TemperatureData' + IncludeTempDependence=false + EnableFeedback=false + Temperature='22cel' + $end 'TemperatureData' + $begin 'UserDefinedSolutionMgr' + NextUniqueID=1000000 + MoveBackwards=false + $end 'UserDefinedSolutionMgr' + $begin 'DatasetSolutionMgr' + NextUniqueID=2000000 + MoveBackwards=false + $end 'DatasetSolutionMgr' + Notes=$begin_cdata$ $end_cdata$ + $begin 'AnimationSetups' + $end 'AnimationSetups' + CacheHeaderFile='HDR6CBA363617189547153.tmp' + $end 'PlanarEMCircuit' + $begin 'DataInstances' + DesignEditor='TopLevel' + Refdes('0', 'U1') + $begin 'CompInstances' + $begin 'Compinst' + ID='0' + Status='Status' + CompName='main' + GatesInUse() + $begin 'Properties' + TextProp('ID', 'SRID', '', '0') + $end 'Properties' + $begin 'Parameters' + MenuProp('CoSimulator', 'OHD', '', 'DefaultNetlist', 0) + ButtonProp('CosimDefinition', 'OHD', '', 'Edit', 'Edit', 40501, ButtonPropClientData()) + $end 'Parameters' + $end 'Compinst' + $end 'CompInstances' + $begin 'Instance' + DesignEditor='main' + ID='0' + $begin 'PlanarEMItem' + Editor3D=true + $begin 'PostProcessing' + DesignInstanceID=1 + $begin 'WindowPosition' + $begin 'EditorWindow' + Circuit(Layout(View(WindowPos(3, -1, -1, -16, -72, 0, 0, 324, 88), Extent(-3.06630444526672, -1, 3.06630444526672, 1, 14294.3901877805, 14289.1680718094, -0.0477049872279167, 0.0901622250676155, 0.230649910867214, 0.104624703526497, 1), ViewingXfm(-2.20454549789429, 2.20454549789429, -1, 1, 255.771438598633, 273.350341796875, 19.1159439086914, 0, 0, 0, 0, 19.1159439086914, 0, 0, 0, 0, 19.1159439086914, 0, -1.29261958599091, -0.72353607416153, -264.577545166016, 1))), Layout()) + $end 'EditorWindow' + $end 'WindowPosition' + $begin 'ReportSetup' + $begin 'ReportManager' + $begin 'Reports' + $end 'Reports' + NextUniqueID=0 + MoveBackwards=false + $begin 'NextVersID' + NextUniqueID=0 + MoveBackwards=false + $end 'NextVersID' + $end 'ReportManager' + $begin 'Reports' + $end 'Reports' + $begin 'ReportsWindowInfoList' + $end 'ReportsWindowInfoList' + $end 'ReportSetup' + $end 'PostProcessing' + $begin 'Properties' + $end 'Properties' + $begin 'UserDefinedDocument' + $begin 'Data' + $end 'Data' + $end 'UserDefinedDocument' + $end 'PlanarEMItem' + $begin 'TopLayout' + DefaultUnits='mm' + DefaultAngleUnits='deg' + MajorSize='10mm' + MinorSize='1mm' + PixelSnapTolerance=20 + SnapAcrossHierarchy=true + SnapTargetVertex_on=true + SnapTargetEdgeCenter_on=true + SnapTargetObjCenter_on=true + SnapTargetEdge_on=false + SnapTargetElecConnection_on=true + SnapTargetIntersection_on=false + SnapTargetGrid_on=true + SnapSourceVertex_on=true + SnapSourceEdgeCenter_on=true + SnapSourceObjCenter_on=true + SnapSourceEdge_on=false + SnapSourceElecConnection_on=true + ConstrainToGrid=false + DirectionConstraint=0 + defaultholesize='25mil' + anglesnap='5deg' + $begin 'NamingConvention' + OptionUseNamingConvention_PadPort=false + OptionNamingConvention_PadPort='$REFDES_$PINNAME_$NETNAME' + OptionUseNamingConvention_EdgePort=false + OptionNamingConvention_EdgePort='$NETNAME' + OptionUseNamingConvention_PointPort=false + OptionNamingConvention_PointPort='$POSTERM_LAYER_$NEGTERM_LAYER' + OptionUseNamingConvention_PinGroup=false + OptionNamingConvention_PinGroup='$REFDES_GROUP_$NETNAME' + OptionUseNamingConvention_PinGroupPort=false + OptionNamingConvention_PinGroupPort='$REFDES_$GROUPNAME_$NETNAME' + OptionUseNamingConvention_PointISource=false + OptionNamingConvention_PointISource='I_$POSTERM_NETNAME' + OptionUseNamingConvention_PointVSource=false + OptionNamingConvention_PointVSource='V_$POSTERM_NETNAME' + OptionUseNamingConvention_PointVProbe=false + OptionNamingConvention_PointVProbe='VP_$POSTERM_NETNAME' + OptionUseNamingConvention_PointDCTerm=false + OptionNamingConvention_PointDCTerm='DCT_$NETNAME' + OptionUseNamingConvention_PinISource=false + OptionNamingConvention_PinISource='I_$REFDES_$NETNAME' + OptionUseNamingConvention_PinVSource=false + OptionNamingConvention_PinVSource='V_$REFDES_$NETNAME' + OptionUseNamingConvention_PinVProbe=false + OptionNamingConvention_PinVProbe='VP_$REFDES_$NETNAME' + OptionUseNamingConvention_PinDCTerm=false + OptionNamingConvention_PinDCTerm='DCT_$REFDES_$NETNAME' + OptionUseNamingConvention_GroupISource=false + OptionNamingConvention_GroupISource='I_$REFDES_$NETNAME' + OptionUseNamingConvention_GroupVSource=false + OptionNamingConvention_GroupVSource='V_$REFDES_$NETNAME' + OptionUseNamingConvention_GroupVProbe=false + OptionNamingConvention_GroupVProbe='VP_$REFDES_$NETNAME' + OptionUseNamingConvention_GroupDCTerm=false + OptionNamingConvention_GroupDCTerm='DCT_$REFDES_$NETNAME' + OptionUseNamingConvention_NCPortInstPort=false + OptionNamingConvention_NCPortInstPort='$REFDES_$PORTNAME_$TERMNAME' + $end 'NamingConvention' + $begin 'TextStyles' + TextStyle(N='', F='Arial', Hght=12, Scale=false) + TextStyle(N='', Plot=true, F='RomanSimplex', Hght=5, HghtUnt='mm') + TextStyle(N='', Plot=true, F='RomanSimplex', Hght=1, HghtUnt='mm') + $end 'TextStyles' + $begin 'TraceStyles' + TraceStyle(name='Half Grid', size='0.5mm', bendStyle=0, capStyle=0, capStyle=0) + TraceStyle(name='1 Grid', size='1mm', bendStyle=0, capStyle=0, capStyle=0) + TraceStyle(name='2 Grids', size='2mm', bendStyle=0, capStyle=0, capStyle=0) + TraceStyle(name='5 Grids', size='5mm', bendStyle=0, capStyle=0, capStyle=0) + $end 'TraceStyles' + 'current via style'='PlanarEMVia' + 'current pin style'='' + MajorColor=14599364 + MinorColor=15391450 + ShowGrid=true + PageExtent(-0.1, -0.1, 0.1, 0.1) + 'background color'=16777215 + DefaultToSketchMode=true + fillMode=false + DocVisibilityFlag=962 + FastViewTransforms=true + StartingHierarchyLevel=0 + EndingHierarchyLevel=-1 + SingleLevelView=false + DesignMode=1 + Is2dRendering=false + 'show connection points'=false + 'draw rats'=false + 'display vertex labels'=false + ColorByNet=false + 'display package graphics'=false + 'rectangle description'=0 + snaptoport=true + autoplacecomp=false + AutoScale=true + 'measure display digits'=3 + 'display measure units'=false + SuppressPads=true + AntiPadsOption=0 + TextIsVisible=true + 'primary selection color'=255 + 'secondary selection color'=3289780 + 'preview selection'=false + AllowDragOnFirstClick=false + PinConnectivityPopup=false + CreatePortsOnComp=false + OptionUseNamingConvention_PadPort=false + OptionNamingConvention_PadPort='$REFDES_$PINNAME_$NETNAME' + OptionUseNamingConvention_EdgePort=false + OptionNamingConvention_EdgePort='$NETNAME' + OptionUseNamingConvention_PointPort=false + OptionNamingConvention_PointPort='$POSTERM_LAYER_$NEGTERM_LAYER' + OptionUseNamingConvention_PinGroup=false + OptionNamingConvention_PinGroup='$REFDES_GROUP_$NETNAME' + OptionUseNamingConvention_PinGroupPort=false + OptionNamingConvention_PinGroupPort='$REFDES_$GROUPNAME_$NETNAME' + OptionUseNamingConvention_PointISource=false + OptionNamingConvention_PointISource='I_$POSTERM_NETNAME' + OptionUseNamingConvention_PointVSource=false + OptionNamingConvention_PointVSource='V_$POSTERM_NETNAME' + OptionUseNamingConvention_PointVProbe=false + OptionNamingConvention_PointVProbe='VP_$POSTERM_NETNAME' + OptionUseNamingConvention_PointDCTerm=false + OptionNamingConvention_PointDCTerm='DCT_$NETNAME' + OptionUseNamingConvention_PinISource=false + OptionNamingConvention_PinISource='I_$REFDES_$NETNAME' + OptionUseNamingConvention_PinVSource=false + OptionNamingConvention_PinVSource='V_$REFDES_$NETNAME' + OptionUseNamingConvention_PinVProbe=false + OptionNamingConvention_PinVProbe='VP_$REFDES_$NETNAME' + OptionUseNamingConvention_PinDCTerm=false + OptionNamingConvention_PinDCTerm='DCT_$REFDES_$NETNAME' + OptionUseNamingConvention_GroupISource=false + OptionNamingConvention_GroupISource='I_$REFDES_$NETNAME' + OptionUseNamingConvention_GroupVSource=false + OptionNamingConvention_GroupVSource='V_$REFDES_$NETNAME' + OptionUseNamingConvention_GroupVProbe=false + OptionNamingConvention_GroupVProbe='VP_$REFDES_$NETNAME' + OptionUseNamingConvention_GroupDCTerm=false + OptionNamingConvention_GroupDCTerm='DCT_$REFDES_$NETNAME' + OptionUseNamingConvention_NCPortInstPort=false + OptionNamingConvention_NCPortInstPort='$REFDES_$PORTNAME_$TERMNAME' + useFixedDrawingResolution=false + DrawingResolution='0.002mm' + $begin 'ViewConfigs' + ViewConfigsCurrent='' + $end 'ViewConfigs' + currentTextStyle=0 + currentTraceStyle=0 + prevBounds(-3.06630444526672, -1, 3.06630444526672, 1) + prevMapFactor(14294.3901877805, 14289.1680718094) + prevOrigin(-0.0477049872279167, 0.0901622250676155) + prevViewExtent(0.230649910867214, 0.104624703526497) + prevZoomScale=1 + $begin 'Animation' + LabelColor(R=230, G=230, B=230) + FontName='Arial' + FontHeight=60 + FontWeight=400 + $end 'Animation' + $end 'TopLayout' + $end 'Instance' + $begin 'SODInfo' + $begin 'CAPC0603X33X15LL03T05' + $begin 'CosimDefinition' + CosimDefName='DefaultNetlist' + $begin 'SODInstanceMap' + $end 'SODInstanceMap' + SODComponentList() + $end 'CosimDefinition' + $end 'CAPC0603X33X15LL03T05' + $begin 'CAPC1005X05N' + $begin 'CosimDefinition' + CosimDefName='DefaultNetlist' + $begin 'SODInstanceMap' + $end 'SODInstanceMap' + SODComponentList() + $end 'CosimDefinition' + $end 'CAPC1005X05N' + $begin 'CAPC1005X33X10LL5' + $begin 'CosimDefinition' + CosimDefName='DefaultNetlist' + $begin 'SODInstanceMap' + $end 'SODInstanceMap' + SODComponentList() + $end 'CosimDefinition' + $end 'CAPC1005X33X10LL5' + $begin 'CAPC1005X55X10LL05' + $begin 'CosimDefinition' + CosimDefName='DefaultNetlist' + $begin 'SODInstanceMap' + $end 'SODInstanceMap' + SODComponentList() + $end 'CosimDefinition' + $end 'CAPC1005X55X10LL05' + $begin 'CAPC1005X55X23ML05T8' + $begin 'CosimDefinition' + CosimDefName='DefaultNetlist' + $begin 'SODInstanceMap' + $end 'SODInstanceMap' + SODComponentList() + $end 'CosimDefinition' + $end 'CAPC1005X55X23ML05T8' + $begin 'CAPC1005X55X25LL05T10' + $begin 'CosimDefinition' + CosimDefName='DefaultNetlist' + $begin 'SODInstanceMap' + $end 'SODInstanceMap' + SODComponentList() + $end 'CosimDefinition' + $end 'CAPC1005X55X25LL05T10' + $begin 'CAPC1005X55X25ML05T10' + $begin 'CosimDefinition' + CosimDefName='DefaultNetlist' + $begin 'SODInstanceMap' + $end 'SODInstanceMap' + SODComponentList() + $end 'CosimDefinition' + $end 'CAPC1005X55X25ML05T10' + $begin 'CAPC1005X55X25NL05T10' + $begin 'CosimDefinition' + CosimDefName='DefaultNetlist' + $begin 'SODInstanceMap' + $end 'SODInstanceMap' + SODComponentList() + $end 'CosimDefinition' + $end 'CAPC1005X55X25NL05T10' + $begin 'CAPC1608X08N' + $begin 'CosimDefinition' + CosimDefName='DefaultNetlist' + $begin 'SODInstanceMap' + $end 'SODInstanceMap' + SODComponentList() + $end 'CosimDefinition' + $end 'CAPC1608X08N' + $begin 'CAPC1608X90X35ML10T15' + $begin 'CosimDefinition' + CosimDefName='DefaultNetlist' + $begin 'SODInstanceMap' + $end 'SODInstanceMap' + SODComponentList() + $end 'CosimDefinition' + $end 'CAPC1608X90X35ML10T15' + $begin 'CAPC2012X12N' + $begin 'CosimDefinition' + CosimDefName='DefaultNetlist' + $begin 'SODInstanceMap' + $end 'SODInstanceMap' + SODComponentList() + $end 'CosimDefinition' + $end 'CAPC2012X12N' + $begin 'CAPC2013X100X20NL20' + $begin 'CosimDefinition' + CosimDefName='DefaultNetlist' + $begin 'SODInstanceMap' + $end 'SODInstanceMap' + SODComponentList() + $end 'CosimDefinition' + $end 'CAPC2013X100X20NL20' + $begin 'CAPC3216X180X20ML20' + $begin 'CosimDefinition' + CosimDefName='DefaultNetlist' + $begin 'SODInstanceMap' + $end 'SODInstanceMap' + SODComponentList() + $end 'CosimDefinition' + $end 'CAPC3216X180X20ML20' + $begin 'CAPC3216X180X55ML20T25' + $begin 'CosimDefinition' + CosimDefName='DefaultNetlist' + $begin 'SODInstanceMap' + $end 'SODInstanceMap' + SODComponentList() + $end 'CosimDefinition' + $end 'CAPC3216X180X55ML20T25' + $begin 'CAPC3216X190X55ML30T25' + $begin 'CosimDefinition' + CosimDefName='DefaultNetlist' + $begin 'SODInstanceMap' + $end 'SODInstanceMap' + SODComponentList() + $end 'CosimDefinition' + $end 'CAPC3216X190X55ML30T25' + $begin 'CAPMP7343X31N' + $begin 'CosimDefinition' + CosimDefName='DefaultNetlist' + $begin 'SODInstanceMap' + $end 'SODInstanceMap' + SODComponentList() + $end 'CosimDefinition' + $end 'CAPMP7343X31N' + $begin 'COIL-1008CS_V' + $begin 'CosimDefinition' + CosimDefName='DefaultNetlist' + $begin 'SODInstanceMap' + $end 'SODInstanceMap' + SODComponentList() + $end 'CosimDefinition' + $end 'COIL-1008CS_V' + $begin 'MURA-BLM15-CHIP-2_V' + $begin 'CosimDefinition' + CosimDefName='DefaultNetlist' + $begin 'SODInstanceMap' + $end 'SODInstanceMap' + SODComponentList() + $end 'CosimDefinition' + $end 'MURA-BLM15-CHIP-2_V' + $begin 'MURA-BLM15AG221SN1x_V' + $begin 'CosimDefinition' + CosimDefName='DefaultNetlist' + $begin 'SODInstanceMap' + $end 'SODInstanceMap' + SODComponentList() + $end 'CosimDefinition' + $end 'MURA-BLM15AG221SN1x_V' + $begin 'RESC1005X35X25NL8T10' + $begin 'CosimDefinition' + CosimDefName='DefaultNetlist' + $begin 'SODInstanceMap' + $end 'SODInstanceMap' + SODComponentList() + $end 'CosimDefinition' + $end 'RESC1005X35X25NL8T10' + $begin 'RESC1005X40X25LL05T05' + $begin 'CosimDefinition' + CosimDefName='DefaultNetlist' + $begin 'SODInstanceMap' + $end 'SODInstanceMap' + SODComponentList() + $end 'CosimDefinition' + $end 'RESC1005X40X25LL05T05' + $begin 'RESC1005X40X25ML05T05' + $begin 'CosimDefinition' + CosimDefName='DefaultNetlist' + $begin 'SODInstanceMap' + $end 'SODInstanceMap' + SODComponentList() + $end 'CosimDefinition' + $end 'RESC1005X40X25ML05T05' + $begin 'RESC1005X40X25NL05T05' + $begin 'CosimDefinition' + CosimDefName='DefaultNetlist' + $begin 'SODInstanceMap' + $end 'SODInstanceMap' + SODComponentList() + $end 'CosimDefinition' + $end 'RESC1005X40X25NL05T05' + $begin 'RESC1005X40X25NL5T10' + $begin 'CosimDefinition' + CosimDefName='DefaultNetlist' + $begin 'SODInstanceMap' + $end 'SODInstanceMap' + SODComponentList() + $end 'CosimDefinition' + $end 'RESC1005X40X25NL5T10' + $begin 'RESC1608X05N' + $begin 'CosimDefinition' + CosimDefName='DefaultNetlist' + $begin 'SODInstanceMap' + $end 'SODInstanceMap' + SODComponentList() + $end 'CosimDefinition' + $end 'RESC1608X05N' + $begin 'SMD-0603' + $begin 'CosimDefinition' + CosimDefName='DefaultNetlist' + $begin 'SODInstanceMap' + $end 'SODInstanceMap' + SODComponentList() + $end 'CosimDefinition' + $end 'SMD-0603' + $begin 'WE-Coil-744301047' + $begin 'CosimDefinition' + CosimDefName='DefaultNetlist' + $begin 'SODInstanceMap' + $end 'SODInstanceMap' + SODComponentList() + $end 'CosimDefinition' + $end 'WE-Coil-744301047' + $begin 'WE-Coil-PD4-S' + $begin 'CosimDefinition' + CosimDefName='DefaultNetlist' + $begin 'SODInstanceMap' + $end 'SODInstanceMap' + SODComponentList() + $end 'CosimDefinition' + $end 'WE-Coil-PD4-S' + $begin 'main' + $begin 'CosimDefinition' + CosimDefName='DefaultNetlist' + $begin 'SODInstanceMap' + $end 'SODInstanceMap' + SODComponentList() + $end 'CosimDefinition' + $end 'main' + $end 'SODInfo' + $end 'DataInstances' + $begin 'WBSystemIDToDesignInstanceIDMap' + $end 'WBSystemIDToDesignInstanceIDMap' + $begin 'WBSysIDSysDetails' + $end 'WBSysIDSysDetails' + $begin 'WBConnIDConnDetails' + $end 'WBConnIDConnDetails' + $begin 'WBMaterialGuidDetails' + WBMaterialGuidMap() + $end 'WBMaterialGuidDetails' + $begin 'MinervaProjectSettingsBlk' + MinervaRemoteFilePath='' + FolderContainerString='' + $end 'MinervaProjectSettingsBlk' +$end 'AnsoftProject' +$begin 'AllReferencedFilesForProject' +$end 'AllReferencedFilesForProject' +$begin 'ProjectPreview' + IsEncrypted=false + Thumbnail64='/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE\ +BAQICAQECAQEBAgICAgICAgICAQICAgICAgICAgL/2wBDAQEBAQEBAQEBAQECAQEBAgICAgICAgICAg\ +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgL/wAARCABgAGADASIAAhEBAxEB/\ +8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQR\ +BRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUp\ +TVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5us\ +LDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAA\ +AECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHB\ +CSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ\ +3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4u\ +Pk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD+q/xDoGhQaFrlzDoukw3EOk6nPFcRadZxzRTR2\ +c8kc0cqQhklVwGDAggjIOa1v+EZ8Of9C/on/gqsP/kesnxDotnDoWuXCTasZItJ1OZVl1/XZ4S6Wc7g\ +SW02otHNFkDKOjIwyrKVJFa3/CP2H/Pxrf8A4U3iP/5a197bV+6n/W+2/wDkvlzmR4f8P6DcaDolxca\ +JpE88+kabNNNNptnLLNLLZwvJLLI8JMkjOzFmJJJJJOaNE8P6DPZzPNomkTOur+IIVeXTbORhFb69qV\ +vbxBnhJEaQRRoi9FSNVUAACjw/olnPoOiTPNq6vNpGmyusPiDXreINJZwuwit7fUljgjyTtRFVFGFVQ\ +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' + $begin 'DesignInfo' + DesignName='main' + Notes='' + Factory='HFSS 3D Layout Design' + IsSolved=false + 'Nominal Setups'[0:] + 'Nominal Setup Types'[0:] + 'Optimetrics Setups'[0:] + 'Optimetrics Experiment Types'[0:] + Image64='/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE\ +BAQICAQECAQEBAgICAgICAgICAQICAgICAgICAgL/2wBDAQEBAQEBAQEBAQECAQEBAgICAgICAgICAg\ +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgL/wAARCADIAMgDASIAAhEBAxEB/\ +8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQR\ +BRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUp\ +TVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5us\ +LDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAA\ +AECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHB\ +CSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ\ +3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4u\ +Pk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD+w698I6Av9oZ8KaOu3+1858LWUe3Z/wALCzn/A\ +ItzD5e37PJn/UbPsp/49fsx/sPL8U+FtFttF8TzweGNLt57fS/E8sM0Xhi0glglgtPiQ6SRunw3iMEi\ +PbMQQITGbMkC2Nt/xI+svbLb9v8A9A2bP7W/5hPl7PL/AOE//wCpAh8rb9k/6YeX9h/5dfsv/Eix/F1\ +lt0DxWP7P27dH8UjH9kbNvl2XxG4x/wAK9j8vb9k6bYtn2LpbfZcaH9lFtSi07NNHOFt4R0A312o8Ka\ +OxHiXUYyv/AAi1k5Vl8ReEIzCY/wDhXMmxg0qJ5XkxbTOIv7Pg84WGqFl4R0Bv7Px4U0dt39kYx4Wsp\ +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\ +7Hz/QqO/3fmj//2Q==' + $end 'DesignInfo' +$end 'ProjectPreview' diff --git a/_unittest_solvers/example_models/T45/components.json b/_unittest_solvers/example_models/T45/components.json new file mode 100644 index 00000000000..3af202036b6 --- /dev/null +++ b/_unittest_solvers/example_models/T45/components.json @@ -0,0 +1,19 @@ +{ + "components": [ + { + "reference_designator": "U1", + "part_type": "io", + "solder_ball_properties": { + "shape": "cylinder", + "diameter": "244um", + "height": "406um" + }, + "port_properties": { + "reference_offset": "0.1mm", + "reference_size_auto": true, + "reference_size_x": 0, + "reference_size_y": 0 + } + } + ] +} \ No newline at end of file diff --git a/_unittest_solvers/example_models/T45/expression_catalog_custom.toml b/_unittest_solvers/example_models/T45/expression_catalog_custom.toml new file mode 100644 index 00000000000..dce3f726b87 --- /dev/null +++ b/_unittest_solvers/example_models/T45/expression_catalog_custom.toml @@ -0,0 +1,13 @@ +[e_field_magnitude] +name = "EField_magnitude" +description = "E field magnitude" +design_type = ["HFSS"] +fields_type = ["Fields"] +solution_type = "" +primary_sweep = "Freq" +assignment = "" +assignment_type = ["Line", "Face", "Solid"] +operations = ["Fundamental_Quantity('E')", + "Operation('Mag')" +] +report = ["Field_3D", "Rectangular Plot"] diff --git a/_unittest_solvers/example_models/T45/fields_calculator_solved.aedtz b/_unittest_solvers/example_models/T45/fields_calculator_solved.aedtz new file mode 100644 index 00000000000..8e79c239299 Binary files /dev/null and b/_unittest_solvers/example_models/T45/fields_calculator_solved.aedtz differ diff --git a/_unittest_solvers/example_models/T45/maxwell_fields_calculator.aedtz b/_unittest_solvers/example_models/T45/maxwell_fields_calculator.aedtz new file mode 100644 index 00000000000..cf87ea18eaf Binary files /dev/null and b/_unittest_solvers/example_models/T45/maxwell_fields_calculator.aedtz differ diff --git a/_unittest_solvers/example_models/T45/ports.json b/_unittest_solvers/example_models/T45/ports.json new file mode 100644 index 00000000000..51f910ad913 --- /dev/null +++ b/_unittest_solvers/example_models/T45/ports.json @@ -0,0 +1,35 @@ +{ + "ports": [ + { + "name": "COAX_U1_AM17", + "reference_designator": "U1", + "type": "coax", + "positive_terminal": { + "pin": "AM17" + } + }, + { + "name": "COAX_U1_PCIe_Gen4_TX2_CAP_N", + "reference_designator": "U1", + "type": "coax", + "positive_terminal": { + "net": "PCIe_Gen4_TX2_CAP_N" + } + }, + { + "name": "CIRCUIT_U7_VDD_DDR_GND", + "reference_designator": "U7", + "type": "circuit", + "distributed": true, + "positive_terminal": { + "net": "VDD_DDR" + }, + "negative_terminal": { + "nearest_pin": { + "reference_net": "GND", + "search_radius": 5e-3 + } + } + } + ] +} \ No newline at end of file diff --git a/_unittest_solvers/example_models/T45/stackup.json b/_unittest_solvers/example_models/T45/stackup.json new file mode 100644 index 00000000000..692870ac08e --- /dev/null +++ b/_unittest_solvers/example_models/T45/stackup.json @@ -0,0 +1,95 @@ +{ + "stackup": { + "materials": [ + { + "name": "copper", + "conductivity": 570000000 + }, + { + "name": "Megtron4", + "permittivity": 3.77, + "dielectric_loss_tangent": 0.005 + }, + { + "name": "Megtron4_2", + "permittivity": 3.77, + "dielectric_loss_tangent": 0.005 + }, + { + "name": "Solder Resist", + "permittivity": 4, + "dielectric_loss_tangent": 0 + } + ], + "layers": [ + { + "fill_material": "Solder Resist", + "material": "copper", + "name": "1_Top", + "thickness": "0.5mm", + "type": "signal" + }, + { + "fill_material": "Megtron4", + "material": "copper", + "name": "Inner1", + "thickness": "0.017mm", + "type": "signal" + }, + { + "material": "Megtron4", + "name": "DE2", + "thickness": "0.088mm", + "type": "dielectric" + }, + { + "material": "Megtron4", + "name": "DE3", + "thickness": "0.1mm", + "type": "dielectric" + }, + { + "fill_material": "Megtron4", + "material": "copper", + "name": "Inner2", + "thickness": "0.017mm", + "type": "signal" + }, + { + "fill_material": "Megtron4", + "material": "copper", + "name": "Inner3", + "thickness": "0.017mm", + "type": "signal" + }, + { + "fill_material": "Megtron4", + "material": "copper", + "name": "Inner4", + "thickness": "0.017mm", + "type": "signal" + }, + { + "fill_material": "Megtron4", + "material": "copper", + "name": "Inner5", + "thickness": "0.017mm", + "type": "signal" + }, + { + "fill_material": "Megtron4", + "material": "copper", + "name": "Inner6", + "thickness": "0.017mm", + "type": "signal" + }, + { + "fill_material": "Solder Resist", + "material": "copper", + "name": "16_Bottom", + "thickness": "0.035mm", + "type": "signal" + } + ] + } +} \ No newline at end of file diff --git a/_unittest_solvers/test_00_analyze.py b/_unittest_solvers/test_00_analyze.py index a591033740c..b1606b1e9a1 100644 --- a/_unittest_solvers/test_00_analyze.py +++ b/_unittest_solvers/test_00_analyze.py @@ -10,7 +10,7 @@ from pathlib import Path -from pyaedt import is_linux +from pyaedt.generic.settings import is_linux from pyaedt import Icepak from pyaedt import Hfss3dLayout from pyaedt import Circuit, Maxwell3d @@ -37,28 +37,28 @@ def sbr_platform(add_app): app = add_app(project_name=sbr_platform_name, subfolder=test_subfolder) yield app - app.close_project(save_project=False) + app.close_project(save=False) @pytest.fixture() def array(add_app): app = add_app(project_name=array_name, subfolder=test_subfolder) yield app - app.close_project(save_project=False) + app.close_project(save=False) @pytest.fixture() def sbr_app(add_app): app = add_app(project_name="SBR_test", solution_type="SBR+") yield app - app.close_project(save_project=False) + app.close_project(save=False) @pytest.fixture() def hfss_app(add_app): app = add_app(project_name="Hfss_test") yield app - app.close_project(save_project=False) + app.close_project(save=False) @pytest.fixture(scope="class") @@ -108,18 +108,25 @@ def init(self, local_scratch, icepak_app, hfss3dl_solve): @pytest.mark.skipif(is_linux or sys.version_info < (3, 8), reason="Not supported.") def test_01a_sbr_link_array(self, sbr_platform, array): assert sbr_platform.create_sbr_linked_antenna(array, target_cs="antenna_CS", field_type="farfield") - sbr_platform.analyze(cores=6) + profile = sbr_platform.setups[0].get_profile() + assert profile is None + sbr_platform.analyze(cores=4) + profile = sbr_platform.setups[0].get_profile() + assert isinstance(profile, dict) + assert not sbr_platform.get_profile("Invented_setup") + ffdata = sbr_platform.get_antenna_ffd_solution_data(frequencies=12e9, sphere="3D") ffdata2 = sbr_platform.get_antenna_ffd_solution_data(frequencies=12e9, sphere="3D", overwrite=False) ffdata.plot_2d_cut(quantity="RealizedGain", primary_sweep="theta", secondary_sweep_value=[75], theta=20, - title="Azimuth at {}Hz".format(ffdata.frequency), quantity_format="dB10", + title="Azimuth at {}Hz".format(ffdata.frequency), quantity_format="dB10", show=False, image_path=os.path.join(self.local_scratch.path, "2d1_array.jpg")) assert os.path.exists(os.path.join(self.local_scratch.path, "2d1_array.jpg")) ffdata2.polar_plot_3d_pyvista(quantity="RealizedGain", rotation=[[1, 0.0, 0.0], [0.0, 0.0, 1.0], [0.0, 1.0, 0.0]], - image_path=os.path.join(self.local_scratch.path, "3d2_array.jpg"), show=False, + image_path=os.path.join(self.local_scratch.path, "3d2_array.jpg"), + show=False, convert_to_db=True) assert os.path.exists(os.path.join(self.local_scratch.path, "3d2_array.jpg")) @@ -176,7 +183,7 @@ def test_02_hfss_export_results(self, hfss_app): setup.props["Frequency"] = "1GHz" exported_files = hfss_app.export_results() assert len(exported_files) == 0 - hfss_app.analyze_setup(name="test", cores=6) + hfss_app.analyze_setup(name="test", cores=4) exported_files = hfss_app.export_results() assert len(exported_files) == 39 exported_files = hfss_app.export_results( @@ -214,7 +221,7 @@ def test_03a_icepak_analyze_and_export_summary(self): monitor_quantity=["Temperature", "HeatFlowRate"], monitor_name="test_monitor2", ) - self.icepak_app.analyze("SetupIPK", cores=6) + self.icepak_app.analyze("SetupIPK", cores=4) self.icepak_app.save_project() assert self.icepak_app.export_summary( self.icepak_app.working_directory, geometryType="Surface", variationlist=[], filename="A" @@ -321,14 +328,14 @@ def test_04a_3dl_generate_mesh(self): @pytest.mark.skipif(desktop_version < "2023.2", reason="Working only from 2023 R2") def test_04b_3dl_analyze_setup(self): - assert self.hfss3dl_solve.analyze_setup("Setup1", cores=6, blocking=False) + assert self.hfss3dl_solve.analyze_setup("Setup1", cores=4, blocking=False) assert self.hfss3dl_solve.are_there_simulations_running assert self.hfss3dl_solve.stop_simulations() while self.hfss3dl_solve.are_there_simulations_running: time.sleep(1) def test_04c_3dl_analyze_setup(self): - assert self.hfss3dl_solve.analyze_setup("Setup1", cores=6) + assert self.hfss3dl_solve.analyze_setup("Setup1", cores=4) self.hfss3dl_solve.save_project() assert os.path.exists(self.hfss3dl_solve.export_profile("Setup1")) assert os.path.exists(self.hfss3dl_solve.export_mesh_stats("Setup1")) @@ -406,13 +413,13 @@ def test_06_m3d_harmonic_forces(self, m3dtransient): use_number_of_last_cycles=True, last_cycles_number=3, calculate_force="Harmonic") m3dtransient.save_project() - m3dtransient.analyze(m3dtransient.active_setup, cores=2, use_auto_settings=False) + m3dtransient.analyze(m3dtransient.active_setup, cores=4, use_auto_settings=False) assert m3dtransient.export_element_based_harmonic_force(start_frequency=1, stop_frequency=100, number_of_frequency=None) assert m3dtransient.export_element_based_harmonic_force(number_of_frequency=5) def test_07_export_maxwell_fields(self, m3dtransient): - m3dtransient.analyze(m3dtransient.active_setup, cores=2, use_auto_settings=False) + m3dtransient.analyze(m3dtransient.active_setup, cores=4, use_auto_settings=False) fld_file_3 = os.path.join(self.local_scratch.path, "test_fld_3.fld") assert m3dtransient.post.export_field_file(quantity="Mag_B", solution=m3dtransient.nominal_sweep, variations={}, output_dir=fld_file_3, assignment="Coil_A2", objects_type="Surf", diff --git a/_unittest_solvers/test_26_emit.py b/_unittest_solvers/test_26_emit.py index bde7c4b6a38..3ccc018fcb5 100644 --- a/_unittest_solvers/test_26_emit.py +++ b/_unittest_solvers/test_26_emit.py @@ -5,18 +5,19 @@ from _unittest_solvers.conftest import config import pytest - -from pyaedt import Emit -from pyaedt import generate_unique_project_name -from pyaedt.emit_core.emit_constants import EmiCategoryFilter -from pyaedt.emit_core.emit_constants import InterfererType -from pyaedt.emit_core.emit_constants import ResultType -from pyaedt.emit_core.emit_constants import TxRxMode -from pyaedt.generic import constants as consts from pyaedt.generic.general_methods import is_linux -from pyaedt.modeler.circuits.PrimitivesEmit import EmitAntennaComponent -from pyaedt.modeler.circuits.PrimitivesEmit import EmitComponent -from pyaedt.modeler.circuits.PrimitivesEmit import EmitComponents +from pyaedt.generic import constants as consts + +if (3,7) < sys.version_info <(3, 12): + from pyaedt import Emit + from pyaedt import generate_unique_project_name + from pyaedt.emit_core.emit_constants import EmiCategoryFilter + from pyaedt.emit_core.emit_constants import InterfererType + from pyaedt.emit_core.emit_constants import ResultType + from pyaedt.emit_core.emit_constants import TxRxMode + from pyaedt.modeler.circuits.PrimitivesEmit import EmitAntennaComponent + from pyaedt.modeler.circuits.PrimitivesEmit import EmitComponent + from pyaedt.modeler.circuits.PrimitivesEmit import EmitComponents TEST_SUBFOLDER = "T26" TEST_REVIEW_FLAG = True @@ -29,7 +30,8 @@ def aedtapp(add_app): @pytest.mark.skipif(is_linux, reason="Emit API fails on linux.") -@pytest.mark.skipif(sys.version_info < (3,8), reason="Emit API is only available for Python 3.8+.") +@pytest.mark.skipif(is_linux, reason="Emit API fails on linux.") +@pytest.mark.skipif(sys.version_info < (3,8) or sys.version_info >=(3, 12), reason="Emit API is only available for Python 3.8+.") class TestClass: @pytest.fixture(autouse=True) diff --git a/_unittest_solvers/test_31_Q3D.py b/_unittest_solvers/test_31_Q3D.py index 9b68473a1c8..1d92c2a22fc 100644 --- a/_unittest_solvers/test_31_Q3D.py +++ b/_unittest_solvers/test_31_Q3D.py @@ -188,7 +188,7 @@ def test_07B_create_source_tosheet(self): assert len(obj_list[self.aedtapp.nets[0]]) == 0 def test_08_create_faceted_bondwire(self): - self.aedtapp.load_project(self.test_project, close_active_proj=True, save_active_project=False) + self.aedtapp.load_project(self.test_project, close_active=True, set_active=False) test = self.aedtapp.modeler.create_faceted_bondwire_from_true_surface("bondwire_example", self.aedtapp.AXIS.Z, min_size=0.2, number_of_segments=8) assert test @@ -270,7 +270,7 @@ def test_13_matrix_reduction(self, add_app): assert q3d.matrices[0].get_sources_for_plot(first_element_filter="Box?", second_element_filter="B*2") == [ "C(Box1,Box1_2)" ] - self.aedtapp.close_project(q3d.project_name, save_project=False) + self.aedtapp.close_project(q3d.project_name, save=False) def test_14_edit_sources(self, add_app): q3d = add_app(application=Q3d, project_name=self.test_matrix, just_open=True) @@ -306,7 +306,7 @@ def test_14_edit_sources(self, add_app): sources_dc = {"Box1:Source1": ["20v"]} assert q3d.edit_sources(None, None, sources_dc) - self.aedtapp.close_project(q3d.project_name, save_project=False) + self.aedtapp.close_project(q3d.project_name, save=False) def test_15_export_matrix_data(self, add_app): q3d = add_app(application=Q3d, project_name=self.test_matrix, just_open=True) @@ -370,7 +370,7 @@ def test_15_export_matrix_data(self, add_app): assert not q3d.export_matrix_data(file_name=os.path.join(self.local_scratch.path, "test.txt"), c_unit="H") assert q3d.export_matrix_data(file_name=os.path.join(self.local_scratch.path, "test.txt"), g_unit="fSie") assert not q3d.export_matrix_data(file_name=os.path.join(self.local_scratch.path, "test.txt"), g_unit="A") - self.aedtapp.close_project(q3d.project_name, save_project=False) + self.aedtapp.close_project(q3d.project_name, save=False) def test_16_export_equivalent_circuit(self, add_app): test_matrix2 = self.local_scratch.copyfile( @@ -415,7 +415,7 @@ def test_16_export_equivalent_circuit(self, add_app): output_file=os.path.join(self.local_scratch.path, "test_export_circuit.cir"), model="test_14") assert not q3d.export_equivalent_circuit( output_file=os.path.join(self.local_scratch.path, "test_export_circuit.cir"), model="test") - self.aedtapp.close_project(q3d.project_name, save_project=False) + self.aedtapp.close_project(q3d.project_name, save=False) def test_17_export_results_q3d(self, add_app): q3d = add_app(application=Q3d, project_name=self.test_matrix, just_open=True) @@ -429,7 +429,7 @@ def test_17_export_results_q3d(self, add_app): q3d.analyze(cores=6) exported_files = q3d.export_results() assert len(exported_files) > 0 - q3d.close_project(q3d.project_name, save_project=False) + q3d.close_project(q3d.project_name, save=False) def test_18_set_variable(self): self.aedtapp.variable_manager.set_variable("var_test", expression="123") diff --git a/_unittest_solvers/test_45_workflows.py b/_unittest_solvers/test_45_workflows.py index 7e830c56294..7097a61b170 100644 --- a/_unittest_solvers/test_45_workflows.py +++ b/_unittest_solvers/test_45_workflows.py @@ -3,14 +3,16 @@ import shutil import pyaedt -from pyaedt import is_linux -# from _unittest_solvers.conftest import local_path as solver_local_path +from pyaedt.generic.settings import is_linux from _unittest.conftest import local_path +from _unittest_solvers.conftest import local_path as solver_local_path push_project = "push_excitation" export_3d_project = "export" twinbuilder_circuit = "TB_test" report = "report" +fields_calculator = "fields_calculator_solved" +m2d_electrostatic = "maxwell_fields_calculator" test_subfolder = "T45" @@ -150,6 +152,150 @@ def test_07_twinbuilder_convert_circuit(self, add_app): assert main({"is_test": True}) - circuit = pyaedt.Circuit() - assert len(circuit.modeler.schematic.components) == 10 + def test_08_configure_a3d(self, local_scratch): + from pyaedt.workflows.project.configure_edb import main + + configuration_path = shutil.copy(os.path.join(solver_local_path, "example_models", "T45", "ports.json"), + os.path.join(local_scratch.path, "ports.json")) + file_path = os.path.join(local_scratch.path, "ANSYS-HSD_V1.aedb") + 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}) + + def test_08_advanced_fields_calculator_non_general(self, add_app): + aedtapp = add_app(application=pyaedt.Hfss, + project_name=fields_calculator, + subfolder=test_subfolder) + + assert isinstance(aedtapp.post.fields_calculator.expression_names, list) + name = aedtapp.post.fields_calculator.add_expression("voltage_line", "Polyline1") + assert name == "Voltage_Line" + name2 = aedtapp.post.fields_calculator.add_expression("voltage_line", "Polyline1") + assert name == name2 + assert not aedtapp.post.fields_calculator.expression_plot("voltage_line_invented", "Polyline1", [name]) + assert aedtapp.post.fields_calculator.expression_plot("voltage_line", "Polyline1", [name]) + assert aedtapp.post.fields_calculator.delete_expression(name) + assert aedtapp.post.fields_calculator.delete_expression() + assert not aedtapp.post.fields_calculator.is_expression_defined(name) + assert not aedtapp.post.fields_calculator.add_expression("voltage_line", "Polyline1_invented") + assert not aedtapp.post.fields_calculator.add_expression("voltage_line", "inner") + assert not aedtapp.post.fields_calculator.add_expression("voltage_line", 500) + + from pyaedt.workflows.project.advanced_fields_calculator import main + + assert main({"is_test": True, + "setup": "Setup1 : LastAdaptive", + "calculation": "voltage_line", + "assignment": ["Polyline1", "Polyline2"]}) + + assert len(aedtapp.post.all_report_names) == 6 + + assert not main({"is_test": True, + "setup": "Setup1 : LastAdaptive", + "calculation": "", + "assignment": ["Polyline1", "Polyline2"]}) + + assert not main({"is_test": True, + "setup": "Setup1 : LastAdaptive", + "calculation": "voltage_line_invented", + "assignment": ["Polyline1", "Polyline2"]}) + + aedtapp.close_project(aedtapp.project_name) + + def test_09_advanced_fields_calculator_general(self, add_app): + aedtapp = add_app(application=pyaedt.Q3d, + project_name=fields_calculator, + subfolder=test_subfolder) + + initial_catalog = len(aedtapp.post.fields_calculator.expression_names) + example_file = os.path.join(solver_local_path, "example_models", + test_subfolder, + "expression_catalog_custom.toml") + new_catalog = aedtapp.post.fields_calculator.load_expression_file(example_file) + assert initial_catalog != len(new_catalog) + assert new_catalog == aedtapp.post.fields_calculator.expression_catalog + assert not aedtapp.post.fields_calculator.add_expression("e_field_magnitude", "Polyline1") + assert not aedtapp.post.fields_calculator.load_expression_file("invented.toml") + + from pyaedt.workflows.project.advanced_fields_calculator import main + + assert main({"is_test": True, + "setup": "Setup1 : LastAdaptive", + "calculation": "voltage_drop", + "assignment": ["Face9", "inner"]}) + + assert len(aedtapp.post.ofieldsreporter.GetChildNames()) == 2 + + aedtapp.close_project(aedtapp.project_name) + + aedtapp = add_app(application=pyaedt.Maxwell2d, + project_name=m2d_electrostatic, + design_name="e_tangential", + subfolder=test_subfolder) + name = aedtapp.post.fields_calculator.add_expression("e_line", None) + assert name + assert aedtapp.post.fields_calculator.expression_plot("e_line", "Poly1", [name]) + + assert main({"is_test": True, + "setup": "MySetupAuto : LastAdaptive", + "calculation": "e_line", + "assignment": ["Polyl1"]}) + aedtapp.close_project(aedtapp.project_name) + + aedtapp = add_app(application=pyaedt.Maxwell2d, + project_name=m2d_electrostatic, + design_name="stress_tensor", + subfolder=test_subfolder) + name = aedtapp.post.fields_calculator.add_expression("radial_stress_tensor", None) + assert name + assert aedtapp.post.fields_calculator.expression_plot("radial_stress_tensor", "Polyline1", [name]) + name = aedtapp.post.fields_calculator.add_expression("tangential_stress_tensor", None) + assert name + assert aedtapp.post.fields_calculator.expression_plot("tangential_stress_tensor", "Polyline1", [name]) + + aedtapp.close_project(aedtapp.project_name) + + def test_10_push_excitation_3dl(self, local_scratch, desktop): + from pyaedt.workflows.hfss3dlayout.push_excitation_from_file_3dl import main + + project_path = shutil.copy(os.path.join(local_path, "example_models", + "T41", + "test_post_3d_layout_solved_23R2.aedtz"), + os.path.join(local_scratch.path, "test_post_3d_layout_solved_23R2.aedtz")) + + h3d = pyaedt.Hfss3dLayout(project_path, version=desktop.aedt_version_id, port=str(desktop.port)) + + file_path = os.path.join(local_path, "example_models", "T20", "Sinusoidal.csv") + assert main({"is_test": True, "file_path": file_path, "choice": ""}) + h3d.save_project() + assert not h3d.design_datasets + + # Correct choice + assert main({"is_test": True, "file_path": file_path, "choice": "Port1"}) + h3d.save_project() + # In 3D Layout datasets are not retrieved + # assert h3d.design_datasets + h3d.close_project(h3d.project_name) + + def test_11_cutout(self, add_app, local_scratch): + from pyaedt.workflows.hfss3dlayout.cutout import main + + + app = add_app("ANSYS-HSD_V1", application=pyaedt.Hfss3dLayout, subfolder=test_subfolder) + + assert main({"is_test": True, "choice": "ConvexHull", + "signals": ["DDR4_A0"], + "reference": ["GND"], + "expansion_factor": 3, + "fix_disjoints": True, }) + app.close_project() + def test_12_export_layout(self, add_app, local_scratch): + from pyaedt.workflows.hfss3dlayout.export_layout import main + + + app = add_app("ANSYS-HSD_V1", application=pyaedt.Hfss3dLayout, subfolder=test_subfolder) + + assert main({"is_test": True, "export_ipc": True, "export_configuration": True, "export_bom": True }) + app.close_project() diff --git a/doc/source/_static/logo.png b/doc/source/_static/logo.png new file mode 100644 index 00000000000..2e9d129d87e Binary files /dev/null and b/doc/source/_static/logo.png differ diff --git a/doc/source/conf.py b/doc/source/conf.py index 4e3a6246035..adcdfbfcdd0 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -353,16 +353,16 @@ def setup(app): }, } -# Add button to download PDF -html_theme_options["icon_links"].append( - { - "name": "Download documentation in PDF", - # NOTE: Changes to this URL must be reflected in CICD documentation build - "url": f"https://{cname}/version/{switcher_version}/_static/assets/download/pyaedt.pdf", - # noqa: E501 - "icon": "fa fa-file-pdf fa-fw", - } -) +# # Add button to download PDF +# html_theme_options["icon_links"].append( +# { +# "name": "Download documentation in PDF", +# # NOTE: Changes to this URL must be reflected in CICD documentation build +# "url": f"https://{cname}/version/{switcher_version}/_static/assets/download/pyaedt.pdf", +# # noqa: E501 +# "icon": "fa fa-file-pdf fa-fw", +# } +# ) html_static_path = ["_static"] diff --git a/doc/source/create_documentation.bat b/doc/source/create_documentation.bat index bb57ace6ba6..c3c306b674d 100644 --- a/doc/source/create_documentation.bat +++ b/doc/source/create_documentation.bat @@ -1 +1,2 @@ +set PYAEDT_DOC_RUN_EXAMPLES=1 sphinx-build -b html -a . ../../../PyAEDT-docs_dev -j 4 diff --git a/doc/source/index.rst b/doc/source/index.rst index b805fb58c85..b68931e800f 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -6,6 +6,10 @@ PyAEDT documentation |version| `Source Repository `_ | `Issues `_ +.. figure:: _static/logo.png + :align: center + :width: 640px + PyAEDT is a Python client library that interacts directly with the Ansys Electronics Desktop (AEDT) API, enabling straightforward and efficient automation in your workflow. diff --git a/doc/source/logo.svg b/doc/source/logo.svg new file mode 100644 index 00000000000..6ca2fafefa0 --- /dev/null +++ b/doc/source/logo.svg @@ -0,0 +1,102 @@ + + + + + + + + + PyAEDT + + + + + + + + + + + + diff --git a/examples/01-HFSS3DLayout/Dcir_in_3DLayout.py b/examples/01-HFSS3DLayout/Dcir_in_3DLayout.py index 1d50229b835..50937948d9d 100644 --- a/examples/01-HFSS3DLayout/Dcir_in_3DLayout.py +++ b/examples/01-HFSS3DLayout/Dcir_in_3DLayout.py @@ -98,7 +98,7 @@ # Analysis DCIR in AEDT # ~~~~~~~~~~~~~~~~~~~~~ # Launch AEDT and import the configured EDB and analysis DCIR -desktop = pyaedt.Desktop(aedt_version, non_graphical=False, new_desktop_session=True) +desktop = pyaedt.Desktop(aedt_version, non_graphical=False, new_desktop=True) hfss3dl = pyaedt.Hfss3dLayout(local_path) hfss3dl.analyze() hfss3dl.save_project() diff --git a/examples/01-HFSS3DLayout/HFSS3DLayout_Via.py b/examples/01-HFSS3DLayout/HFSS3DLayout_Via.py index 483e06aa081..8bc57f40882 100644 --- a/examples/01-HFSS3DLayout/HFSS3DLayout_Via.py +++ b/examples/01-HFSS3DLayout/HFSS3DLayout_Via.py @@ -32,7 +32,7 @@ # ~~~~~~~~~~~ # Launch AEDT 2023 R2 in graphical mode. -h3d = pyaedt.Hfss3dLayout(specified_version=aedt_version, new_desktop_session=True, non_graphical=non_graphical) +h3d = pyaedt.Hfss3dLayout(version=aedt_version, new_desktop=True, non_graphical=non_graphical) ############################################################################### # Set up variables diff --git a/examples/01-HFSS3DLayout/Hfss3DComponent.py b/examples/01-HFSS3DLayout/Hfss3DComponent.py index daeb0177ae3..ad29c9bc499 100644 --- a/examples/01-HFSS3DLayout/Hfss3DComponent.py +++ b/examples/01-HFSS3DLayout/Hfss3DComponent.py @@ -52,7 +52,7 @@ # ~~~~~~~~~~~ # Launch HFSS application -hfss = pyaedt.Hfss(new_desktop_session=True, specified_version=aedt_version, non_graphical=non_graphical) +hfss = pyaedt.Hfss(new_desktop=True, version=aedt_version, non_graphical=non_graphical) hfss.solution_type = "Terminal" diff --git a/examples/01-Modeling-Setup/Configurations.py b/examples/01-Modeling-Setup/Configurations.py index 34fd7b1eedb..ee397799237 100644 --- a/examples/01-Modeling-Setup/Configurations.py +++ b/examples/01-Modeling-Setup/Configurations.py @@ -55,8 +55,8 @@ project_full_name = pyaedt.downloads.download_icepak(pyaedt.generate_unique_folder_name(folder_name="Graphic_Card")) -ipk = pyaedt.Icepak(projectname=project_full_name, specified_version=aedt_version, - new_desktop_session=True, non_graphical=non_graphical) +ipk = pyaedt.Icepak(project=project_full_name, version=aedt_version, + new_desktop=True, non_graphical=non_graphical) ipk.autosave_disable() ############################################################################### @@ -115,7 +115,7 @@ # ~~~~~~~~~~~~~~ # Create an Icepak project and import the step. -app = pyaedt.Icepak(projectname="new_proj_Ipk") +app = pyaedt.Icepak(project="new_proj_Ipk") app.modeler.import_3d_cad(file_path) ############################################################################### diff --git a/examples/01-Modeling-Setup/HFSS_CoordinateSystem.py b/examples/01-Modeling-Setup/HFSS_CoordinateSystem.py index da40f1b1d3c..bafa2513ab6 100644 --- a/examples/01-Modeling-Setup/HFSS_CoordinateSystem.py +++ b/examples/01-Modeling-Setup/HFSS_CoordinateSystem.py @@ -32,14 +32,14 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Launch AEDT 2023 R2 in graphical mode. -d = pyaedt.launch_desktop(specified_version=aedt_version, non_graphical=non_graphical, new_desktop_session=True) +d = pyaedt.launch_desktop(version=aedt_version, non_graphical=non_graphical, new_desktop=True) ############################################################################### # Insert HFSS design # ~~~~~~~~~~~~~~~~~~ # Insert an HFSS design with the default name. -hfss = pyaedt.Hfss(projectname=pyaedt.generate_unique_project_name(folder_name="CoordSysDemo")) +hfss = pyaedt.Hfss(project=pyaedt.generate_unique_project_name(folder_name="CoordSysDemo")) ############################################################################### # Create coordinate system diff --git a/examples/01-Modeling-Setup/Optimetrics.py b/examples/01-Modeling-Setup/Optimetrics.py index 2e3143e9e94..3ed3a177148 100644 --- a/examples/01-Modeling-Setup/Optimetrics.py +++ b/examples/01-Modeling-Setup/Optimetrics.py @@ -34,7 +34,7 @@ # Initialize the ``Hfss`` object and create two needed design variables, # ``w1`` and ``w2``. -hfss = pyaedt.Hfss(specified_version=aedt_version, new_desktop_session=True, non_graphical=non_graphical) +hfss = pyaedt.Hfss(version=aedt_version, new_desktop=True, non_graphical=non_graphical, solution_type="Modal") hfss["w1"] = "1mm" hfss["w2"] = "100mm" @@ -74,12 +74,12 @@ setup = hfss.create_setup() hfss.create_linear_step_sweep( - setup_name=setup.name, + setup=setup.name, unit="GHz", start_frequency=1, stop_frequency=5, step_size=0.1, - sweep_name="Sweep1", + name="Sweep1", save_fields=True ) diff --git a/examples/01-Modeling-Setup/Polyline_Primitives.py b/examples/01-Modeling-Setup/Polyline_Primitives.py index 3d91003ffd6..869fa62b32f 100644 --- a/examples/01-Modeling-Setup/Polyline_Primitives.py +++ b/examples/01-Modeling-Setup/Polyline_Primitives.py @@ -32,8 +32,8 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~ # Create a :class:`pyaedt.maxwell.Maxwell3d` object and set the unit type to ``"mm"``. -M3D = pyaedt.Maxwell3d(solution_type="Transient", designname="test_polyline_3D", specified_version=aedt_version, - new_desktop_session=True, non_graphical=non_graphical, ) +M3D = pyaedt.Maxwell3d(solution_type="Transient", design="test_polyline_3D", version=aedt_version, + new_desktop=True, non_graphical=non_graphical, ) M3D.modeler.model_units = "mm" prim3D = M3D.modeler diff --git a/examples/02-HFSS/Array.py b/examples/02-HFSS/Array.py index 57db00411d4..6226fc58fc1 100644 --- a/examples/02-HFSS/Array.py +++ b/examples/02-HFSS/Array.py @@ -40,11 +40,11 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Launch HFSS and save the project. project_name = pyaedt.generate_unique_project_name(project_name="array") -hfss = pyaedt.Hfss(projectname=project_name, - specified_version=aedt_version, - designname="Array_Simple", +hfss = pyaedt.Hfss(project=project_name, + version=aedt_version, + design="Array_Simple", non_graphical=non_graphical, - new_desktop_session=True) + new_desktop=True) print("Project name " + project_name) diff --git a/examples/02-HFSS/Create_3d_Component_and_use_it.py b/examples/02-HFSS/Create_3d_Component_and_use_it.py index d04c7c6480d..20e10cfb9d1 100644 --- a/examples/02-HFSS/Create_3d_Component_and_use_it.py +++ b/examples/02-HFSS/Create_3d_Component_and_use_it.py @@ -30,7 +30,7 @@ # PyAEDT can initialize a new session of Electronics Desktop or connect to an existing one. # Once Desktop is connected, a new HFSS session is started and a design is created. -hfss = Hfss(specified_version=aedt_version, new_desktop_session=True, close_on_exit=True) +hfss = Hfss(version=aedt_version, new_desktop=True, close_on_exit=True) ########################################################## # Variables @@ -100,7 +100,7 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~ # PyAEDT allows to control multiple projects, design and solution type at the same time. -hfss2 = Hfss(projectname="new_project", designname="new_design") +hfss2 = Hfss(project="new_project", design="new_design") ########################################################## # Insert of 3d component diff --git a/examples/02-HFSS/Flex_CPWG.py b/examples/02-HFSS/Flex_CPWG.py index 90b5e26d3a8..b69b0267d9b 100644 --- a/examples/02-HFSS/Flex_CPWG.py +++ b/examples/02-HFSS/Flex_CPWG.py @@ -33,9 +33,9 @@ # ~~~~~~~~~~~ # Launch AEDT 2023 R2 in graphical mode. -hfss = pyaedt.Hfss(specified_version=aedt_version, +hfss = pyaedt.Hfss(version=aedt_version, solution_type="DrivenTerminal", - new_desktop_session=True, + new_desktop=True, non_graphical=non_graphical) hfss.change_material_override(True) hfss.change_automatically_use_causal_materials(True) diff --git a/examples/02-HFSS/HFSS_Choke.py b/examples/02-HFSS/HFSS_Choke.py index cfdc790d040..90d0699617b 100644 --- a/examples/02-HFSS/HFSS_Choke.py +++ b/examples/02-HFSS/HFSS_Choke.py @@ -43,10 +43,10 @@ # ~~~~~~~~~~~ # Launches HFSS 2023 R2 in graphical mode. -hfss = pyaedt.Hfss(projectname=project_name, - specified_version=aedt_version, +hfss = pyaedt.Hfss(project=project_name, + version=aedt_version, non_graphical=non_graphical, - new_desktop_session=True, + new_desktop=True, solution_type="Terminal") ############################################################################### diff --git a/examples/02-HFSS/HFSS_Dipole.py b/examples/02-HFSS/HFSS_Dipole.py index a1e66b8aad1..d6585e37ae8 100644 --- a/examples/02-HFSS/HFSS_Dipole.py +++ b/examples/02-HFSS/HFSS_Dipole.py @@ -34,14 +34,14 @@ # ~~~~~~~~~~~ # Launch AEDT 2023 R2 in graphical mode. -d = pyaedt.launch_desktop(aedt_version, non_graphical=non_graphical, new_desktop_session=True) +d = pyaedt.launch_desktop(aedt_version, non_graphical=non_graphical, new_desktop=True) ############################################################################### # Launch HFSS # ~~~~~~~~~~~ # Launch HFSS 2023 R2 in graphical mode. -hfss = pyaedt.Hfss(projectname=project_name, solution_type="Modal") +hfss = pyaedt.Hfss(project=project_name, solution_type="Modal") ############################################################################### # Define variable @@ -153,7 +153,7 @@ # method with an arbitrary name. hfss["post_x"] = 2 -hfss.variable_manager.set_variable(variable_name="y_post", expression=1, postprocessing=True) +hfss.variable_manager.set_variable(name="y_post", expression=1, is_post_processing=True) hfss.modeler.create_coordinate_system(origin=["post_x", "y_post", 0], name="CS_Post") hfss.insert_infinite_sphere(custom_coordinate_system="CS_Post", name="Sphere_Custom") diff --git a/examples/02-HFSS/HFSS_FSS_unitcell.py b/examples/02-HFSS/HFSS_FSS_unitcell.py index 182ea23c047..6c0768dc67f 100644 --- a/examples/02-HFSS/HFSS_FSS_unitcell.py +++ b/examples/02-HFSS/HFSS_FSS_unitcell.py @@ -34,14 +34,14 @@ # ~~~~~~~~~~~ # Launch AEDT 2023 R2 in graphical mode. -d = pyaedt.launch_desktop(aedt_version, non_graphical=non_graphical, new_desktop_session=True) +d = pyaedt.launch_desktop(aedt_version, non_graphical=non_graphical, new_desktop=True) ############################################################################### # Launch HFSS # ~~~~~~~~~~~ # Launch HFSS 2023 R2 in graphical mode. -hfss = pyaedt.Hfss(projectname=project_name, solution_type="Modal") +hfss = pyaedt.Hfss(project=project_name, solution_type="Modal") ############################################################################### # Define variable diff --git a/examples/02-HFSS/HFSS_Spiral.py b/examples/02-HFSS/HFSS_Spiral.py index 4ba80a21c52..37a591f0edc 100644 --- a/examples/02-HFSS/HFSS_Spiral.py +++ b/examples/02-HFSS/HFSS_Spiral.py @@ -35,8 +35,8 @@ # Launch HFSS 2023 R2 in non-graphical mode and change the # units to microns. -hfss = pyaedt.Hfss(specified_version=aedt_version, non_graphical=non_graphical, designname="A1", - new_desktop_session=True) +hfss = pyaedt.Hfss(version=aedt_version, non_graphical=non_graphical, design="A1", + new_desktop=True) hfss.solution_type = "Modal" hfss.modeler.model_units = "um" p = hfss.modeler diff --git a/examples/02-HFSS/HFSS_eigenmode.py b/examples/02-HFSS/HFSS_eigenmode.py index c7de9106ab5..a770bd22d62 100644 --- a/examples/02-HFSS/HFSS_eigenmode.py +++ b/examples/02-HFSS/HFSS_eigenmode.py @@ -57,14 +57,14 @@ # ~~~~~~~~~~~ # Launch AEDT 2023 R2 in graphical mode. -d = pyaedt.launch_desktop(aedt_version, non_graphical=non_graphical, new_desktop_session=True) +d = pyaedt.launch_desktop(aedt_version, non_graphical=non_graphical, new_desktop=True) ############################################################################### # Launch HFSS # ~~~~~~~~~~~ # Launch HFSS 2023 R2 in graphical mode. -hfss = pyaedt.Hfss(projectname=project_path, non_graphical=non_graphical) +hfss = pyaedt.Hfss(project=project_path, non_graphical=non_graphical) ############################################################################### # Input parameters for eigenmode solver diff --git a/examples/02-HFSS/Probe_Fed_Patch.py b/examples/02-HFSS/Probe_Fed_Patch.py index 626620508bf..1409fe0e4f0 100644 --- a/examples/02-HFSS/Probe_Fed_Patch.py +++ b/examples/02-HFSS/Probe_Fed_Patch.py @@ -60,12 +60,12 @@ # ----------- # -hfss = pyaedt.Hfss(projectname=proj_name, +hfss = pyaedt.Hfss(project=proj_name, solution_type="Terminal", - designname="patch", + design="patch", non_graphical=non_graphical, - new_desktop_session=True, - specified_version=aedt_version) + new_desktop=True, + version=aedt_version) hfss.modeler.model_units = length_units diff --git a/examples/02-HFSS/Waveguide_Filter.py b/examples/02-HFSS/Waveguide_Filter.py index 163f893c281..092f17f9e0c 100644 --- a/examples/02-HFSS/Waveguide_Filter.py +++ b/examples/02-HFSS/Waveguide_Filter.py @@ -61,11 +61,11 @@ project_name = os.path.join(project_folder, general_methods.generate_unique_name("wgf", n=2)) # Instantiate the HFSS application -hfss = pyaedt.Hfss(projectname=project_name + '.aedt', - specified_version=aedt_version, - designname="filter", +hfss = pyaedt.Hfss(project=project_name + '.aedt', + version=aedt_version, + design="filter", non_graphical=non_graphical, - new_desktop_session=True, + new_desktop=True, close_on_exit=True, solution_type="Modal") diff --git a/examples/02-SBR+/SBR_City_Import.py b/examples/02-SBR+/SBR_City_Import.py index 2b727fea10c..818733d24d0 100644 --- a/examples/02-SBR+/SBR_City_Import.py +++ b/examples/02-SBR+/SBR_City_Import.py @@ -35,10 +35,10 @@ # Each design is connected to a different object. app = Hfss( - designname="Ansys", + design="Ansys", solution_type="SBR+", - specified_version=aedt_version, - new_desktop_session=True, + version=aedt_version, + new_desktop=True, non_graphical=non_graphical ) diff --git a/examples/02-SBR+/SBR_Doppler_Example.py b/examples/02-SBR+/SBR_Doppler_Example.py index 2e92b5f1cce..f5e7a68a7b0 100644 --- a/examples/02-SBR+/SBR_Doppler_Example.py +++ b/examples/02-SBR+/SBR_Doppler_Example.py @@ -45,10 +45,10 @@ # Instantiate the application. app = pyaedt.Hfss( - specified_version=aedt_version, + version=aedt_version, solution_type="SBR+", - new_desktop_session=True, - projectname=project_name, + new_desktop=True, + project=project_name, close_on_exit=True, non_graphical=non_graphical ) diff --git a/examples/02-SBR+/SBR_Example.py b/examples/02-SBR+/SBR_Example.py index ca5e2ed1c13..41e6f8a16a1 100644 --- a/examples/02-SBR+/SBR_Example.py +++ b/examples/02-SBR+/SBR_Example.py @@ -37,17 +37,17 @@ # a different object. target = pyaedt.Hfss( - projectname=project_full_name, - designname="Cassegrain_", + project=project_full_name, + design="Cassegrain_", solution_type="SBR+", - specified_version=aedt_version, - new_desktop_session=True, + version=aedt_version, + new_desktop=True, non_graphical=non_graphical ) -source = pyaedt.Hfss(projectname=target.project_name, - designname="feeder", - specified_version=aedt_version, +source = pyaedt.Hfss(project=target.project_name, + design="feeder", + version=aedt_version, ) ############################################################################### diff --git a/examples/02-SBR+/SBR_Time_Plot.py b/examples/02-SBR+/SBR_Time_Plot.py index 6384ef137ff..94d6c625e0f 100644 --- a/examples/02-SBR+/SBR_Time_Plot.py +++ b/examples/02-SBR+/SBR_Time_Plot.py @@ -35,7 +35,7 @@ project_file = downloads.download_sbr_time() -hfss = Hfss(projectname=project_file, specified_version=aedt_version, non_graphical=non_graphical, new_desktop_session=True) +hfss = Hfss(project=project_file, version=aedt_version, non_graphical=non_graphical, new_desktop=True) hfss.analyze() diff --git a/examples/03-Maxwell/Maxwell2D_DCConduction.py b/examples/03-Maxwell/Maxwell2D_DCConduction.py index 2b9828647ae..7a693c8f97f 100644 --- a/examples/03-Maxwell/Maxwell2D_DCConduction.py +++ b/examples/03-Maxwell/Maxwell2D_DCConduction.py @@ -26,12 +26,12 @@ # ``Maxwell2d`` class named ``m2d``. m2d = pyaedt.Maxwell2d( - specified_version=aedt_version, - new_desktop_session=True, + version=aedt_version, + new_desktop=True, close_on_exit=True, solution_type="DCConduction", - projectname="M2D_DC_Conduction", - designname="Ansys_resistor" + project="M2D_DC_Conduction", + design="Ansys_resistor" ) ########################################################## diff --git a/examples/03-Maxwell/Maxwell2D_Electrostatic.py b/examples/03-Maxwell/Maxwell2D_Electrostatic.py index 3f044ffd9bc..f9866f34186 100644 --- a/examples/03-Maxwell/Maxwell2D_Electrostatic.py +++ b/examples/03-Maxwell/Maxwell2D_Electrostatic.py @@ -66,11 +66,11 @@ # ~~~~~~~~~~~~~~~~~ # Launch Maxwell 2D and save the project. -M2D = pyaedt.Maxwell2d(projectname=project_name, - specified_version=aedt_version, - designname=design_name, +M2D = pyaedt.Maxwell2d(project=project_name, + version=aedt_version, + design=design_name, solution_type=solver, - new_desktop_session=True, + new_desktop=True, non_graphical=non_graphical ) diff --git a/examples/03-Maxwell/Maxwell2D_PMSynchronousMotor.py b/examples/03-Maxwell/Maxwell2D_PMSynchronousMotor.py index 4435be7cc96..4d0d80e04b9 100644 --- a/examples/03-Maxwell/Maxwell2D_PMSynchronousMotor.py +++ b/examples/03-Maxwell/Maxwell2D_PMSynchronousMotor.py @@ -123,11 +123,11 @@ # ~~~~~~~~~~~~~~~~~ # Launch Maxwell 2D and save the project. -M2D = pyaedt.Maxwell2d(projectname=project_name, - specified_version=aedt_version, - designname=design_name, +M2D = pyaedt.Maxwell2d(project=project_name, + version=aedt_version, + design=design_name, solution_type=solver, - new_desktop_session=True, + new_desktop=True, non_graphical=non_graphical ) diff --git a/examples/03-Maxwell/Maxwell2D_Transformer_LL.py b/examples/03-Maxwell/Maxwell2D_Transformer_LL.py index af134dc8802..7137bcee552 100644 --- a/examples/03-Maxwell/Maxwell2D_Transformer_LL.py +++ b/examples/03-Maxwell/Maxwell2D_Transformer_LL.py @@ -30,10 +30,10 @@ solver = "MagnetostaticXY" desktop_version = "2024.1" -m2d = Maxwell2d(specified_version=desktop_version, - new_desktop_session=False, - designname=design_name, - projectname=project_name, +m2d = Maxwell2d(version=desktop_version, + new_desktop=False, + design=design_name, + project=project_name, solution_type=solver, non_graphical=non_graphical) @@ -86,12 +86,12 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Define design variables from the created dictionaries. -m2d.variable_manager.set_variable(variable_name="Dimensions") +m2d.variable_manager.set_variable(name="Dimensions") for k, v in dimensions.items(): m2d[k] = v -m2d.variable_manager.set_variable(variable_name="Windings") +m2d.variable_manager.set_variable(name="Windings") for k, v in specifications.items(): m2d[k] = v diff --git a/examples/03-Maxwell/Maxwell2D_Transient.py b/examples/03-Maxwell/Maxwell2D_Transient.py index d92c6f87247..f9b14ceff37 100644 --- a/examples/03-Maxwell/Maxwell2D_Transient.py +++ b/examples/03-Maxwell/Maxwell2D_Transient.py @@ -54,8 +54,8 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Insert a Maxwell 2D design and save the project. -maxwell_2d = pyaedt.Maxwell2d(solution_type="TransientXY", specified_version=aedt_version, non_graphical=non_graphical, - new_desktop_session=True, projectname=pyaedt.generate_unique_project_name()) +maxwell_2d = pyaedt.Maxwell2d(solution_type="TransientXY", version=aedt_version, non_graphical=non_graphical, + new_desktop=True, project=pyaedt.generate_unique_project_name()) ############################################################################### # Create rectangle and duplicate it diff --git a/examples/03-Maxwell/Maxwell3DTeam7.py b/examples/03-Maxwell/Maxwell3DTeam7.py index 436ca8f3382..68fccd5ca7e 100644 --- a/examples/03-Maxwell/Maxwell3DTeam7.py +++ b/examples/03-Maxwell/Maxwell3DTeam7.py @@ -50,12 +50,12 @@ solver = "EddyCurrent" m3d = Maxwell3d( - projectname=project_name, - designname=design_name, + project=project_name, + design=design_name, solution_type=solver, - specified_version=aedt_version, + version=aedt_version, non_graphical=non_graphical, - new_desktop_session=True + new_desktop=True ) m3d.modeler.model_units = "mm" diff --git a/examples/03-Maxwell/Maxwell3D_Choke.py b/examples/03-Maxwell/Maxwell3D_Choke.py index e6f59c608a0..8b19f350943 100644 --- a/examples/03-Maxwell/Maxwell3D_Choke.py +++ b/examples/03-Maxwell/Maxwell3D_Choke.py @@ -40,11 +40,11 @@ # ~~~~~~~~~~~~~~~~ # Launch Maxwell 3D 2023 R2 in graphical mode. -m3d = pyaedt.Maxwell3d(projectname=pyaedt.generate_unique_project_name(), +m3d = pyaedt.Maxwell3d(project=pyaedt.generate_unique_project_name(), solution_type="EddyCurrent", - specified_version=aedt_version, + version=aedt_version, non_graphical=non_graphical, - new_desktop_session=True + new_desktop=True ) ############################################################################### diff --git a/examples/03-Maxwell/Maxwell3D_Segmentation.py b/examples/03-Maxwell/Maxwell3D_Segmentation.py index 49956cd9f90..fa38433ff52 100644 --- a/examples/03-Maxwell/Maxwell3D_Segmentation.py +++ b/examples/03-Maxwell/Maxwell3D_Segmentation.py @@ -48,9 +48,9 @@ # ~~~~~~~~~~~~~~~~~ # Launch Maxwell 3D. -m3d = Maxwell3d(projectname=aedt_file, - specified_version=aedt_version, - new_desktop_session=True, +m3d = Maxwell3d(project=aedt_file, + version=aedt_version, + new_desktop=True, non_graphical=non_graphical) ################################################################################## diff --git a/examples/03-Maxwell/Maxwell3D_Team3_bath_plate.py b/examples/03-Maxwell/Maxwell3D_Team3_bath_plate.py index 67cc322a43d..1b1d485e9cc 100644 --- a/examples/03-Maxwell/Maxwell3D_Team3_bath_plate.py +++ b/examples/03-Maxwell/Maxwell3D_Team3_bath_plate.py @@ -43,17 +43,17 @@ # the solver, and the version. The following code also creates an instance of the # ``Maxwell3d`` class named ``M3D``. -project_name = "COMPUMAG" +project_name = os.path.join(temp_dir.name, "COMPUMAG.aedt") design_name = "TEAM 3 Bath Plate" solver = "EddyCurrent" m3d = pyaedt.Maxwell3d( - projectname=project_name, - designname=design_name, + project=project_name, + design=design_name, solution_type=solver, - specified_version=aedt_version, + version=aedt_version, non_graphical=non_graphical, - new_desktop_session=True, + new_desktop=True, ) m3d.modeler.model_units = "mm" @@ -235,5 +235,6 @@ # ~~~~~~~~~~~~ # Release AEDT from the script engine, leaving both AEDT and the project open. -m3d.release_desktop(False, False) +m3d.release_desktop() + temp_dir.cleanup() diff --git a/examples/03-Maxwell/Maxwell_Control_Program.py b/examples/03-Maxwell/Maxwell_Control_Program.py index 035f1f8db69..cace045c035 100644 --- a/examples/03-Maxwell/Maxwell_Control_Program.py +++ b/examples/03-Maxwell/Maxwell_Control_Program.py @@ -13,7 +13,7 @@ # Perform required imports. from pyaedt import downloads -from pyaedt import generate_unique_folder_name +from pyaedt.generic.general_methods import generate_unique_folder_name from pyaedt import Maxwell2d ########################################################## @@ -44,9 +44,9 @@ # ~~~~~~~~~~~~~~~~~ # Launch Maxwell 2D. -m2d = Maxwell2d(projectname=aedt_file, - specified_version=aedt_version, - new_desktop_session=True, +m2d = Maxwell2d(project=aedt_file, + version=aedt_version, + new_desktop=True, non_graphical=non_graphical) ################################################################################## diff --git a/examples/03-Maxwell/Maxwell_Magnet.py b/examples/03-Maxwell/Maxwell_Magnet.py index 41882c8bb3f..1dc2fdd1fe9 100644 --- a/examples/03-Maxwell/Maxwell_Magnet.py +++ b/examples/03-Maxwell/Maxwell_Magnet.py @@ -41,9 +41,9 @@ # ~~~~~~~~~~~ # Launch AEDT in graphical mode. -m3d = Maxwell3d(projectname=generate_unique_project_name(), - specified_version=aedt_version, - new_desktop_session=True, +m3d = Maxwell3d(project=generate_unique_project_name(), + version=aedt_version, + new_desktop=True, non_graphical=non_graphical) ############################################################################### diff --git a/examples/03-Maxwell/Maxwell_Transformer_Coreloss.py b/examples/03-Maxwell/Maxwell_Transformer_Coreloss.py index bc975659219..768f4c33275 100644 --- a/examples/03-Maxwell/Maxwell_Transformer_Coreloss.py +++ b/examples/03-Maxwell/Maxwell_Transformer_Coreloss.py @@ -10,7 +10,7 @@ # Perform required imports. from pyaedt import downloads -from pyaedt import generate_unique_folder_name +from pyaedt.generic.general_methods import generate_unique_folder_name from pyaedt import Maxwell3d from pyaedt.generic.constants import unit_converter from pyaedt.generic.general_methods import read_csv_pandas @@ -60,10 +60,10 @@ # ~~~~~~~~~~~ # Launch AEDT in graphical mode. -m3d = Maxwell3d(projectname=aedt_file, - designname="02_3D eddycurrent_CmXY_for_thermal", - specified_version=aedt_version, - new_desktop_session=True, +m3d = Maxwell3d(project=aedt_file, + design="02_3D eddycurrent_CmXY_for_thermal", + version=aedt_version, + new_desktop=True, non_graphical=False) ############################################################################### diff --git a/examples/04-Icepak/Icepak_3DComponents_Example.py b/examples/04-Icepak/Icepak_3DComponents_Example.py index 7a9bec5cdf0..fecf8aec461 100644 --- a/examples/04-Icepak/Icepak_3DComponents_Example.py +++ b/examples/04-Icepak/Icepak_3DComponents_Example.py @@ -38,11 +38,11 @@ # ~~~~~~~~~~~~~~~ # Open a new project in non-graphical mode. -ipk = Icepak(projectname=os.path.join(temp_folder, "Heatsink.aedt"), - specified_version=aedt_version, +ipk = Icepak(project=os.path.join(temp_folder, "Heatsink.aedt"), + version=aedt_version, non_graphical=non_graphical, close_on_exit=True, - new_desktop_session=True) + new_desktop=True) # Remove air region created by default because it is not needed as the heatsink will be exported as a 3DComponent. @@ -88,30 +88,20 @@ component_name="Heatsink", auxiliary_dict=True ) -ipk.close_project(save_project=False) +ipk.close_project(save=False) ############################################################################### # Create QFP # ~~~~~~~~~~ # Download and open a project containing a QPF. -ipk = Icepak(projectname=qfp_temp_name) +ipk = Icepak(project=qfp_temp_name) ipk.plot(show=False, output_file=os.path.join(temp_folder, "QFP2.jpg")) # Create dataset for power dissipation. x_datalist = [45, 53, 60, 70] y_datalist = [0.5, 3, 6, 9] -ipk.create_dataset( - "PowerDissipationDataset", - x_datalist, - y_datalist, - zlist=None, - vlist=None, - is_project_dataset=False, - xunit="cel", - yunit="W", - zunit="", - vunit="", -) +ipk.create_dataset("PowerDissipationDataset", x_datalist, y_datalist, z=None, v=None, is_project_dataset=False, + x_unit="cel", y_unit="W", v_unit="") # Assign source power condition to the die. ipk.create_source_power( @@ -147,8 +137,8 @@ # Create electronic package # ~~~~~~~~~~~~~~~~~~~~~~~~~ # Download and open a project containing the electronic package. -ipk = Icepak(projectname=package_temp_name, - specified_version=aedt_version, +ipk = Icepak(project=package_temp_name, + version=aedt_version, non_graphical=non_graphical) ipk.plot(show=False, output_file=os.path.join(temp_folder, "electronic_package_missing_obj.jpg")) diff --git a/examples/04-Icepak/Icepak_CSV_Import.py b/examples/04-Icepak/Icepak_CSV_Import.py index d4d0dd11980..9fe505d335f 100644 --- a/examples/04-Icepak/Icepak_CSV_Import.py +++ b/examples/04-Icepak/Icepak_CSV_Import.py @@ -39,9 +39,9 @@ temp_folder = pyaedt.generate_unique_folder_name() -ipk = pyaedt.Icepak(projectname=os.path.join(temp_folder, "Icepak_CSV_Import.aedt"), - specified_version=aedt_version, - new_desktop_session=True, +ipk = pyaedt.Icepak(project=os.path.join(temp_folder, "Icepak_CSV_Import.aedt"), + version=aedt_version, + new_desktop=True, non_graphical=non_graphical ) diff --git a/examples/04-Icepak/Icepak_ECAD_Import.py b/examples/04-Icepak/Icepak_ECAD_Import.py index 0fb554991e3..2e4caa2dcde 100644 --- a/examples/04-Icepak/Icepak_ECAD_Import.py +++ b/examples/04-Icepak/Icepak_ECAD_Import.py @@ -43,9 +43,9 @@ temp_folder = pyaedt.generate_unique_folder_name() -ipk = pyaedt.Icepak(projectname=os.path.join(temp_folder, "Icepak_ECAD_Import.aedt"), - specified_version=aedt_version, - new_desktop_session=True, +ipk = pyaedt.Icepak(project=os.path.join(temp_folder, "Icepak_ECAD_Import.aedt"), + version=aedt_version, + new_desktop=True, non_graphical=non_graphical ) @@ -94,7 +94,7 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ipk.modeler.fit_all() # scales to fit all objects in AEDT -ipk.save_project() # saves the project +ipk.save_project() # saves the project ############################################################################### # Add an HFSS 3D Layout design with the layout information of the PCB @@ -106,7 +106,7 @@ #edb_full_path = os.path.join(os.getcwd(), Layout_name+'.aedb\edb.def') # path to the EDB file hfss3dLO.import_edb(def_path) # importing the EDB file -hfss3dLO.save_project() # save the new project so files are stored in the path +hfss3dLO.save_project() # save the new project so files are stored in the path ipk.delete_design(name='PCB_temp', fallback_design=None) # deleting the dummy layout from the original project diff --git a/examples/04-Icepak/Icepak_Example.py b/examples/04-Icepak/Icepak_Example.py index 1d728543ab9..ec0415c16e3 100644 --- a/examples/04-Icepak/Icepak_Example.py +++ b/examples/04-Icepak/Icepak_Example.py @@ -35,9 +35,9 @@ temp_folder = pyaedt.generate_unique_folder_name() project_temp_name = pyaedt.downloads.download_icepak(temp_folder) -ipk = pyaedt.Icepak(projectname=project_temp_name, - specified_version=aedt_version, - new_desktop_session=True, +ipk = pyaedt.Icepak(project=project_temp_name, + version=aedt_version, + new_desktop=True, non_graphical=non_graphical ) diff --git a/examples/04-Icepak/Sherlock_Example.py b/examples/04-Icepak/Sherlock_Example.py index cfeeade0a1a..ddd4b250a26 100644 --- a/examples/04-Icepak/Sherlock_Example.py +++ b/examples/04-Icepak/Sherlock_Example.py @@ -52,7 +52,7 @@ # ~~~~~~~~~~~ # Launch AEDT 2023 R2 in graphical mode. -d = pyaedt.launch_desktop(specified_version=aedt_version, non_graphical=non_graphical, new_desktop_session=True) +d = pyaedt.launch_desktop(version=aedt_version, non_graphical=non_graphical, new_desktop=True) start = time.time() material_list = os.path.join(input_dir, material_name) @@ -106,7 +106,7 @@ # ~~~~~~~~~~~~~ # Save the CAD file and refresh the properties from the parsing of the AEDT file. -ipk.save_project(refresh_obj_ids_after_save=True) +ipk.save_project(refresh_ids=True) ############################################################################### # Plot model diff --git a/examples/05-Q3D/Q2D_Armoured_Cable.py b/examples/05-Q3D/Q2D_Armoured_Cable.py index 00d431a755b..6a933a6ff47 100644 --- a/examples/05-Q3D/Q2D_Armoured_Cable.py +++ b/examples/05-Q3D/Q2D_Armoured_Cable.py @@ -90,7 +90,7 @@ setup_name = "MySetupAuto" sweep_name = "sweep1" tb_design_name = 'CableSystem' -q2d = pyaedt.Q2d(projectname=project_name, designname=q2d_design_name, specified_version=aedt_version) +q2d = pyaedt.Q2d(project=project_name, design=q2d_design_name, version=aedt_version) ########################################################## # Define variables from dictionaries @@ -238,7 +238,7 @@ # Add a Simplorer/Twin Builder design and the Q3D dynamic component # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -tb = pyaedt.TwinBuilder(designname=tb_design_name) +tb = pyaedt.TwinBuilder(design=tb_design_name) ########################################################## # Add a Q3D dynamic component diff --git a/examples/05-Q3D/Q2D_Example_CPWG.py b/examples/05-Q3D/Q2D_Example_CPWG.py index 5afd3abcb71..ce244f1d304 100644 --- a/examples/05-Q3D/Q2D_Example_CPWG.py +++ b/examples/05-Q3D/Q2D_Example_CPWG.py @@ -33,11 +33,11 @@ # Launch AEDT 2023 R2 in graphical mode and launch 2D Extractor. This example # uses SI units. -q = pyaedt.Q2d(specified_version=aedt_version, +q = pyaedt.Q2d(version=aedt_version, non_graphical=non_graphical, - new_desktop_session=True, - projectname=pyaedt.generate_unique_name("pyaedt_q2d_example"), - designname="coplanar_waveguide") + new_desktop=True, + project=pyaedt.generate_unique_name("pyaedt_q2d_example"), + design="coplanar_waveguide") ############################################################################### # Define variables diff --git a/examples/05-Q3D/Q2D_Example_Stripline.py b/examples/05-Q3D/Q2D_Example_Stripline.py index d76b2f7a974..9b5abf112a4 100644 --- a/examples/05-Q3D/Q2D_Example_Stripline.py +++ b/examples/05-Q3D/Q2D_Example_Stripline.py @@ -34,11 +34,11 @@ # Launch AEDT 2023 R2 in graphical mode and launch 2D Extractor. This example # uses SI units. -q = pyaedt.Q2d(projectname=project_path, - designname="differential_stripline", - specified_version=aedt_version, +q = pyaedt.Q2d(project=project_path, + design="differential_stripline", + version=aedt_version, non_graphical=non_graphical, - new_desktop_session=True + new_desktop=True ) ############################################################################### diff --git a/examples/05-Q3D/Q3D_DC_IR.py b/examples/05-Q3D/Q3D_DC_IR.py index e0ccdcd97c7..88775d31728 100644 --- a/examples/05-Q3D/Q3D_DC_IR.py +++ b/examples/05-Q3D/Q3D_DC_IR.py @@ -93,7 +93,7 @@ edb.save_edb_as(output_edb) edb.close_edb() -h3d = pyaedt.Hfss3dLayout(output_edb, specified_version=aedt_version, non_graphical=False, new_desktop_session=True) +h3d = pyaedt.Hfss3dLayout(output_edb, version=aedt_version, non_graphical=False, new_desktop=True) ############################################################################### # Export to Q3D diff --git a/examples/05-Q3D/Q3D_Example.py b/examples/05-Q3D/Q3D_Example.py index cf3a870abcb..14b4fc13f4b 100644 --- a/examples/05-Q3D/Q3D_Example.py +++ b/examples/05-Q3D/Q3D_Example.py @@ -44,10 +44,10 @@ # Launch AEDT 2023 R2 in graphical mode and launch Q3D Extractor. # This example uses SI units. -q = pyaedt.Q3d(projectname=pyaedt.generate_unique_project_name(), - specified_version=aedt_version, +q = pyaedt.Q3d(project=pyaedt.generate_unique_project_name(), + version=aedt_version, non_graphical=non_graphical, - new_desktop_session=True) + new_desktop=True) ############################################################################### # Create primitives diff --git a/examples/05-Q3D/Q3D_from_EDB.py b/examples/05-Q3D/Q3D_from_EDB.py index 8124187ba76..2b5cbc53f9c 100644 --- a/examples/05-Q3D/Q3D_from_EDB.py +++ b/examples/05-Q3D/Q3D_from_EDB.py @@ -78,7 +78,7 @@ edb.save_edb() edb.close_edb() -h3d = pyaedt.Hfss3dLayout(output_edb, specified_version=aedt_version, non_graphical=True, new_desktop_session=True) +h3d = pyaedt.Hfss3dLayout(output_edb, version=aedt_version, non_graphical=True, new_desktop=True) ############################################################################### # Export to Q3D diff --git a/examples/06-Multiphysics/Hfss_Icepak_Coupling.py b/examples/06-Multiphysics/Hfss_Icepak_Coupling.py index 272bcb130d3..0e9e22ace4e 100644 --- a/examples/06-Multiphysics/Hfss_Icepak_Coupling.py +++ b/examples/06-Multiphysics/Hfss_Icepak_Coupling.py @@ -48,10 +48,10 @@ # Launch AEDT and initialize HFSS. If there is an active HFSS design, the ``aedtapp`` # object is linked to it. Otherwise, a new design is created. -aedtapp = pyaedt.Hfss(projectname=project_file, - specified_version=aedt_version, +aedtapp = pyaedt.Hfss(project=project_file, + version=aedt_version, non_graphical=non_graphical, - new_desktop_session=NewThread + new_desktop=NewThread ) ############################################################################### diff --git a/examples/06-Multiphysics/Hfss_Mechanical.py b/examples/06-Multiphysics/Hfss_Mechanical.py index 5972750c9d9..e2f4912ea52 100644 --- a/examples/06-Multiphysics/Hfss_Mechanical.py +++ b/examples/06-Multiphysics/Hfss_Mechanical.py @@ -40,8 +40,8 @@ # ~~~~~~~~~~ # Start HFSS and initialize the PyAEDT object. -hfss = pyaedt.Hfss(projectname=project_temp_name, specified_version=aedt_version, non_graphical=non_graphical, - new_desktop_session=True) +hfss = pyaedt.Hfss(project=project_temp_name, version=aedt_version, non_graphical=non_graphical, + new_desktop=True) pin_names = hfss.excitations hfss.change_material_override(True) diff --git a/examples/06-Multiphysics/MRI.py b/examples/06-Multiphysics/MRI.py index 75f5c496eaa..be712f8794f 100644 --- a/examples/06-Multiphysics/MRI.py +++ b/examples/06-Multiphysics/MRI.py @@ -47,8 +47,8 @@ # Material properties defined in this project already contain #electrical and thermal properties. project_path = downloads.download_file(directory="mri") -hfss = Hfss(os.path.join(project_path, "background_SAR.aedt"), specified_version=aedt_version, non_graphical=non_graphical, - new_desktop_session=True) +hfss = Hfss(os.path.join(project_path, "background_SAR.aedt"), version=aedt_version, non_graphical=non_graphical, + new_desktop=True) ############################################################################### # Insert 3D component @@ -152,7 +152,7 @@ # Initialize a new Mechanical Transient Thermal analysis. # Mechanical Transient Thermal is available in AEDT from 2023 R2 as a Beta feature. -mech = Mechanical(solution_type="Transient Thermal", specified_version=aedt_version) +mech = Mechanical(solution_type="Transient Thermal", version=aedt_version) ############################################################################### # Copy geometries @@ -220,7 +220,7 @@ # ~~~~~~~~~~~~~~~~~~ # Initialize a new Icepak Transient Thermal analysis. -ipk = Icepak(solution_type="Transient", specified_version=aedt_version) +ipk = Icepak(solution_type="Transient", version=aedt_version) ipk.design_solutions.problem_type = "TemperatureOnly" ############################################################################### diff --git a/examples/06-Multiphysics/Maxwell3D_Icepak_2Way_Coupling.py b/examples/06-Multiphysics/Maxwell3D_Icepak_2Way_Coupling.py index aea6e29d8ba..1a6eb9a69e9 100644 --- a/examples/06-Multiphysics/Maxwell3D_Icepak_2Way_Coupling.py +++ b/examples/06-Multiphysics/Maxwell3D_Icepak_2Way_Coupling.py @@ -41,10 +41,10 @@ icepak_design_name = "2 Icepak" m3d = pyaedt.Maxwell3d( - projectname=project_name, - designname=maxwell_design_name, + project=project_name, + design=maxwell_design_name, solution_type="EddyCurrent", - specified_version=aedt_version, + version=aedt_version, non_graphical=non_graphical, ) @@ -175,8 +175,8 @@ # ~~~~~~~~~~~~~ # Insert Icepak design, copy solid objects from Maxwell, and modify region dimensions. -ipk = pyaedt.Icepak(designname=icepak_design_name) -ipk.copy_solid_bodies_from(m3d, pec=False) +ipk = pyaedt.Icepak(design=icepak_design_name) +ipk.copy_solid_bodies_from(m3d, no_pec=False) # Set domain dimensions suitable for natural convection using the diameter of the coil ipk.modeler["Region"].delete() diff --git a/examples/07-Circuit/Circuit_AMI.py b/examples/07-Circuit/Circuit_AMI.py index f90e8e5b0b3..df422dafdce 100644 --- a/examples/07-Circuit/Circuit_AMI.py +++ b/examples/07-Circuit/Circuit_AMI.py @@ -47,8 +47,8 @@ # and starts the specified version in the specified mode. pyaedt.settings.enable_pandas_output = True -cir = pyaedt.Circuit(projectname=os.path.join(project_path), non_graphical=non_graphical, - specified_version=aedt_version, new_desktop_session=NewThread) +cir = pyaedt.Circuit(project=os.path.join(project_path), non_graphical=non_graphical, + version=aedt_version, new_desktop=NewThread) ############################################################################### # Solve AMI setup diff --git a/examples/07-Circuit/Circuit_Example.py b/examples/07-Circuit/Circuit_Example.py index fff442bf276..fa0e686bf66 100644 --- a/examples/07-Circuit/Circuit_Example.py +++ b/examples/07-Circuit/Circuit_Example.py @@ -38,7 +38,7 @@ # starts the specified version in the specified mode. desktop = pyaedt.launch_desktop(aedt_version, non_graphical, new_thread) -aedt_app = pyaedt.Circuit(projectname=pyaedt.generate_unique_project_name()) +aedt_app = pyaedt.Circuit(project=pyaedt.generate_unique_project_name()) aedt_app.modeler.schematic.schematic_units = "mil" ############################################################################### # Create circuit setup diff --git a/examples/07-Circuit/Circuit_Siwave_Multizones.py b/examples/07-Circuit/Circuit_Siwave_Multizones.py index 28a61516a3b..9b91153b6ab 100644 --- a/examples/07-Circuit/Circuit_Siwave_Multizones.py +++ b/examples/07-Circuit/Circuit_Siwave_Multizones.py @@ -69,7 +69,7 @@ # ~~~~~~~ # Create circuit design, import all sub-project as EM model and connect all corresponding pins in circuit. -circuit = Circuit(specified_version=aedt_version, projectname=circuit_project_file) +circuit = Circuit(version=aedt_version, project=circuit_project_file) circuit.connect_circuit_models_from_multi_zone_cutout(project_connections=project_connexions, edb_zones_dict=edb_zones, ports=defined_ports, model_inc=70) diff --git a/examples/07-Circuit/Circuit_Subcircuit_Example.py b/examples/07-Circuit/Circuit_Subcircuit_Example.py index a5f05b47fc6..359508e4f41 100644 --- a/examples/07-Circuit/Circuit_Subcircuit_Example.py +++ b/examples/07-Circuit/Circuit_Subcircuit_Example.py @@ -32,10 +32,10 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~ # Launch AEDT 2023 R2 in graphical mode with Circuit. -circuit = pyaedt.Circuit(projectname=pyaedt.generate_unique_project_name(), - specified_version=aedt_version, +circuit = pyaedt.Circuit(project=pyaedt.generate_unique_project_name(), + version=aedt_version, non_graphical=non_graphical, - new_desktop_session=True + new_desktop=True ) circuit.modeler.schematic_units = "mil" @@ -56,9 +56,9 @@ # the parameter values in the following code example. Connect them in series # and then use the ``pop_up`` # method to get back to the parent design. -circuit.variable_manager.set_variable(variable_name="R_val", expression="35ohm") -circuit.variable_manager.set_variable(variable_name="L_val", expression="1e-7H") -circuit.variable_manager.set_variable(variable_name="C_val", expression="5e-10F") +circuit.variable_manager.set_variable(name="R_val", expression="35ohm") +circuit.variable_manager.set_variable(name="L_val", expression="1e-7H") +circuit.variable_manager.set_variable(name="C_val", expression="5e-10F") p1 = circuit.modeler.schematic.create_interface_port(name="In") r1 = circuit.modeler.schematic.create_resistor(value="R_val") l1 = circuit.modeler.schematic.create_inductor(value="L_val") diff --git a/examples/07-Circuit/Circuit_Transient.py b/examples/07-Circuit/Circuit_Transient.py index e63fdb6655d..25972732565 100644 --- a/examples/07-Circuit/Circuit_Transient.py +++ b/examples/07-Circuit/Circuit_Transient.py @@ -35,9 +35,9 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~ # Launch AEDT 2023 R2 in graphical mode with Circuit. -cir = pyaedt.Circuit(projectname=pyaedt.generate_unique_project_name(), - specified_version=aedt_version, - new_desktop_session=True, +cir = pyaedt.Circuit(project=pyaedt.generate_unique_project_name(), + version=aedt_version, + new_desktop=True, non_graphical=non_graphical ) diff --git a/examples/07-Circuit/Create_Netlist.py b/examples/07-Circuit/Create_Netlist.py index e284bcbf17a..c2f999fe746 100644 --- a/examples/07-Circuit/Create_Netlist.py +++ b/examples/07-Circuit/Create_Netlist.py @@ -44,7 +44,7 @@ # and starts it on the specified version in the specified graphical mode. desktop = pyaedt.launch_desktop(aedt_version, non_graphical, NewThread) -aedtapp = pyaedt.Circuit(projectname=project_name) +aedtapp = pyaedt.Circuit(project=project_name) ############################################################################### # Define variable diff --git a/examples/07-Circuit/Reports.py b/examples/07-Circuit/Reports.py index baf0118c3e7..14f4db69c87 100644 --- a/examples/07-Circuit/Reports.py +++ b/examples/07-Circuit/Reports.py @@ -41,10 +41,10 @@ # Launch AEDT with Circuit. The :class:`pyaedt.Desktop` class initializes AEDT # and starts the specified version in the specified mode. -cir = pyaedt.Circuit(projectname=os.path.join(project_path, 'CISPR25_Radiated_Emissions_Example23R1.aedtz'), +cir = pyaedt.Circuit(project=os.path.join(project_path, 'CISPR25_Radiated_Emissions_Example23R1.aedtz'), non_graphical=non_graphical, - specified_version=aedt_version, - new_desktop_session=True + version=aedt_version, + new_desktop=True ) cir.analyze() diff --git a/examples/07-Circuit/Virtual_Compliance.py b/examples/07-Circuit/Virtual_Compliance.py index 721e06437a2..05fbe880dd8 100644 --- a/examples/07-Circuit/Virtual_Compliance.py +++ b/examples/07-Circuit/Virtual_Compliance.py @@ -45,7 +45,7 @@ # ~~~~~~~~~~~ # Launch AEDT. -d = pyaedt.Desktop(aedt_version, new_desktop_session=new_thread, non_graphical=non_graphical) +d = pyaedt.Desktop(aedt_version, new_desktop=new_thread, non_graphical=non_graphical) ############################################################################### # Open and solve layout @@ -54,7 +54,7 @@ # Before solving, this code ensures that the model is solved from DC to 70GHz and that # causality and passivity are enforced. -h3d = pyaedt.Hfss3dLayout(os.path.join(projectdir, "PCIE_GEN5_only_layout.aedtz"), specified_version=241) +h3d = pyaedt.Hfss3dLayout(os.path.join(projectdir, "PCIE_GEN5_only_layout.aedtz"), version=241) h3d.remove_all_unused_definitions() h3d.edit_cosim_options(simulate_missing_solution=False) h3d.setups[0].sweeps[0].props["EnforcePassivity"] = True @@ -62,7 +62,7 @@ h3d.setups[0].sweeps[0].props["EnforceCausality"] = True h3d.setups[0].sweeps[0].update() h3d.analyze() -h3d = pyaedt.Hfss3dLayout(specified_version=241) +h3d = pyaedt.Hfss3dLayout(version=241) touchstone_path = h3d.export_touchstone() ############################################################################### @@ -71,7 +71,7 @@ # Use the LNA setup to retrieve Touchstone files # and generate frequency domain reports. -cir = pyaedt.Circuit(projectname=h3d.project_name, designname="Touchstone") +cir = pyaedt.Circuit(project=h3d.project_name, design="Touchstone") status, diff_pairs, comm_pairs = cir.create_lna_schematic_from_snp(input_file=touchstone_path, start_frequency=0, stop_frequency=70, auto_assign_diff_pairs=True, separation=".", pattern=["component", "pin", "net"], diff --git a/examples/07-EMIT/ComputeInterferenceType.py b/examples/07-EMIT/ComputeInterferenceType.py index fc368b36cc0..00572e3268c 100644 --- a/examples/07-EMIT/ComputeInterferenceType.py +++ b/examples/07-EMIT/ComputeInterferenceType.py @@ -60,10 +60,10 @@ def install(package): non_graphical = False new_thread = True -desktop = pyaedt.launch_desktop(aedt_version, non_graphical=non_graphical, new_desktop_session=new_thread) +desktop = pyaedt.launch_desktop(aedt_version, non_graphical=non_graphical, new_desktop=new_thread) path_to_desktop_project = pyaedt.downloads.download_file("emit", "interference.aedtz") -emitapp = Emit(non_graphical=False, new_desktop_session=False, projectname=path_to_desktop_project) +emitapp = Emit(non_graphical=False, new_desktop=False, project=path_to_desktop_project) # Get all the radios in the project # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/examples/07-TwinBuilder/01-RC_Circuit_Example.py b/examples/07-TwinBuilder/01-RC_Circuit_Example.py index 0deec81cc46..940f6e50080 100644 --- a/examples/07-TwinBuilder/01-RC_Circuit_Example.py +++ b/examples/07-TwinBuilder/01-RC_Circuit_Example.py @@ -39,10 +39,10 @@ # Launch Twin Builder using an implicit declaration and add a new design with # a default setup. -tb = pyaedt.TwinBuilder(projectname=pyaedt.generate_unique_project_name(), - specified_version=aedt_version, +tb = pyaedt.TwinBuilder(project=pyaedt.generate_unique_project_name(), + version=aedt_version, non_graphical=non_graphical, - new_desktop_session=new_thread + new_desktop=new_thread ) tb.modeler.schematic_units = "mil" diff --git a/examples/07-TwinBuilder/02-Wiring_A_Rectifier.py b/examples/07-TwinBuilder/02-Wiring_A_Rectifier.py index c9192f669e2..ba977468e41 100644 --- a/examples/07-TwinBuilder/02-Wiring_A_Rectifier.py +++ b/examples/07-TwinBuilder/02-Wiring_A_Rectifier.py @@ -41,10 +41,10 @@ # Launch Twin Builder using an implicit declaration and add a new design with # a default setup. -tb = pyaedt.TwinBuilder(projectname=pyaedt.generate_unique_project_name(), - specified_version=aedt_version, +tb = pyaedt.TwinBuilder(project=pyaedt.generate_unique_project_name(), + version=aedt_version, non_graphical=non_graphical, - new_desktop_session=new_thread + new_desktop=new_thread ) ############################################################################### diff --git a/examples/07-TwinBuilder/03-Dynamic_ROM_Creation_And_Visualization.py b/examples/07-TwinBuilder/03-Dynamic_ROM_Creation_And_Visualization.py index 78bdef0d291..e891c1b811c 100644 --- a/examples/07-TwinBuilder/03-Dynamic_ROM_Creation_And_Visualization.py +++ b/examples/07-TwinBuilder/03-Dynamic_ROM_Creation_And_Visualization.py @@ -19,9 +19,9 @@ import matplotlib.pyplot as plt from pyaedt import TwinBuilder from pyaedt import generate_unique_project_name -from pyaedt import generate_unique_folder_name +from pyaedt.generic.general_methods import generate_unique_folder_name from pyaedt import downloads -from pyaedt import settings +from pyaedt.generic.settings import settings ########################################################## # Set AEDT version @@ -73,10 +73,10 @@ # Launch Twin Builder using an implicit declaration and add a new design with # a default setup for building the dynamic ROM component. -tb = TwinBuilder(projectname=generate_unique_project_name(), - specified_version=aedt_version, +tb = TwinBuilder(project=generate_unique_project_name(), + version=aedt_version, non_graphical=non_graphical, - new_desktop_session=new_thread) + new_desktop=new_thread) # Switch the current desktop configuration and the schematic environment to "Twin Builder". # The Dynamic ROM feature is only available with a twin builder license. diff --git a/examples/07-TwinBuilder/04-Static_ROM_Creation_And_Visualization.py b/examples/07-TwinBuilder/04-Static_ROM_Creation_And_Visualization.py index 1583c42fdd4..df40afe2985 100644 --- a/examples/07-TwinBuilder/04-Static_ROM_Creation_And_Visualization.py +++ b/examples/07-TwinBuilder/04-Static_ROM_Creation_And_Visualization.py @@ -20,9 +20,9 @@ import matplotlib.pyplot as plt from pyaedt import TwinBuilder from pyaedt import generate_unique_project_name -from pyaedt import generate_unique_folder_name +from pyaedt.generic.general_methods import generate_unique_folder_name from pyaedt import downloads -from pyaedt import settings +from pyaedt.generic.settings import settings ########################################################## # Set AEDT version @@ -77,8 +77,8 @@ # Launch Twin Builder using an implicit declaration and add a new design with # a default setup for building the static ROM component. -tb = TwinBuilder(projectname=generate_unique_project_name(), specified_version=aedt_version, - non_graphical=non_graphical, new_desktop_session=new_thread) +tb = TwinBuilder(project=generate_unique_project_name(), version=aedt_version, + non_graphical=non_graphical, new_desktop=new_thread) # Switch the current desktop configuration and the schematic environment to "Twin Builder". # The Static ROM feature is only available with a twin builder license. diff --git a/pyaedt/__init__.py b/pyaedt/__init__.py index 34f82cf8fb1..813506620dc 100644 --- a/pyaedt/__init__.py +++ b/pyaedt/__init__.py @@ -1,4 +1,27 @@ # -*- 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 sys import warnings @@ -44,33 +67,17 @@ def custom_show_warning(message, category, filename, lineno, file=None, line=Non version = __version__ # - -import pyaedt.downloads as downloads +if not ("IronPython" in sys.version or ".NETFramework" in sys.version): # pragma: no cover + import pyaedt.downloads as downloads +from pyaedt.edb import Edb # nosec +from pyaedt.edb import Siwave # nosec from pyaedt.generic import constants import pyaedt.generic.DataHandlers as data_handler -import pyaedt.generic.general_methods as general_methods -from pyaedt.generic.general_methods import _retry_ntimes -from pyaedt.generic.general_methods import generate_unique_folder_name -from pyaedt.generic.general_methods import generate_unique_name -from pyaedt.generic.general_methods import generate_unique_project_name -from pyaedt.generic.general_methods import inside_desktop -from pyaedt.generic.general_methods import is_ironpython -from pyaedt.generic.general_methods import is_linux -from pyaedt.generic.general_methods import is_windows -from pyaedt.generic.general_methods import online_help -from pyaedt.generic.general_methods import pyaedt_function_handler -from pyaedt.generic.general_methods import settings - -try: - from pyaedt.generic.design_types import Hfss3dLayout -except Exception: - from pyaedt.generic.design_types import Hfss3dLayout - from pyaedt.generic.design_types import Circuit from pyaedt.generic.design_types import Desktop -from pyaedt.generic.design_types import Edb from pyaedt.generic.design_types import Emit from pyaedt.generic.design_types import Hfss +from pyaedt.generic.design_types import Hfss3dLayout from pyaedt.generic.design_types import Icepak from pyaedt.generic.design_types import Maxwell2d from pyaedt.generic.design_types import Maxwell3d @@ -80,10 +87,21 @@ def custom_show_warning(message, category, filename, lineno, file=None, line=Non from pyaedt.generic.design_types import Q3d from pyaedt.generic.design_types import Rmxprt from pyaedt.generic.design_types import Simplorer -from pyaedt.generic.design_types import Siwave from pyaedt.generic.design_types import TwinBuilder from pyaedt.generic.design_types import get_pyaedt_app from pyaedt.generic.design_types import launch_desktop +import pyaedt.generic.general_methods as general_methods +from pyaedt.generic.general_methods import _retry_ntimes +from pyaedt.generic.general_methods import generate_unique_folder_name +from pyaedt.generic.general_methods import generate_unique_name +from pyaedt.generic.general_methods import generate_unique_project_name +from pyaedt.generic.general_methods import inside_desktop +from pyaedt.generic.general_methods import is_ironpython +from pyaedt.generic.general_methods import is_linux +from pyaedt.generic.general_methods import is_windows +from pyaedt.generic.general_methods import online_help +from pyaedt.generic.general_methods import pyaedt_function_handler +from pyaedt.generic.general_methods import settings from pyaedt.misc import current_student_version from pyaedt.misc import current_version from pyaedt.misc import installed_versions diff --git a/pyaedt/aedt_logger.py b/pyaedt/aedt_logger.py index 060afeabda5..fce4e646541 100644 --- a/pyaedt/aedt_logger.py +++ b/pyaedt/aedt_logger.py @@ -1,4 +1,27 @@ # -*- 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 logging from logging.handlers import RotatingFileHandler import os diff --git a/pyaedt/application/AEDT_File_Management.py b/pyaedt/application/AEDT_File_Management.py index 6d641ba45a4..bd64a1aeed0 100644 --- a/pyaedt/application/AEDT_File_Management.py +++ b/pyaedt/application/AEDT_File_Management.py @@ -1,3 +1,27 @@ +# -*- 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 import os import re diff --git a/pyaedt/application/Analysis.py b/pyaedt/application/Analysis.py index abd7571957d..83001a3c655 100644 --- a/pyaedt/application/Analysis.py +++ b/pyaedt/application/Analysis.py @@ -1,3 +1,27 @@ +# -*- 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. + """ This module contains the ``analysis`` class. @@ -14,9 +38,6 @@ import tempfile import time -from pyaedt import is_ironpython -from pyaedt import is_linux -from pyaedt import is_windows from pyaedt.application.Design import Design from pyaedt.application.JobManager import update_hpc_option from pyaedt.application.Variables import Variable @@ -29,6 +50,9 @@ from pyaedt.generic.constants import VIEW from pyaedt.generic.general_methods import filter_tuple from pyaedt.generic.general_methods import generate_unique_name +from pyaedt.generic.general_methods import is_ironpython +from pyaedt.generic.general_methods import is_linux +from pyaedt.generic.general_methods import is_windows from pyaedt.generic.general_methods import open_file from pyaedt.generic.general_methods import pyaedt_function_handler from pyaedt.generic.settings import settings @@ -40,6 +64,7 @@ from pyaedt.modules.SolveSetup import Setup from pyaedt.modules.SolveSetup import SetupHFSS from pyaedt.modules.SolveSetup import SetupHFSSAuto +from pyaedt.modules.SolveSetup import SetupIcepak from pyaedt.modules.SolveSetup import SetupMaxwell from pyaedt.modules.SolveSetup import SetupQ3D from pyaedt.modules.SolveSetup import SetupSBR @@ -77,7 +102,7 @@ class Analysis(Design, object): Version of AEDT to use. NG : bool Whether to run AEDT in the non-graphical mode. - new_desktop_session : bool, optional + new_desktop : bool, optional Whether to launch an instance of AEDT in a new thread, even if another instance of the ``specified_version`` is active on the machine. @@ -86,12 +111,15 @@ class Analysis(Design, object): student_version : bool Whether to enable the student version of AEDT. aedt_process_id : int, optional - Only used when ``new_desktop_session = False``, specifies by process ID which instance + Only used when ``new_desktop = False``, specifies by process ID which instance of Electronics Desktop to point PyAEDT at. ic_mode : bool, optional Whether to set the design to IC mode. The default is ``None``, which means to retain the existing setting. This parameter applies only to HFSS 3D Layout. - + remove_lock : bool, optional + Whether to remove lock to project before opening it or not. + The default is ``False``, which means to not unlock + the existing project if needed and raise an exception. """ def __init__( @@ -103,13 +131,14 @@ def __init__( setup_name, specified_version, non_graphical, - new_desktop_session, + new_desktop, close_on_exit, student_version, machine="", port=0, aedt_process_id=None, ic_mode=None, + remove_lock=False, ): Design.__init__( self, @@ -119,13 +148,14 @@ def __init__( solution_type, specified_version, non_graphical, - new_desktop_session, + new_desktop, close_on_exit, student_version, machine, port, aedt_process_id, ic_mode, + remove_lock, ) self._excitation_objects = {} self._setup = None @@ -509,7 +539,7 @@ def get_traces_for_plot( first_element_filter=None, second_element_filter=None, category="dB(S", - differential_pairs=[], + differential_pairs=None, ): # type: (bool, bool, str, str, str, list) -> list """Retrieve a list of traces of specified designs ready to use in plot reports. @@ -528,9 +558,9 @@ def get_traces_for_plot( This parameter accepts ``*`` and ``?`` as special characters. The default is ``None``. category : str, optional Plot category name as in the report (including operator). - The default is ``"dB(S"``, which is the plot category name for capacitance. + The default is ``"dB(S)"``, which is the plot category name for capacitance. differential_pairs : list, optional - Differential pairs defined. The default is ``[]``. + Differential pairs defined. The default is ``None`` in which case an empty list is set. Returns ------- @@ -547,6 +577,7 @@ def get_traces_for_plot( ... first_element_filter="*_U1_data?", ... second_element_filter="*_U0_*", category="dB(S") """ + differential_pairs = [] if differential_pairs is None else differential_pairs if not first_element_filter: first_element_filter = "*" if not second_element_filter: @@ -1296,6 +1327,8 @@ def _create_setup(self, name="MySetupAuto", setup_type=None, props=None): setup = SetupMaxwell(self, setup_type, name) elif setup_type == 14: setup = SetupQ3D(self, setup_type, name) + elif setup_type in [11, 36]: + setup = SetupIcepak(self, setup_type, name) else: setup = SetupHFSS(self, setup_type, name) @@ -1922,7 +1955,7 @@ def solve_in_batch( Number of tasks to use in the simulation. Set ``num_tasks`` to ``-1`` to apply auto settings and distributed mode. setup : str - Name of the setup, which can be an optimetric setup or a simple setup. + Name of the setup, which can be an optimetrics setup or a simple setup. The default is ``None``, in which case all setups are solved. revert_to_initial_mesh : bool, optional Whether to revert to the initial mesh before solving. The default is ``False``. diff --git a/pyaedt/application/Analysis3D.py b/pyaedt/application/Analysis3D.py index dc19a77bc33..435badc9708 100644 --- a/pyaedt/application/Analysis3D.py +++ b/pyaedt/application/Analysis3D.py @@ -1,7 +1,30 @@ +# -*- 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 import ntpath import os -import warnings from pyaedt.application.Analysis import Analysis from pyaedt.generic.configurations import Configurations @@ -39,13 +62,13 @@ class FieldAnalysis3D(Analysis, object): Name of the setup to use as the nominal. The default is ``None``, in which case the active setup is used or nothing is used. - specified_version : str, int, float, optional + version : str, int, float, optional Version of AEDT to use. The default is ``None``, in which case the active version or latest installed version is used. non_graphical : bool, optional Whether to run AEDT in non-graphical mode. The default is ``False``, in which case AEDT is launched in the graphical mode. - new_desktop_session : bool, optional + new_desktop : bool, optional Whether to launch an instance of AEDT in a new thread, even if another instance of the ``specified_version`` is active on the machine. The default is ``False``. @@ -55,8 +78,12 @@ class FieldAnalysis3D(Analysis, object): Whether to enable the student version of AEDT. The default is ``False``. aedt_process_id : int, optional - Only used when ``new_desktop_session = False``, specifies by process ID which instance + Only used when ``new_desktop = False``, specifies by process ID which instance of Electronics Desktop to point PyAEDT at. + remove_lock : bool, optional + Whether to remove lock to project before opening it or not. + The default is ``False``, which means to not unlock + the existing project if needed and raise an exception. """ def __init__( @@ -66,14 +93,15 @@ def __init__( designname, solution_type, setup_name=None, - specified_version=None, + version=None, non_graphical=False, - new_desktop_session=False, + new_desktop=False, close_on_exit=False, student_version=False, machine="", port=0, aedt_process_id=None, + remove_lock=False, ): Analysis.__init__( self, @@ -82,14 +110,15 @@ def __init__( designname, solution_type, setup_name, - specified_version, + version, non_graphical, - new_desktop_session, + new_desktop, close_on_exit, student_version, machine, port, aedt_process_id, + remove_lock=remove_lock, ) self._post = None self._modeler = None @@ -422,8 +451,8 @@ def get_property_value(self, assignment, property_name, property_type=None): return val return None - @pyaedt_function_handler(object_list="assignment", no_vacuum="vacuum", no_pec="pec") - def copy_solid_bodies_from(self, design, assignment=None, vacuum=True, pec=True, include_sheets=False): + @pyaedt_function_handler(object_list="assignment") + def copy_solid_bodies_from(self, design, assignment=None, no_vacuum=True, no_pec=True, include_sheets=False): """Copy a list of objects and user defined models from one design to the active design. If user defined models are selected, the project will be saved automatically. @@ -433,10 +462,10 @@ def copy_solid_bodies_from(self, design, assignment=None, vacuum=True, pec=True, Starting application object. For example, ``hfss1= HFSS3DLayout``. assignment : list, optional List of objects and user defined components to copy. The default is ``None``. - vacuum : bool, optional + no_vacuum : bool, optional Whether to include vacuum objects for the copied objects. The default is ``True``. - pec : + no_pec : Whether to include pec objects for the copied objects. The default is ``True``. include_sheets : @@ -487,9 +516,9 @@ def copy_solid_bodies_from(self, design, assignment=None, vacuum=True, pec=True, include_object = True for key, val in material_properties.items(): if val.name == body: - if vacuum and val.material_name.lower() == "vacuum": + if no_vacuum and val.material_name.lower() == "vacuum": include_object = False - if pec and val.material_name == "pec": + if no_pec and val.material_name == "pec": include_object = False if include_object: selection_list.append(body) @@ -504,7 +533,99 @@ def copy_solid_bodies_from(self, design, assignment=None, vacuum=True, pec=True, self.modeler.refresh_all_ids() return True - @pyaedt_function_handler(object_list="assignment_to_export", removed_objects="assignment_to_remove") + @pyaedt_function_handler(filename="input_file") + def import_3d_cad( + self, + input_file, + healing=False, + refresh_all_ids=True, + import_materials=False, + create_lightweigth_part=False, + group_by_assembly=False, + create_group=True, + separate_disjoints_lumped_object=False, + import_free_surfaces=False, + point_coicidence_tolerance=1e-6, + heal_stl=True, + reduce_stl=False, + reduce_percentage=0, + reduce_error=0, + merge_planar_faces=True, + ): + """Import a CAD model. + + Parameters + ---------- + input_file : str + Full path and name of the CAD file. + healing : bool, optional + Whether to perform healing. The default is ``False``. + refresh_all_ids : bool, optional + Whether to refresh all IDs after the CAD file is loaded. The + default is ``True``. Refreshing IDs can take a lot of time in + a big project. + import_materials : bool optional + Whether to import material names from the file if present. The + default is ``False``. + create_lightweigth_part : bool ,optional + Whether to import a lightweight part. The default is ``True``. + group_by_assembly : bool, optional + Whether to import by subassembly. The default is ``False``, in which + case the import is by individual parts. + create_group : bool, optional + Whether to create a group of imported objects. The default is ``True``. + separate_disjoints_lumped_object : bool, optional + Whether to automatically separate disjoint parts. The default is ``False``. + import_free_surfaces : bool, optional + Whether to import free surfaces parts. The default is ``False``. + point_coicidence_tolerance : float, optional + Tolerance on the point. The default is ``1e-6``. + heal_stl : bool, optional + Whether to heal the STL file on import. The default is ``True``. + reduce_stl : bool, optional + Whether to reduce the STL file on import. The default is ``True``. + reduce_percentage : int, optional + Percentage to reduce the STL file by if ``reduce_stl=True``. The default is ``0``. + reduce_error : int, optional + Error percentage during STL reduction operation. The default is ``0``. + merge_planar_faces : bool, optional + Whether to merge planar faces during import. The default is ``True``. + + Returns + ------- + bool + ``True`` when successful, ``False`` when failed. + + References + ---------- + + >>> oEditor.Import + """ + return self.modeler.import_3d_cad( + input_file=input_file, + healing=healing, + refresh_all_ids=refresh_all_ids, + import_materials=import_materials, + create_lightweigth_part=create_lightweigth_part, + group_by_assembly=group_by_assembly, + create_group=create_group, + separate_disjoints_lumped_object=separate_disjoints_lumped_object, + import_free_surfaces=import_free_surfaces, + point_coicidence_tolerance=point_coicidence_tolerance, + heal_stl=heal_stl, + reduce_stl=reduce_stl, + reduce_percentage=reduce_percentage, + reduce_error=reduce_error, + merge_planar_faces=merge_planar_faces, + ) + + @pyaedt_function_handler( + object_list="assignment_to_export", + removed_objects="assignment_to_remove", + fileName="file_name", + filePath="file_path", + fileFormat="file_format", + ) def export_3d_model( self, file_name="", @@ -514,7 +635,6 @@ def export_3d_model( assignment_to_remove=None, major_version=-1, minor_version=-1, - **kwargs # fmt: skip ): """Export the 3D model. @@ -545,83 +665,15 @@ def export_3d_model( >>> oEditor.Export """ - if "fileName" in kwargs: - warnings.warn( - "`fileName` is deprecated. Use `file_name` instead.", - DeprecationWarning, - ) - - file_name = kwargs["fileName"] - if "filePath" in kwargs: - warnings.warn( - "`filePath` is deprecated. Use `file_path` instead.", - DeprecationWarning, - ) - - file_path = kwargs["filePath"] - if "fileFormat" in kwargs: - warnings.warn( - "`fileFormat` is deprecated. Use `file_format` instead.", - DeprecationWarning, - ) - - file_format = kwargs["fileFormat"] - if not file_name: - file_name = self.project_name + "_" + self.design_name - if not file_path: - file_path = self.working_directory - if assignment_to_export is None: - assignment_to_export = [] - if assignment_to_remove is None: - assignment_to_remove = [] - - sub_regions = [] - if self.settings.aedt_version > "2023.2": - sub_regions = [ - o for o in self.modeler.non_model_objects if self.modeler[o].history().command == "CreateSubRegion" - ] - - if not assignment_to_export: - allObjects = self.modeler.object_names - if assignment_to_remove: - for rem in assignment_to_remove: - allObjects.remove(rem) - else: - if "Region" in allObjects: - allObjects.remove("Region") - for o in sub_regions: - allObjects.remove(o) - else: - allObjects = assignment_to_export[:] - - self.logger.debug("Exporting {} objects".format(len(allObjects))) - - # actual version supported by AEDT is 29.0 - if major_version == -1: - if file_format in [".sm3", ".sat", ".sab"]: - major_version = 29 - if minor_version == -1: - if file_format in [".sm3", ".sat", ".sab"]: - minor_version = 0 - stringa = ",".join(allObjects) - arg = [ - "NAME:ExportParameters", - "AllowRegionDependentPartSelectionForPMLCreation:=", - True, - "AllowRegionSelectionForPMLCreation:=", - True, - "Selections:=", - stringa, - "File Name:=", - os.path.join(file_path, file_name + file_format).replace("\\", "/"), - "Major Version:=", - major_version, - "Minor Version:=", - minor_version, - ] - - self.modeler.oeditor.Export(arg) - return True + return self.modeler.export_3d_model( + file_name=file_name, + file_path=file_path, + file_format=file_format, + assignment_to_export=assignment_to_export, + assignment_to_remove=assignment_to_remove, + major_version=major_version, + minor_version=minor_version, + ) @pyaedt_function_handler() def get_all_sources(self): @@ -1073,7 +1125,7 @@ def flatten_3d_components(self, components=None, purge_history=True, password=No self.modeler.set_working_coordinate_system(target_cs) comp.delete() obj_set = set(self.modeler.objects.values()) - self.copy_solid_bodies_from(app, vacuum=False, pec=False, include_sheets=True) + self.copy_solid_bodies_from(app, no_vacuum=False, no_pec=False, include_sheets=True) self.modeler.refresh_all_ids() self.modeler.set_working_coordinate_system(oldcs) if self.design_type == "Icepak": diff --git a/pyaedt/application/Analysis3DLayout.py b/pyaedt/application/Analysis3DLayout.py index 7e720234103..fee24cda10e 100644 --- a/pyaedt/application/Analysis3DLayout.py +++ b/pyaedt/application/Analysis3DLayout.py @@ -1,3 +1,27 @@ +# -*- 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 from pyaedt.application.Analysis import Analysis @@ -35,13 +59,13 @@ class FieldAnalysis3DLayout(Analysis): Name of the setup to use as the nominal. The default is ``None``, in which case the active setup is used or nothing is used. - specified_version : str, int, float, optional + version : str, int, float, optional Version of AEDT to use. The default is ``None``, in which case the active version or latest installed version is used. - NG : bool, optional + non_graphical : bool, optional Whether to run AEDT in the non-graphical mode. The default is ``False``, in which case AEDT is launched in the graphical mode. - new_desktop_session : bool, optional + new_desktop : bool, optional Whether to launch an instance of AEDT in a new thread, even if another instance of the ``specified_version`` is active on the machine. The default is ``False``. @@ -52,10 +76,14 @@ class FieldAnalysis3DLayout(Analysis): is ``False``. aedt_process_id : int, optional Specifies by process ID the instance of AEDT to point PyAEDT at. - This parameter is only used when ``new_desktop_session=False``. + This parameter is only used when ``new_desktop=False``. ic_mode : bool, optional Whether to set the design to IC mode. The default is ``None``, which means to retain the existing setting. + remove_lock : bool, optional + Whether to remove lock to project before opening it or not. + The default is ``False``, which means to not unlock + the existing project if needed and raise an exception. """ @@ -66,15 +94,16 @@ def __init__( designname, solution_type, setup_name=None, - specified_version=None, + version=None, non_graphical=False, - new_desktop_session=False, + new_desktop=False, close_on_exit=False, student_version=False, machine="", port=0, aedt_process_id=None, ic_mode=None, + remove_lock=False, ): Analysis.__init__( self, @@ -83,15 +112,16 @@ def __init__( designname, solution_type, setup_name, - specified_version, + version, non_graphical, - new_desktop_session, + new_desktop, close_on_exit, student_version, machine, port, aedt_process_id, ic_mode, + remove_lock=remove_lock, ) self._modeler = None self._mesh = None diff --git a/pyaedt/application/AnalysisMaxwellCircuit.py b/pyaedt/application/AnalysisMaxwellCircuit.py index 3e53372604a..8f34e2e9977 100644 --- a/pyaedt/application/AnalysisMaxwellCircuit.py +++ b/pyaedt/application/AnalysisMaxwellCircuit.py @@ -1,3 +1,27 @@ +# -*- 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 pyaedt.application.Analysis import Analysis from pyaedt.generic.settings import settings @@ -19,14 +43,14 @@ class AnalysisMaxwellCircuit(Analysis): Name of the design to select. The default is ``None``, in which case an attempt is made to get an active design. If no designs are present, an empty design is created. - specified_version : str, int, float, optional + version : str, int, float, optional Version of AEDT to use. The default is ``None``. If ``None``, the active setup is used or the latest installed version is used. NG : bool, optional Whether to launch AEDT in the non-graphical mode. The default is ``False``, in which case AEDT is launched in the graphical mode. - new_desktop_session : bool, optional + new_desktop : bool, optional Whether to launch an instance of AEDT in a new thread, even if another instance of the ``specified_version`` is active on the machine. The default is ``False``. @@ -35,9 +59,12 @@ class AnalysisMaxwellCircuit(Analysis): student_version : bool, optional Whether to open the AEDT student version. The default is ``False``. aedt_process_id : int, optional - Only used when ``new_desktop_session = False``, specifies by process ID which instance + Only used when ``new_desktop = False``, specifies by process ID which instance of Electronics Desktop to point PyAEDT at. - + remove_lock : bool, optional + Whether to remove lock to project before opening it or not. + The default is ``False``, which means to not unlock + the existing project if needed and raise an exception. """ def __init__( @@ -45,14 +72,15 @@ def __init__( application, projectname, designname, - specified_version=None, + version=None, non_graphical=False, - new_desktop_session=False, + new_desktop=False, close_on_exit=False, student_version=False, machine="", port=0, aedt_process_id=None, + remove_lock=False, ): Analysis.__init__( self, @@ -61,14 +89,15 @@ def __init__( designname, None, None, - specified_version, + version, non_graphical, - new_desktop_session, + new_desktop, close_on_exit, student_version, machine, port, aedt_process_id, + remove_lock=remove_lock, ) self._modeler = None if not settings.lazy_load: diff --git a/pyaedt/application/AnalysisNexxim.py b/pyaedt/application/AnalysisNexxim.py index 30a3307ff53..4ae54d9e5a9 100644 --- a/pyaedt/application/AnalysisNexxim.py +++ b/pyaedt/application/AnalysisNexxim.py @@ -1,3 +1,27 @@ +# -*- 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 pyaedt.application.Analysis import Analysis from pyaedt.generic.general_methods import pyaedt_function_handler from pyaedt.generic.settings import settings @@ -35,14 +59,15 @@ def __init__( designname, solution_type, setup_name=None, - specified_version=None, + version=None, non_graphical=False, - new_desktop_session=False, + new_desktop=False, close_on_exit=False, student_version=False, machine="", port=0, aedt_process_id=None, + remove_lock=False, ): Analysis.__init__( self, @@ -51,14 +76,15 @@ def __init__( designname, solution_type, setup_name, - specified_version, + version, non_graphical, - new_desktop_session, + new_desktop, close_on_exit, student_version, machine, port, aedt_process_id, + remove_lock=remove_lock, ) self._modeler = None @@ -123,7 +149,7 @@ def push_down(self, component): out_name = component try: self.desktop_class.active_design(self.oproject, out_name, self.design_type) - self.__init__(projectname=self.project_name, designname=out_name) + self.__init__(project=self.project_name, design=out_name) except Exception: # pragma: no cover return False return True @@ -140,7 +166,7 @@ def pop_up(self): try: parent_name = self.odesign.GetName().split(";")[1].split("/")[0] self.desktop_class.active_design(self.oproject, parent_name, self.design_type) - self.__init__(projectname=self.project_name, designname=parent_name) + self.__init__(project=self.project_name, design=parent_name) except Exception: return False return True diff --git a/pyaedt/application/AnalysisRMxprt.py b/pyaedt/application/AnalysisRMxprt.py index a63acd5bc83..4989ecc2ef7 100644 --- a/pyaedt/application/AnalysisRMxprt.py +++ b/pyaedt/application/AnalysisRMxprt.py @@ -1,3 +1,27 @@ +# -*- 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 pyaedt.application.Analysis import Analysis from pyaedt.generic.general_methods import pyaedt_function_handler from pyaedt.generic.settings import settings @@ -24,14 +48,15 @@ def __init__( designname, solution_type, setup_name=None, - specified_version=None, + version=None, non_graphical=False, - new_desktop_session=False, + new_desktop=False, close_on_exit=False, student_version=False, machine="", port=0, aedt_process_id=None, + remove_lock=False, ): Analysis.__init__( self, @@ -40,14 +65,15 @@ def __init__( designname, solution_type, setup_name, - specified_version, + version, non_graphical, - new_desktop_session, + new_desktop, close_on_exit, student_version, machine, port, aedt_process_id, + remove_lock=remove_lock, ) self._modeler = None self._post = None diff --git a/pyaedt/application/AnalysisTwinBuilder.py b/pyaedt/application/AnalysisTwinBuilder.py index 85d9dc246a0..1acabd68878 100644 --- a/pyaedt/application/AnalysisTwinBuilder.py +++ b/pyaedt/application/AnalysisTwinBuilder.py @@ -1,3 +1,27 @@ +# -*- 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 pyaedt.application.Analysis import Analysis from pyaedt.generic.general_methods import pyaedt_function_handler from pyaedt.generic.settings import settings @@ -46,14 +70,15 @@ def __init__( designname, solution_type, setup_name=None, - specified_version=None, + version=None, non_graphical=False, - new_desktop_session=False, + new_desktop=False, close_on_exit=False, student_version=False, machine="", port=0, aedt_process_id=None, + remove_lock=False, ): Analysis.__init__( self, @@ -62,14 +87,15 @@ def __init__( designname, solution_type, setup_name, - specified_version, + version, non_graphical, - new_desktop_session, + new_desktop, close_on_exit, student_version, machine, port, aedt_process_id, + remove_lock=remove_lock, ) self._modeler = None self._post = None diff --git a/pyaedt/application/Design.py b/pyaedt/application/Design.py index 6f88d4a0131..536f70c5080 100644 --- a/pyaedt/application/Design.py +++ b/pyaedt/application/Design.py @@ -1,3 +1,27 @@ +# -*- 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. + """ This module contains these classes: ``Design``. @@ -51,6 +75,7 @@ from pyaedt.generic.general_methods import read_csv from pyaedt.generic.general_methods import read_tab from pyaedt.generic.general_methods import read_xlsx +from pyaedt.generic.general_methods import remove_project_lock from pyaedt.generic.general_methods import settings from pyaedt.generic.general_methods import write_csv from pyaedt.modules.Boundary import BoundaryObject @@ -89,13 +114,13 @@ class Design(AedtObjects): solution_type : str, optional Solution type to apply to the design. The default is ``None``, in which case the default type is applied. - specified_version : str, int, float, optional + version : str, int, float, optional Version of AEDT to use. The default is ``None``, in which case the active version or latest installed version is used. non_graphical : bool, optional Whether to run AEDT in non-graphical mode. The default is ``False``, in which case AEDT launches in graphical mode. - new_desktop_session : bool, optional + new_desktop : bool, optional Whether to launch an instance of AEDT in a new thread, even if another instance of the ``specified_version`` is active on the machine. The default is ``False``. @@ -105,12 +130,15 @@ class Design(AedtObjects): Whether to enable the student version of AEDT. The default is ``False``. aedt_process_id : int, optional - Only used when ``new_desktop_session = False``, specifies by process ID which instance + Only used when ``new_desktop = False``, specifies by process ID which instance of Electronics Desktop to point PyAEDT at. ic_mode : bool, optional Whether to set the design to IC mode or not. The default is ``None``, which means to retain the existing setting. Applicable only to ``Hfss3dLayout``. - + remove_lock : bool, optional + Whether to remove lock to project before opening it or not. + The default is ``False``, which means to not unlock + the existing project if needed and raise an exception. """ @property @@ -178,12 +206,12 @@ def info(self): def _init_design(self, project_name, design_name, solution_type=None): # calls the method from the application class self._init_from_design( - projectname=project_name, - designname=design_name, + project=project_name, + design=design_name, solution_type=solution_type, - specified_version=settings.aedt_version, + version=settings.aedt_version, non_graphical=self._desktop_class.non_graphical, - new_desktop_session=False, + new_desktop=False, close_on_exit=self.close_on_exit, student_version=self.student_version, machine=self._desktop_class.machine, @@ -196,17 +224,19 @@ def __init__( project_name=None, design_name=None, solution_type=None, - specified_version=None, + version=None, non_graphical=False, - new_desktop_session=False, + new_desktop=False, close_on_exit=False, student_version=False, machine="", port=0, aedt_process_id=None, ic_mode=None, + remove_lock=False, ): - + self._design_name = None + self._project_name = None self.__t = None if ( not is_ironpython @@ -230,9 +260,9 @@ def __init__( self.close_on_exit = close_on_exit self._desktop_class = None self._desktop_class = _init_desktop_from_design( - specified_version, + version, non_graphical, - new_desktop_session, + new_desktop, close_on_exit, student_version, machine, @@ -263,14 +293,13 @@ def __init__( self.design_solutions = DesignSolution(None, design_type, self._aedt_version) self.design_solutions._solution_type = solution_type self._temp_solution_type = solution_type + self._remove_lock = remove_lock self.oproject = project_name self.odesign = design_name self._logger.oproject = self.oproject self._logger.odesign = self.odesign AedtObjects.__init__(self, self._desktop_class, self.oproject, self.odesign, is_inherithed=True) self.logger.info("Aedt Objects correctly read") - # if t: - # t.join() if not self.__t and not settings.lazy_load and not is_ironpython and os.path.exists(self.project_file): self.__t = threading.Thread(target=load_aedt_thread, args=(self.project_file,), daemon=True) self.__t.start() @@ -611,11 +640,11 @@ def design_name(self): if not self.odesign: return None - name = _retry_ntimes(5, self.odesign.GetName) - if ";" in name: - return name.split(";")[1] + self._design_name = _retry_ntimes(5, self.odesign.GetName) + if ";" in self._design_name: + return self._design_name.split(";")[1] else: - return name + return self._design_name @design_name.setter def design_name(self, new_name): @@ -638,6 +667,7 @@ def design_name(self, new_name): timeout -= timestep if timeout < 0: raise RuntimeError("Timeout reached while checking design renaming.") + self._design_name = new_name @property def design_list(self): @@ -694,7 +724,8 @@ def project_name(self): """ if self.oproject: try: - return self.oproject.GetName() + self._project_name = self.oproject.GetName() + return self._project_name except Exception: return None else: @@ -1063,6 +1094,10 @@ def odesign(self): >>> oProject.SetActiveDesign >>> oProject.InsertDesign """ + if settings.use_multi_desktop: # pragma: no cover + self._desktop_class.grpc_plugin.recreate_application(True) + if self._design_name: + self._odesign = self.oproject.SetActiveDesign(self._design_name) return self._odesign @odesign.setter @@ -1090,6 +1125,7 @@ def odesign(self, des_name): self.solution_type == "HFSS3DLayout" or self.solution_type == "HFSS 3D Layout Design" ): self.set_oo_property_value(self.odesign, "Design Settings", "Design Mode/IC", self._ic_mode) + self.desktop_class.active_design(self.oproject, des_name) @property def oproject(self): @@ -1106,6 +1142,8 @@ def oproject(self): >>> oDesktop.SetActiveProject >>> oDesktop.NewProject """ + if settings.use_multi_desktop: # pragma: no cover + self._desktop_class.grpc_plugin.recreate_application(True) return self._oproject @oproject.setter @@ -1147,7 +1185,11 @@ def oproject(self, proj_name=None): self.logger.info("Project %s set to active.", pname) elif os.path.exists(project): if is_project_locked(project): - raise RuntimeError("Project is locked. Close or remove the lock before proceeding.") + if self._remove_lock: # pragma: no cover + self.logger.warning("Project is locked. Removing it and opening.") + remove_project_lock(project) + else: # pragma: no cover + raise RuntimeError("Project is locked. Close or remove the lock before proceeding.") self.logger.info("aedt project found. Loading it.") self._oproject = self.odesktop.OpenProject(project) self._add_handler() @@ -1172,7 +1214,11 @@ def oproject(self, proj_name=None): self.logger.info("Project %s set to active.", pname) else: if is_project_locked(proj_name): - raise RuntimeError("Project is locked. Close or remove the lock before proceeding.") + if self._remove_lock: # pragma: no cover + self.logger.warning("Project is locked. Removing it and opening.") + remove_project_lock(proj_name) + else: # pragma: no cover + raise RuntimeError("Project is locked. Close or remove the lock before proceeding.") self._oproject = self.odesktop.OpenProject(proj_name) if not is_windows and settings.aedt_version: time.sleep(1) @@ -1245,6 +1291,47 @@ def remove_all_unused_definitions(self): self.oproject.RemoveAllUnusedDefinitions() return True + @pyaedt_function_handler() + def get_profile(self, name=None): + """Get profile information. + + Parameters + ---------- + name : str + Setup name. The default is ``None``, in which case all available setups are returned. + + Returns + ------- + dict of :class:`pyaedt.modeler.cad.elements3d.BinaryTree` when successful, + ``False`` when failed. + """ + from pyaedt.modeler.cad.elements3d import BinaryTreeNode + + if not name: + name = self.setup_names + if not isinstance(name, list): + name = [name] + + profile_setups_obj = self.get_oo_object(self.odesign, "results/profile") + + profile_objs = {} + if profile_setups_obj: + profile_setup_names = self.get_oo_name(self.odesign, "results/profile") + for n in name: + for profile_setup_name in profile_setup_names: + if n in profile_setup_name: + profile_setup_obj = self.get_oo_object(profile_setups_obj, profile_setup_name) + if profile_setup_obj and self.get_oo_name(profile_setup_obj): + try: + profile_tree = BinaryTreeNode("profile", profile_setup_obj) + profile_objs[profile_setup_name] = profile_tree + except Exception: # pragma: no cover + self.logger.error("{} profile could not be obtained.".format(profile_setup_name)) + return profile_objs + else: # pragma: no cover + self.logger.error("Profile can not be obtained.") + return False + @pyaedt_function_handler() def get_oo_name(self, aedt_object, object_name=None): """Return the object-oriented AEDT property names. @@ -1361,17 +1448,17 @@ def set_oo_property_value(self, aedt_object, object_name, prop_name, value): except Exception: return False - @pyaedt_function_handler() - def export_profile(self, setup_name, variation_string="", file_path=None): + @pyaedt_function_handler(setup_name="setup", variation_string="variation", file_path="output_file") + def export_profile(self, setup, variation="", output_file=None): """Export a solution profile to a PROF file. Parameters ---------- - setup_name : str + setup : str Setup name. For example, ``'Setup1'``. - variation_string : str + variation : str Variation string with values. For example, ``'radius=3mm'``. - file_path : str, optional + output_file : str, optional Full path to the PROF file. The default is ``None``, in which case the working directory is used. @@ -1387,55 +1474,54 @@ def export_profile(self, setup_name, variation_string="", file_path=None): >>> oDesign.ExportProfile """ - if not file_path: - file_path = os.path.join(self.working_directory, generate_unique_name("Profile") + ".prof") - if not variation_string: + if not output_file: + output_file = os.path.join(self.working_directory, generate_unique_name("Profile") + ".prof") + if not variation: val_str = [] for el, val in self.available_variations.nominal_w_values_dict.items(): val_str.append("{}={}".format(el, val)) if self.design_type == "HFSS 3D Layout Design": - variation_string = " ".join(val_str) + variation = " ".join(val_str) else: - variation_string = ",".join(val_str) + variation = ",".join(val_str) if self.design_type == "2D Extractor": - for setup in self.setups: - if setup.name == setup_name: - if "CGDataBlock" in setup.props: - file_path = os.path.splitext(file_path)[0] + "CG" + os.path.splitext(file_path)[1] - self.odesign.ExportProfile(setup_name, variation_string, "CG", file_path, True) - self.logger.info("Exported Profile to file {}".format(file_path)) - if "RLDataBlock" in setup.props: - file_path = os.path.splitext(file_path)[0] + "RL" + os.path.splitext(file_path)[1] - self.odesign.ExportProfile(setup_name, variation_string, "RL", file_path, True) - self.logger.info("Exported Profile to file {}".format(file_path)) + for s in self.setups: + if s.name == setup: + if "CGDataBlock" in s.props: + output_file = os.path.splitext(output_file)[0] + "CG" + os.path.splitext(output_file)[1] + self.odesign.ExportProfile(setup, variation, "CG", output_file, True) + self.logger.info("Exported Profile to file {}".format(output_file)) + if "RLDataBlock" in s.props: + output_file = os.path.splitext(output_file)[0] + "RL" + os.path.splitext(output_file)[1] + self.odesign.ExportProfile(setup, variation, "RL", output_file, True) + self.logger.info("Exported Profile to file {}".format(output_file)) break elif self.design_type == "Q3D Extractor": - for setup in self.setups: - if setup.name == setup_name: - if "Cap" in setup.props: - file_path = os.path.splitext(file_path)[0] + "CG" + os.path.splitext(file_path)[1] - self.odesign.ExportProfile(setup_name, variation_string, "CG", file_path, True) - self.logger.info("Exported Profile to file {}".format(file_path)) - if "AC" in setup.props: - file_path = os.path.splitext(file_path)[0] + "ACRL" + os.path.splitext(file_path)[1] - self.odesign.ExportProfile(setup_name, variation_string, "AC RL", file_path, True) - self.logger.info("Exported Profile to file {}".format(file_path)) - if "DC" in setup.props: - file_path = os.path.splitext(file_path)[0] + "DC" + os.path.splitext(file_path)[1] - self.odesign.ExportProfile(setup_name, variation_string, "DC RL", file_path, True) - self.logger.info("Exported Profile to file {}".format(file_path)) - + for s in self.setups: + if s.name == setup: + if "Cap" in s.props: + output_file = os.path.splitext(output_file)[0] + "CG" + os.path.splitext(output_file)[1] + self.odesign.ExportProfile(setup, variation, "CG", output_file, True) + self.logger.info("Exported Profile to file {}".format(output_file)) + if "AC" in s.props: + output_file = os.path.splitext(output_file)[0] + "ACRL" + os.path.splitext(output_file)[1] + self.odesign.ExportProfile(setup, variation, "AC RL", output_file, True) + self.logger.info("Exported Profile to file {}".format(output_file)) + if "DC" in s.props: + output_file = os.path.splitext(output_file)[0] + "DC" + os.path.splitext(output_file)[1] + self.odesign.ExportProfile(setup, variation, "DC RL", output_file, True) + self.logger.info("Exported Profile to file {}".format(output_file)) break else: try: - self.odesign.ExportProfile(setup_name, variation_string, file_path) + self.odesign.ExportProfile(setup, variation, output_file) except Exception: - self.odesign.ExportProfile(setup_name, variation_string, file_path, True) - self.logger.info("Exported Profile to file {}".format(file_path)) - return file_path + self.odesign.ExportProfile(setup, variation, output_file, True) + self.logger.info("Exported Profile to file {}".format(output_file)) + return output_file - @pyaedt_function_handler() - def add_info_message(self, message_text, message_type=None): + @pyaedt_function_handler(message_text="text", message_type="level") + def add_info_message(self, text, level=None): """Add a type 0 "Info" message to either the global, active project, or active design level of the message manager tree. @@ -1443,9 +1529,9 @@ def add_info_message(self, message_text, message_type=None): Parameters ---------- - message_text : str + text : str Text to display as the info message. - message_type : str, optional + level : str, optional Level to add the "Info" message to. Options are ``"Global"``, ``"Project"``, and ``"Design"``. The default is ``None``, in which case the "Info" message gets added to the ``"Design"`` @@ -1469,16 +1555,16 @@ def add_info_message(self, message_text, message_type=None): "`add_info_message` is deprecated. Use `logger.design_logger.info` instead.", DeprecationWarning, ) - if message_type.lower() == "project": - self.logger.project_logger.info(message_text) - elif message_type.lower() == "design": - self.logger.design_logger.info(message_text) + if level.lower() == "project": + self.logger.project_logger.info(text) + elif level.lower() == "design": + self.logger.design_logger.info(text) else: - self.logger.info(message_text) + self.logger.info(text) return True - @pyaedt_function_handler() - def add_warning_message(self, message_text, message_type=None): + @pyaedt_function_handler(message_text="text", message_type="level") + def add_warning_message(self, text, level=None): """Add a type 0 "Warning" message to either the global, active project, or active design level of the message manager tree. @@ -1486,9 +1572,9 @@ def add_warning_message(self, message_text, message_type=None): Parameters ---------- - message_text : str + text : str Text to display as the "Warning" message. - message_type : str, optional + level : str, optional Level to add the "Warning" message to. Options are ``"Global"``, ``"Project"``, and ``"Design"``. The default is ``None``, in which case the "Warning" message gets added to the ``"Design"`` @@ -1513,16 +1599,16 @@ def add_warning_message(self, message_text, message_type=None): DeprecationWarning, ) - if message_type.lower() == "project": - self.logger.project_logger.warning(message_text) - elif message_type.lower() == "design": - self.logger.design_logger.warning(message_text) + if level.lower() == "project": + self.logger.project_logger.warning(text) + elif level.lower() == "design": + self.logger.design_logger.warning(text) else: - self.logger.warning(message_text) + self.logger.warning(text) return True - @pyaedt_function_handler() - def add_error_message(self, message_text, message_type=None): + @pyaedt_function_handler(message_text="text", message_type="level") + def add_error_message(self, text, level=None): """Add a type 0 "Error" message to either the global, active project, or active design level of the message mmanager tree. @@ -1530,9 +1616,9 @@ def add_error_message(self, message_text, message_type=None): Parameters ---------- - message_text : str + text : str Text to display as the "Error" message. - message_type : str, optional + level : str, optional Level to add the "Error" message to. Options are ``"Global"``, ``"Project"``, and ``"Design"``. The default is ``None``, in which case the "Error" message gets added to the ``"Design"`` @@ -1557,12 +1643,12 @@ def add_error_message(self, message_text, message_type=None): DeprecationWarning, ) - if message_type.lower() == "project": - self.logger.project_logger.error(message_text) - elif message_type.lower() == "design": - self.logger.design_logger.error(message_text) + if level.lower() == "project": + self.logger.project_logger.error(text) + elif level.lower() == "design": + self.logger.design_logger.error(text) else: - self.logger.error(message_text) + self.logger.error(text) return True @property @@ -1633,15 +1719,15 @@ def set_license_type(self, license_type="Pool"): except Exception: return False - @pyaedt_function_handler() - def set_registry_key(self, key_full_name, key_value): + @pyaedt_function_handler(key_full_name="name", key_value="value") + def set_registry_key(self, name, value): """Change a specific registry key to a new value. Parameters ---------- - key_full_name : str + name : str Full name of the AEDT registry key. - key_value : str, int + value : str, int Value for the AEDT registry key. Returns ------- @@ -1654,33 +1740,33 @@ def set_registry_key(self, key_full_name, key_value): >>> oDesktop.SetRegistryString >>> oDesktop.SetRegistryInt """ - if isinstance(key_value, str): + if isinstance(value, str): try: - self.odesktop.SetRegistryString(key_full_name, key_value) - self.logger.info("Key %s correctly changed.", key_full_name) + self.odesktop.SetRegistryString(name, value) + self.logger.info("Key %s correctly changed.", name) return True except Exception: - self.logger.warning("Error setting up Key %s.", key_full_name) + self.logger.warning("Error setting up Key %s.", name) return False - elif isinstance(key_value, int): + elif isinstance(value, int): try: - self.odesktop.SetRegistryInt(key_full_name, key_value) - self.logger.info("Key %s correctly changed.", key_full_name) + self.odesktop.SetRegistryInt(name, value) + self.logger.info("Key %s correctly changed.", name) return True except Exception: - self.logger.warning("Error setting up Key %s.", key_full_name) + self.logger.warning("Error setting up Key %s.", name) return False else: self.logger.warning("Key value must be an integer or string.") return False - @pyaedt_function_handler() - def get_registry_key_string(self, key_full_name): + @pyaedt_function_handler(key_full_name="name") + def get_registry_key_string(self, name): """Get the value for the AEDT registry key if one exists. Parameters ---------- - key_full_name : str + name : str Full name of the AEDT registry key. Returns @@ -1693,15 +1779,15 @@ def get_registry_key_string(self, key_full_name): >>> oDesktop.GetRegistryString """ - return self.odesktop.GetRegistryString(key_full_name) + return self.odesktop.GetRegistryString(name) - @pyaedt_function_handler() - def get_registry_key_int(self, key_full_name): + @pyaedt_function_handler(key_full_name="name") + def get_registry_key_int(self, name): """Get the value for the AEDT registry key if one exists. Parameters ---------- - key_full_name : str + name : str Full name of the AEDT registry key. Returns @@ -1714,15 +1800,15 @@ def get_registry_key_int(self, key_full_name): >>> oDesktop.GetRegistryInt """ - return self.odesktop.GetRegistryInt(key_full_name) + return self.odesktop.GetRegistryInt(name) - @pyaedt_function_handler() - def check_beta_option_enabled(self, beta_option_name): + @pyaedt_function_handler(beta_option_name="beta_option") + def check_beta_option_enabled(self, beta_option): """Check if a beta option is enabled. Parameters ---------- - beta_option_name : str + beta_option : str Name of the beta option to check. For example, ``'SF43060_HFSS_PI'``. Returns @@ -1739,7 +1825,7 @@ def check_beta_option_enabled(self, beta_option_name): i = 0 while limit > 0: a = self.get_registry_key_string("Desktop/Settings/ProjectOptions/EnabledBetaOptions/Item{}".format(i)) - if a and a == beta_option_name: + if a and a == beta_option: return True elif a: i += 1 @@ -1904,19 +1990,19 @@ def _optimetrics_variable_args( arg3 = [tab, ["NAME:PropServers", propserver], ["NAME:ChangedProps", ["NAME:" + variable_name, arg2]]] arg.append(arg3) - @pyaedt_function_handler() + @pyaedt_function_handler(variable_name="name", min_val="minimum", max_val="maximum") def activate_variable_statistical( - self, variable_name, min_val=None, max_val=None, tolerance=None, probability=None, mean=None + self, name, minimum=None, maximum=None, tolerance=None, probability=None, mean=None ): """Activate statitistical analysis for a variable and optionally set up ranges. Parameters ---------- - variable_name : str + name : str Name of the variable. - min_val : optional + minimum : optional Minimum value for the variable. The default is ``None``. - max_val : optional + maximum : optional Maximum value for the variable. The default is ``None``. tolerance : optional Tolerance value for the variable. The default is ``None``. @@ -1936,26 +2022,24 @@ def activate_variable_statistical( >>> oDesign.ChangeProperty """ arg = ["NAME:AllTabs"] - self._optimetrics_variable_args( - arg, "Statistical", variable_name, min_val, max_val, tolerance, probability, mean - ) - if "$" in variable_name: + self._optimetrics_variable_args(arg, "Statistical", name, minimum, maximum, tolerance, probability, mean) + if "$" in name: self.oproject.ChangeProperty(arg) else: self.odesign.ChangeProperty(arg) return True - @pyaedt_function_handler() - def activate_variable_optimization(self, variable_name, min_val=None, max_val=None): + @pyaedt_function_handler(variable_name="name", min_val="minimum", max_val="maximum") + def activate_variable_optimization(self, name, minimum=None, maximum=None): """Activate optimization analysis for a variable and optionally set up ranges. Parameters ---------- - variable_name : str + name : str Name of the variable. - min_val : optional + minimum : optional Minimum value for the variable. The default is ``None``. - max_val : optional + maximum : optional Maximum value for the variable. The default is ``None``. Returns @@ -1969,24 +2053,24 @@ def activate_variable_optimization(self, variable_name, min_val=None, max_val=No >>> oDesign.ChangeProperty """ arg = ["NAME:AllTabs"] - self._optimetrics_variable_args(arg, "Optimization", variable_name, min_val, max_val) - if variable_name.startswith("$"): + self._optimetrics_variable_args(arg, "Optimization", name, minimum, maximum) + if name.startswith("$"): self.oproject.ChangeProperty(arg) else: self.odesign.ChangeProperty(arg) return True - @pyaedt_function_handler() - def activate_variable_sensitivity(self, variable_name, min_val=None, max_val=None): + @pyaedt_function_handler(variable_name="name", min_val="minimum", max_val="maximum") + def activate_variable_sensitivity(self, name, minimum=None, maximum=None): """Activate sensitivity analysis for a variable and optionally set up ranges. Parameters ---------- - variable_name : str + name : str Name of the variable. - min_val : optional + minimum : optional Minimum value for the variable. The default is ``None``. - max_val : optional + maximum : optional Maximum value for the variable. The default is ``None``. Returns @@ -2000,24 +2084,24 @@ def activate_variable_sensitivity(self, variable_name, min_val=None, max_val=Non >>> oDesign.ChangeProperty """ arg = ["NAME:AllTabs"] - self._optimetrics_variable_args(arg, "Sensitivity", variable_name, min_val, max_val) - if "$" in variable_name: + self._optimetrics_variable_args(arg, "Sensitivity", name, minimum, maximum) + if "$" in name: self.oproject.ChangeProperty(arg) else: self.odesign.ChangeProperty(arg) return True - @pyaedt_function_handler() - def activate_variable_tuning(self, variable_name, min_val=None, max_val=None): + @pyaedt_function_handler(variable_name="name", min_val="minimum", max_val="maximum") + def activate_variable_tuning(self, name, minimum=None, maximum=None): """Activate tuning analysis for a variable and optionally set up ranges. Parameters ---------- - variable_name : str + name : str Name of the variable. - min_val : optional + minimum : optional Minimum value for the variable. The default is ``None``. - max_val : optional + maximum : optional Maximum value for the variable. The default is ``None``. Returns @@ -2031,20 +2115,20 @@ def activate_variable_tuning(self, variable_name, min_val=None, max_val=None): >>> oDesign.ChangeProperty """ arg = ["NAME:AllTabs"] - self._optimetrics_variable_args(arg, "Tuning", variable_name, min_val, max_val) - if "$" in variable_name: + self._optimetrics_variable_args(arg, "Tuning", name, minimum, maximum) + if "$" in name: self.oproject.ChangeProperty(arg) else: self.odesign.ChangeProperty(arg) return True - @pyaedt_function_handler() - def deactivate_variable_statistical(self, variable_name): + @pyaedt_function_handler(variable_name="name") + def deactivate_variable_statistical(self, name): """Deactivate the statistical analysis for a variable. Parameters ---------- - variable_name : str + name : str Name of the variable. Returns @@ -2058,20 +2142,20 @@ def deactivate_variable_statistical(self, variable_name): >>> oDesign.ChangeProperty """ arg = ["NAME:AllTabs"] - self._optimetrics_variable_args(arg, "Statistical", variable_name, enable=False) - if "$" in variable_name: + self._optimetrics_variable_args(arg, "Statistical", name, enable=False) + if "$" in name: self.oproject.ChangeProperty(arg) else: self.odesign.ChangeProperty(arg) return True - @pyaedt_function_handler() - def deactivate_variable_optimization(self, variable_name): + @pyaedt_function_handler(variable_name="name") + def deactivate_variable_optimization(self, name): """Deactivate the optimization analysis for a variable. Parameters ---------- - variable_name : str + name : str Name of the variable. Returns @@ -2085,20 +2169,20 @@ def deactivate_variable_optimization(self, variable_name): >>> oDesign.ChangeProperty """ arg = ["NAME:AllTabs"] - self._optimetrics_variable_args(arg, "Optimization", variable_name, enable=False) - if "$" in variable_name: + self._optimetrics_variable_args(arg, "Optimization", name, enable=False) + if "$" in name: self.oproject.ChangeProperty(arg) else: self.odesign.ChangeProperty(arg) return True - @pyaedt_function_handler() - def deactivate_variable_sensitivity(self, variable_name): + @pyaedt_function_handler(variable_name="name") + def deactivate_variable_sensitivity(self, name): """Deactivate the sensitivity analysis for a variable. Parameters ---------- - variable_name : str + name : str Name of the variable. Returns @@ -2112,20 +2196,20 @@ def deactivate_variable_sensitivity(self, variable_name): >>> oDesign.ChangeProperty """ arg = ["NAME:AllTabs"] - self._optimetrics_variable_args(arg, "Sensitivity", variable_name, enable=False) - if "$" in variable_name: + self._optimetrics_variable_args(arg, "Sensitivity", name, enable=False) + if "$" in name: self.oproject.ChangeProperty(arg) else: self.odesign.ChangeProperty(arg) return True - @pyaedt_function_handler() - def deactivate_variable_tuning(self, variable_name): + @pyaedt_function_handler(variable_name="name") + def deactivate_variable_tuning(self, name): """Deactivate the tuning analysis for a variable. Parameters ---------- - variable_name : str + name : str Name of the variable. Returns @@ -2139,20 +2223,20 @@ def deactivate_variable_tuning(self, variable_name): >>> oDesign.ChangeProperty """ arg = ["NAME:AllTabs"] - self._optimetrics_variable_args(arg, "Tuning", variable_name, enable=False) - if "$" in variable_name: + self._optimetrics_variable_args(arg, "Tuning", name, enable=False) + if "$" in name: self.oproject.ChangeProperty(arg) else: self.odesign.ChangeProperty(arg) return True - @pyaedt_function_handler - def hidden_variable(self, variable_name, value=True): + @pyaedt_function_handler(variable_name="name") + def hidden_variable(self, name, value=True): """Set the variable to a hidden or unhidden variable. Parameters ---------- - variable_name : str or list + name : str or list One or more variable names. value : bool, optional Whether to hide the variable. The default is ``True``, in which case the variable @@ -2173,16 +2257,14 @@ def hidden_variable(self, variable_name, value=True): >>> from pyaedt import Hfss >>> hfss = Hfss() >>> hfss["my_hidden_leaf"] = "15mm" - >>> hfss.hidden_variable("my_hidden_leaf", True) - + >>> hfss.hidden_variable("my_hidden_leaf",True) """ - - if not isinstance(variable_name, list): - self.variable_manager[variable_name].hidden = value + if not isinstance(name, list): + self.variable_manager[name].hidden = value else: design_variables = ["NAME:ChangedProps"] project_variables = ["NAME:ChangedProps"] - for name in variable_name: + for name in name: if name in self.variable_manager.design_variable_names: design_variables.append(["NAME:" + name, "Hidden:=", value]) elif name in self.variable_manager.project_variable_names: @@ -2202,13 +2284,13 @@ def hidden_variable(self, variable_name, value=True): self.oproject.ChangeProperty(command) return True - @pyaedt_function_handler - def read_only_variable(self, variable_name, value=True): + @pyaedt_function_handler(variable_name="name") + def read_only_variable(self, name, value=True): """Set the variable to a read-only or not read-only variable. Parameters ---------- - variable_name : str + name : str Name of the variable. value : bool, optional Whether the variable is read-only. The default is ``True``, in which case @@ -2230,9 +2312,8 @@ def read_only_variable(self, variable_name, value=True): >>> hfss = Hfss() >>> hfss["my_read_only_variable"] = "15mm" >>> hfss.make_read_only_variable("my_read_only_variable") - """ - self.variable_manager[variable_name].read_only = value + self.variable_manager[name].read_only = value return True @pyaedt_function_handler() @@ -2468,8 +2549,8 @@ def release_desktop(self, close_projects=True, close_desktop=True): gc.collect() return True - @pyaedt_function_handler() - def generate_temp_project_directory(self, subdir_name): + @pyaedt_function_handler(subdir_name="name") + def generate_temp_project_directory(self, name): """Generate a unique directory string to save a project to. This method creates a directory for storage of a project in the ``temp`` directory @@ -2479,7 +2560,7 @@ def generate_temp_project_directory(self, subdir_name): Parameters ---------- - subdir_name : str + name : str Base name of the subdirectory to create in the ``temp`` directory. Returns @@ -2495,10 +2576,10 @@ def generate_temp_project_directory(self, subdir_name): """ base_path = self.temp_directory - if not isinstance(subdir_name, str): + if not isinstance(name, str): self.logger.error("Input argument 'subdir' must be a string") return False - dir_name = generate_unique_name(subdir_name) + dir_name = generate_unique_name(name) project_dir = os.path.join(base_path, dir_name) try: if not os.path.exists(project_dir): @@ -2507,19 +2588,24 @@ def generate_temp_project_directory(self, subdir_name): except OSError: return False - @pyaedt_function_handler() - def load_project(self, project_file, design_name=None, close_active_proj=False, save_active_project=False): + @pyaedt_function_handler( + project_file="file_name", + design_name="design", + close_active_proj="close_active", + save_active_project="set_active", + ) + def load_project(self, file_name, design=None, close_active=False, set_active=False): """Open an AEDT project based on a project and optional design. Parameters ---------- - project_file : str - Full path and name for the project. - design_name : str, optional + file_name : str + Full path of the project to load. + design : str, optional Design name. The default is ``None``. - close_active_proj : bool, optional + close_active : bool, optional Whether to close the active project. The default is ``False``. - save_active_project : bool, optional + set_active : bool, optional Whether to save the active project. The default is ``False``. Returns @@ -2532,12 +2618,12 @@ def load_project(self, project_file, design_name=None, close_active_proj=False, >>> oDesktop.OpenProject """ - proj = self.odesktop.OpenProject(project_file) - if close_active_proj and self.oproject: + proj = self.odesktop.OpenProject(file_name) + if close_active and self.oproject: self._close_edb() - self.close_project(self.project_name, save_project=save_active_project) + self.close_project(self.project_name, save=set_active) if proj: - self._init_design(project_name=proj.GetName(), design_name=design_name) + self._init_design(project_name=proj.GetName(), design_name=design) return True else: return False @@ -2548,22 +2634,24 @@ def _close_edb(self): if self.modeler and self.modeler._edb: self.modeler._edb.close_edb() - @pyaedt_function_handler() - def create_dataset1d_design(self, dsname, xlist, ylist, xunit="", yunit=""): + @pyaedt_function_handler(dsname="name", xlist="x", ylist="y", xunit="x_unit", yunit="y_unit") + def create_dataset1d_design(self, name, x, y, x_unit="", y_unit="", sort=True): """Create a design dataset. Parameters ---------- - dsname : str + name : str Name of the dataset (without a prefix for a project dataset). - xlist : list + x : list List of X-axis values for the dataset. - ylist : list + y : list List of Y-axis values for the dataset. - xunit : str, optional + x_unit : str, optional Units for the X axis. The default is ``""``. - yunit : str, optional + y_unit : str, optional Units for the Y axis. The default is ``""``. + sort : bool, optional + Sort dataset. The default is ``True``. Returns ------- @@ -2575,24 +2663,26 @@ def create_dataset1d_design(self, dsname, xlist, ylist, xunit="", yunit=""): >>> oProject.AddDataset >>> oDesign.AddDataset """ - return self.create_dataset(dsname, xlist, ylist, is_project_dataset=False, xunit=xunit, yunit=yunit) + return self.create_dataset(name, x, y, is_project_dataset=False, x_unit=x_unit, y_unit=y_unit, sort=sort) - @pyaedt_function_handler() - def create_dataset1d_project(self, dsname, xlist, ylist, xunit="", yunit=""): + @pyaedt_function_handler(dsname="name", xlist="x", ylist="y", xunit="x_unit", yunit="y_unit") + def create_dataset1d_project(self, name, x, y, x_unit="", y_unit="", sort=True): """Create a project dataset. Parameters ---------- - dsname : str + name : str Name of dataset (without a prefix for a project dataset). - xlist : list + x : list List of X-axis values for the dataset. - ylist : list + y : list List of Y-axis values for the dataset. - xunit : str, optional + x_unit : str, optional Units for the X axis. The default is ``""``. - yunit : str, optional + y_unit : str, optional Units for the Y axis. The default is ``""``. + sort : bool, optional + Sort dataset. The default is ``True``. Returns ------- @@ -2605,46 +2695,48 @@ def create_dataset1d_project(self, dsname, xlist, ylist, xunit="", yunit=""): >>> oProject.AddDataset >>> oDesign.AddDataset """ - return self.create_dataset(dsname, xlist, ylist, is_project_dataset=True, xunit=xunit, yunit=yunit) - - @pyaedt_function_handler() + return self.create_dataset(name, x, y, is_project_dataset=True, x_unit=x_unit, y_unit=y_unit, sort=sort) + + @pyaedt_function_handler( + dsname="name", + xlist="x", + ylist="y", + zlist="z", + vlist="v", + xunit="x_unit", + yunit="y_unit", + zunit="z_unit", + vunit="v_unit", + ) def create_dataset3d( - self, - dsname, - xlist, - ylist, - zlist=None, - vlist=None, - xunit="", - yunit="", - zunit="", - vunit="", - is_project_dataset=True, + self, name, x, y, z=None, v=None, x_unit="", y_unit="", z_unit="", v_unit="", is_project_dataset=True, sort=True ): """Create a 3D dataset. Parameters ---------- - dsname : str + name : str Name of the dataset (without a prefix for a project dataset). - xlist : list + x : list List of X-axis values for the dataset. - ylist : list + y : list List of Y-axis values for the dataset. - zylist : list, optional + z : list, optional List of Z-axis values for a 3D dataset only. The default is ``None``. - vylist : list, optional + v : list, optional List of V-axis values for a 3D dataset only. The default is ``None``. - xunit : str, optional + x_unit : str, optional Units for the X axis. The default is ``""``. - yunit : str, optional + y_unit : str, optional Units for the Y axis. The default is ``""``. - zunit : str, optional + z_unit : str, optional Units for the Z axis for a 3D dataset only. The default is ``""``. - vunit : str, optional + v_unit : str, optional Units for the V axis for a 3D dataset only. The default is ``""``. is_project_dataset : bool, optional Whether it is a project data set. The default is ``True``. + sort : bool, optional + Sort dataset. The default is ``True``. Returns ------- @@ -2656,37 +2748,40 @@ def create_dataset3d( >>> oDesign.AddDataset """ - if dsname[0] == "$": - dsname = dsname[1:] + if name[0] == "$": + name = name[1:] is_project_dataset = True if self.design_type != "Maxwell 3D" and self.design_type != "Icepak": is_project_dataset = True return self.create_dataset( - dsname=dsname, - xlist=xlist, - ylist=ylist, - zlist=zlist, - vlist=vlist, - xunit=xunit, - yunit=yunit, - zunit=zunit, - vunit=vunit, + name=name, + x=x, + y=y, + z=z, + v=v, is_project_dataset=is_project_dataset, + x_unit=x_unit, + y_unit=y_unit, + z_unit=z_unit, + v_unit=v_unit, + sort=sort, ) - @pyaedt_function_handler() - def import_dataset1d(self, filename, dsname=None, is_project_dataset=True): + @pyaedt_function_handler(filename="input_file", dsname="name") + def import_dataset1d(self, input_file, name=None, is_project_dataset=True, sort=True): """Import a 1D dataset. Parameters ---------- - filename : str + input_file : str Full path and name for the TAB file. - dsname : str, optional + name : str, optional Name of the dataset. The default is the file name. is_project_dataset : bool, optional Whether it is a project data set. The default is ``True``. + sort : bool, optional + Sort dataset. The default is ``True``. Returns ------- @@ -2698,7 +2793,7 @@ def import_dataset1d(self, filename, dsname=None, is_project_dataset=True): >>> oProject.AddDataset >>> oDesign.AddDataset """ - with open_file(filename, "r") as f: + with open_file(input_file, "r") as f: lines = f.read().splitlines() header = lines[0] points = lines[1:] @@ -2718,31 +2813,33 @@ def import_dataset1d(self, filename, dsname=None, is_project_dataset=True): xlist.append(float(item.split()[0])) ylist.append(float(item.split()[1])) - if not dsname: - dsname = os.path.basename(os.path.splitext(filename)[0]) + if not name: + name = os.path.basename(os.path.splitext(input_file)[0]) - if dsname[0] == "$": - dsname = dsname[1:] + if name[0] == "$": + name = name[1:] is_project_dataset = True return self.create_dataset( - dsname, xlist, ylist, is_project_dataset=is_project_dataset, xunit=units[0], yunit=units[1] + name, xlist, ylist, is_project_dataset=is_project_dataset, x_unit=units[0], y_unit=units[1], sort=sort ) - @pyaedt_function_handler() - def import_dataset3d(self, filename, dsname=None, encoding="utf-8-sig", is_project_dataset=True): + @pyaedt_function_handler(filename="input_file", dsname="name") + def import_dataset3d(self, input_file, name=None, encoding="utf-8-sig", is_project_dataset=True, sort=True): """Import a 3D dataset. Parameters ---------- - filename : str + input_file : str Full path and name for the tab/csv/xlsx file. - dsname : str, optional + name : str, optional Name of the dataset. The default is the file name. encoding : str, optional File encoding to be provided for csv. is_project_dataset : bool, optional Whether it is a project data set. The default is ``True``. + sort : bool, optional + Sort dataset. The default is ``True``. Returns ------- @@ -2753,8 +2850,8 @@ def import_dataset3d(self, filename, dsname=None, encoding="utf-8-sig", is_proje >>> oProject.AddDataset """ - index_of_dot = filename.rfind(".") - file_extension = filename[index_of_dot + 1 :] + index_of_dot = input_file.rfind(".") + file_extension = input_file[index_of_dot + 1 :] xlist = [] ylist = [] zlist = [] @@ -2762,7 +2859,7 @@ def import_dataset3d(self, filename, dsname=None, encoding="utf-8-sig", is_proje if file_extension == "xlsx": self.logger.warning("You need pandas and openpyxl library installed for reading excel files") - lines = read_xlsx(filename) + lines = read_xlsx(input_file) if list(lines): header = str([lines.columns[i] for i in range(len(lines.columns))]) xlist = list((lines.iloc[:, 0]).array) @@ -2774,7 +2871,7 @@ def import_dataset3d(self, filename, dsname=None, encoding="utf-8-sig", is_proje return False elif file_extension == "csv": - lines = read_csv(filename, encoding) + lines = read_csv(input_file, encoding) header = " ".join(lines[0]) for row in lines[1:]: xlist.append(float(row[0])) @@ -2783,7 +2880,7 @@ def import_dataset3d(self, filename, dsname=None, encoding="utf-8-sig", is_proje vlist.append(float(row[3])) elif file_extension == "tab": - lines = read_tab(filename) + lines = read_tab(input_file) header = lines[0] for item in lines[1:]: xlist.append(float(item.split()[0])) @@ -2800,66 +2897,69 @@ def import_dataset3d(self, filename, dsname=None, encoding="utf-8-sig", is_proje units[cont] = result.group(1) cont += 1 - if not dsname: - dsname = os.path.basename(os.path.splitext(filename)[0]) + if not name: + name = os.path.basename(os.path.splitext(input_file)[0]) - if dsname[0] == "$": - dsname = dsname[1:] + if name[0] == "$": + name = name[1:] is_project_dataset = True if self.design_type != "Maxwell 3D" and self.design_type != "Icepak": is_project_dataset = True return self.create_dataset( - dsname, + name, xlist, ylist, zlist, vlist, is_project_dataset=is_project_dataset, - xunit=units[0], - yunit=units[1], - zunit=units[2], - vunit=units[3], + x_unit=units[0], + y_unit=units[1], + z_unit=units[2], + v_unit=units[3], + sort=sort, ) - @pyaedt_function_handler() + @pyaedt_function_handler( + dsname="name", + xlist="x", + ylist="y", + zlist="z", + vlist="v", + xunit="x_unit", + yunit="y_unit", + zunit="z_unit", + vunit="v_unit", + ) def create_dataset( - self, - dsname, - xlist, - ylist, - zlist=None, - vlist=None, - is_project_dataset=True, - xunit="", - yunit="", - zunit="", - vunit="", + self, name, x, y, z=None, v=None, is_project_dataset=True, x_unit="", y_unit="", z_unit="", v_unit="", sort=True ): """Create a dataset. Parameters ---------- - dsname : str + name : str Name of the dataset (without a prefix for a project dataset). - xlist : list + x : list List of X-axis values for the dataset. - ylist : list + y : list List of Y-axis values for the dataset. - zlist : list, optional + z : list, optional List of Z-axis values for a 3D dataset only. The default is ``None``. - vlist : list, optional + v : list, optional List of V-axis values for a 3D dataset only. The default is ``None``. is_project_dataset : bool, optional Whether it is a project data set. The default is ``True``. - xunit : str, optional + x_unit : str, optional Units for the X axis. The default is ``""``. - yunit : str, optional + y_unit : str, optional Units for the Y axis. The default is ``""``. - zunit : str, optional + z_unit : str, optional Units for the Z axis for a 3D dataset only. The default is ``""``. - vunit : str, optional + v_unit : str, optional Units for the V axis for a 3D dataset only. The default is ``""``. + sort : bool, optional + Sort dataset. The default is ``True``. Returns ------- @@ -2872,19 +2972,19 @@ def create_dataset( >>> oProject.AddDataset >>> oDesign.AddDataset """ - if not self.dataset_exists(dsname, is_project_dataset): + if not self.dataset_exists(name, is_project_dataset): if is_project_dataset: - dsname = "$" + dsname - ds = DataSet(self, dsname, xlist, ylist, zlist, vlist, xunit, yunit, zunit, vunit) + name = "$" + name + ds = DataSet(self, name, x, y, z, v, x_unit, y_unit, z_unit, v_unit, sort) else: - self.logger.warning("Dataset %s already exists", dsname) + self.logger.warning("Dataset %s already exists", name) return False ds.create() if is_project_dataset: - self.project_datasets[dsname] = ds + self.project_datasets[name] = ds else: - self.design_datasets[dsname] = ds - self.logger.info("Dataset %s created successfully.", dsname) + self.design_datasets[name] = ds + self.logger.info("Dataset %s created successfully.", name) return ds @pyaedt_function_handler() @@ -3065,8 +3165,8 @@ def clean_proj_folder(self, directory=None, name=None): self.logger.info("Project Directory cleaned") return True - @pyaedt_function_handler() - def copy_project(self, path, dest): + @pyaedt_function_handler(path="destination", dest="name") + def copy_project(self, destination, name): """Copy the project to another destination. .. note:: @@ -3074,9 +3174,9 @@ def copy_project(self, path, dest): Parameters ---------- - path : str + destination : str Path to save a copy of the project to. - dest : + name : Name to give the project in the new destination. Returns @@ -3091,16 +3191,16 @@ def copy_project(self, path, dest): """ self.logger.info("Copy AEDT Project ") self.oproject.Save() - self.oproject.SaveAs(os.path.join(path, dest + ".aedt"), True) + self.oproject.SaveAs(os.path.join(destination, name + ".aedt"), True) return True - @pyaedt_function_handler() - def create_new_project(self, proj_name): + @pyaedt_function_handler(proj_name="name") + def create_new_project(self, name): """Create a project within AEDT. Parameters ---------- - proj_name : + name : Name of the project. Returns @@ -3114,14 +3214,14 @@ def create_new_project(self, proj_name): >>> oDesktop.NewProject """ self.logger.info("Creating new Project ") - prj = self.odesktop.NewProject(proj_name) + prj = self.odesktop.NewProject(name) prj_name = prj.GetName() self.oproject = prj_name self.odesign = None return True - @pyaedt_function_handler() - def close_project(self, name=None, save_project=True): + @pyaedt_function_handler(save_project="save") + def close_project(self, name=None, save=True): """Close an AEDT project. Parameters @@ -3129,7 +3229,7 @@ def close_project(self, name=None, save_project=True): name : str, optional Name of the project. The default is ``None``, in which case the active project is closed. - save_project : bool, optional + save : bool, optional Whether to save the project before closing it. The default is ``True``. @@ -3155,7 +3255,7 @@ def close_project(self, name=None, save_project=True): oproj = self.desktop_class.active_project(name) proj_path = oproj.GetPath() proj_file = os.path.join(proj_path, name + ".aedt") - if save_project: + if save: oproj.Save() if name == legacy_name: self._global_logger.remove_file_logger(name) @@ -3231,13 +3331,13 @@ def delete_design(self, name=None, fallback_design=None): self._odesign = None return True - @pyaedt_function_handler() - def delete_separator(self, separator_name): + @pyaedt_function_handler(separator_name="name") + def delete_separator(self, name): """Delete a separator from either the active project or a design. Parameters ---------- - separator_name : str + name : str Name of the separator. Returns @@ -3251,15 +3351,15 @@ def delete_separator(self, separator_name): >>> oProject.ChangeProperty >>> oDesign.ChangeProperty """ - return self._variable_manager.delete_separator(separator_name) + return self._variable_manager.delete_separator(name) - @pyaedt_function_handler() - def delete_variable(self, sVarName): + @pyaedt_function_handler(sVarName="name") + def delete_variable(self, name): """Delete a variable. Parameters ---------- - sVarName : + name : Name of the variable. References @@ -3268,7 +3368,7 @@ def delete_variable(self, sVarName): >>> oProject.ChangeProperty >>> oDesign.ChangeProperty """ - return self.variable_manager.delete_variable(sVarName) + return self.variable_manager.delete_variable(name) @pyaedt_function_handler() def delete_unused_variables(self): @@ -3281,15 +3381,15 @@ def delete_unused_variables(self): """ return self.variable_manager.delete_unused_variables() - @pyaedt_function_handler() - def insert_design(self, design_name=None, solution_type=None): + @pyaedt_function_handler(design_name="name") + def insert_design(self, name=None, solution_type=None): """Add a design of a specified type. The default design type is taken from the derived application class. Parameters ---------- - design_name : str, optional + name : str, optional Name of the design. The default is ``None``, in which case the default design name is ``Design<_index>``. If the given or default design name is in use, then an underscore and @@ -3312,7 +3412,7 @@ def insert_design(self, design_name=None, solution_type=None): self._close_edb() self._init_design( project_name=self.project_name if self.project_name else generate_unique_name("Project"), - design_name=design_name, + design_name=name, solution_type=solution_type if solution_type else self.solution_type, ) @@ -3400,15 +3500,15 @@ def _generate_unique_project_name(self): proj_name = "Project_" + uName + ".aedt" return proj_name - @pyaedt_function_handler() - def rename_design(self, new_name, save_after_duplicate=True): + @pyaedt_function_handler(new_name="name", save_after_duplicate="save") + def rename_design(self, name, save=True): """Rename the active design. Parameters ---------- - new_name : str + name : str New name of the design. - save_after_duplicate : bool, optional + save : bool, optional Save project after the duplication is completed. If ``False``, pyaedt objects like boundaries will not be available. @@ -3422,22 +3522,22 @@ def rename_design(self, new_name, save_after_duplicate=True): >>> oDesign.RenameDesignInstance """ - self._odesign.RenameDesignInstance(self.design_name, new_name) - if save_after_duplicate: + self._odesign.RenameDesignInstance(self.design_name, name) + if save: self.oproject.Save() self._project_dictionary = None return True - @pyaedt_function_handler() - def copy_design_from(self, project_fullname, design_name, save_project=True, set_active_design=True): + @pyaedt_function_handler(project_fullname="project", design_name="design") + def copy_design_from(self, project, design, save_project=True, set_active_design=True): """Copy a design from a project into the active project. Parameters ---------- - project_fullname : str + project : str Full path and name for the project containing the design to copy. The active design is maintained. - design_name : str + design : str Name of the design to copy into the active design. If a design with this name is already present in the destination project, AEDT automatically changes the name. @@ -3462,16 +3562,16 @@ def copy_design_from(self, project_fullname, design_name, save_project=True, set self.save_project() active_design = self.design_name # open the origin project - if os.path.exists(project_fullname): - proj_from = self.odesktop.OpenProject(project_fullname) + if os.path.exists(project): + proj_from = self.odesktop.OpenProject(project) proj_from_name = proj_from.GetName() else: return None # check if the requested design exists in the origin project - if design_name not in [x for i in list(proj_from.GetDesigns()) for x in (i.GetName(), i.GetName()[2:])]: + if design not in [x for i in list(proj_from.GetDesigns()) for x in (i.GetName(), i.GetName()[2:])]: return None # copy the source design - proj_from.CopyDesign(design_name) + proj_from.CopyDesign(design) # paste in the destination project and get the name self._oproject.Paste() new_designname = self.desktop_class.active_design(self._oproject, design_type=self.design_type).GetName() @@ -3491,8 +3591,8 @@ def copy_design_from(self, project_fullname, design_name, save_project=True, set # return the pasted design name return new_designname - @pyaedt_function_handler() - def duplicate_design(self, label, save_after_duplicate=True): + @pyaedt_function_handler(label="name") + def duplicate_design(self, name, save_after_duplicate=True): """Copy a design to a new name. The new name consists of the original @@ -3501,7 +3601,7 @@ def duplicate_design(self, label, save_after_duplicate=True): Parameters ---------- - label : str + name : str Name of the design to copy. save_after_duplicate : bool, optional Save project after the duplication is completed. If ``False``, pyaedt objects like boundaries will not be @@ -3518,15 +3618,14 @@ def duplicate_design(self, label, save_after_duplicate=True): >>> oProject.CopyDesign >>> oProject.Paste """ - active_design = self.design_name design_list = self.design_list self._oproject.CopyDesign(active_design) self._oproject.Paste() - newname = label + newname = name ind = 1 while newname in self.design_list: - newname = label + "_" + str(ind) + newname = name + "_" + str(ind) ind += 1 actual_name = [i for i in self.design_list if i not in design_list] self.odesign = actual_name[0] @@ -3538,13 +3637,13 @@ def duplicate_design(self, label, save_after_duplicate=True): self._project_dictionary = None return True - @pyaedt_function_handler() - def export_design_preview_to_jpg(self, filename): + @pyaedt_function_handler(filename="output_file") + def export_design_preview_to_jpg(self, output_file): """Export design preview image to a JPG file. Parameters ---------- - filename : str + output_file : str Full path and name for the JPG file. Returns @@ -3558,7 +3657,7 @@ def export_design_preview_to_jpg(self, filename): # is self.design_name guaranteed to be there? design_info = [design for design in design_info if design["DesignName"] == self.design_name][0] image_data_str = design_info["Image64"] - with open_file(filename, "wb") as f: + with open_file(output_file, "wb") as f: if sys.version_info.major == 2: bytestring = bytes(image_data_str).decode("base64") else: @@ -3566,17 +3665,19 @@ def export_design_preview_to_jpg(self, filename): f.write(bytestring) return True - @pyaedt_function_handler() - def export_variables_to_csv(self, filename, export_project=True, export_design=True): + @pyaedt_function_handler( + filename="output_file", export_project="export_project_variables", export_design="export_design_properties" + ) + def export_variables_to_csv(self, output_file, export_project_variables=True, export_design_properties=True): """Export design properties, project variables, or both to a CSV file. Parameters ---------- - filename : str + output_file : str Full path and name for the CSV file. - export_project : bool, optional + export_project_variables : bool, optional Whether to export project variables. The default is ``True``. - export_design : bool, optional + export_design_properties : bool, optional Whether to export design properties. The default is ``True``. @@ -3595,9 +3696,9 @@ def export_variables_to_csv(self, filename, export_project=True, export_design=T """ varnames = [] desnames = [] - if export_project: + if export_project_variables: varnames = self.oproject.GetProperties("ProjectVariableTab", "ProjectVariables") - if export_design: + if export_design_properties: desnames = self.odesign.GetProperties("LocalVariableTab", "LocalVariables") if self.design_type in ["HFSS 3D Layout Design", "Circuit Design"]: desnames.extend(self.odesign.GetProperties("DefinitionParameterTab", "LocalVariables")) @@ -3608,7 +3709,7 @@ def export_variables_to_csv(self, filename, export_project=True, export_design=T for el in desnames: value = self.odesign.GetVariableValue(el) list_full.append([el, value]) - return write_csv(filename, list_full) + return write_csv(output_file, list_full) @pyaedt_function_handler() def read_design_data(self): @@ -3625,17 +3726,17 @@ def read_design_data(self): design_data = json.load(fps) return design_data - @pyaedt_function_handler() - def save_project(self, project_file=None, overwrite=True, refresh_obj_ids_after_save=False): + @pyaedt_function_handler(project_file="file_name", refresh_obj_ids_after_save="refresh_ids") + def save_project(self, file_name=None, overwrite=True, refresh_ids=False): """Save the project and add a message. Parameters ---------- - project_file : str, optional + file_name : str, optional Full path and project name. The default is ````None``. overwrite : bool, optional Whether to overwrite the existing project. The default is ``True``. - refresh_obj_ids_after_save : bool, optional + refresh_ids : bool, optional Whether to refresh object IDs after saving the project. The default is ``False``. @@ -3650,14 +3751,14 @@ def save_project(self, project_file=None, overwrite=True, refresh_obj_ids_after_ >>> oProject.Save >>> oProject.SaveAs """ - if project_file and not os.path.exists(os.path.dirname(project_file)): - os.makedirs(os.path.dirname(project_file)) - elif project_file: - self.oproject.SaveAs(project_file, overwrite) + if file_name and not os.path.exists(os.path.dirname(file_name)): + os.makedirs(os.path.dirname(file_name)) + elif file_name: + self.oproject.SaveAs(file_name, overwrite) self._add_handler() else: self.oproject.Save() - if refresh_obj_ids_after_save: + if refresh_ids: self.modeler.refresh_all_ids() self.modeler._refresh_all_ids_from_aedt_file() self.mesh._refresh_mesh_operations() @@ -3665,27 +3766,28 @@ def save_project(self, project_file=None, overwrite=True, refresh_obj_ids_after_ self.logger.info(msg_text) return True - @pyaedt_function_handler() + @pyaedt_function_handler(project_file="project_path", additional_file_lists="additional_files") def archive_project( self, - project_file=None, + project_path=None, include_external_files=True, include_results_file=True, - additional_file_lists=[], + additional_files=None, notes="", ): """Archive the AEDT project and add a message. Parameters ---------- - project_file : str, optional + project_path : str, optional Full path and project name. The default is ``None``. include_external_files : bool, optional Whether to include external files in the archive. The default is ``True``. include_results_file : bool, optional Whether to include simulation results files in the archive. The default is ``True``. - additional_file_lists : list, optional - List of additional files to add to the archive. The default is ``[]``. + additional_files : list, optional + List of additional files to add to the archive. + The default is ``None`` in which case an empty list is set. notes : str, optional Simulation notes to add to the archive. The default is ``""``. @@ -3700,24 +3802,24 @@ def archive_project( >>> oProject.Save >>> oProject.SaveProjectArchive """ + additional_files = [] if additional_files is None else additional_files msg_text = "Saving {0} Project".format(self.project_name) self.logger.info(msg_text) - if not project_file: - project_file = os.path.join(self.project_path, self.project_name + ".aedtz") + if not project_path: + project_path = os.path.join(self.project_path, self.project_name + ".aedtz") self.oproject.Save() self.oproject.SaveProjectArchive( - project_file, include_external_files, include_results_file, additional_file_lists, notes + project_path, include_external_files, include_results_file, additional_files, notes ) - return True - @pyaedt_function_handler() - def delete_project(self, project_name): + @pyaedt_function_handler(project_name="name") + def delete_project(self, name): """Delete a project. Parameters ---------- - project_name : str + name : str Name of the project. Returns @@ -3730,9 +3832,9 @@ def delete_project(self, project_name): >>> oDesktop.DeleteProject """ - if self.project_name == project_name: + if self.project_name == name: raise ValueError("You cannot delete the active project.") - self.odesktop.DeleteProject(project_name) + self.odesktop.DeleteProject(name) return True @pyaedt_function_handler() @@ -3753,13 +3855,13 @@ def set_active_design(self, name): self._init_design(project_name=self.project_name, design_name=name) return True - @pyaedt_function_handler() - def validate_simple(self, logfile=None): + @pyaedt_function_handler(logfile="log_file") + def validate_simple(self, log_file=None): """Validate a design. Parameters ---------- - logfile : str, optional + log_file : str, optional Name of the log file to save validation information to. The default is ``None``. @@ -3773,18 +3875,18 @@ def validate_simple(self, logfile=None): >>> oDesign.ValidateDesign """ - if logfile: - return self._odesign.ValidateDesign(logfile) + if log_file: + return self._odesign.ValidateDesign(log_file) else: return self._odesign.ValidateDesign() - @pyaedt_function_handler() - def get_evaluated_value(self, variable_name, units=None): + @pyaedt_function_handler(variable_name="name") + def get_evaluated_value(self, name, units=None): """Retrieve the evaluated value of a design property or project variable in SI units if no unit is provided. Parameters ---------- - variable_name : str + name : str Name of the design property or project variable. units : str, optional Name of the unit to use for rescaling. The default is ``None``, @@ -3812,27 +3914,27 @@ def get_evaluated_value(self, variable_name, units=None): """ val = None var_obj = None - if "$" in variable_name: + if "$" in name: app = self._oproject - var_obj = self.get_oo_object(app, "Variables/{}".format(variable_name)) + var_obj = self.get_oo_object(app, "Variables/{}".format(name)) else: app = self._odesign if self.design_type in ["Circuit Design", "Twin Builder", "HFSS 3D Layout Design"]: - if variable_name in self.get_oo_name(app, "Instance:{}".format(self._odesign.GetName())): - var_obj = self.get_oo_object(app, "Instance:{}/{}".format(self._odesign.GetName(), variable_name)) - elif variable_name in self.get_oo_object(app, "DefinitionParameters").GetPropNames(): - val = self.get_oo_object(app, "DefinitionParameters").GetPropEvaluatedValue(variable_name) + if name in self.get_oo_name(app, "Instance:{}".format(self._odesign.GetName())): + var_obj = self.get_oo_object(app, "Instance:{}/{}".format(self._odesign.GetName(), name)) + elif name in self.get_oo_object(app, "DefinitionParameters").GetPropNames(): + val = self.get_oo_object(app, "DefinitionParameters").GetPropEvaluatedValue(name) else: - var_obj = self.get_oo_object(app, "Variables/{}".format(variable_name)) + var_obj = self.get_oo_object(app, "Variables/{}".format(name)) if var_obj: val = var_obj.GetPropValue("SIValue") elif not val: try: variation_string = self._odesign.GetNominalVariation() - val = self._odesign.GetVariationVariableValue(variation_string, variable_name) # pragma: no cover + val = self._odesign.GetVariationVariableValue(variation_string, name) # pragma: no cover except Exception: - val_units = app.GetVariableValue(variable_name) + val_units = app.GetVariableValue(name) val, original_units = decompose_variable_value(val_units) try: if original_units: @@ -3854,13 +3956,13 @@ def get_evaluated_value(self, variable_name, units=None): except (ValueError, KeyError, TypeError, AttributeError): # pragma: no cover return val - @pyaedt_function_handler() - def evaluate_expression(self, expression_string): + @pyaedt_function_handler(expression_string="expression") + def evaluate_expression(self, expression): """Evaluate a valid string expression and return the numerical value in SI units. Parameters ---------- - expression_string : str + expression : str A valid string expression for a design property or project variable. For example, ``"34mm*sqrt(2)"`` or ``"$G1*p2/34"``. @@ -3871,40 +3973,36 @@ def evaluate_expression(self, expression_string): """ # Set the value of an internal reserved design variable to the specified string - if expression_string in self._variable_manager.variables: - return self._variable_manager.variables[expression_string].value - elif "pwl" in str(expression_string): + if expression in self._variable_manager.variables: + return self._variable_manager.variables[expression].value + elif "pwl" in str(expression): for ds in self.project_datasets: - if ds in expression_string: - return expression_string + if ds in expression: + return expression for ds in self.design_datasets: - if ds in expression_string: - return expression_string + if ds in expression: + return expression try: - return float(expression_string) + return float(expression) except ValueError: pass try: variable_name = "pyaedt_evaluator" - if "$" in expression_string: + if "$" in expression: variable_name = "$pyaedt_evaluator" self._variable_manager.set_variable( - variable_name, - expression=expression_string, - readonly=True, - hidden=True, - description="Internal_Evaluator", + variable_name, expression=expression, read_only=True, hidden=True, description="Internal_Evaluator" ) eval_value = self._variable_manager.variables[variable_name].value # Extract the numeric value of the expression (in SI units!) self._variable_manager.delete_variable(variable_name) return eval_value except Exception: - self.logger.warning("Invalid string expression {}".format(expression_string)) - return expression_string + self.logger.warning("Invalid string expression {}".format(expression)) + return expression - @pyaedt_function_handler() - def design_variation(self, variation_string=None): + @pyaedt_function_handler(variation_string="variation") + def design_variation(self, variation=None): """Generate a string to specify a desired variation. This method converts an input string defining a desired solution variation into a valid @@ -3918,7 +4016,7 @@ def design_variation(self, variation_string=None): Parameters ---------- - variation_string : str, optional + variation : str, optional Variation string. For example, ``"p1=1mm"`` or ``"p2=3mm"``. Returns @@ -3932,12 +4030,12 @@ def design_variation(self, variation_string=None): >>> oDesign.GetNominalVariation """ nominal = self._odesign.GetNominalVariation() - if variation_string: + if variation: # decompose the nominal variation into a dictionary of name[value] nominal_dict = variation_string_to_dict(nominal) # decompose the desired variation into a dictionary of name[value] - var_dict = variation_string_to_dict(variation_string) + var_dict = variation_string_to_dict(variation) # set the values of the desired variation in the active design for key, value in var_dict.items(): @@ -3992,45 +4090,55 @@ def _check_design_consistency(self): consistent = self._check_solution_consistency() return consistent - @pyaedt_function_handler() - def add_from_toolkit(self, toolkit_object, draw=False, **kwargs): + @pyaedt_function_handler(toolkit_object="toolkit") + def add_from_toolkit(self, toolkit, draw=False, **kwargs): """Add a new toolkit to the current application. Parameters ---------- - toolkit_object : + toolkit : Application object from ``"ansys.aedt.toolkits"``. Returns ------- - - Application-created object.""" - app = toolkit_object(self, **kwargs) + Application-created object. + """ + app = toolkit(self, **kwargs) if draw: app.init_model() app.model_hfss() app.setup_hfss() return app - @pyaedt_function_handler() - def check_if_project_is_loaded(self, project_path): + @pyaedt_function_handler(project_path="input_file") + def check_if_project_is_loaded(self, input_file): """Check if a project path is already loaded in active Desktop. + Parameters + ---------- + input_file : str + Project path to check in active desktop. + Returns ------- str Project name if loaded in Desktop. """ for p in self.odesktop.GetProjects(): - if os.path.normpath(os.path.join(p.GetPath(), p.GetName()) + ".aedt") == os.path.normpath(project_path): + if os.path.normpath(os.path.join(p.GetPath(), p.GetName()) + ".aedt") == os.path.normpath(input_file): return p.GetName() return False - @pyaedt_function_handler - def set_temporary_directory(self, temp_dir_path): + @pyaedt_function_handler(temp_dir_path="path") + def set_temporary_directory(self, path): """Set temporary directory path. + Parameters + ---------- + path : str + Temporary directory path. + Returns ------- bool @@ -4041,7 +4149,7 @@ def set_temporary_directory(self, temp_dir_path): >>> oDesktop.SetTempDirectory() """ - self.odesktop.SetTempDirectory(temp_dir_path) + self.odesktop.SetTempDirectory(path) return True diff --git a/pyaedt/application/JobManager.py b/pyaedt/application/JobManager.py index 1277424e1f5..67f2777b570 100644 --- a/pyaedt/application/JobManager.py +++ b/pyaedt/application/JobManager.py @@ -1,3 +1,28 @@ +# -*- 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. + + def get_hpc_info(filename): """Retrieve HPC information. diff --git a/pyaedt/application/Variables.py b/pyaedt/application/Variables.py index ec3e31e5432..cf147a0570c 100644 --- a/pyaedt/application/Variables.py +++ b/pyaedt/application/Variables.py @@ -1,3 +1,27 @@ +# -*- 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. + """ This module contains these classes: `CSVDataset`, `DataSet`, `Expression`, `Variable`, and `VariableManager`. @@ -22,7 +46,6 @@ import types import warnings -from pyaedt import pyaedt_function_handler from pyaedt.generic.constants import AEDT_UNITS from pyaedt.generic.constants import SI_UNITS from pyaedt.generic.constants import _resolve_unit_system @@ -32,6 +55,7 @@ from pyaedt.generic.general_methods import is_array from pyaedt.generic.general_methods import is_number from pyaedt.generic.general_methods import open_file +from pyaedt.generic.general_methods import pyaedt_function_handler class CSVDataset: @@ -458,13 +482,13 @@ def variables(self): """ return self._variable_dict([self._odesign, self._oproject]) - @pyaedt_function_handler() - def decompose(self, variable_value): + @pyaedt_function_handler(variable_value="variable") + def decompose(self, variable): """Decompose a variable string to a floating with its unit. Parameters ---------- - variable_value : str + variable : str Returns ------- @@ -483,12 +507,12 @@ def decompose(self, variable_value): >>> print(hfss.variable_manager.decompose("v2")) >>> (6.0, 'N') """ - if variable_value in self.independent_variable_names: - val, unit = decompose_variable_value(self[variable_value].expression) - elif variable_value in self.dependent_variable_names: - val, unit = decompose_variable_value(self[variable_value].evaluated_value) + if variable in self.independent_variable_names: + val, unit = decompose_variable_value(self[variable].expression) + elif variable in self.dependent_variable_names: + val, unit = decompose_variable_value(self[variable].evaluated_value) else: - val, unit = decompose_variable_value(variable_value) + val, unit = decompose_variable_value(variable) return val, unit @property @@ -893,10 +917,15 @@ def _variable_dict(self, object_list, dependent=True, independent=True): vars_to_output[k] = v return vars_to_output - @pyaedt_function_handler() - def get_expression(self, variable_name): # TODO: Should be renamed to "evaluate" + @pyaedt_function_handler(variable_name="name") + def get_expression(self, name): # TODO: Should be renamed to "evaluate" """Retrieve the variable value of a project or design variable as a string. + Parameters + ---------- + name : str + Name of the expression. + References ---------- @@ -904,53 +933,53 @@ def get_expression(self, variable_name): # TODO: Should be renamed to "evaluate >>> oDesign.GetVariableValue """ invalid_names = ["CosimDefinition", "CoSimulator", "CoSimulator/Choices", "InstanceName", "ModelName"] - if variable_name not in invalid_names: + if name not in invalid_names: try: - return self.aedt_object(variable_name).GetVariableValue(variable_name) + return self.aedt_object(name).GetVariableValue(name) except Exception: return False else: return False - @pyaedt_function_handler() - def aedt_object(self, variable): + @pyaedt_function_handler(variable="name") + def aedt_object(self, name): """Retrieve an AEDT object. Parameters ---------- - variable : str - Name of the variable. + name : str + Name of the variable. """ - if variable[0] == "$": + if name[0] == "$": return self._oproject else: return self._odesign - @pyaedt_function_handler() + @pyaedt_function_handler(variable_name="name", readonly="read_only", postprocessing="is_post_processing") def set_variable( self, - variable_name, + name, expression=None, - readonly=False, + read_only=False, hidden=False, description=None, overwrite=True, - postprocessing=False, + is_post_processing=False, circuit_parameter=True, ): """Set the value of a design property or project variable. Parameters ---------- - variable_name : str + name : str Name of the design property or project variable (``$var``). If this variable does not exist, a new one is created and a value is set. expression : str Valid string expression within the AEDT design and project structure. For example, ``"3*cos(34deg)"``. - readonly : bool, optional + read_only : bool, optional Whether to set the design property or project variable to read-only. The default is ``False``. hidden : bool, optional @@ -963,7 +992,7 @@ def set_variable( Whether to overwrite an existing value for the design property or project variable. The default is ``False``, in which case this method is ignored. - postprocessing : bool, optional + is_post_processing : bool, optional Whether to define a postprocessing variable. The default is ``False``, in which case the variable is not used in postprocessing. circuit_parameter : bool, optional @@ -982,21 +1011,27 @@ def set_variable( Examples -------- + >>> from pyaedt import Maxwell3d + >>> aedtapp = Maxwell3d(specified_version="2024.1") + Set the value of design property ``p1`` to ``"10mm"``, creating the property if it does not already eixst. - >>> aedtapp.variable_manager.set_variable("p1", expression="10mm") + >>> aedtapp.variable_manager.set_variable("p1",expression="10mm") Set the value of design property ``p1`` to ``"20mm"`` only if the property does not already exist. - >>> aedtapp.variable_manager.set_variable("p1", expression="20mm", overwrite=False) + >>> aedtapp.variable_manager.set_variable("p1",expression="20mm",overwrite=False) Set the value of design property ``p2`` to ``"10mm"``, creating the property if it does not already exist. Also make it read-only and hidden and add a description. - >>> aedtapp.variable_manager.set_variable(variable_name="p2", expression="10mm", readonly=True, hidden=True, + >>> aedtapp.variable_manager.set_variable(name="p2", + ... expression="10mm", + ... read_only=True, + ... hidden=True, ... description="This is the description of this variable.") Set the value of the project variable ``$p1`` to ``"30mm"``, @@ -1005,23 +1040,23 @@ def set_variable( >>> aedtapp.variable_manager.set_variable["$p1"] == "30mm" """ - if variable_name in self._independent_variables: - del self._independent_variables[variable_name] - if variable_name in self._independent_design_variables: - del self._independent_design_variables[variable_name] - elif variable_name in self._independent_project_variables: - del self._independent_project_variables[variable_name] - elif variable_name in self._dependent_variables: - del self._dependent_variables[variable_name] - if variable_name in self._dependent_design_variables: - del self._dependent_design_variables[variable_name] - elif variable_name in self._dependent_project_variables: - del self._dependent_project_variables[variable_name] + if name in self._independent_variables: + del self._independent_variables[name] + if name in self._independent_design_variables: + del self._independent_design_variables[name] + elif name in self._independent_project_variables: + del self._independent_project_variables[name] + elif name in self._dependent_variables: + del self._dependent_variables[name] + if name in self._dependent_design_variables: + del self._dependent_design_variables[name] + elif name in self._dependent_project_variables: + del self._dependent_project_variables[name] if not description: description = "" - desktop_object = self.aedt_object(variable_name) - if variable_name.startswith("$"): + desktop_object = self.aedt_object(name) + if name.startswith("$"): tab_name = "ProjectVariableTab" prop_server = "ProjectVariables" else: @@ -1038,7 +1073,7 @@ def set_variable( prop_server = "Instance:{}".format(desktop_object.GetName()) prop_type = "VariableProp" - if postprocessing or "post" in variable_name.lower()[0:5]: + if is_post_processing or "post" in name.lower()[0:5]: prop_type = "PostProcessingVariableProp" if isinstance(expression, str): # Handle string type variable (including arbitrary expression)# Handle input type variable @@ -1056,12 +1091,12 @@ def set_variable( prop_type = "SeparatorProp" variable = "" try: - if self.delete_separator(variable_name): + if self.delete_separator(name): desktop_object.Undo() self._logger.clear_messages() return except Exception: - self._logger.debug("Something went wrong when deleting '{}'.".format(variable_name)) + self._logger.debug("Something went wrong when deleting '{}'.".format(name)) else: raise Exception("Unhandled input type to the design property or project variable.") # pragma: no cover @@ -1069,7 +1104,7 @@ def set_variable( var_list = self._get_var_list_from_aedt(desktop_object) lower_case_vars = [var_name.lower() for var_name in var_list] - if variable_name.lower() not in lower_case_vars: + if name.lower() not in lower_case_vars: try: desktop_object.ChangeProperty( [ @@ -1080,7 +1115,7 @@ def set_variable( [ "NAME:NewProps", [ - "NAME:" + variable_name, + "NAME:" + name, "PropType:=", prop_type, "UserDef:=", @@ -1090,7 +1125,7 @@ def set_variable( "Description:=", description, "ReadOnly:=", - readonly, + read_only, "Hidden:=", hidden, ], @@ -1110,13 +1145,13 @@ def set_variable( [ "NAME:ChangedProps", [ - "NAME:" + variable_name, + "NAME:" + name, "Value:=", variable, "Description:=", description, "ReadOnly:=", - readonly, + read_only, "Hidden:=", hidden, ], @@ -1134,13 +1169,13 @@ def set_variable( [ "NAME:ChangedProps", [ - "NAME:" + variable_name, + "NAME:" + name, "Value:=", variable, "Description:=", description, "ReadOnly:=", - readonly, + read_only, "Hidden:=", hidden, ], @@ -1151,17 +1186,17 @@ def set_variable( self._cleanup_variables() var_list = self._get_var_list_from_aedt(desktop_object) lower_case_vars = [var_name.lower() for var_name in var_list] - if variable_name.lower() not in lower_case_vars: + if name.lower() not in lower_case_vars: return False return True - @pyaedt_function_handler() - def delete_separator(self, separator_name): + @pyaedt_function_handler(separator_name="name") + def delete_separator(self, name): """Delete a separator from either the active project or design. Parameters ---------- - separator_name : str + name : str Value to use for the delimiter. Returns @@ -1187,7 +1222,7 @@ def delete_separator(self, separator_name): [ "NAME:{0}VariableTab".format(var_type), ["NAME:PropServers", "{0}Variables".format(var_type)], - ["NAME:DeletedProps", separator_name], + ["NAME:DeletedProps", name], ], ] ) @@ -1196,16 +1231,15 @@ def delete_separator(self, separator_name): self._logger.debug("Failed to change desktop object property.") return False - @pyaedt_function_handler() - def delete_variable(self, var_name): + @pyaedt_function_handler(var_name="name") + def delete_variable(self, name): """Delete a variable. Parameters ---------- - var_name : str + name : str Name of the variable. - Returns ------- bool @@ -1217,11 +1251,11 @@ def delete_variable(self, var_name): >>> oProject.ChangeProperty >>> oDesign.ChangeProperty """ - desktop_object = self.aedt_object(var_name) + desktop_object = self.aedt_object(name) var_type = "Project" if desktop_object == self._oproject else "Local" var_list = self._get_var_list_from_aedt(desktop_object) lower_case_vars = [var_name.lower() for var_name in var_list] - if var_name.lower() in lower_case_vars: + if name.lower() in lower_case_vars: try: desktop_object.ChangeProperty( [ @@ -1229,7 +1263,7 @@ def delete_variable(self, var_name): [ "NAME:{0}VariableTab".format(var_type), ["NAME:PropServers", "{0}Variables".format(var_type)], - ["NAME:DeletedProps", var_name], + ["NAME:DeletedProps", name], ], ] ) @@ -1240,40 +1274,39 @@ def delete_variable(self, var_name): return True return False - @pyaedt_function_handler() - def is_used(self, var_name): + @pyaedt_function_handler(var_name="name") + def is_used(self, name): """Find if a variable is used. Parameters ---------- - var_name : str + name : str Name of the variable. Returns ------- bool ``True`` when successful, ``False`` when failed. - """ used = False # Modeler for obj in self._app.modeler.objects.values(): - used = self._find_used_variable_history(obj.history(), var_name) + used = self._find_used_variable_history(obj.history(), name) if used: - self._logger.warning("{} used in modeler.".format(var_name)) + self._logger.warning("{} used in modeler.".format(name)) return used # Material for mat in self._app.materials.material_keys.values(): for _, v in mat._props.items(): - if isinstance(v, str) and var_name in re.findall("[$a-zA-Z0-9_]+", v): + if isinstance(v, str) and name in re.findall("[$a-zA-Z0-9_]+", v): used = True - self._logger.warning("{} used in the material: {}.".format(var_name, mat.name)) + self._logger.warning("{} used in the material: {}.".format(name, mat.name)) return used return used - @pyaedt_function_handler() - def is_used_variable(self, var_name): + @pyaedt_function_handler(var_name="name") + def is_used_variable(self, name): """Find if a variable is used. .. deprecated:: 0.7.4 @@ -1281,7 +1314,7 @@ def is_used_variable(self, var_name): Parameters ---------- - var_name : str + name : str Name of the variable. Returns @@ -1291,7 +1324,7 @@ def is_used_variable(self, var_name): """ warnings.warn("`is_used_variable` is deprecated. Use `is_used` method instead.", DeprecationWarning) - return self.is_used(var_name) + return self.is_used(name) def _find_used_variable_history(self, history, var_name): """Find if a variable is used. @@ -1463,11 +1496,11 @@ def _update_var(self): return self._app.variable_manager.set_variable( self._variable_name, self._expression, - readonly=self._readonly, - postprocessing=self._postprocessing, - circuit_parameter=self._circuit_parameter, - description=self._description, + read_only=self._readonly, hidden=self._hidden, + description=self._description, + is_post_processing=self._postprocessing, + circuit_parameter=self._circuit_parameter, ) return False @@ -2123,10 +2156,11 @@ class DataSet(object): Units for the Z axis for a 3D dataset only. The default is ``""``. vunit : str, optional Units for the V axis for a 3D dataset only. The default is ``""``. - + sort : bool, optional + Sort dataset. The default is ``True``. """ - def __init__(self, app, name, x, y, z=None, v=None, xunit="", yunit="", zunit="", vunit=""): + def __init__(self, app, name, x, y, z=None, v=None, xunit="", yunit="", zunit="", vunit="", sort=True): self._app = app self.name = name self.x = x @@ -2137,12 +2171,12 @@ def __init__(self, app, name, x, y, z=None, v=None, xunit="", yunit="", zunit="" self.yunit = yunit self.zunit = zunit self.vunit = vunit + self.sort = sort @pyaedt_function_handler() def _args(self): """Retrieve arguments.""" - arg = [] - arg.append("Name:" + self.name) + arg = ["Name:" + self.name] arg2 = ["Name:Coordinates"] if self.z is None: arg2.append(["NAME:DimUnits", self.xunit, self.yunit]) @@ -2150,16 +2184,25 @@ def _args(self): arg2.append(["NAME:DimUnits", self.xunit, self.yunit, self.zunit, self.vunit]) else: return False + z = {} + v = {} if self.z: - x, y, z, v = (list(t) for t in zip(*sorted(zip(self.x, self.y, self.z, self.v), key=lambda e: float(e[0])))) + if self.sort: + x, y, z, v = ( + list(t) for t in zip(*sorted(zip(self.x, self.y, self.z, self.v), key=lambda e: float(e[0]))) + ) + else: + x, y, z, v = (list(t) for t in zip(*zip(self.x, self.y, self.z, self.v))) else: - x, y = (list(t) for t in zip(*sorted(zip(self.x, self.y), key=lambda e: float(e[0])))) + if self.sort: + x, y = (list(t) for t in zip(*sorted(zip(self.x, self.y), key=lambda e: float(e[0])))) + else: + x, y = (list(t) for t in zip(*(zip(self.x, self.y)))) + ver = self._app._aedt_version for i in range(len(x)): if ver >= "2022.1": - arg3 = ["NAME:Point"] - arg3.append(float(x[i])) - arg3.append(float(y[i])) + arg3 = ["NAME:Point", float(x[i]), float(y[i])] if self.z: arg3.append(float(z[i])) arg3.append(float(v[i])) diff --git a/pyaedt/application/__init__.py b/pyaedt/application/__init__.py index e69de29bb2d..9c4476773da 100644 --- a/pyaedt/application/__init__.py +++ b/pyaedt/application/__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/pyaedt/application/aedt_objects.py b/pyaedt/application/aedt_objects.py index 81fad1bd4fc..eb26dfef1bd 100644 --- a/pyaedt/application/aedt_objects.py +++ b/pyaedt/application/aedt_objects.py @@ -1,10 +1,34 @@ +# -*- 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 sys import time -from pyaedt import is_linux -from pyaedt import pyaedt_function_handler -from pyaedt import settings from pyaedt.generic.desktop_sessions import _desktop_sessions +from pyaedt.generic.general_methods import is_linux +from pyaedt.generic.general_methods import pyaedt_function_handler +from pyaedt.generic.general_methods import settings class AedtObjects(object): diff --git a/pyaedt/application/analysis_hf.py b/pyaedt/application/analysis_hf.py index 1171624b856..d361b5ef3d0 100644 --- a/pyaedt/application/analysis_hf.py +++ b/pyaedt/application/analysis_hf.py @@ -1,3 +1,27 @@ +# -*- 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 pyaedt.generic.general_methods import pyaedt_function_handler diff --git a/pyaedt/application/design_solutions.py b/pyaedt/application/design_solutions.py index 8b0fa36aab9..af0e789d263 100644 --- a/pyaedt/application/design_solutions.py +++ b/pyaedt/application/design_solutions.py @@ -1,3 +1,27 @@ +# -*- 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 copy from pyaedt.aedt_logger import pyaedt_logger as logger diff --git a/pyaedt/circuit.py b/pyaedt/circuit.py index 82296a387d8..3b81392a75c 100644 --- a/pyaedt/circuit.py +++ b/pyaedt/circuit.py @@ -1,4 +1,27 @@ # -*- 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. + """This module contains the ``Circuit`` class.""" from __future__ import absolute_import # noreorder @@ -10,8 +33,6 @@ import shutil import time -from pyaedt import Hfss3dLayout -from pyaedt import settings from pyaedt.application.AnalysisNexxim import FieldAnalysisCircuit from pyaedt.application.analysis_hf import ScatteringMethods from pyaedt.generic import ibis_reader @@ -22,6 +43,8 @@ from pyaedt.generic.general_methods import is_linux from pyaedt.generic.general_methods import open_file from pyaedt.generic.general_methods import pyaedt_function_handler +from pyaedt.generic.settings import settings +from pyaedt.hfss3dlayout import Hfss3dLayout from pyaedt.modules.Boundary import CurrentSinSource from pyaedt.modules.Boundary import PowerIQSource from pyaedt.modules.Boundary import PowerSinSource @@ -37,23 +60,23 @@ class Circuit(FieldAnalysisCircuit, ScatteringMethods): Parameters ---------- - projectname : str, optional + project : str, optional Name of the project to select or the full path to the project or AEDTZ archive to open. The default is ``None``, in which case an attempt is made to get an active project. If no projects are present, an empty project is created. - designname : str, optional + design : str, optional Name of the design to select. The default is ``None``, in which case an attempt is made to get an active design. If no designs are present, an empty design is created. solution_type : str, optional Solution type to apply to the design. The default is ``None``, in which case the default type is applied. - setup_name : str, optional + setup : str, optional Name of the setup to use as the nominal. The default is ``None``, in which case the active setup is used or nothing is used. - specified_version : str, int, float, optional + version : str, int, float, optional Version of AEDT to use. The default is ``None``, in which case the active version or latest installed version is used. This parameter is ignored when Script is launched within AEDT. @@ -62,7 +85,7 @@ class Circuit(FieldAnalysisCircuit, ScatteringMethods): Whether to run AEDT in non-graphical mode. The default is ``False``, in which case AEDT is launched in graphical mode. This parameter is ignored when a script is launched within AEDT. - new_desktop_session : bool, optional + new_desktop : bool, optional Whether to launch an instance of AEDT in a new thread, even if another instance of the ``specified_version`` is active on the machine. The default is ``False``. This parameter is ignored when @@ -84,7 +107,11 @@ class Circuit(FieldAnalysisCircuit, ScatteringMethods): `"ansysedt.exe -grpcsrv portnum"`. aedt_process_id : int, optional Process ID for the instance of AEDT to point PyAEDT at. The default is - ``None``. This parameter is only used when ``new_desktop_session = False``. + ``None``. This parameter is only used when ``new_desktop = False``. + remove_lock : bool, optional + Whether to remove lock to project before opening it or not. + The default is ``False``, which means to not unlock + the existing project if needed and raise an exception. Examples -------- @@ -113,45 +140,54 @@ class Circuit(FieldAnalysisCircuit, ScatteringMethods): Create an instance of Circuit using the 2023 R2 version and open the specified project, which is ``"myfile.aedt"``. - >>> aedtapp = Circuit(specified_version=2023.2, projectname="myfile.aedt") + >>> aedtapp = Circuit(version=2023.2, project="myfile.aedt") Create an instance of Circuit using the 2023 R2 student version and open the specified project, which is named ``"myfile.aedt"``. - >>> hfss = Circuit(specified_version="2023.2", projectname="myfile.aedt", student_version=True) + >>> hfss = Circuit(version="2023.2", project="myfile.aedt", student_version=True) """ + @pyaedt_function_handler( + designname="design", + projectname="project", + specified_version="version", + setup_name="setup", + new_desktop_session="new_desktop", + ) def __init__( self, - projectname=None, - designname=None, + project=None, + design=None, solution_type=None, - setup_name=None, - specified_version=None, + setup=None, + version=None, non_graphical=False, - new_desktop_session=False, + new_desktop=False, close_on_exit=False, student_version=False, machine="", port=0, aedt_process_id=None, + remove_lock=False, ): FieldAnalysisCircuit.__init__( self, "Circuit Design", - projectname, - designname, + project, + design, solution_type, - setup_name, - specified_version, + setup, + version, non_graphical, - new_desktop_session, + new_desktop, close_on_exit, student_version, machine, port, aedt_process_id, + remove_lock=remove_lock, ) ScatteringMethods.__init__(self, self) self.onetwork_data_explorer = self._desktop.GetTool("NdExplorer") @@ -1620,7 +1656,7 @@ def import_edb_in_circuit(self, input_dir): active_project = hfss.desktop_class.active_project(self.project_name) active_project.Paste() hfss_3d_layout_model = self.modeler.schematic.add_subcircuit_3dlayout(hfss.design_name) - hfss.close_project(save_project=False) + hfss.close_project(save=False) return hfss_3d_layout_model @pyaedt_function_handler(touchstone="input_file") diff --git a/pyaedt/common_rpc.py b/pyaedt/common_rpc.py index b53a519c420..d5739c5bd3b 100644 --- a/pyaedt/common_rpc.py +++ b/pyaedt/common_rpc.py @@ -1,11 +1,35 @@ +# -*- 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 signal import sys import tempfile import time -from pyaedt import is_ironpython from pyaedt.aedt_logger import pyaedt_logger as logger +from pyaedt.generic.general_methods import is_ironpython from pyaedt.generic.settings import settings from pyaedt.misc import list_installed_ansysem @@ -252,7 +276,7 @@ def launch_server(port=18000, ansysem_path=None, non_graphical=False, threaded=T t.start() -def create_session(server_name, client_port=None, launch_aedt_on_server=False, aedt_port=None, non_graphical=True): +def create_session(server_name, client_port=None, launch_aedt_on_server=False, aedt_port=None, non_graphical=False): """ Connect to an existing AEDT server session and create a new client session from it. diff --git a/pyaedt/desktop.py b/pyaedt/desktop.py index 44191724188..df1412b993a 100644 --- a/pyaedt/desktop.py +++ b/pyaedt/desktop.py @@ -1,3 +1,27 @@ +# -*- 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. + """ This module contains the ``Desktop`` class. This module is used to initialize AEDT and the message manager for managing AEDT. @@ -22,12 +46,12 @@ import warnings from pyaedt import __version__ as pyaedt_version -from pyaedt import is_ironpython -from pyaedt import is_linux -from pyaedt import is_windows from pyaedt.aedt_logger import AedtLogger from pyaedt.aedt_logger import pyaedt_logger from pyaedt.generic.general_methods import generate_unique_name +from pyaedt.generic.general_methods import is_ironpython +from pyaedt.generic.general_methods import is_linux +from pyaedt.generic.general_methods import is_windows if is_linux: os.environ["ANS_NODEPCHECK"] = str(1) @@ -38,7 +62,6 @@ import subprocess from pyaedt import __version__ -from pyaedt import pyaedt_function_handler from pyaedt.generic.desktop_sessions import _desktop_sessions from pyaedt.generic.desktop_sessions import _edb_sessions from pyaedt.generic.general_methods import active_sessions @@ -48,6 +71,7 @@ from pyaedt.generic.general_methods import inside_desktop from pyaedt.generic.general_methods import is_ironpython from pyaedt.generic.general_methods import open_file +from pyaedt.generic.general_methods import pyaedt_function_handler from pyaedt.generic.settings import settings from pyaedt.misc import current_student_version from pyaedt.misc import current_version @@ -390,7 +414,7 @@ class Desktop(object): Parameters ---------- - specified_version : str, int, float, optional + version : str, int, float, optional Version of AEDT to use. The default is ``None``, in which case the active setup or latest installed version is used. Examples of input values are ``232``, ``23.2``,``2023.2``,``"2023.2"``. @@ -398,7 +422,7 @@ class Desktop(object): Whether to launch AEDT in non-graphical mode. The default is ``False``, in which case AEDT is launched in graphical mode. This parameter is ignored when a script is launched within AEDT. - new_desktop_session : bool, optional + new_desktop : bool, optional Whether to launch an instance of AEDT in a new thread, even if another instance of the ``specified_version`` is active on the machine. The default is ``True``. @@ -420,17 +444,17 @@ class Desktop(object): later. The remote server must be up and running with the command `"ansysedt.exe -grpcsrv portnum"`. aedt_process_id : int, optional Process ID for the instance of AEDT to point PyAEDT at. The default is - ``None``. This parameter is only used when ``new_desktop_session = False``. + ``None``. This parameter is only used when ``new_desktop = False``. Examples -------- Launch AEDT 2023 R1 in non-graphical mode and initialize HFSS. >>> import pyaedt - >>> desktop = pyaedt.Desktop(specified_version="2023.2", non_graphical=True) + >>> desktop = pyaedt.Desktop(version="2023.2", non_graphical=False) PyAEDT INFO: pyaedt v... PyAEDT INFO: Python version ... - >>> hfss = pyaedt.Hfss(designname="HFSSDesign1") + >>> hfss = pyaedt.Hfss(design="HFSSDesign1") PyAEDT INFO: Project... PyAEDT INFO: Added design 'HFSSDesign1' of type HFSS. @@ -439,7 +463,7 @@ class Desktop(object): >>> desktop = Desktop(232) PyAEDT INFO: pyaedt v... PyAEDT INFO: Python version ... - >>> hfss = pyaedt.Hfss(designname="HFSSDesign1") + >>> hfss = pyaedt.Hfss(design="HFSSDesign1") PyAEDT INFO: No project is defined. Project... """ @@ -448,14 +472,20 @@ class Desktop(object): def __new__(cls, *args, **kwargs): # The following commented lines will be useful when we will need to search among multiple saved desktop. - specified_version = kwargs.get("specified_version") or None if (not args or len(args) < 1) else args[0] - new_desktop_session = kwargs.get("new_desktop_session") or False if (not args or len(args) < 3) else args[2] + specified_version = ( + kwargs.get("specified_version") or kwargs.get("version") or None if (not args or len(args) < 1) else args[0] + ) + new_desktop = ( + kwargs.get("new_desktop_session") or kwargs.get("new_desktop") or False + if (not args or len(args) < 3) + else args[2] + ) # student_version = kwargs.get("student_version") or False if (not args or len(args)<5) else args[4] # machine = kwargs.get("machine") or "" if (not args or len(args)<6) else args[5] specified_version = get_string_version(specified_version) port = kwargs.get("port") or 0 if (not args or len(args) < 7) else args[6] aedt_process_id = kwargs.get("aedt_process_id") or None if (not args or len(args) < 8) else args[7] - if settings.use_multi_desktop and not inside_desktop and new_desktop_session: + if settings.use_multi_desktop and not inside_desktop and new_desktop: pyaedt_logger.info("Initializing new Desktop session.") return object.__new__(cls) elif len(_desktop_sessions.keys()) > 0: @@ -482,20 +512,23 @@ def __new__(cls, *args, **kwargs): pyaedt_logger.info("Initializing new Desktop session.") return object.__new__(cls) - @pyaedt_function_handler() + @pyaedt_function_handler( + specified_version="version", + new_desktop_session="new_desktop", + ) def __init__( self, - specified_version=None, + version=None, non_graphical=False, - new_desktop_session=True, + new_desktop=True, close_on_exit=True, student_version=False, machine="", port=0, aedt_process_id=None, ): - if _desktop_sessions and specified_version is None: - specified_version = list(_desktop_sessions.values())[-1].aedt_version_id + if _desktop_sessions and version is None: + version = list(_desktop_sessions.values())[-1].aedt_version_id if aedt_process_id: # pragma no cover aedt_process_id = int(aedt_process_id) if getattr(self, "_initialized", None) is not None and self._initialized: @@ -516,20 +549,20 @@ def __init__( self.launched_by_pyaedt = False # Used in unit tests. The ``PYAEDT_NON_GRAPHICAL`` environment variable overrides - # the ``non_graphical`` argument. + # the ``graphical`` argument. if os.getenv("PYAEDT_NON_GRAPHICAL", None) is not None: # pragma no cover non_graphical = os.getenv("PYAEDT_NON_GRAPHICAL", "false").lower() in ("true", "1", "t") # Used in Examples generation to force the desktop opening if os.getenv("PYAEDT_DOC_GENERATION", "False").lower() in ("true", "1", "t"): # pragma no cover - new_desktop_session = True + new_desktop = True # Used in toolkit scripts. The ``PYAEDT_SCRIPT_PROCESS_ID`` environment variable overrides # the ``aedt_process_id`` argument. if os.getenv("PYAEDT_SCRIPT_PROCESS_ID", None): # pragma no cover aedt_process_id = int(os.getenv("PYAEDT_SCRIPT_PROCESS_ID")) # Used in toolkit scripts. The ``PYAEDT_SCRIPT_VERSION`` environment variable overrides - # the ``specified_version`` argument. + # the ``version`` argument. if os.getenv("PYAEDT_SCRIPT_VERSION", None): # pragma no cover - specified_version = str(os.getenv("PYAEDT_SCRIPT_VERSION")) + version = str(os.getenv("PYAEDT_SCRIPT_VERSION")) self.close_on_exit = close_on_exit self.machine = machine @@ -557,7 +590,7 @@ def __init__( self._logger.info("Debug logger is enabled. PyAEDT methods will be logged.") else: self._logger.info("Debug logger is disabled. PyAEDT methods will not be logged.") - student_version_flag, version_key, version = self._assert_version(specified_version, student_version) + student_version_flag, version_key, version = self._assert_version(version, student_version) # start the AEDT opening decision tree # starting_mode can be one of these: "grpc", "com", "ironpython", "console_in", "console_out" @@ -573,10 +606,10 @@ def __init__( starting_mode = "grpc" elif is_ironpython: starting_mode = "ironpython" - elif aedt_process_id and not new_desktop_session and not is_ironpython: # pragma: no cover + elif aedt_process_id and not new_desktop and not is_ironpython: # pragma: no cover # connecting to an existing session has the precedence over use_grpc_api user preference sessions = active_sessions( - version=specified_version, student_version=student_version_flag, non_graphical=non_graphical + version=version, student_version=student_version_flag, non_graphical=non_graphical ) self.logger.info(sessions) if aedt_process_id in sessions: @@ -588,15 +621,15 @@ def __init__( else: raise ValueError( "The version specified ({}) doesn't correspond to the pid specified ({})".format( - specified_version, aedt_process_id + version, aedt_process_id ) ) elif float(version_key[0:6]) < 2022.2: # pragma no cover starting_mode = "com" - if non_graphical: + if self.non_graphical: self._logger.disable_desktop_log() elif float(version_key[0:6]) == 2022.2: # pragma no cover - if non_graphical: + if self.non_graphical: self._logger.disable_desktop_log() if self.machine and self.port: starting_mode = "grpc" # if the machine and port is specified, user wants to use gRPC @@ -627,12 +660,12 @@ def __init__( settings.aedt_version = version_key if starting_mode == "ironpython": # pragma no cover self._logger.info("Launching PyAEDT outside AEDT with IronPython.") - self._init_ironpython(non_graphical, new_desktop_session, version) + self._init_ironpython(non_graphical, new_desktop, version) elif starting_mode == "com": # pragma no cover self._logger.info("Launching PyAEDT outside AEDT with CPython and PythonNET.") self._init_dotnet( non_graphical, - new_desktop_session, + new_desktop, version, student_version_flag, version_key, @@ -640,7 +673,7 @@ def __init__( ) elif starting_mode == "grpc": self._logger.info("Launching PyAEDT outside AEDT with gRPC plugin.") - self._init_grpc(non_graphical, new_desktop_session, version, student_version_flag, version_key) + self._init_grpc(non_graphical, new_desktop, version, student_version_flag, version_key) self._set_logger_file() settings.enable_desktop_logs = not self.non_graphical @@ -650,7 +683,7 @@ def __init__( self._logger.info("Python version %s", sys.version) current_pid = int(self.odesktop.GetProcessID()) - if aedt_process_id and not new_desktop_session and aedt_process_id != current_pid: # pragma no cover + if aedt_process_id and not new_desktop and aedt_process_id != current_pid: # pragma no cover raise Exception( "AEDT started a new session instead of connecting to the session with pid: {}".format(aedt_process_id) ) @@ -1547,6 +1580,7 @@ def release_desktop(self, close_projects=True, close_on_exit=True): >>> desktop.release_desktop(close_projects=False, close_on_exit=False) # doctest: +SKIP """ + self.grpc_plugin.recreate_application(True) self.logger.oproject = None self.logger.odesign = None if os.getenv("PYAEDT_DOC_GENERATION", "False").lower() in ("true", "1", "t"): # pragma: no cover @@ -1559,7 +1593,7 @@ def release_desktop(self, close_projects=True, close_on_exit=True): except Exception: self.logger.warning("Failed to close Edb object.") - if close_projects: + if close_projects and "PYTEST_CURRENT_TEST" not in os.environ: projects = self.odesktop.GetProjectList() for project in projects: try: @@ -1577,7 +1611,8 @@ def release_desktop(self, close_projects=True, close_on_exit=True): self.logger.info("Desktop has been released and closed.") else: self.logger.info("Desktop has been released.") - del _desktop_sessions[self.aedt_process_id] + if self.aedt_process_id in _desktop_sessions: + del _desktop_sessions[self.aedt_process_id] props = [a for a in dir(self) if not a.startswith("__")] for a in props: self.__dict__.pop(a, None) @@ -1924,7 +1959,7 @@ def submit_ansys_cloud_job( -------- >>> from pyaedt import Desktop - >>> d = Desktop(specified_version="2023.1", new_desktop_session=False) + >>> d = Desktop(version="2023.1", new_desktop=False) >>> d.select_scheduler("Ansys Cloud") >>> out = d.get_available_cloud_config() >>> job_id, job_name = d.submit_ansys_cloud_job('via_gsg.aedt', @@ -2013,7 +2048,7 @@ def get_ansyscloud_job_info(self, job_id=None, job_name=None): # pragma: no cov -------- >>> from pyaedt import Desktop - >>> d = Desktop(specified_version="2023.1", new_desktop_session=False) + >>> d = Desktop(version="2023.1", new_desktop=False) >>> d.select_scheduler("Ansys Cloud") >>> out = d.get_available_cloud_config() >>> job_id, job_name = d.submit_ansys_cloud_job('via_gsg.aedt', @@ -2080,7 +2115,7 @@ def select_scheduler( -------- >>> from pyaedt import Desktop - >>> d = Desktop(specified_version="2023.1", new_desktop_session=False) + >>> d = Desktop(version="2023.1", new_desktop=False) >>> d.select_scheduler("Ansys Cloud") >>> out = d.get_available_cloud_config() >>> job_id, job_name = d.submit_ansys_cloud_job('via_gsg.aedt', @@ -2122,7 +2157,7 @@ def get_available_cloud_config(self, region="westeurope"): # pragma: no cover -------- >>> from pyaedt import Desktop - >>> d = Desktop(specified_version="2023.1", new_desktop_session=False) + >>> d = Desktop(version="2023.1", new_desktop=False) >>> d.select_scheduler("Ansys Cloud") >>> out = d.get_available_cloud_config() >>> job_id, job_name = d.submit_ansys_cloud_job('via_gsg.aedt', diff --git a/pyaedt/downloads.py b/pyaedt/downloads.py index bb85da981c5..6057dc170c6 100644 --- a/pyaedt/downloads.py +++ b/pyaedt/downloads.py @@ -1,3 +1,27 @@ +# -*- 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. + """Download example datasets from https://github.com/ansys/example-data""" import os diff --git a/pyaedt/edb.py b/pyaedt/edb.py index a3cc69fa28c..bbb9fc0d1b9 100644 --- a/pyaedt/edb.py +++ b/pyaedt/edb.py @@ -1,8 +1,140 @@ -from pyedb import Edb as App +# -*- 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 from pyaedt.generic.settings import settings log = settings.logger -log.warning("pyaedt.edb.Edb is Deprecated. Please use pyedb.Edb or pyaedt.Edb call instead") -Edb = App + +# lazy imports +def Edb( + edbpath=None, + cellname=None, + isreadonly=False, + edbversion=None, + isaedtowned=False, + oproject=None, + student_version=False, + use_ppe=False, + technology_file=None, +): + """Provides the EDB application interface. + + This module inherits all objects that belong to EDB. + + Parameters + ---------- + edbpath : str, optional + Full path to the ``aedb`` folder. The variable can also contain + the path to a layout to import. Allowed formats are BRD, + XML (IPC2581), GDS, and DXF. The default is ``None``. + For GDS import, the Ansys control file (also XML) should have the same + name as the GDS file. Only the file extension differs. + cellname : str, optional + Name of the cell to select. The default is ``None``. + isreadonly : bool, optional + Whether to open EBD in read-only mode when it is + owned by HFSS 3D Layout. The default is ``False``. + edbversion : str, optional + Version of EDB to use. The default is ``"2021.2"``. + isaedtowned : bool, optional + Whether to launch EDB from HFSS 3D Layout. The + default is ``False``. + oproject : optional + Reference to the AEDT project object. + student_version : bool, optional + Whether to open the AEDT student version. The default is ``False.`` + technology_file : str, optional + Full path to technology file to be converted to xml before importing or xml. Supported by GDS format only. + + Returns + ------- + :class:`pyedb.dotnet.edb.Edb`, :class:`pyedb.grpc.edb.Edb` + + Examples + -------- + Create an ``Edb`` object and a new EDB cell. + + >>> from pyedb import Edb + >>> app = Edb() + + Add a new variable named "s1" to the ``Edb`` instance. + + >>> app['s1'] = "0.25 mm" + >>> app['s1'].tofloat + >>> 0.00025 + >>> app['s1'].tostring + >>> "0.25mm" + + or add a new parameter with description: + + >>> app['s2'] = ["20um", "Spacing between traces"] + >>> app['s2'].value + >>> 1.9999999999999998e-05 + >>> app['s2'].description + >>> 'Spacing between traces' + + + Create an ``Edb`` object and open the specified project. + + >>> app = Edb("myfile.aedb") + + Create an ``Edb`` object from GDS and control files. + The XML control file resides in the same directory as the GDS file: (myfile.xml). + + >>> app = Edb("/path/to/file/myfile.gds") + + """ + + # Use EDB legacy (default choice) + if bool(os.getenv("PYEDB_USE_DOTNET", "1")): + from pyedb.dotnet.edb import Edb as app + + return app( + edbpath=edbpath, + cellname=cellname, + isreadonly=isreadonly, + edbversion=edbversion, + isaedtowned=isaedtowned, + oproject=oproject, + student_version=student_version, + use_ppe=use_ppe, + technology_file=technology_file, + ) + # TODO: Use EDB gRPC + else: + raise Exception("not implemented yet.") + + +def Siwave( + specified_version=None, +): + """Siwave Class.""" + from pyedb.siwave import Siwave as app + + return app( + specified_version=specified_version, + ) diff --git a/pyaedt/emit.py b/pyaedt/emit.py index f67e403be6e..a9c1accb876 100644 --- a/pyaedt/emit.py +++ b/pyaedt/emit.py @@ -1,3 +1,27 @@ +# -*- 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 __future__ import absolute_import import warnings @@ -17,19 +41,19 @@ class Emit(Design, object): Parameters ---------- - projectname : str, optional + project : str, optional Name of the project to select or the full path to the project or AEDTZ archive to open. The default is ``None``, in which case an attempt is made to get an active project. If no projects are present, an empty project is created. - designname : str, optional + design : str, optional Name of the design to select. The default is ``None``, in which case an attempt is made to get an active design. If no designs are present, an empty design is created. solution_type : str, optional Solution type to apply to the design. The default is ``None``, in which case the default type is applied. - specified_version : str, int, float, optional + version : str, int, float, optional Version of AEDT to use. The default is ``None``, in which case the active setup is used or the latest installed version is used. @@ -38,7 +62,7 @@ class Emit(Design, object): Whether to launch AEDT in non-graphical mode. The default is ``False``, in which case AEDT is launched in graphical mode. This parameter is ignored when a script is launched within AEDT. - new_desktop_session : bool, optional + new_desktop : bool, optional Whether to launch an instance of AEDT in a new thread, even if another instance of the ``specified_version`` is active on the machine. The default is ``False``. @@ -58,7 +82,11 @@ class Emit(Design, object): If the machine is `"localhost"`, the server starts if it is not present. aedt_process_id : int, optional Process ID for the instance of AEDT to point PyAEDT at. The default is - ``None``. This parameter is only used when ``new_desktop_session = False``. + ``None``. This parameter is only used when ``new_desktop = False``. + remove_lock : bool, optional + Whether to remove lock to project before opening it or not. + The default is ``False``, which means to not unlock + the existing project if needed and raise an exception. Examples -------- @@ -69,7 +97,7 @@ class Emit(Design, object): Typically, it is desirable to specify a project name, design name, and other parameters. - >>> aedtapp = Emit(projectname, designame, specified_version=232) + >>> aedtapp = Emit(projectname, designame, version=232) Once an ``Emit`` instance is initialized, you can edit the schematic: @@ -99,19 +127,27 @@ class Emit(Design, object): >>> print("Worst-case sensitivity for Rx '{}' is {}dB.".format(domain.rx_radio_name, val)) """ + @pyaedt_function_handler( + designname="design", + projectname="project", + specified_version="version", + setup_name="setup", + new_desktop_session="new_desktop", + ) def __init__( self, - projectname=None, - designname=None, + project=None, + design=None, solution_type=None, - specified_version=None, + version=None, non_graphical=False, - new_desktop_session=True, + new_desktop=True, close_on_exit=True, student_version=False, machine="", port=0, aedt_process_id=None, + remove_lock=False, ): self.__emit_api_enabled = False self.results = None @@ -123,17 +159,18 @@ def __init__( Design.__init__( self, "EMIT", - projectname, - designname, + project, + design, solution_type, - specified_version, + version, non_graphical, - new_desktop_session, + new_desktop, close_on_exit, student_version, machine=machine, port=port, aedt_process_id=aedt_process_id, + remove_lock=remove_lock, ) self._modeler = ModelerEmit(self) self._couplings = CouplingsEmit(self) diff --git a/pyaedt/emit_core/Couplings.py b/pyaedt/emit_core/Couplings.py index 918ad5f8874..2eee0ec58e4 100644 --- a/pyaedt/emit_core/Couplings.py +++ b/pyaedt/emit_core/Couplings.py @@ -1,3 +1,27 @@ +# -*- 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. + """ This module contains these classes: `CouplingsEmit`. This module provides for interacting with EMIT Analysis and Results windows. diff --git a/pyaedt/emit_core/__init__.py b/pyaedt/emit_core/__init__.py index 1a7b6de9744..c30f1f602b6 100644 --- a/pyaedt/emit_core/__init__.py +++ b/pyaedt/emit_core/__init__.py @@ -1,4 +1,27 @@ -import imp +# -*- 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 importlib import import_module import os import sys @@ -10,6 +33,13 @@ from pyaedt.emit_core.emit_constants import TxRxMode from pyaedt.emit_core.emit_constants import UnitType +# TODO: Remove once IronPython compatibility is removed +if sys.version_info < (3, 12): + import imp +else: # pragma: no cover + from importlib.util import find_spec + + EMIT_API_PYTHON = None @@ -69,8 +99,17 @@ def _set_api(aedt_version): if override_path_key in os.environ: path = os.environ.get(override_path_key) sys.path.insert(0, path) - module_path = imp.find_module("EmitApiPython")[1] - logger.info("Importing EmitApiPython from: {}".format(module_path)) + # TODO: Remove once IronPython compatibility is removed + if sys.version_info < (3, 12): + module_path = imp.find_module("EmitApiPython")[1] + logger.info("Importing EmitApiPython from: {}".format(module_path)) + else: # pragma: no cover + spec = find_spec("EmitApiPython") + if spec is None: + logger.warning("Module {} not found".format("EmitApiPython")) + else: + module_path = spec.origin + logger.info("Importing EmitApiPython from: {}".format(module_path)) global EMIT_API_PYTHON EMIT_API_PYTHON = import_module("EmitApiPython") logger.info("Loaded {}".format(EMIT_API_PYTHON.EmitApi().get_version(True))) diff --git a/pyaedt/emit_core/emit_constants.py b/pyaedt/emit_core/emit_constants.py index 90364082825..9c09566b676 100644 --- a/pyaedt/emit_core/emit_constants.py +++ b/pyaedt/emit_core/emit_constants.py @@ -1,3 +1,27 @@ +# -*- 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. + """ Enums from the ``EmitApiPython`` module are defined as ``None`` until this module initializes. This allows IDE auto-complete to find them and ``emit_constants`` to import before the diff --git a/pyaedt/emit_core/results/__init__.py b/pyaedt/emit_core/results/__init__.py index 8b137891791..9c4476773da 100644 --- a/pyaedt/emit_core/results/__init__.py +++ b/pyaedt/emit_core/results/__init__.py @@ -1 +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/pyaedt/emit_core/results/results.py b/pyaedt/emit_core/results/results.py index 5cc9d46b2f2..19b634523bf 100644 --- a/pyaedt/emit_core/results/results.py +++ b/pyaedt/emit_core/results/results.py @@ -1,3 +1,27 @@ +# -*- 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 warnings from pyaedt import emit_core diff --git a/pyaedt/emit_core/results/revision.py b/pyaedt/emit_core/results/revision.py index 86973012ac4..ce94aceb32d 100644 --- a/pyaedt/emit_core/results/revision.py +++ b/pyaedt/emit_core/results/revision.py @@ -1,3 +1,27 @@ +# -*- 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 warnings from pyaedt.emit_core.emit_constants import EmiCategoryFilter diff --git a/pyaedt/generic/DataHandlers.py b/pyaedt/generic/DataHandlers.py index 5312aa61439..19db10aac28 100644 --- a/pyaedt/generic/DataHandlers.py +++ b/pyaedt/generic/DataHandlers.py @@ -1,4 +1,27 @@ # -*- 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 collections import OrderedDict from decimal import Decimal import math @@ -596,7 +619,7 @@ def from_rkm_to_aedt(code): setup = os.getenv('setup') with Desktop() as d: - maxwell_2d = Maxwell2d(designname=design_name, name=setup) + maxwell_2d = Maxwell2d(design=design_name, name=setup) maxwell_2d.setup_ctrlprog(keep_modifications=True ) d.logger.info("Successfully updated project definitions") maxwell_2d.save_project() diff --git a/pyaedt/generic/LoadAEDTFile.py b/pyaedt/generic/LoadAEDTFile.py index b679456cb04..785f3307ada 100644 --- a/pyaedt/generic/LoadAEDTFile.py +++ b/pyaedt/generic/LoadAEDTFile.py @@ -1,4 +1,27 @@ # -*- 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.path import re diff --git a/pyaedt/generic/__init__.py b/pyaedt/generic/__init__.py index e69de29bb2d..9c4476773da 100644 --- a/pyaedt/generic/__init__.py +++ b/pyaedt/generic/__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/pyaedt/generic/clr_module.py b/pyaedt/generic/clr_module.py index 7564603c433..c331515755b 100644 --- a/pyaedt/generic/clr_module.py +++ b/pyaedt/generic/clr_module.py @@ -1,3 +1,27 @@ +# -*- 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 pkgutil import sys diff --git a/pyaedt/generic/com_parameters.py b/pyaedt/generic/com_parameters.py index e69de29bb2d..9c4476773da 100644 --- a/pyaedt/generic/com_parameters.py +++ b/pyaedt/generic/com_parameters.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/pyaedt/generic/compliance.py b/pyaedt/generic/compliance.py index 9f24c0012b1..27c702c74f5 100644 --- a/pyaedt/generic/compliance.py +++ b/pyaedt/generic/compliance.py @@ -1,3 +1,27 @@ +# -*- 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.path from pathlib import Path import time diff --git a/pyaedt/generic/configurations.py b/pyaedt/generic/configurations.py index 55349386ca4..351d0aa67cd 100644 --- a/pyaedt/generic/configurations.py +++ b/pyaedt/generic/configurations.py @@ -1,3 +1,27 @@ +# -*- 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 collections import OrderedDict import copy from datetime import datetime @@ -6,16 +30,14 @@ import tempfile import pyaedt -from pyaedt import Icepak from pyaedt import __version__ -from pyaedt import generate_unique_folder_name -from pyaedt import get_pyaedt_app -from pyaedt import is_ironpython from pyaedt.application.Variables import decompose_variable_value from pyaedt.generic.DataHandlers import _arg2dict from pyaedt.generic.LoadAEDTFile import load_keyword_in_aedt_file from pyaedt.generic.general_methods import GrpcApiError +from pyaedt.generic.general_methods import generate_unique_folder_name from pyaedt.generic.general_methods import generate_unique_name +from pyaedt.generic.general_methods import is_ironpython from pyaedt.generic.general_methods import open_file from pyaedt.generic.general_methods import pyaedt_function_handler from pyaedt.generic.general_methods import read_configuration_file @@ -1094,7 +1116,7 @@ def import_config(self, config_file, *args): self.results.import_variables = True try: for k, v in dict_in["general"]["postprocessing_variables"].items(): - self._app.variable_manager.set_variable(k, v, postprocessing=True) + self._app.variable_manager.set_variable(k, v, is_post_processing=True) except KeyError: self.results.import_postprocessing_variables = False else: @@ -1118,9 +1140,7 @@ def import_config(self, config_file, *args): if numcol > 2: zunit = val["Coordinates"]["DimUnits"][2] zval = new_list[2] - if not self._app.create_dataset( - el[1:], xunit=xunit, yunit=yunit, zunit=zunit, xlist=xval, ylist=yval, zlist=zval - ): + if not self._app.create_dataset(el[1:], x=xval, y=yval, z=zval, x_unit=xunit, y_unit=yunit): self.results.import_material_datasets = False if self.options.import_materials and dict_in.get("materials", None): @@ -1865,6 +1885,8 @@ def import_config(self, config_file, *args): @pyaedt_function_handler def _get_duplicate_names(self): # Copy project to get dictionary + from pyaedt.icepak import Icepak + directory = os.path.join( self._app.toolkit_directory, self._app.design_name, @@ -1872,7 +1894,7 @@ def _get_duplicate_names(self): ) os.makedirs(directory) tempproj_name = os.path.join(directory, "temp_proj.aedt") - tempproj = Icepak(tempproj_name, specified_version=self._app._aedt_version) + tempproj = Icepak(tempproj_name, version=self._app._aedt_version) empty_design = tempproj.design_list[0] self._app.modeler.refresh() self._app.modeler.delete( @@ -2090,6 +2112,8 @@ def apply_operations_to_native_components(obj, operation_dict, native_dict): # ]["DefnLink"]["Project"] not in [self._app.project_file or "This Project*"]: prj = list(set(self._app.project_list) - prj_list)[0] design = nc_dict["NativeComponentDefinitionProvider"]["DefnLink"]["Design"] + from pyaedt.generic.design_types import get_pyaedt_app + app = get_pyaedt_app(prj, design) app.oproject.Close() user_defined_component = UserDefinedComponent( diff --git a/pyaedt/generic/constants.py b/pyaedt/generic/constants.py index 854916e1640..33bcb86eda6 100644 --- a/pyaedt/generic/constants.py +++ b/pyaedt/generic/constants.py @@ -1,3 +1,27 @@ +# -*- 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 math import warnings diff --git a/pyaedt/generic/design_types.py b/pyaedt/generic/design_types.py index d63284d4b15..e54feb076b8 100644 --- a/pyaedt/generic/design_types.py +++ b/pyaedt/generic/design_types.py @@ -1,1557 +1,58 @@ -import re -import sys -import time - -from pyaedt import is_linux -from pyaedt.generic.settings import settings - - -# lazy imports -def Circuit( - projectname=None, - designname=None, - solution_type=None, - setup_name=None, - specified_version=None, - non_graphical=False, - new_desktop_session=False, - close_on_exit=False, - student_version=False, - machine="", - port=0, - aedt_process_id=None, -): - """Circuit Class. - - Parameters - ---------- - projectname : str, optional - Name of the project to select or the full path to the project - or AEDTZ archive to open. The default is ``None``, in which - case an attempt is made to get an active project. If no - projects are present, an empty project is created. - designname : str, optional - Name of the design to select. The default is ``None``, in - which case an attempt is made to get an active design. If no - designs are present, an empty design is created. - solution_type : str, optional - Solution type to apply to the design. The default is - ``None``, in which case the default type is applied. - setup_name : str, optional - Name of the setup to use as the nominal. The default is - ``None``, in which case the active setup is used or - nothing is used. - specified_version : str, int, float, optional - Version of AEDT to use. The default is ``None``, in which case - the active version or latest installed version is used. - This parameter is ignored when Script is launched within AEDT. - Examples of input values are ``232``, ``23.2``,``2023.2``,``"2023.2"``. - non_graphical : bool, optional - Whether to run AEDT in non-graphical mode. The default - is ``False``, in which case AEDT is launched in graphical mode. - This parameter is ignored when a script is launched within AEDT. - new_desktop_session : bool, optional - Whether to launch an instance of AEDT in a new thread, even if - another instance of the ``specified_version`` is active on the - machine. The default is ``False``. This parameter is ignored when - a script is launched within AEDT. - close_on_exit : bool, optional - Whether to release AEDT on exit. The default is ``False``. - student_version : bool, optional - Whether to open the AEDT student version. The default is ``False``. - This parameter is ignored when Script is launched within AEDT. - machine : str, optional - Machine name to which connect the oDesktop Session. Works only in 2022 R2 - or later. The remote server must be up and running with the command - `"ansysedt.exe -grpcsrv portnum"`. If a machine is `"localhost"`, the - server also starts if not present. - port : int, optional - Port number on which to start the oDesktop communication on an already existing server. - This parameter is ignored when creating a new server. It works only in 2022 R2 or - later. The remote server must be up and running with the command - `"ansysedt.exe -grpcsrv portnum"`. - aedt_process_id : int, optional - Process ID for the instance of AEDT to point PyAEDT at. The default is - ``None``. This parameter is only used when ``new_desktop_session = False``. - - Returns - ------- - :class:`pyaedt.circuit.Circuit` - - Examples - -------- - Create an instance of Circuit and connect to an existing HFSS - design or create a new HFSS design if one does not exist. - - >>> from pyaedt import Circuit - >>> aedtapp = Circuit() - - Create an instance of Circuit and link to a project named - ``"projectname"``. If this project does not exist, create one with - this name. - - >>> aedtapp = Circuit(projectname) - - Create an instance of Circuit and link to a design named - ``"designname"`` in a project named ``"projectname"``. - - >>> aedtapp = Circuit(projectname,designame) - - Create an instance of Circuit and open the specified project, - which is ``"myfie.aedt"``. - - >>> aedtapp = Circuit("myfile.aedt") - - Create an instance of Circuit using the 2023 R2 version and - open the specified project, which is ``"myfile.aedt"``. - - >>> aedtapp = Circuit(specified_version=2023.2, projectname="myfile.aedt") - - Create an instance of Circuit using the 2023 R2 student version and open - the specified project, which is named ``"myfile.aedt"``. - - >>> hfss = Circuit(specified_version="2023.2", projectname="myfile.aedt", student_version=True) - - """ - from pyaedt.circuit import Circuit as app - - return app( - projectname=projectname, - designname=designname, - solution_type=solution_type, - setup_name=setup_name, - specified_version=specified_version, - non_graphical=non_graphical, - new_desktop_session=new_desktop_session, - close_on_exit=close_on_exit, - student_version=student_version, - machine=machine, - port=port, - aedt_process_id=aedt_process_id, - ) - - -def Hfss( - projectname=None, - designname=None, - solution_type=None, - setup_name=None, - specified_version=None, - non_graphical=False, - new_desktop_session=False, - close_on_exit=False, - student_version=False, - machine="", - port=0, - aedt_process_id=None, -): - """Return an instance of the Hfss Class. - - Parameters - ---------- - projectname : str, optional - Name of the project to select or the full path to the project - or AEDTZ archive to open. The default is ``None``, in which - case an attempt is made to get an active project. If no - projects are present, an empty project is created. - designname : str, optional - Name of the design to select. The default is ``None``, in - which case an attempt is made to get an active design. If no - designs are present, an empty design is created. - solution_type : str, optional - Solution type to apply to the design. The default is - ``None``, in which case the default type is applied. - setup_name : str, optional - Name of the setup to use as the nominal. The default is - ``None``, in which case the active setup is used or - nothing is used. - specified_version : str, int, float, optional - Version of AEDT to use. The default is ``None``, in which case - the active version or latest installed version is used. - This parameter is ignored when a script is launched within AEDT. - Examples of input values are ``232``, ``23.2``,``2023.2``,``"2023.2"``. - non_graphical : bool, optional - Whether to run AEDT in non-graphical mode. The default - is ``False``, in which case AEDT is launched in graphical mode. - This parameter is ignored when a script is launched within AEDT. - new_desktop_session : bool, optional - Whether to launch an instance of AEDT in a new thread, even if - another instance of the ``specified_version`` is active on the - machine. The default is ``False``. This parameter is ignored when - a script is launched within AEDT. - close_on_exit : bool, optional - Whether to release AEDT on exit. The default is ``False``. - student_version : bool, optional - Whether to open the AEDT student version. The default is - ``False``. This parameter is ignored when a script is launched - within AEDT. - machine : str, optional - Machine name to connect the oDesktop session to. This parameter works only on - 2022 R2 or later. The remote Server must be up and running with the command - `"ansysedt.exe -grpcsrv portnum"`. If the machine is `"localhost"`, the server - starts if it is not present. - port : int, optional - Port number on which to start the oDesktop communication on an already existing server. - This parameter is ignored when creating a new server. It works only in 2022 R2 or later. - The remote server must be up and running with the command `"ansysedt.exe -grpcsrv portnum"`. - aedt_process_id : int, optional - Process ID for the instance of AEDT to point PyAEDT at. The default is - ``None``. This parameter is only used when ``new_desktop_session = False``. - - Returns - ------- - :class:`pyaedt.hfss.Hfss` - - Examples - -------- - Create an instance of HFSS and connect to an existing HFSS - design or create a new HFSS design if one does not exist. - - >>> from pyaedt import Hfss - >>> hfss = Hfss() - PyAEDT INFO: No project is defined... - PyAEDT INFO: Active design is set to... - - - Create an instance of HFSS and link to a project named - ``HfssProject``. If this project does not exist, create one with - this name. - - >>> hfss = Hfss("HfssProject") - PyAEDT INFO: Project HfssProject has been created. - PyAEDT INFO: No design is present. Inserting a new design. - PyAEDT INFO: Added design ... - - - Create an instance of HFSS and link to a design named - ``HfssDesign1`` in a project named ``HfssProject``. - - >>> hfss = Hfss("HfssProject","HfssDesign1") - PyAEDT INFO: Added design 'HfssDesign1' of type HFSS. - - - Create an instance of HFSS and open the specified project, - which is named ``"myfile.aedt"``. - - >>> hfss = Hfss("myfile.aedt") - PyAEDT INFO: Project myfile has been created. - PyAEDT INFO: No design is present. Inserting a new design. - PyAEDT INFO: Added design... - - - Create an instance of HFSS using the 2023 R2 release and open - the specified project, which is named ``"myfile2.aedt"``. - - >>> hfss = Hfss(specified_version=232, projectname="myfile2.aedt") - PyAEDT INFO: Project myfile2 has been created. - PyAEDT INFO: No design is present. Inserting a new design. - PyAEDT INFO: Added design... - - - Create an instance of HFSS using the 2023 R2 student version and open - the specified project, which is named ``"myfile3.aedt"``. - - >>> hfss = Hfss(specified_version="2023.2", projectname="myfile3.aedt", student_version=True) - PyAEDT INFO: Project myfile3 has been created. - PyAEDT INFO: No design is present. Inserting a new design. - PyAEDT INFO: Added design... - - """ - from pyaedt.hfss import Hfss as app - - return app( - projectname=projectname, - designname=designname, - solution_type=solution_type, - setup_name=setup_name, - specified_version=specified_version, - non_graphical=non_graphical, - new_desktop_session=new_desktop_session, - close_on_exit=close_on_exit, - student_version=student_version, - machine=machine, - port=port, - aedt_process_id=aedt_process_id, - ) - - -def Icepak( - projectname=None, - designname=None, - solution_type=None, - setup_name=None, - specified_version=None, - non_graphical=False, - new_desktop_session=False, - close_on_exit=False, - student_version=False, - machine="", - port=0, - aedt_process_id=None, -): - """Icepak Class. - - Parameters - ---------- - projectname : str, optional - Name of the project to select or the full path to the project - or AEDTZ archive to open. The default is ``None``, in which - case an attempt is made to get an active project. If no - projects are present, an empty project is created. - designname : str, optional - Name of the design to select. The default is ``None``, in - which case an attempt is made to get an active design. If no - designs are present, an empty design is created. - solution_type : str, optional - Solution type to apply to the design. The default is - ``None``, in which case the default type is applied. - setup_name : str, optional - Name of the setup to use as the nominal. The default is - ``None``, in which case the active setup is used or - nothing is used. - specified_version : str, int, float, optional - Version of AEDT to use. The default is ``None``, in which case - the active version or latest installed version is used. - This parameter is ignored when Script is launched within AEDT. - Examples of input values are ``232``, ``23.2``,``2023.2``,``"2023.2"``. - non-graphical : bool, optional - Whether to launch AEDT in non-graphical mode. The default - is ``False``, in which case AEDT is launched in graphical mode. - This parameter is ignored when a script is launched within AEDT. - new_desktop_session : bool, optional - Whether to launch an instance of AEDT in a new thread, even if - another instance of the ``specified_version`` is active on the - machine. The default is ``False``. - close_on_exit : bool, optional - Whether to release AEDT on exit. The default is ``False``. - student_version : bool, optional - Whether to open the AEDT student version. The default is ``False``. - This parameter is ignored when a script is launched within AEDT. - machine : str, optional - Machine name to connect the oDesktop session to. This works only in 2022 R2 or later. - The remote server must be up and running with the command `"ansysedt.exe -grpcsrv portnum"`. - If the machine is `"localhost"`, the server also starts if not present. - port : int, optional - Port number of which to start the oDesktop communication on an already existing server. - This parameter is ignored when creating a new server. It works only in 2022 R2 or later. - The remote server must be up and running with the command `"ansysedt.exe -grpcsrv portnum"`. - aedt_process_id : int, optional - Process ID for the instance of AEDT to point PyAEDT at. The default is - ``None``. This parameter is only used when ``new_desktop_session = False``. - - Returns - ------- - :class:`pyaedt.icepak.Icepak` - - Examples - -------- - - Create an instance of Icepak and connect to an existing Icepak - design or create a new Icepak design if one does not exist. - - >>> from pyaedt import Icepak - >>> icepak = Icepak() - PyAEDT INFO: No project is defined. Project ... - PyAEDT INFO: Active design is set to ... - - Create an instance of Icepak and link to a project named - ``IcepakProject``. If this project does not exist, create one with - this name. - - >>> icepak = Icepak("IcepakProject") - PyAEDT INFO: Project ... - PyAEDT INFO: Added design ... - - Create an instance of Icepak and link to a design named - ``IcepakDesign1`` in a project named ``IcepakProject``. - - >>> icepak = Icepak("IcepakProject", "IcepakDesign1") - PyAEDT INFO: Added design 'IcepakDesign1' of type Icepak. - - Create an instance of Icepak and open the specified project, - which is ``myipk.aedt``. - - >>> icepak = Icepak("myipk.aedt") - PyAEDT INFO: Project myipk has been created. - PyAEDT INFO: No design is present. Inserting a new design. - PyAEDT INFO: Added design ... - - Create an instance of Icepak using the 2023 R2 release and - open the specified project, which is ``myipk2.aedt``. - - >>> icepak = Icepak(specified_version=2023.2, projectname="myipk2.aedt") - PyAEDT INFO: Project... - PyAEDT INFO: No design is present. Inserting a new design. - PyAEDT INFO: Added design... - """ - from pyaedt.icepak import Icepak as app - - return app( - projectname=projectname, - designname=designname, - solution_type=solution_type, - setup_name=setup_name, - specified_version=specified_version, - non_graphical=non_graphical, - new_desktop_session=new_desktop_session, - close_on_exit=close_on_exit, - student_version=student_version, - machine=machine, - port=port, - aedt_process_id=aedt_process_id, - ) - - -def Emit( - projectname=None, - designname=None, - solution_type=None, - specified_version=None, - non_graphical=False, - new_desktop_session=False, - close_on_exit=False, - student_version=False, - machine="", - port=0, - aedt_process_id=None, -): - """Emit Class. - - Parameters - ---------- - projectname : str, optional - Name of the project to select or the full path to the project - or AEDTZ archive to open. The default is ``None``, in which case - an attempt is made to get an active project. If no projects are - present, an empty project is created. - designname : str, optional - Name of the design to select. The default is ``None``, in which case - an attempt is made to get an active design. If no designs are - present, an empty design is created. - solution_type : str, optional - Solution type to apply to the design. The default is ``None``, in which - case the default type is applied. - specified_version : str, int, float, optional - Version of AEDT to use. The default is ``None``, in which case - the active setup is used or the latest installed version is - used. - Examples of input values are ``232``, ``23.2``,``2023.2``,``"2023.2"``. - non_graphical : bool, optional - Whether to launch AEDT in non-graphical mode. The default - is ``False``, in which case AEDT is launched in graphical mode. - This parameter is ignored when a script is launched within AEDT. - new_desktop_session : bool, optional - Whether to launch an instance of AEDT in a new thread, even if - another instance of the ``specified_version`` is active on the - machine. The default is ``False``. - close_on_exit : bool, optional - Whether to release AEDT on exit. The default is ``False``. - student_version : bool, optional - Whether to start the AEDT student version. The default is ``False``. - port : int, optional - Port number on which to start the oDesktop communication on an already existing server. - This parameter is ignored when creating a server. This parameter works only in 2022 R2 or later. - The remote server must be up and running with the command `"ansysedt.exe -grpcsrv portnum"`. - The default is ``0``. - machine : str, optional - Machine name that the Desktop session is to connect to. This - parameter works only in 2022 R2 and later. The remote server must be - up and running with the command `"ansysedt.exe -grpcsrv portnum"`. - If the machine is `"localhost"`, the server starts if it is not present. - aedt_process_id : int, optional - Process ID for the instance of AEDT to point PyAEDT at. The default is - ``None``. This parameter is only used when ``new_desktop_session = False``. - - Returns - ------- - :class:`pyaedt.emit.Emit` - - Examples - -------- - Create an ``Emit`` instance. You can also choose to define parameters for this instance here. - - >>> from pyaedt import Emit - >>> aedtapp = Emit() - - Typically, it is desirable to specify a project name, design name, and other parameters. - - >>> aedtapp = Emit(projectname, designame, specified_version=232) - - Once an ``Emit`` instance is initialized, you can edit the schematic: - - >>> rad1 = aedtapp.modeler.components.create_component("Bluetooth") - >>> ant1 = aedtapp.modeler.components.create_component("Antenna") - >>> if rad1 and ant1: - >>> ant1.move_and_connect_to(rad1) - - Once the schematic is generated, the ``Emit`` object can be analyzed to generate - a revision. Each revision is added as an element of the ``Emit`` object member's - revisions_list. - - >>> aedtapp.analyze() - - A revision within PyAEDT is analogous to a revision in AEDT. An interaction domain must - be defined and then used as the input to the run command used on that revision. - - >>> domain = aedtapp.interaction_domain() - >>> domain.rx_radio_name = "UE - HandHeld" - >>> interaction = aedtapp.revisions_list[0].run(domain) - - The output of the run command is an ``interaction`` object. This object summarizes the interaction data - that is defined in the interaction domain. - - >>> instance = interaction.worst_instance(ResultType.SENSITIVITY) - >>> val = instance.value(ResultType.SENSITIVITY) - >>> print("Worst-case sensitivity for Rx '{}' is {}dB.".format(domain.rx_radio_name, val)) - """ - from pyaedt.emit import Emit as app - - return app( - projectname=projectname, - designname=designname, - solution_type=solution_type, - specified_version=specified_version, - non_graphical=non_graphical, - new_desktop_session=new_desktop_session, - close_on_exit=close_on_exit, - student_version=student_version, - machine=machine, - port=port, - aedt_process_id=aedt_process_id, - ) - - -def Hfss3dLayout( - projectname=None, - designname=None, - solution_type=None, - setup_name=None, - specified_version=None, - non_graphical=False, - new_desktop_session=False, - close_on_exit=False, - student_version=False, - machine="", - port=0, - aedt_process_id=None, - ic_mode=None, -): - """Hfss3dLayout Class. - - Parameters - ---------- - projectname : str, optional - Name of the project to select or the full path to the project - or AEDTZ archive to open or the path to the ``aedb`` folder or - ``edb.def`` file. The default is ``None``, in which case an - attempt is made to get an active project. If no projects are present, - an empty project is created. - designname : str, optional - Name of the design to select. The default is ``None``, in - which case an attempt is made to get an active design. If no - designs are present, an empty design is created. - solution_type : str, optional - Solution type to apply to the design. The default is - ``None``, in which case the default type is applied. - setup_name : str, optional - Name of the setup to use as the nominal. The default is - ``None``, in which case the active setup is used or - nothing is used. - specified_version : str, int, float, optional - Version of AEDT to use. The default is ``None``, in which case - the active version or latest installed version is used. - Examples of input values are ``232``, ``23.2``,``2023.2``,``"2023.2"``. - non_graphical : bool, optional - Whether to launch AEDT in non-graphical mode. The default - is ``False```, in which case AEDT is launched in graphical mode. - This parameter is ignored when a script is launched within AEDT. - new_desktop_session : bool, optional - Whether to launch an instance of AEDT in a new thread, even if - another instance of the ``specified_version`` is active on the - machine. The default is ``False``. - close_on_exit : bool, optional - Whether to release AEDT on exit. The default is ``False``. - student_version : bool, optional - Whether to open the AEDT student version. The default is ``False``. - machine : str, optional - Machine name to connect the oDesktop session to. This works only in 2022 R2 or later. - The remote server must be up and running with the command `"ansysedt.exe -grpcsrv portnum"`. - If the machine is `"localhost"`. the server also starts if not present. - port : int, optional - Port number on which to start the oDesktop communication on an already existing server. - This parameter is ignored when creating a new server. It works only in 2022 R2 or later. - The remote server must be up and running with the command `"ansysedt.exe -grpcsrv portnum"`. - aedt_process_id : int, optional - Process ID for the instance of AEDT to point PyAEDT at. The default is - ``None``. This parameter is only used when ``new_desktop_session = False``. - ic_mode : bool, optional - Whether to set the design to IC mode or not. The default is ``None``, which means to retain - the existing setting. - - Returns - ------- - :class:`pyaedt.hfss3dlayout.Hfss3dLayout` - - Examples - -------- - Create an ``Hfss3dLayout`` object and connect to an existing HFSS - design or create a new HFSS design if one does not exist. - - >>> from pyaedt import Hfss3dLayout - >>> aedtapp = Hfss3dLayout() - - Create an ``Hfss3dLayout`` object and link to a project named - ``projectname``. If this project does not exist, create one with - this name. - - >>> aedtapp = Hfss3dLayout(projectname) - - Create an ``Hfss3dLayout`` object and link to a design named - ``designname`` in a project named ``projectname``. - - >>> aedtapp = Hfss3dLayout(projectname,designame) - - Create an ``Hfss3dLayout`` object and open the specified project. - - >>> aedtapp = Hfss3dLayout("myfile.aedt") - - Create an AEDT 2023 R1 object and then create a - ``Hfss3dLayout`` object and open the specified project. - - >>> aedtapp = Hfss3dLayout(specified_version="2023.1", projectname="myfile.aedt") - - Create an instance of ``Hfss3dLayout`` from an ``Edb`` - - >>> import pyaedt - >>> edb_path = "/path/to/edbfile.aedb" - >>> edb = pyaedt.Edb(edb_path, edbversion=231) - >>> edb.stackup.import_stackup("stackup.xml") # Import stackup. Manipulate edb, ... - >>> edb.save_edb() - >>> edb.close_edb() - >>> aedtapp = pyaedt.Hfss3dLayout(specified_version=231, projectname=edb_path) - """ - from pyaedt.hfss3dlayout import Hfss3dLayout as app - - return app( - projectname=projectname, - designname=designname, - solution_type=solution_type, - setup_name=setup_name, - specified_version=specified_version, - non_graphical=non_graphical, - new_desktop_session=new_desktop_session, - close_on_exit=close_on_exit, - student_version=student_version, - machine=machine, - port=port, - aedt_process_id=aedt_process_id, - ic_mode=ic_mode, - ) - - -def Maxwell2d( - projectname=None, - designname=None, - solution_type=None, - setup_name=None, - specified_version=None, - non_graphical=False, - new_desktop_session=False, - close_on_exit=False, - student_version=False, - machine="", - port=0, - aedt_process_id=None, -): - """Maxwell2d Class. - - Parameters - ---------- - projectname : str, optional - Name of the project to select or the full path to the project - or AEDTZ archive to open. The default is ``None``, in which - case an attempt is made to get an active project. If no - projects are present, an empty project is created. - designname : str, optional - Name of the design to select. The default is ``None``, in - which case an attempt is made to get an active design. If no - designs are present, an empty design is created. - solution_type : str, optional - Solution type to apply to the design. The default is - ``None``, in which case the default type is applied. - setup_name : str, optional - Name of the setup to use as the nominal. The default is - ``None``, in which case the active setup is used or - nothing is used. - specified_version : str, int, float, optional - Version of AEDT to use. The default is ``None``, in which case - the active version or latest installed version is used. - This parameter is ignored when a script is launched within AEDT. - Examples of input values are ``232``, ``23.2``,``2023.2``,``"2023.2"``. - non_graphical : bool, optional - Whether to launch AEDT in non-graphical mode. The default - is ``False``, in which case AEDT is launched in graphical mode. - This parameter is ignored when a script is launched within AEDT. - new_desktop_session : bool, optional - Whether to launch an instance of AEDT in a new thread, even if - another instance of the ``specified_version`` is active on the - machine. The default is ``False``. This parameter is ignored when - a script is launched within AEDT. - close_on_exit : bool, optional - Whether to release AEDT on exit. The default is ``False``. - student_version : bool, optional - Whether to open the AEDT student version. The default is ``False``. - This parameter is ignored when a script is launched within AEDT. - machine : str, optional - Machine name to connect the oDesktop session to. This works only in 2022 R2 - or later. The remote server must be up and running with the command - `"ansysedt.exe -grpcsrv portnum"`. If the machine is `"localhost"`, - the server also starts if not present. - port : int, optional - Port number of which to start the oDesktop communication on an already existing - server. This parameter is ignored when creating a new server. It works only in 2022 - R2 or later. The remote server must be up and running with the command `"ansysedt.exe -grpcsrv portnum"`. - aedt_process_id : int, optional - Process ID for the instance of AEDT to point PyAEDT at. The default is - ``None``. This parameter is only used when ``new_desktop_session = False``. - - Returns - ------- - :class:`pyaedt.maxwell.Maxwell2d`""" - from pyaedt.maxwell import Maxwell2d as app - - return app( - projectname=projectname, - designname=designname, - solution_type=solution_type, - setup_name=setup_name, - specified_version=specified_version, - non_graphical=non_graphical, - new_desktop_session=new_desktop_session, - close_on_exit=close_on_exit, - student_version=student_version, - machine=machine, - port=port, - aedt_process_id=aedt_process_id, - ) - - -def Maxwell3d( - projectname=None, - designname=None, - solution_type=None, - setup_name=None, - specified_version=None, - non_graphical=False, - new_desktop_session=False, - close_on_exit=False, - student_version=False, - machine="", - port=0, - aedt_process_id=None, -): - """Maxwell3d Class. - - Parameters - ---------- - projectname : str, optional - Name of the project to select or the full path to the project - or AEDTZ archive to open. The default is ``None``, in which - case an attempt is made to get an active project. If no - projects are present, an empty project is created. - designname : str, optional - Name of the design to select. The default is ``None``, in - which case an attempt is made to get an active design. If no - designs are present, an empty design is created. - solution_type : str, optional - Solution type to apply to the design. The default is - ``None``, in which case the default type is applied. - setup_name : str, optional - Name of the setup to use as the nominal. The default is - ``None``, in which case the active setup is used or - nothing is used. - specified_version : str, int, float, optional - Version of AEDT to use. The default is ``None``, in which case - the active version or latest installed version is used. This - parameter is ignored when a script is launched within AEDT. - Examples of input values are ``232``, ``23.2``,``2023.2``,``"2023.2"``. - non_graphical : bool, optional - Whether to launch AEDT in non-graphical mode. The default - is ``False``, in which case AEDT is launched in graphical - mode. This parameter is ignored when a script is launched within - AEDT. - new_desktop_session : bool, optional - Whether to launch an instance of AEDT in a new thread, even if - another instance of the ``specified_version`` is active on the - machine. The default is ``False``. This parameter is ignored - when a script is launched within AEDT. - close_on_exit : bool, optional - Whether to release AEDT on exit. The default is ``False``. - student_version : bool, optional - Whether to open the AEDT student version. The default is - ``False``. This parameter is ignored when a script is launched - within AEDT. - machine : str, optional - Machine name to connect the oDesktop session to. This works only in 2022 R2 - or later. The remote server must be up and running with the command - `"ansysedt.exe -grpcsrv portnum"`. If the machine is `"localhost"`, the - server also starts if not present. - port : int, optional - Port number on which to start the oDesktop communication on an already existing server. - This parameter is ignored when a new server is created. It works only in 2022 R2 or later. - The remote server must be up and running with the command `"ansysedt.exe -grpcsrv portnum"`. - aedt_process_id : int, optional - Process ID for the instance of AEDT to point PyAEDT at. The default is - ``None``. This parameter is only used when ``new_desktop_session = False``. - - Returns - ------- - :class:`pyaedt.maxwell.Maxwell3d` - - Examples - -------- - Create an instance of Maxwell 3D and open the specified - project, which is named ``mymaxwell.aedt``. - - >>> from pyaedt import Maxwell3d - >>> aedtapp = Maxwell3d("mymaxwell.aedt") - PyAEDT INFO: Added design ... - - Create an instance of Maxwell 3D using the 2023 R2 release and open - the specified project, which is named ``mymaxwell2.aedt``. - - >>> aedtapp = Maxwell3d(specified_version="2023.2", projectname="mymaxwell2.aedt") - PyAEDT INFO: Added design ... - """ - from pyaedt.maxwell import Maxwell3d as app - - return app( - projectname=projectname, - designname=designname, - solution_type=solution_type, - setup_name=setup_name, - specified_version=specified_version, - non_graphical=non_graphical, - new_desktop_session=new_desktop_session, - close_on_exit=close_on_exit, - student_version=student_version, - machine=machine, - port=port, - aedt_process_id=aedt_process_id, - ) - - -def MaxwellCircuit( - projectname=None, - designname=None, - solution_type=None, - specified_version=None, - non_graphical=False, - new_desktop_session=False, - close_on_exit=False, - student_version=False, - machine="", - port=0, - aedt_process_id=None, -): - """MaxwellCircuit Class. - - Parameters - ---------- - projectname : str, optional - Name of the project to select or the full path to the project - or AEDTZ archive to open. The default is ``None``, in which - case an attempt is made to get an active project. If no - projects are present, an empty project is created. - designname : str, optional - Name of the design to select. The default is ``None``, in - which case an attempt is made to get an active design. If no - designs are present, an empty design is created. - specified_version : str, int, float, optional - Version of AEDT to use. The default is ``None``. If ``None``, - the active setup is used or the latest installed version is - used. - Examples of input values are ``232``, ``23.2``,``2023.2``,``"2023.2"``. - non-graphical : bool, optional - Whether to launch AEDT in non-graphical mode. The default - is ``False``, in which case AEDT is launched in graphical mode. - This parameter is ignored when a script is launched within AEDT. - new_desktop_session : bool, optional - Whether to launch an instance of AEDT in a new thread, even if - another instance of the ``specified_version`` is active on the - machine. The default is ``False``. - close_on_exit : bool, optional - Whether to release AEDT on exit. The default is ``False``. - student_version : bool, optional - Whether to open the AEDT student version. The default is ``False``. - machine : str, optional - Machine name to connect the oDesktop session to. This works only in 2022 R2 - and later. The remote server must be up and running with the command - `"ansysedt.exe -grpcsrv portnum"`. If the machine is `"localhost"`, the server - is also started if not present. - port : int, optional - Port number on which to start the oDesktop communication on an already existing server. - This parameter is ignored when creating a new server. It works only in 2022 R2 or - later. The remote server must be up and running with the command `"ansysedt.exe -grpcsrv portnum"`. - aedt_process_id : int, optional - Process ID for the instance of AEDT to point PyAEDT at. The default is - ``None``. This parameter is only used when ``new_desktop_session = False``. - - Returns - ------- - :class:`pyaedt.maxwellcircuit.MaxwellCircuit`""" - from pyaedt.maxwellcircuit import MaxwellCircuit as app - - return app( - projectname=projectname, - designname=designname, - solution_type=solution_type, - specified_version=specified_version, - non_graphical=non_graphical, - new_desktop_session=new_desktop_session, - close_on_exit=close_on_exit, - student_version=student_version, - machine=machine, - port=port, - aedt_process_id=aedt_process_id, - ) - - -def Mechanical( - projectname=None, - designname=None, - solution_type=None, - setup_name=None, - specified_version=None, - non_graphical=False, - new_desktop_session=False, - close_on_exit=False, - student_version=False, - machine="", - port=0, - aedt_process_id=None, -): - """Mechanical Class. - - Parameters - ---------- - projectname : str, optional - Name of the project to select or the full path to the project - or AEDTZ archive to open. The default is ``None``, in which - case an attempt is made to get an active project. If no - projects are present, an empty project is created. - designname : str, optional - Name of the design to select. The default is ``None``, in - which case an attempt is made to get an active design. If no - designs are present, an empty design is created. - solution_type : str, optional - Solution type to apply to the design. The default is - ``None``, in which case the default type is applied. - setup_name : str, optional - Name of the setup to use as the nominal. The default is - ``None``, in which case the active setup is used or - nothing is used. - specified_version : str, int, float, optional - Version of AEDT to use. The default is ``None``, in which case - the active version or latest installed version is used. - This parameter is ignored when a script is launched within AEDT. - Examples of input values are ``232``, ``23.2``,``2023.2``,``"2023.2"``. - non_graphical : bool, optional - Whether to launch AEDT in the non-graphical mode. The default - is ``False``, in which case AEDT is launched in the graphical mode. - This parameter is ignored when a script is launched within AEDT. - new_desktop_session : bool, optional - Whether to launch an instance of AEDT in a new thread, even if - another instance of the ``specified_version`` is active on the - machine. The default is ``False``. This parameter is ignored when - a script is launched within AEDT. - close_on_exit : bool, optional - Whether to release AEDT on exit. The default is ``False``. - student_version : bool, optional - Whether to open the AEDT student version. The default is ``False``. - This parameter is ignored when a script is launched within AEDT. - machine : str, optional - Machine name to connect the oDesktop session to. Works only in 2022R2 and - later. The remote server must be up and running with the command - `"ansysedt.exe -grpcsrv portnum"`. If the machine is `"localhost"`, - the server also starts if not present. - port : int, optional - Port number on which to start the oDesktop communication on an already existing server. - This parameter is ignored when creating a new server. It works only in 2022 R2 or - later. The remote server must be up and running with the command `"ansysedt.exe -grpcsrv portnum"`. - aedt_process_id : int, optional - Process ID for the instance of AEDT to point PyAEDT at. The default is - ``None``. This parameter is only used when ``new_desktop_session = False``. - - Returns - ------- - :class:`pyaedt.mechanical.Mechanical` - - Examples - -------- - Create an instance of Mechanical and connect to an existing - HFSS design or create a new HFSS design if one does not exist. - - >>> from pyaedt import Mechanical - >>> aedtapp = Mechanical() - - Create an instance of Mechanical and link to a project named - ``"projectname"``. If this project does not exist, create one with - this name. - - >>> aedtapp = Mechanical(projectname) - - Create an instance of Mechanical and link to a design named - ``"designname"`` in a project named ``"projectname"``. - - >>> aedtapp = Mechanical(projectname,designame) - - Create an instance of Mechanical and open the specified - project, which is named ``"myfile.aedt"``. - - >>> aedtapp = Mechanical("myfile.aedt") - - Create a ``Desktop on 2023 R2`` object and then create an - ``Mechanical`` object and open the specified project, which is - named ``"myfile.aedt"``. - - >>> aedtapp = Mechanical(specified_version=23.2, projectname="myfile.aedt") - """ - from pyaedt.mechanical import Mechanical as app - - return app( - projectname=projectname, - designname=designname, - solution_type=solution_type, - setup_name=setup_name, - specified_version=specified_version, - non_graphical=non_graphical, - new_desktop_session=new_desktop_session, - close_on_exit=close_on_exit, - student_version=student_version, - machine=machine, - port=port, - aedt_process_id=aedt_process_id, - ) - - -def Q2d( - projectname=None, - designname=None, - solution_type=None, - setup_name=None, - specified_version=None, - non_graphical=False, - new_desktop_session=False, - close_on_exit=False, - student_version=False, - machine="", - port=0, - aedt_process_id=None, -): - """Q2D Class. - - Parameters - ---------- - projectname : str, optional - Name of the project to select or the full path to the project - or AEDTZ archive to open. The default is ``None``, in which - case an attempt is made to get an active project. If no - projects are present, an empty project is created. - designname : str, optional - Name of the design to select. The default is ``None``, in - which case an attempt is made to get an active design. If no - designs are present, an empty design is created. - solution_type : str, optional - Solution type to apply to the design. The default is - ``None``, in which case the default type is applied. - setup_name : str, optional - Name of the setup to use as the nominal. The default is - ``None``, in which case the active setup is used or - nothing is used. - specified_version : str, int, float, optional - Version of AEDT to use. The default is ``None``, in which case - the active version or latest installed version is used. This - parameter is ignored when a script is launched within AEDT. - Examples of input values are ``232``, ``23.2``,``2023.2``,``"2023.2"``. - non_graphical : bool, optional - Whether to launch AEDT in non-graphical mode. The default - is ``False``, in which case AEDT is launched in graphical mode. - This parameter is ignored when a script is launched within AEDT. - new_desktop_session : bool, optional - Whether to launch an instance of AEDT in a new thread, even if - another instance of the ``specified_version`` is active on the - machine. The default is ``False``. This parameter is ignored - when a script is launched within AEDT. - close_on_exit : bool, optional - Whether to release AEDT on exit. The default is ``False``. - student_version : bool, optional - Whether to open the AEDT student version. This parameter is - ignored when a script is launched within AEDT. - machine : str, optional - Machine name to connect the oDesktop session to. This works only in 2022 R2 - and later. The remote server must be up and running with the command - `"ansysedt.exe -grpcsrv portnum"`. If the machine is `"localhost"`, - the server also starts if not present. - port : int, optional - Port number on which to start the oDesktop communication on an already existing server. - This parameter is ignored when creating a new server. It works only in 2022 R2 or later. - The remote server must be up and running with the command `"ansysedt.exe -grpcsrv portnum"`. - aedt_process_id : int, optional - Process ID for the instance of AEDT to point PyAEDT at. The default is - ``None``. This parameter is only used when ``new_desktop_session = False``. - - Returns - ------- - :class:`pyaedt.q3d.Q2d`""" - from pyaedt.q3d import Q2d as app - - return app( - projectname=projectname, - designname=designname, - solution_type=solution_type, - setup_name=setup_name, - specified_version=specified_version, - non_graphical=non_graphical, - new_desktop_session=new_desktop_session, - close_on_exit=close_on_exit, - student_version=student_version, - machine=machine, - port=port, - aedt_process_id=aedt_process_id, - ) - - -def Q3d( - projectname=None, - designname=None, - solution_type=None, - setup_name=None, - specified_version=None, - non_graphical=False, - new_desktop_session=False, - close_on_exit=False, - student_version=False, - machine="", - port=0, - aedt_process_id=None, -): - """Q3D Class. - - Parameters - ---------- - projectname : str, optional - Name of the project to select or the full path to the project - or AEDTZ archive to open. The default is ``None``, in which - case an attempt is made to get an active project. If no - projects are present, an empty project is created. - designname : str, optional - Name of the design to select. The default is ``None``, in - which case an attempt is made to get an active design. If no - designs are present, an empty design is created. - solution_type : str, optional - Solution type to apply to the design. The default is - ``None``, in which case the default type is applied. - setup_name : str, optional - Name of the setup to use as the nominal. The default is - ``None``, in which case the active setup is used or nothing - is used. - specified_version : str, int, float, optional - Version of AEDT to use. The default is ``None``, in which case - the active version or latest installed version is used. - This parameter is ignored when Script is launched within AEDT. - Examples of input values are ``232``, ``23.2``,``2023.2``,``"2023.2"``. - non_graphical : bool, optional - Whether to launch AEDT in non-graphical mode. The default - is ``False``, in which case AEDT is launched in graphical mode. - This parameter is ignored when a script is launched within AEDT. - new_desktop_session : bool, optional - Whether to launch an instance of AEDT in a new thread, even if - another instance of the ``specified_version`` is active on the - machine. The default is ``False``. This parameter is ignored when - a script is launched within AEDT. - close_on_exit : bool, optional - Whether to release AEDT on exit. The default is ``False``. - student_version : bool, optional - Whether to open the AEDT student version. The default is ``False``. - This parameter is ignored when a script is launched within AEDT. - machine : str, optional - Machine name to connect the oDesktop session to. This works only in - 2022 R2 and later. The remote server must be up and running with the - command `"ansysedt.exe -grpcsrv portnum"`. If the machine is `"localhost"`, - the server also starts if not present. - port : int, optional - Port number on which to start the oDesktop communication on an already - existing server. This parameter is ignored when a new server is created. - It works only in 2022 R2 and later. The remote server must be up and - running with the command `"ansysedt.exe -grpcsrv portnum"`. - aedt_process_id : int, optional - Process ID for the instance of AEDT to point PyAEDT at. The default is - ``None``. This parameter is only used when ``new_desktop_session = False``. - - Returns - ------- - :class:`pyaedt.q3d.Q3d`""" - from pyaedt.q3d import Q3d as app - - return app( - projectname=projectname, - designname=designname, - solution_type=solution_type, - setup_name=setup_name, - specified_version=specified_version, - non_graphical=non_graphical, - new_desktop_session=new_desktop_session, - close_on_exit=close_on_exit, - student_version=student_version, - machine=machine, - port=port, - aedt_process_id=aedt_process_id, - ) - - -def Rmxprt( - projectname=None, - designname=None, - solution_type=None, - setup_name=None, - specified_version=None, - non_graphical=False, - new_desktop_session=False, - close_on_exit=False, - student_version=False, - machine="", - port=0, - aedt_process_id=None, -): - """Rmxprt Class. - - Parameters - ---------- - projectname : str, optional - Name of the project to select or the full path to the project - or AEDTZ archive to open. The default is ``None``, in which - case an attempt is made to get an active project. If no - projects are present, an empty project is created. - designname : str, optional - Name of the design to select. The default is ``None``, in - which case an attempt is made to get an active design. If no - designs are present, an empty design is created. - solution_type : str, optional - Solution type to apply to the design. The default is - ``None``, in which case the default type is applied. - setup_name : str, optional - Name of the setup to use as the nominal. The default is - ``None``, in which case the active setup is used or - nothing is used. - specified_version : str, int, float, optional - Version of AEDT to use. The default is ``None``, in which case - the active setup is used or the latest installed version is - used. - Examples of input values are ``232``, ``23.2``,``2023.2``,``"2023.2"``. - non_graphical : bool, optional - Whether to launch AEDT in non-graphical mode. The default - is ``False``, in which case AEDT is launched in graphical mode. - This parameter is ignored when a script is launched within AEDT. - new_desktop_session : bool, optional - Whether to launch an instance of AEDT in a new thread, even if - another instance of the ``specified_version`` is active on the - machine. The default is ``False``. - close_on_exit : bool, optional - Whether to release AEDT on exit. The default is ``False``. - student_version : bool, optional - Whether to open the AEDT student version. The default is ``False``. - machine : str, optional - Machine name to connect the oDesktop session to. This works only in 2022 R2 or - later. The remote server must be up and running with the command - `"ansysedt.exe -grpcsrv portnum"`. If the machine is `"localhost"`, the - server also starts if not present. - port : int, optional - Port number on which to start the oDesktop communication on an already existing server. - This parameter is ignored when creating a new server. It works only in 2022 R2 or later. - The remote server must be up and running with the command `"ansysedt.exe -grpcsrv portnum"`. - aedt_process_id : int, optional - Process ID for the instance of AEDT to point PyAEDT at. The default is - ``None``. This parameter is only used when ``new_desktop_session = False``. - - Returns - ------- - :class:`pyaedt.rmxprt.Rmxprt`""" - from pyaedt.rmxprt import Rmxprt as app - - return app( - projectname=projectname, - designname=designname, - solution_type=solution_type, - setup_name=setup_name, - specified_version=specified_version, - non_graphical=non_graphical, - new_desktop_session=new_desktop_session, - close_on_exit=close_on_exit, - student_version=student_version, - machine=machine, - port=port, - aedt_process_id=aedt_process_id, - ) - - -def TwinBuilder( - projectname=None, - designname=None, - solution_type=None, - setup_name=None, - specified_version=None, - non_graphical=False, - new_desktop_session=False, - close_on_exit=False, - student_version=False, - machine="", - port=0, - aedt_process_id=None, -): - """TwinBuilder Class. - - Parameters - ---------- - projectname : str, optional - Name of the project to select or the full path to the project - or AEDTZ archive to open. The default is ``None``, in which - case an attempt is made to get an active project. If no - projects are present, an empty project is created. - designname : str, optional - Name of the design to select. The default is ``None``, in - which case an attempt is made to get an active design. If no - designs are present, an empty design is created. - solution_type : str, optional - Solution type to apply to the design. The default is - ``None``, in which case the default type is applied. - setup_name : str, optional - Name of the setup to use as the nominal. The default is - ``None``, in which case the active setup is used or - nothing is used. - specified_version : str, int, float, optional - Version of AEDT to use. The default is ``None``, in which - case the active setup or latest installed version is - used. - Examples of input values are ``232``, ``23.2``,``2023.2``,``"2023.2"``. - non_graphical : bool, optional - Whether to launch AEDT in non-graphical mode. The default - is ``False``, in which case AEDT is launched in graphical mode. - This parameter is ignored when a script is launched within AEDT. - new_desktop_session : bool, optional - Whether to launch an instance of AEDT in a new thread, even if - another instance of the ``specified_version`` is active on the - machine. The default is ``False``. - close_on_exit : bool, optional - Whether to release AEDT on exit. The default is ``False``. - student_version : bool, optional - Whether to open the AEDT student version. The default is ``False``. - machine : str, optional - Machine name to connect the oDesktop session to. This works only in 2022 R2 - or later. The remote server must be up and running with the command - `"ansysedt.exe -grpcsrv portnum"`. If the machine is `"localhost"`, - the server also starts if not present. - port : int, optional - Port number on which to start the oDesktop communication on an already existing server. - This parameter is ignored when creating a new server. It works only in 2022 R2 or later. - The remote server must be up and running with command `"ansysedt.exe -grpcsrv portnum"`. - aedt_process_id : int, optional - Process ID for the instance of AEDT to point PyAEDT at. The default is - ``None``. This parameter is only used when ``new_desktop_session = False``. - - Returns - ------- - :class:`pyaedt.twinbuilder.TwinBuilder`""" - from pyaedt.twinbuilder import TwinBuilder as app - - return app( - projectname=projectname, - designname=designname, - solution_type=solution_type, - setup_name=setup_name, - specified_version=specified_version, - non_graphical=non_graphical, - new_desktop_session=new_desktop_session, - close_on_exit=close_on_exit, - student_version=student_version, - machine=machine, - port=port, - aedt_process_id=aedt_process_id, - ) - +# -*- 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. -def Simplorer( - projectname=None, - designname=None, - solution_type=None, - setup_name=None, - specified_version=None, - non_graphical=False, - new_desktop_session=False, - close_on_exit=False, - student_version=False, - machine="", - port=0, - aedt_process_id=None, -): - """Simplorer Class. - - Parameters - ---------- - projectname : str, optional - Name of the project to select or the full path to the project - or AEDTZ archive to open. The default is ``None``, in which - case an attempt is made to get an active project. If no - projects are present, an empty project is created. - designname : str, optional - Name of the design to select. The default is ``None``, in - which case an attempt is made to get an active design. If no - designs are present, an empty design is created. - solution_type : str, optional - Solution type to apply to the design. The default is - ``None``, in which case the default type is applied. - setup_name : str, optional - Name of the setup to use as the nominal. The default is - ``None``, in which case the active setup is used or - nothing is used. - specified_version : str, int, float, optional - Version of AEDT to use. The default is ``None``, in which - case the active setup or latest installed version is - used. - Examples of input values are ``232``, ``23.2``,``2023.2``,``"2023.2"``. - non_graphical : bool, optional - Whether to launch AEDT in non-graphical mode. The default - is ``False``, in which case AEDT is launched in graphical mode. - This parameter is ignored when a script is launched within AEDT. - new_desktop_session : bool, optional - Whether to launch an instance of AEDT in a new thread, even if - another instance of the ``specified_version`` is active on the - machine. The default is ``False``. - close_on_exit : bool, optional - Whether to release AEDT on exit. The default is ``False``. - student_version : bool, optional - Whether to open the AEDT student version. The default is ``False``. - machine : str, optional - Machine name to connect the oDesktop session to. This works only in 2022 R2 - or later. The remote server must be up and running with the command - `"ansysedt.exe -grpcsrv portnum"`. If the machine is `"localhost"`, - the server also starts if not present. - port : int, optional - Port number on which to start the oDesktop communication on an already existing server. - This parameter is ignored when creating a new server. It works only in 2022 R2 or later. - The remote server must be up and running with command `"ansysedt.exe -grpcsrv portnum"`. - aedt_process_id : int, optional - Process ID for the instance of AEDT to point PyAEDT at. The default is - ``None``. This parameter is only used when ``new_desktop_session = False``. - - Returns - ------- - :class:`pyaedt.twinbuilder.TwinBuilder`""" - from pyaedt.twinbuilder import TwinBuilder as app - - return app( - projectname=projectname, - designname=designname, - solution_type=solution_type, - setup_name=setup_name, - specified_version=specified_version, - non_graphical=non_graphical, - new_desktop_session=new_desktop_session, - close_on_exit=close_on_exit, - student_version=student_version, - machine=machine, - port=port, - aedt_process_id=aedt_process_id, - ) - - -def Desktop( - specified_version=None, - non_graphical=False, - new_desktop_session=True, - close_on_exit=True, - student_version=False, - machine="", - port=0, - aedt_process_id=None, -): - """Desktop Class. - Parameters - ---------- - specified_version : str, int, float, optional - Version of AEDT to use. The default is ``None``, in which case the - active setup or latest installed version is used. - Examples of input values are ``232``, ``23.2``,``2023.2``,``"2023.2"``. - non_graphical : bool, optional - Whether to launch AEDT in non-graphical mode. The default - is ``False``, in which case AEDT is launched in graphical mode. - This parameter is ignored when a script is launched within AEDT. - new_desktop_session : bool, optional - Whether to launch an instance of AEDT in a new thread, even if - another instance of the ``specified_version`` is active on the machine. - The default is ``True``. - close_on_exit : bool, optional - Whether to close AEDT on exit. The default is ``True``. - This option is used only when Desktop is used in a context manager (``with`` statement). - If Desktop is used outside a context manager, see the ``release_desktop`` arguments. - student_version : bool, optional - Whether to open the AEDT student version. The default is - ``False``. - machine : str, optional - Machine name to connect the oDesktop session to. This parameter works only in 2022 R2 - and later. The remote server must be up and running with the command - `"ansysedt.exe -grpcsrv portnum"`. If the machine is `"localhost"`, the server also - starts if not present. - port : int, optional - Port number on which to start the oDesktop communication on the already existing server. - This parameter is ignored when creating a new server. It works only in 2022 R2 and - later. The remote server must be up and running with the command `"ansysedt.exe -grpcsrv portnum"`. - aedt_process_id : int, optional - Process ID for the instance of AEDT to point PyAEDT at. The default is - ``None``. This parameter is only used when ``new_desktop_session = False``. - - Returns - ------- - :class:`pyaedt.desktop.Desktop` - - Examples - -------- - Launch AEDT 2023 R1 in non-graphical mode and initialize HFSS. - - >>> import pyaedt - >>> desktop = pyaedt.Desktop(specified_version="2023.2", non_graphical=True) - PyAEDT INFO: pyaedt v... - PyAEDT INFO: Python version ... - >>> hfss = pyaedt.Hfss(designname="HFSSDesign1") - PyAEDT INFO: Project... - PyAEDT INFO: Added design 'HFSSDesign1' of type HFSS. +import re +import sys +import time - Launch AEDT 2023 R2 in graphical mode and initialize HFSS. +from pyaedt.circuit import Circuit +from pyaedt.desktop import Desktop - >>> desktop = Desktop(232) - PyAEDT INFO: pyaedt v... - PyAEDT INFO: Python version ... - >>> hfss = pyaedt.Hfss(designname="HFSSDesign1") - PyAEDT INFO: No project is defined. Project... - """ - from pyaedt.desktop import Desktop as app +Emit = None +if not ("IronPython" in sys.version or ".NETFramework" in sys.version): # pragma: no cover + from pyaedt.emit import Emit +from pyaedt.generic.general_methods import is_linux +from pyaedt.generic.settings import settings +from pyaedt.hfss3dlayout import Hfss3dLayout +from pyaedt.hfss import Hfss +from pyaedt.icepak import Icepak +from pyaedt.maxwell import Maxwell2d +from pyaedt.maxwell import Maxwell3d +from pyaedt.maxwellcircuit import MaxwellCircuit +from pyaedt.mechanical import Mechanical +from pyaedt.q3d import Q2d +from pyaedt.q3d import Q3d +from pyaedt.rmxprt import Rmxprt +from pyaedt.twinbuilder import TwinBuilder - return app( - specified_version=specified_version, - non_graphical=non_graphical, - new_desktop_session=new_desktop_session, - close_on_exit=close_on_exit, - student_version=student_version, - machine=machine, - port=port, - aedt_process_id=aedt_process_id, - ) +Simplorer = TwinBuilder def launch_desktop( - specified_version=None, + version=None, non_graphical=False, - new_desktop_session=True, + new_desktop=True, close_on_exit=True, student_version=False, machine="", @@ -1562,14 +63,14 @@ def launch_desktop( Parameters ---------- - specified_version : str, int, float, optional + version : str, int, float, optional Version of AEDT to use. The default is ``None``, in which case the active setup or latest installed version is used. non_graphical : bool, optional Whether to launch AEDT in non-graphical mode. The default is ``False``, in which case AEDT is launched in graphical mode. This parameter is ignored when a script is launched within AEDT. - new_desktop_session : bool, optional + new_desktop : bool, optional Whether to launch an instance of AEDT in a new thread, even if another instance of the ``specified_version`` is active on the machine. The default is ``False``. @@ -1589,7 +90,7 @@ def launch_desktop( later. The remote server must be up and running with the command `"ansysedt.exe -grpcsrv portnum"`. aedt_process_id : int, optional Process ID for the instance of AEDT to point PyAEDT at. The default is - ``None``. This parameter is only used when ``new_desktop_session = False``. + ``None``. This parameter is only used when ``new_desktop = False``. Returns ------- @@ -1604,7 +105,7 @@ def launch_desktop( >>> desktop = pyaedt.launch_desktop("2022.2", non_graphical=True) PyAEDT INFO: pyaedt v... PyAEDT INFO: Python version ... - >>> hfss = pyaedt.Hfss(designname="HFSSDesign1") + >>> hfss = pyaedt.Hfss(design="HFSSDesign1") PyAEDT INFO: Project... PyAEDT INFO: Added design 'HFSSDesign1' of type HFSS. @@ -1613,13 +114,13 @@ def launch_desktop( >>> desktop = Desktop("2021.2") PyAEDT INFO: pyaedt v... PyAEDT INFO: Python version ... - >>> hfss = pyaedt.Hfss(designname="HFSSDesign1") + >>> hfss = pyaedt.Hfss(design="HFSSDesign1") PyAEDT INFO: No project is defined. Project... """ d = Desktop( - specified_version=specified_version, + version=version, non_graphical=non_graphical, - new_desktop_session=new_desktop_session, + new_desktop=new_desktop, close_on_exit=close_on_exit, student_version=student_version, machine=machine, @@ -1629,110 +130,6 @@ def launch_desktop( return d -def Edb( - edbpath=None, - cellname=None, - isreadonly=False, - edbversion=None, - isaedtowned=False, - oproject=None, - student_version=False, - use_ppe=False, - technology_file=None, -): - """Provides the EDB application interface. - - This module inherits all objects that belong to EDB. - - Parameters - ---------- - edbpath : str, int, float optional - Full path to the ``aedb`` folder. The variable can also contain - the path to a layout to import. Allowed formats are BRD, - XML (IPC2581), GDS, and DXF. The default is ``None``. - For GDS import, the Ansys control file (also XML) should have the same - name as the GDS file. Only the file extension differs. - cellname : str, optional - Name of the cell to select. The default is ``None``. - isreadonly : bool, optional - Whether to open EBD in read-only mode when it is - owned by HFSS 3D Layout. The default is ``False``. - edbversion : str, optional - Version of EDB to use. The default is ``"2021.2"``. - isaedtowned : bool, optional - Whether to launch EDB from HFSS 3D Layout. The - default is ``False``. - oproject : optional - Reference to the AEDT project object. - student_version : bool, optional - Whether to open the AEDT student version. The default is ``False.`` - technology_file : str, optional - Full path to technology file to be converted to xml before importing or xml. Supported by GDS format only. - - Returns - ------- - :class:`pyaedt.edb.Edb` - - Examples - -------- - Create an ``Edb`` object and a new EDB cell. - - >>> from pyaedt import Edb - >>> app = Edb() - - Add a new variable named "s1" to the ``Edb`` instance. - - >>> app['s1'] = "0.25 mm" - >>> app['s1'].tofloat - >>> 0.00025 - >>> app['s1'].tostring - >>> "0.25mm" - - or add a new parameter with description: - - >>> app['s2'] = ["20um", "Spacing between traces"] - >>> app['s2'].value - >>> 1.9999999999999998e-05 - >>> app['s2'].description - >>> 'Spacing between traces' - - - Create an ``Edb`` object and open the specified project. - - >>> app = Edb("myfile.aedb") - - Create an ``Edb`` object from GDS and control files. - The XML control file resides in the same directory as the GDS file: (myfile.xml). - - >>> app = Edb("/path/to/file/myfile.gds") - - """ - from pyedb import Edb as app - - return app( - edbpath=edbpath, - cellname=cellname, - isreadonly=isreadonly, - edbversion=edbversion, - isaedtowned=isaedtowned, - oproject=oproject, - student_version=student_version, - use_ppe=use_ppe, - technology_file=technology_file, - ) - - -def Siwave( - specified_version=None, -): - """Siwave Class.""" - from pyedb.siwave import Siwave as app - - return app( - specified_version=specified_version, - ) - - app_map = { "Maxwell 2D": Maxwell2d, "Maxwell 3D": Maxwell3d, @@ -1747,9 +144,6 @@ def Siwave( "Rmxprt": Rmxprt, "HFSS 3D Layout Design": Hfss3dLayout, "EMIT": Emit, - "EDB": Edb, - "Desktop": Desktop, - "Siwave": Siwave, } @@ -1821,5 +215,5 @@ def get_pyaedt_app(project_name=None, design_name=None, desktop=None): if design_type in list(app_map.keys()): version = odesktop.GetVersion().split(".") v = ".".join([version[0], version[1]]) - return app_map[design_type](project_name, design_name, specified_version=v, aedt_process_id=process_id) + return app_map[design_type](project_name, design_name, version=v, aedt_process_id=process_id) return None diff --git a/pyaedt/generic/desktop_sessions.py b/pyaedt/generic/desktop_sessions.py index 87032cbae18..d348a47d551 100644 --- a/pyaedt/generic/desktop_sessions.py +++ b/pyaedt/generic/desktop_sessions.py @@ -1,3 +1,27 @@ +# -*- 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. + # This contains the Desktops database. # When AEDT will support multiple desktops, it will be filled with additional properties and methods diff --git a/pyaedt/generic/filesystem.py b/pyaedt/generic/filesystem.py index 694351b7a6d..06f206e3f98 100644 --- a/pyaedt/generic/filesystem.py +++ b/pyaedt/generic/filesystem.py @@ -1,3 +1,27 @@ +# -*- 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 random import shutil @@ -124,9 +148,7 @@ def copyfolder(self, src_folder, destfolder): ------- """ - from distutils.dir_util import copy_tree - - copy_tree(src_folder, destfolder) + shutil.copytree(src_folder, destfolder, dirs_exist_ok=True) return True def __enter__(self): diff --git a/pyaedt/generic/general_methods.py b/pyaedt/generic/general_methods.py index c3569028787..7d06b7d67cc 100644 --- a/pyaedt/generic/general_methods.py +++ b/pyaedt/generic/general_methods.py @@ -1,4 +1,27 @@ # -*- 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 __future__ import absolute_import import ast @@ -25,6 +48,7 @@ from pyaedt.aedt_logger import pyaedt_logger from pyaedt.generic.constants import CSS4_COLORS from pyaedt.generic.settings import settings +from pyaedt.misc.misc import installed_versions is_ironpython = "IronPython" in sys.version or ".NETFramework" in sys.version is_linux = os.name == "posix" @@ -34,6 +58,16 @@ if not is_ironpython: import psutil +inclusion_list = [ + "CreateVia", + "PasteDesign", + "Paste", + "PushExcitations", + "Rename", + "RestoreProjectArchive", + "ImportGerber", +] + class GrpcApiError(Exception): """ """ @@ -195,6 +229,8 @@ def raise_exception_or_return_false(e): for v in list(_desktop_sessions.values())[:]: v.release_desktop(v.launched_by_pyaedt, v.launched_by_pyaedt) raise e + elif "__init__" in str(e): # pragma: no cover + return else: return False @@ -810,15 +846,6 @@ def _retry_ntimes(n, function, *args, **kwargs): pyaedt_logger.debug("An error occurred while accessing the arguments of a function " "called multiple times.") retry = 0 ret_val = None - inclusion_list = [ - "CreateVia", - "PasteDesign", - "Paste", - "PushExcitations", - "Rename", - "RestoreProjectArchive", - "ImportGerber", - ] # if func_name and func_name not in inclusion_list and not func_name.startswith("Get"): if func_name and func_name not in inclusion_list: n = 1 @@ -944,6 +971,73 @@ def is_project_locked(project_path): return check_if_path_exists(project_path + ".lock") +@pyaedt_function_handler() +def is_license_feature_available(feature="electronics_desktop", count=1): # pragma: no cover + """Check if license feature is available. + + Parameters + ---------- + feature : str + Feature increment name. The default is the electronics desktop one. + count : int + Number of increments of the same feature available. + + Returns + ------- + bool + ``True`` when feature available, ``False`` when feature not available. + """ + import subprocess # nosec B404 + + aedt_install_folder = list(installed_versions().values())[0] + + if is_linux: + ansysli_util_path = os.path.join(aedt_install_folder, "licensingclient", "linx64", "ansysli_util") + else: + ansysli_util_path = os.path.join(aedt_install_folder, "licensingclient", "winx64", "ansysli_util") + my_env = os.environ.copy() + + tempfile_status = tempfile.NamedTemporaryFile(suffix=".txt", delete=False).name + tempfile_checkout = tempfile.NamedTemporaryFile(suffix=".txt", delete=False).name + + # License server status + cmd = [ansysli_util_path, "-statli"] + + f = open(tempfile_status, "w") + + subprocess.Popen(cmd, stdout=f, stderr=f, env=my_env).wait() # nosec + + f.close() + + is_server_down = False + with open_file(tempfile_status, "r") as f: + for line in f: + if line == "ansysli_server process could not be found.\n": + is_server_down = True + break + + if is_server_down: + pyaedt_logger.warning("License server process could not be found.") + return False + + cmd = [ansysli_util_path, "-checkcount", str(count), "-checkout", feature] + + f = open(tempfile_checkout, "w") + + subprocess.Popen(cmd, stdout=f, stderr=f, env=my_env).wait() # nosec + + f.close() + + checkout_lines = [] + with open_file(tempfile_checkout, "r") as f: + for line in f: + checkout_lines.append(line) + if "CHECKOUT FAILED" in checkout_lines[1] or len(checkout_lines) != 2: + pyaedt_logger.warning(checkout_lines[0]) + return False + return True + + @pyaedt_function_handler() def remove_project_lock(project_path): """Check if an AEDT project exists and try to remove the lock file. @@ -1681,9 +1775,9 @@ def conversion_function(data, function=None): # pragma: no cover return data -@pyaedt_function_handler() +@pyaedt_function_handler(file_name="input_file") def parse_excitation_file( - file_name, + input_file, is_time_domain=True, x_scale=1, y_scale=1, @@ -1697,7 +1791,7 @@ def parse_excitation_file( Parameters ---------- - file_name : str + input_file : str Full name of the input file. is_time_domain : bool, optional Either if the input data is Time based or Frequency Based. Frequency based data are Mag/Phase (deg). @@ -1726,7 +1820,7 @@ def parse_excitation_file( except ImportError: pyaedt_logger.error("NumPy is not available. Install it.") return False - df = read_csv_pandas(file_name, encoding=encoding) + df = read_csv_pandas(input_file, encoding=encoding) if is_time_domain: time = df[df.keys()[0]].values * x_scale val = df[df.keys()[1]].values * y_scale diff --git a/pyaedt/generic/grpc_plugin_dll_class.py b/pyaedt/generic/grpc_plugin_dll_class.py index 41104c659aa..f9504503aa0 100644 --- a/pyaedt/generic/grpc_plugin_dll_class.py +++ b/pyaedt/generic/grpc_plugin_dll_class.py @@ -1,3 +1,27 @@ +# -*- 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 CFUNCTYPE from ctypes import PyDLL from ctypes import c_bool @@ -12,6 +36,7 @@ from pyaedt.generic.general_methods import GrpcApiError from pyaedt.generic.general_methods import _retry_ntimes +from pyaedt.generic.general_methods import inclusion_list from pyaedt.generic.general_methods import settings logger = settings.logger @@ -88,7 +113,7 @@ def __Invoke__(self, funcName, argv): if settings.enable_debug_grpc_api_logger: settings.logger.debug("{} {}".format(funcName, argv)) try: - if settings.use_multi_desktop and funcName not in exclude_list: + if (settings.use_multi_desktop and funcName not in exclude_list) or funcName in inclusion_list: self.dllapi.recreate_application(True) ret = _retry_ntimes( settings.number_of_grpc_api_retries, @@ -294,6 +319,7 @@ def __init__(self, pathDir): self.AedtAPI = AedtAPI self.SetPyObjCalbacks() self.aedt = None + self.non_graphical = False def SetPyObjCalbacks(self): self.callback_type = CFUNCTYPE(py_object, c_int, c_bool, py_object) @@ -330,6 +356,7 @@ def CreateAedtApplication(self, machine="", port=0, NGmode=False, alwaysNew=True if not self.aedt: raise GrpcApiError("Failed to connect to Desktop Session") self.machine = machine + self.non_graphical = NGmode if port == 0: self.port = self.aedt.GetAppDesktop().GetGrpcServerPort() else: @@ -351,7 +378,7 @@ def run(): self.__init__(self.original_path) self.port = port self.machine = machine - self.aedt = self.AedtAPI.CreateAedtApplication(self.machine, self.port, False, False) + self.aedt = self.AedtAPI.CreateAedtApplication(self.machine, self.port, self.non_graphical, False) return self.aedt if force: diff --git a/pyaedt/generic/ibis_reader.py b/pyaedt/generic/ibis_reader.py index bbc4bc29698..25bd8078a4d 100644 --- a/pyaedt/generic/ibis_reader.py +++ b/pyaedt/generic/ibis_reader.py @@ -1,3 +1,27 @@ +# -*- 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 json import os import re diff --git a/pyaedt/generic/near_field_import.py b/pyaedt/generic/near_field_import.py index 34c403a2455..fa27440a399 100644 --- a/pyaedt/generic/near_field_import.py +++ b/pyaedt/generic/near_field_import.py @@ -1,3 +1,27 @@ +# -*- 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 import os import re diff --git a/pyaedt/generic/pdf.py b/pyaedt/generic/pdf.py index e9d7fb9b2c2..64cc29b29bb 100644 --- a/pyaedt/generic/pdf.py +++ b/pyaedt/generic/pdf.py @@ -1,3 +1,27 @@ +# -*- 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 dataclasses import dataclass from dataclasses import field import json diff --git a/pyaedt/generic/plot.py b/pyaedt/generic/plot.py index a2ed87de43e..549f7550a6c 100644 --- a/pyaedt/generic/plot.py +++ b/pyaedt/generic/plot.py @@ -1,3 +1,27 @@ +# -*- 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 ast from collections import defaultdict import csv @@ -8,11 +32,11 @@ import time import warnings -from pyaedt import pyaedt_function_handler from pyaedt.generic.constants import AEDT_UNITS from pyaedt.generic.constants import CSS4_COLORS from pyaedt.generic.general_methods import is_ironpython from pyaedt.generic.general_methods import open_file +from pyaedt.generic.general_methods import pyaedt_function_handler if not is_ironpython: try: @@ -469,8 +493,9 @@ def plot_2d_chart( Matplotlib figure object. """ dpi = 100.0 - figsize = (size[0] / dpi, size[1] / dpi) - fig, ax = plt.subplots(figsize=figsize) + ax = plt.subplot(111) + fig = plt.gcf() + fig.set_size_inches(size[0] / dpi, size[1] / dpi) label_id = 1 for plo_obj in plot_data: if isinstance(plo_obj[0], np.ndarray): @@ -479,7 +504,10 @@ def plot_2d_chart( else: x = np.array([i for i, j in zip(plo_obj[0], plo_obj[1]) if j]) y = np.array([i for i in plo_obj[1] if i]) - ax.plot(x, y) + label = "Plot {}".format(str(label_id)) + if len(plo_obj) > 2: + label = plo_obj[2] + ax.plot(x, y, label=label) label_id += 1 ax.set(xlabel=xlabel, ylabel=ylabel, title=title) @@ -488,7 +516,7 @@ def plot_2d_chart( if snapshot_path: fig.savefig(snapshot_path) - elif not is_notebook(): + elif show and not is_notebook(): fig.show() return fig diff --git a/pyaedt/generic/python_optimizers.py b/pyaedt/generic/python_optimizers.py index 2d0bf18df25..57ac916e7cc 100644 --- a/pyaedt/generic/python_optimizers.py +++ b/pyaedt/generic/python_optimizers.py @@ -1,3 +1,27 @@ +# -*- 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 sys import threading import warnings diff --git a/pyaedt/generic/report_file_parser.py b/pyaedt/generic/report_file_parser.py index 55c2467e560..1a45b3cd21b 100644 --- a/pyaedt/generic/report_file_parser.py +++ b/pyaedt/generic/report_file_parser.py @@ -1,3 +1,27 @@ +# -*- 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 pyaedt.generic.LoadAEDTFile import load_keyword_in_aedt_file from pyaedt.generic.constants import SI_UNITS from pyaedt.generic.constants import unit_system diff --git a/pyaedt/generic/settings.py b/pyaedt/generic/settings.py index 40e962b3a8b..7c23d27251a 100644 --- a/pyaedt/generic/settings.py +++ b/pyaedt/generic/settings.py @@ -1,3 +1,27 @@ +# -*- 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 @@ -73,7 +97,7 @@ def __init__(self): self._retry_n_times_time_interval = 0.1 self._wait_for_license = False self.__lazy_load = True - self.__objects_lazy_load = False + self.__objects_lazy_load = True @property def release_on_exception(self): diff --git a/pyaedt/generic/spisim.py b/pyaedt/generic/spisim.py index df5f1910880..5203dfdb230 100644 --- a/pyaedt/generic/spisim.py +++ b/pyaedt/generic/spisim.py @@ -1,3 +1,27 @@ +# -*- 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. + # coding=utf-8 from collections import OrderedDict import os @@ -9,13 +33,13 @@ from numpy import float64 from numpy import zeros -from pyaedt import generate_unique_folder_name from pyaedt import generate_unique_name -from pyaedt import is_linux -from pyaedt import pyaedt_function_handler -from pyaedt import settings from pyaedt.generic.general_methods import env_value +from pyaedt.generic.general_methods import generate_unique_folder_name from pyaedt.generic.general_methods import open_file +from pyaedt.generic.general_methods import pyaedt_function_handler +from pyaedt.generic.settings import is_linux +from pyaedt.generic.settings import settings from pyaedt.misc import current_version from pyaedt.misc.spisim_com_configuration_files.com_parameters import COMParametersVer3p4 diff --git a/pyaedt/generic/touchstone_parser.py b/pyaedt/generic/touchstone_parser.py index e70e07fc381..bed51504ac1 100644 --- a/pyaedt/generic/touchstone_parser.py +++ b/pyaedt/generic/touchstone_parser.py @@ -1,10 +1,34 @@ +# -*- 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 copy import copy import itertools import os import re import subprocess -from pyaedt import is_ironpython +from pyaedt.generic.general_methods import is_ironpython from pyaedt.misc.misc import installed_versions if not is_ironpython: diff --git a/pyaedt/hfss.py b/pyaedt/hfss.py index ecd98a0ca37..40590f4131b 100644 --- a/pyaedt/hfss.py +++ b/pyaedt/hfss.py @@ -1,3 +1,27 @@ +# -*- 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. + """This module contains these classes: ``Hfss`` and ``BoundaryType``.""" from __future__ import absolute_import # noreorder @@ -40,12 +64,12 @@ class Hfss(FieldAnalysis3D, ScatteringMethods): Parameters ---------- - projectname : str, optional + project : str, optional Name of the project to select or the full path to the project or AEDTZ archive to open. The default is ``None``, in which case an attempt is made to get an active project. If no projects are present, an empty project is created. - designname : str, optional + design : str, optional Name of the design to select. The default is ``None``, in which case an attempt is made to get an active design. If no designs are present, an empty design is created. @@ -61,11 +85,11 @@ class Hfss(FieldAnalysis3D, ScatteringMethods): - "Transient" - "Eigenmode" - setup_name : str, optional + setup : str, optional Name of the setup to use as the nominal. The default is ``None``, in which case the active setup is used or nothing is used. - specified_version : str, int, float, optional + version : str, int, float, optional Version of AEDT to use. The default is ``None``, in which case the active version or latest installed version is used. This parameter is ignored when a script is launched within AEDT. @@ -74,7 +98,7 @@ class Hfss(FieldAnalysis3D, ScatteringMethods): Whether to run AEDT in non-graphical mode. The default is ``False``, in which case AEDT is launched in graphical mode. This parameter is ignored when a script is launched within AEDT. - new_desktop_session : bool, optional + new_desktop : bool, optional Whether to launch an instance of AEDT in a new thread, even if another instance of the ``specified_version`` is active on the machine. The default is ``False``. This parameter is ignored when @@ -96,7 +120,11 @@ class Hfss(FieldAnalysis3D, ScatteringMethods): The remote server must be up and running with the command `"ansysedt.exe -grpcsrv portnum"`. aedt_process_id : int, optional Process ID for the instance of AEDT to point PyAEDT at. The default is - ``None``. This parameter is only used when ``new_desktop_session = False``. + ``None``. This parameter is only used when ``new_desktop = False``. + remove_lock : bool, optional + Whether to remove lock to project before opening it or not. + The default is ``False``, which means to not unlock + the existing project if needed and raise an exception. Examples -------- @@ -138,7 +166,7 @@ class Hfss(FieldAnalysis3D, ScatteringMethods): Create an instance of HFSS using the 2023 R2 release and open the specified project, which is named ``"myfile2.aedt"``. - >>> hfss = Hfss(specified_version=232, projectname="myfile2.aedt") + >>> hfss = Hfss(version=232, project="myfile2.aedt") PyAEDT INFO: Project myfile2 has been created. PyAEDT INFO: No design is present. Inserting a new design. PyAEDT INFO: Added design... @@ -147,7 +175,7 @@ class Hfss(FieldAnalysis3D, ScatteringMethods): Create an instance of HFSS using the 2023 R2 student version and open the specified project, which is named ``"myfile3.aedt"``. - >>> hfss = Hfss(specified_version="2023.2", projectname="myfile3.aedt", student_version=True) + >>> hfss = Hfss(version="2023.2", project="myfile3.aedt", student_version=True) PyAEDT INFO: Project myfile3 has been created. PyAEDT INFO: No design is present. Inserting a new design. PyAEDT INFO: Added design... @@ -162,36 +190,45 @@ class Hfss(FieldAnalysis3D, ScatteringMethods): # except Exception: # return "HFSS Module" + @pyaedt_function_handler( + designname="design", + projectname="project", + specified_version="version", + setup_name="setup", + new_desktop_session="new_desktop", + ) def __init__( self, - projectname=None, - designname=None, + project=None, + design=None, solution_type=None, - setup_name=None, - specified_version=None, + setup=None, + version=None, non_graphical=False, - new_desktop_session=False, + new_desktop=False, close_on_exit=False, student_version=False, machine="", port=0, aedt_process_id=None, + remove_lock=False, ): FieldAnalysis3D.__init__( self, "HFSS", - projectname, - designname, + project, + design, solution_type, - setup_name, - specified_version, + setup, + version, non_graphical, - new_desktop_session, + new_desktop, close_on_exit, student_version, machine, port, aedt_process_id, + remove_lock=remove_lock, ) ScatteringMethods.__init__(self, self) self._field_setups = [] @@ -937,7 +974,12 @@ def create_linear_count_sweep( return False @pyaedt_function_handler( - setupname="setup", freqstart="start_frequency", freqstop="stop_frequency", sweepname="name" + setup_name="setup", + setupname="setup", + freqstart="start_frequency", + freqstop="stop_frequency", + sweepname="name", + sweep_name="name", ) def create_linear_step_sweep( self, @@ -1173,10 +1215,10 @@ def create_sbr_linked_antenna( >>> from pyaedt import Hfss >>> target_project = "my/path/to/targetProject.aedt" >>> source_project = "my/path/to/sourceProject.aedt" - >>> target = Hfss(projectname=target_project, solution_type="SBR+", - ... specified_version="2021.2", new_desktop_session=False) # doctest: +SKIP - >>> source = Hfss(projectname=source_project, designname="feeder", - ... specified_version="2021.2", new_desktop_session=False) # doctest: +SKIP + >>> 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 """ @@ -3585,11 +3627,11 @@ def edit_source(self, assignment=None, power="1W", phase="0deg"): ) return True - @pyaedt_function_handler(portandmode="assignment") + @pyaedt_function_handler(portandmode="assignment", file_name="input_file") def edit_source_from_file( self, assignment, - file_name, + input_file, is_time_domain=True, x_scale=1, y_scale=1, @@ -3606,7 +3648,7 @@ def edit_source_from_file( assignment : str Port name and mode. For example, ``"Port1:1"``. The port name must be defined if the solution type is other than Eigenmodal. - file_name : str + input_file : str Full name of the input file. is_time_domain : bool, optional Whether the input data is time-based or frequency-based. Frequency based data are Mag/Phase (deg). @@ -3638,7 +3680,7 @@ def find_scale(data, header_line): return data[td] return None - with open(file_name, "r") as f: + with open(input_file, "r") as f: header = f.readlines()[0] time_data = {"[ps]": 1e-12, "[ns]": 1e-9, "[us]": 1e-6, "[ms]": 1e-3, "[s]": 1} curva_data_V = { @@ -3686,7 +3728,7 @@ def find_scale(data, header_line): else: out = "Voltage" freq, mag, phase = parse_excitation_file( - file_name=file_name, + input_file=input_file, is_time_domain=is_time_domain, x_scale=x_scale, y_scale=y_scale, @@ -3703,14 +3745,14 @@ def find_scale(data, header_line): self.design_datasets[ds_name_mag].y = mag self.design_datasets[ds_name_mag].update() else: - self.create_dataset1d_design(ds_name_mag, freq, mag, xunit="Hz") + self.create_dataset1d_design(ds_name_mag, freq, mag, x_unit="Hz") if self.dataset_exists(ds_name_phase, False): self.design_datasets[ds_name_phase].x = freq self.design_datasets[ds_name_phase].y = phase self.design_datasets[ds_name_phase].update() else: - self.create_dataset1d_design(ds_name_phase, freq, phase, xunit="Hz", yunit="deg") + self.create_dataset1d_design(ds_name_phase, freq, phase, x_unit="Hz", y_unit="deg") self.osolution.EditSources( [ ["IncludePortPostProcessing:=", True, "SpecifySystemPower:=", False], diff --git a/pyaedt/hfss3dlayout.py b/pyaedt/hfss3dlayout.py index f95be62f400..57f70613fe4 100644 --- a/pyaedt/hfss3dlayout.py +++ b/pyaedt/hfss3dlayout.py @@ -1,3 +1,27 @@ +# -*- 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. + """This module contains the ``Hfss3dLayout`` class.""" from __future__ import absolute_import # noreorder @@ -8,10 +32,10 @@ import os import re -from pyaedt import is_ironpython from pyaedt.application.Analysis3DLayout import FieldAnalysis3DLayout from pyaedt.application.analysis_hf import ScatteringMethods from pyaedt.generic.general_methods import generate_unique_name +from pyaedt.generic.general_methods import is_ironpython from pyaedt.generic.general_methods import open_file from pyaedt.generic.general_methods import parse_excitation_file from pyaedt.generic.general_methods import pyaedt_function_handler @@ -29,32 +53,32 @@ class Hfss3dLayout(FieldAnalysis3DLayout, ScatteringMethods): Parameters ---------- - projectname : str, optional + project : str, optional Name of the project to select or the full path to the project or AEDTZ archive to open or the path to the ``aedb`` folder or ``edb.def`` file. The default is ``None``, in which case an attempt is made to get an active project. If no projects are present, an empty project is created. - designname : str, optional + design : str, optional Name of the design to select. The default is ``None``, in which case an attempt is made to get an active design. If no designs are present, an empty design is created. solution_type : str, optional Solution type to apply to the design. The default is ``None``, in which case the default type is applied. - setup_name : str, optional + setup : str, optional Name of the setup to use as the nominal. The default is ``None``, in which case the active setup is used or nothing is used. - specified_version : str, int, float, optional + version : str, int, float, optional Version of AEDT to use. The default is ``None``, in which case the active version or latest installed version is used. Examples of input values are ``232``, ``23.2``,``2023.2``,``"2023.2"``. non_graphical : bool, optional Whether to launch AEDT in non-graphical mode. The default - is ``False```, in which case AEDT is launched in graphical mode. + is ``True```, in which case AEDT is launched in graphical mode. This parameter is ignored when a script is launched within AEDT. - new_desktop_session : bool, optional + new_desktop : bool, optional Whether to launch an instance of AEDT in a new thread, even if another instance of the ``specified_version`` is active on the machine. The default is ``False``. @@ -72,10 +96,14 @@ class Hfss3dLayout(FieldAnalysis3DLayout, ScatteringMethods): The remote server must be up and running with the command `"ansysedt.exe -grpcsrv portnum"`. aedt_process_id : int, optional Process ID for the instance of AEDT to point PyAEDT at. The default is - ``None``. This parameter is only used when ``new_desktop_session = False``. + ``None``. This parameter is only used when ``new_desktop = False``. ic_mode : bool, optional Whether to set the design to IC mode or not. The default is ``None``, which means to retain the existing setting. + remove_lock : bool, optional + Whether to remove lock to project before opening it or not. + The default is ``False``, which means to not unlock + the existing project if needed and raise an exception. Examples -------- @@ -103,7 +131,7 @@ class Hfss3dLayout(FieldAnalysis3DLayout, ScatteringMethods): Create an AEDT 2023 R1 object and then create a ``Hfss3dLayout`` object and open the specified project. - >>> aedtapp = Hfss3dLayout(specified_version="2023.1", projectname="myfile.aedt") + >>> aedtapp = Hfss3dLayout(version="2023.1", project="myfile.aedt") Create an instance of ``Hfss3dLayout`` from an ``Edb`` @@ -113,42 +141,51 @@ class Hfss3dLayout(FieldAnalysis3DLayout, ScatteringMethods): >>> edb.stackup.import_stackup("stackup.xml") # Import stackup. Manipulate edb, ... >>> edb.save_edb() >>> edb.close_edb() - >>> aedtapp = pyaedt.Hfss3dLayout(specified_version=231, projectname=edb_path) + >>> aedtapp = pyaedt.Hfss3dLayout(version=231, project=edb_path) """ + @pyaedt_function_handler( + designname="design", + projectname="project", + specified_version="version", + setup_name="setup", + new_desktop_session="new_desktop", + ) def __init__( self, - projectname=None, - designname=None, + project=None, + design=None, solution_type=None, - setup_name=None, - specified_version=None, + setup=None, + version=None, non_graphical=False, - new_desktop_session=False, + new_desktop=False, close_on_exit=False, student_version=False, machine="", port=0, aedt_process_id=None, ic_mode=None, + remove_lock=False, ): FieldAnalysis3DLayout.__init__( self, "HFSS 3D Layout Design", - projectname, - designname, + project, + design, solution_type, - setup_name, - specified_version, + setup, + version, non_graphical, - new_desktop_session, + new_desktop, close_on_exit, student_version, machine, port, aedt_process_id, ic_mode, + remove_lock=remove_lock, ) ScatteringMethods.__init__(self, self) @@ -710,7 +747,7 @@ def import_edb(self, input_folder): self._close_edb() project_name = self.desktop_class.active_project().GetName() design_name = self.desktop_class.active_design(self.desktop_class.active_project()).GetName().split(";")[-1] - self.__init__(projectname=project_name, designname=design_name) + self.__init__(project=project_name, design=design_name) return True @pyaedt_function_handler(outputdir="output_dir") @@ -1036,7 +1073,12 @@ def create_linear_count_sweep( return False @pyaedt_function_handler( - setupname="setup", freqstart="start_frequency", freqstop="stop_frequency", sweepname="name" + setup_name="setup", + setupname="setup", + freqstart="start_frequency", + freqstop="stop_frequency", + sweepname="name", + sweep_name="name", ) def create_linear_step_sweep( self, @@ -2035,9 +2077,59 @@ def edit_source_from_file( ------- bool """ + + def find_scale(data, header_line): + for td in data.keys(): + if td in header_line: + return data[td] + return None + + with open(input_file, "r") as f: + header = f.readlines()[0] + time_data = {"[ps]": 1e-12, "[ns]": 1e-9, "[us]": 1e-6, "[ms]": 1e-3, "[s]": 1} + curva_data_V = { + "[nV]": 1e-9, + "[pV]": 1e-12, + "[uV]": 1e-6, + "[mV]": 1e-3, + "[V]": 1, + "[kV]": 1e3, + } + curva_data_W = { + "[nW]": 1e-9, + "[pW]": 1e-12, + "[uW]": 1e-6, + "[mW]": 1e-3, + "[W]": 1, + "[kW]": 1e3, + } + curva_data_A = { + "[nA]": 1e-9, + "[pA]": 1e-12, + "[uA]": 1e-6, + "[mA]": 1e-3, + "[A]": 1, + "[kA]": 1e3, + } + scale = find_scale(time_data, header) + x_scale = scale if scale else x_scale + scale = find_scale(curva_data_V, header) + if scale: + y_scale = scale + data_format = "Voltage" + else: + scale = find_scale(curva_data_W, header) + if scale: + y_scale = scale + data_format = "Power" + else: + scale = find_scale(curva_data_A, header) + if scale: + y_scale = scale + data_format = "Current" out = "Voltage" freq, mag, phase = parse_excitation_file( - file_name=input_file, + input_file=input_file, is_time_domain=is_time_domain, x_scale=x_scale, y_scale=y_scale, @@ -2054,14 +2146,14 @@ def edit_source_from_file( self.design_datasets[ds_name_mag].y = mag self.design_datasets[ds_name_mag].update() else: - self.create_dataset1d_design(ds_name_mag, freq, mag, xunit="Hz") + self.create_dataset1d_design(ds_name_mag, freq, mag, x_unit="Hz") if self.dataset_exists(ds_name_phase, False): self.design_datasets[ds_name_phase].x = freq self.design_datasets[ds_name_phase].y = phase self.design_datasets[ds_name_phase].update() else: - self.create_dataset1d_design(ds_name_phase, freq, phase, xunit="Hz", yunit="deg") + self.create_dataset1d_design(ds_name_phase, freq, phase, x_unit="Hz", y_unit="deg") for p in self.boundaries: if p.name == source: str_val = ["TotalVoltage"] diff --git a/pyaedt/icepak.py b/pyaedt/icepak.py index 01e92a528fa..375c106e602 100644 --- a/pyaedt/icepak.py +++ b/pyaedt/icepak.py @@ -1,3 +1,27 @@ +# -*- 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. + """This module contains the ``Icepak`` class.""" from __future__ import absolute_import # noreorder @@ -9,7 +33,6 @@ import warnings import pyaedt -from pyaedt import is_linux from pyaedt.application.Analysis3D import FieldAnalysis3D from pyaedt.application.Design import DesignSettingsManipulation from pyaedt.generic.DataHandlers import _arg2dict @@ -20,6 +43,7 @@ from pyaedt.generic.general_methods import generate_unique_name from pyaedt.generic.general_methods import open_file from pyaedt.generic.general_methods import pyaedt_function_handler +from pyaedt.generic.settings import is_linux from pyaedt.generic.settings import settings from pyaedt.modeler.cad.components_3d import UserDefinedComponent from pyaedt.modeler.cad.elements3d import FacePrimitive @@ -49,32 +73,32 @@ class Icepak(FieldAnalysis3D): Parameters ---------- - projectname : str, optional + project : str, optional Name of the project to select or the full path to the project or AEDTZ archive to open. The default is ``None``, in which case an attempt is made to get an active project. If no projects are present, an empty project is created. - designname : str, optional + design : str, optional Name of the design to select. The default is ``None``, in which case an attempt is made to get an active design. If no designs are present, an empty design is created. solution_type : str, optional Solution type to apply to the design. The default is ``None``, in which case the default type is applied. - setup_name : str, optional + setup : str, optional Name of the setup to use as the nominal. The default is ``None``, in which case the active setup is used or nothing is used. - specified_version : str, int, float, optional + version : str, int, float, optional Version of AEDT to use. The default is ``None``, in which case the active version or latest installed version is used. This parameter is ignored when Script is launched within AEDT. Examples of input values are ``232``, ``23.2``,``2023.2``,``"2023.2"``. - non-graphical : bool, optional + non_graphical : bool, optional Whether to launch AEDT in non-graphical mode. The default is ``False``, in which case AEDT is launched in graphical mode. This parameter is ignored when a script is launched within AEDT. - new_desktop_session : bool, optional + new_desktop : bool, optional Whether to launch an instance of AEDT in a new thread, even if another instance of the ``specified_version`` is active on the machine. The default is ``False``. @@ -93,7 +117,11 @@ class Icepak(FieldAnalysis3D): The remote server must be up and running with the command `"ansysedt.exe -grpcsrv portnum"`. aedt_process_id : int, optional Process ID for the instance of AEDT to point PyAEDT at. The default is - ``None``. This parameter is only used when ``new_desktop_session = False``. + ``None``. This parameter is only used when ``new_desktop = False``. + remove_lock : bool, optional + Whether to remove lock to project before opening it or not. + The default is ``False``, which means to not unlock + the existing project if needed and raise an exception. Examples -------- @@ -131,42 +159,51 @@ class Icepak(FieldAnalysis3D): Create an instance of Icepak using the 2023 R2 release and open the specified project, which is ``myipk2.aedt``. - >>> icepak = Icepak(specified_version=2023.2, projectname="myipk2.aedt") + >>> icepak = Icepak(version=2023.2, project="myipk2.aedt") PyAEDT INFO: Project... PyAEDT INFO: No design is present. Inserting a new design. PyAEDT INFO: Added design... """ + @pyaedt_function_handler( + designname="design", + projectname="project", + specified_version="version", + setup_name="setup", + new_desktop_session="new_desktop", + ) def __init__( self, - projectname=None, - designname=None, + project=None, + design=None, solution_type=None, - setup_name=None, - specified_version=None, + setup=None, + version=None, non_graphical=False, - new_desktop_session=False, + new_desktop=False, close_on_exit=False, student_version=False, machine="", port=0, aedt_process_id=None, + remove_lock=False, ): FieldAnalysis3D.__init__( self, "Icepak", - projectname, - designname, + project, + design, solution_type, - setup_name, - specified_version, + setup, + version, non_graphical, - new_desktop_session, + new_desktop, close_on_exit, student_version, machine, port, aedt_process_id, + remove_lock=remove_lock, ) self._monitor = Monitor(self) self._configurations = ConfigurationsIcepak(self) @@ -2587,7 +2624,7 @@ def create_pcb_from_3dlayout( if close_linked_project_after_import and ".aedt" in project_name: prjname = os.path.splitext(os.path.basename(project_name))[0] - self.close_project(prjname, save_project=False) + self.close_project(prjname, save=False) self.logger.info("PCB component correctly created in Icepak.") return status @@ -3996,7 +4033,7 @@ def assign_stationary_wall_with_htc( ) @pyaedt_function_handler(setupname="name", setuptype="setup_type") - def create_setup(self, name="MySetupAuto", setup_type=None, **kwargs): + def create_setup(self, name=None, setup_type=None, **kwargs): """Create an analysis setup for Icepak. Optional arguments are passed along with ``setup_type`` and ``name``. Keyword names correspond to the ``setup_type`` @@ -4009,7 +4046,7 @@ def create_setup(self, name="MySetupAuto", setup_type=None, **kwargs): Parameters ---------- name : str, optional - Name of the setup. The default is ``"Setup1"``. + Name of the setup. setup_type : int, str, optional Type of the setup. Options are ``"IcepakSteadyState"`` and ``"IcepakTransient"``. The default is ``"IcepakSteadyState"``. @@ -4130,7 +4167,7 @@ def assign_source( >>> from pyaedt import Icepak >>> app = Icepak() >>> box = app.modeler.create_box([0, 0, 0],[20, 20, 20],name="box") - >>> ds = app.create_dataset1d_design("Test_DataSet", [1, 2, 3], [3, 4, 5]) + >>> ds = app.create_dataset1d_design("Test_DataSet",[1, 2, 3],[3, 4, 5]) >>> app.solution_type = "Transient" >>> b = app.assign_source("box", "Total Power", assignment_value={"Type": "Temp Dep", ... "Function": "Piecewise Linear", "Values": "Test_DataSet"}) @@ -4551,7 +4588,7 @@ def get_fans_operating_point(self, export_file=None, setup_name=None, time_step= export_file : str, optional Name of the file in which the fans' operating point is saved. The default is ``None``, in which case the filename is automatically generated. - setup_name : str, optional + setup : str, optional Setup name from which to determine the fans' operating point. The default is ``None``, in which case the first available setup is used. time_step : str, optional diff --git a/pyaedt/maxwell.py b/pyaedt/maxwell.py index eb46ce4fadb..b1bbe65663f 100644 --- a/pyaedt/maxwell.py +++ b/pyaedt/maxwell.py @@ -1,3 +1,27 @@ +# -*- 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. + """This module contains these Maxwell classes: ``Maxwell``, ``Maxwell2d``, and ``Maxwell3d``.""" from __future__ import absolute_import # noreorder @@ -8,7 +32,6 @@ import re import time -from pyaedt import settings from pyaedt.application.Analysis3D import FieldAnalysis3D from pyaedt.application.Variables import decompose_variable_value from pyaedt.generic.constants import SOLUTIONS @@ -18,6 +41,7 @@ from pyaedt.generic.general_methods import pyaedt_function_handler from pyaedt.generic.general_methods import read_configuration_file from pyaedt.generic.general_methods import write_configuration_file +from pyaedt.generic.settings import settings from pyaedt.modeler.geometry_operators import GeometryOperators from pyaedt.modules.Boundary import BoundaryObject from pyaedt.modules.Boundary import MaxwellParameters @@ -281,7 +305,7 @@ def assign_matrix( Set matrix in a Maxwell magnetostatic analysis. >>> from pyaedt import Maxwell2d - >>> m2d = Maxwell2d(solution_type="MagnetostaticXY",specified_version="2022.1",close_on_exit=True) + >>> m2d = Maxwell2d(solution_type="MagnetostaticXY",version="2022.1",close_on_exit=True) >>> coil1 = m2d.modeler.create_rectangle([0, 1.5, 0], [8, 3], is_covered=True, name="Coil_1") >>> coil2 = m2d.modeler.create_rectangle([8.5, 1.5, 0], [8, 3], is_covered=True, name="Coil_2") >>> coil3 = m2d.modeler.create_rectangle([16, 1.5, 0], [8, 3], is_covered=True, name="Coil_3") @@ -2084,23 +2108,23 @@ class Maxwell3d(Maxwell, FieldAnalysis3D, object): Parameters ---------- - projectname : str, optional + project : str, optional Name of the project to select or the full path to the project or AEDTZ archive to open. The default is ``None``, in which case an attempt is made to get an active project. If no projects are present, an empty project is created. - designname : str, optional + design : str, optional Name of the design to select. The default is ``None``, in which case an attempt is made to get an active design. If no designs are present, an empty design is created. solution_type : str, optional Solution type to apply to the design. The default is ``None``, in which case the default type is applied. - setup_name : str, optional + setup : str, optional Name of the setup to use as the nominal. The default is ``None``, in which case the active setup is used or nothing is used. - specified_version : str, int, float, optional + version : str, int, float, optional Version of AEDT to use. The default is ``None``, in which case the active version or latest installed version is used. This parameter is ignored when a script is launched within AEDT. @@ -2110,7 +2134,7 @@ class Maxwell3d(Maxwell, FieldAnalysis3D, object): is ``False``, in which case AEDT is launched in graphical mode. This parameter is ignored when a script is launched within AEDT. - new_desktop_session : bool, optional + new_desktop : bool, optional Whether to launch an instance of AEDT in a new thread, even if another instance of the ``specified_version`` is active on the machine. The default is ``False``. This parameter is ignored @@ -2132,7 +2156,11 @@ class Maxwell3d(Maxwell, FieldAnalysis3D, object): The remote server must be up and running with the command `"ansysedt.exe -grpcsrv portnum"`. aedt_process_id : int, optional Process ID for the instance of AEDT to point PyAEDT at. The default is - ``None``. This parameter is only used when ``new_desktop_session = False``. + ``None``. This parameter is only used when ``new_desktop = False``. + remove_lock : bool, optional + Whether to remove lock to project before opening it or not. + The default is ``False``, which means to not unlock + the existing project if needed and raise an exception. Examples -------- @@ -2146,7 +2174,7 @@ class Maxwell3d(Maxwell, FieldAnalysis3D, object): Create an instance of Maxwell 3D using the 2024 R1 release and open the specified project, which is named ``mymaxwell2.aedt``. - >>> m3d = Maxwell3d(specified_version="2024.1", projectname="mymaxwell2.aedt") + >>> m3d = Maxwell3d(version="2024.1", project="mymaxwell2.aedt") PyAEDT INFO: Added design ... """ @@ -2156,20 +2184,28 @@ def dim(self): """Dimensions.""" return "3D" + @pyaedt_function_handler( + designname="design", + projectname="project", + specified_version="version", + setup_name="setup", + new_desktop_session="new_desktop", + ) def __init__( self, - projectname=None, - designname=None, + project=None, + design=None, solution_type=None, - setup_name=None, - specified_version=None, + setup=None, + version=None, non_graphical=False, - new_desktop_session=False, + new_desktop=False, close_on_exit=False, student_version=False, machine="", port=0, aedt_process_id=None, + remove_lock=False, ): """ Initialize the ``Maxwell`` class. @@ -2178,18 +2214,19 @@ def __init__( FieldAnalysis3D.__init__( self, "Maxwell 3D", - projectname, - designname, + project, + design, solution_type, - setup_name, - specified_version, + setup, + version, non_graphical, - new_desktop_session, + new_desktop, close_on_exit, student_version, machine, port, aedt_process_id, + remove_lock=remove_lock, ) Maxwell.__init__(self) @@ -2838,23 +2875,23 @@ class Maxwell2d(Maxwell, FieldAnalysis3D, object): Parameters ---------- - projectname : str, optional + project : str, optional Name of the project to select or the full path to the project or AEDTZ archive to open. The default is ``None``, in which case an attempt is made to get an active project. If no projects are present, an empty project is created. - designname : str, optional + design : str, optional Name of the design to select. The default is ``None``, in which case an attempt is made to get an active design. If no designs are present, an empty design is created. solution_type : str, optional Solution type to apply to the design. The default is ``None``, in which case the default type is applied. - setup_name : str, optional + setup : str, optional Name of the setup to use as the nominal. The default is ``None``, in which case the active setup is used or nothing is used. - specified_version : str, int, float, optional + version : str, int, float, optional Version of AEDT to use. The default is ``None``, in which case the active version or latest installed version is used. This parameter is ignored when a script is launched within AEDT. @@ -2863,7 +2900,7 @@ class Maxwell2d(Maxwell, FieldAnalysis3D, object): Whether to launch AEDT in non-graphical mode. The default is ``False``, in which case AEDT is launched in graphical mode. This parameter is ignored when a script is launched within AEDT. - new_desktop_session : bool, optional + new_desktop : bool, optional Whether to launch an instance of AEDT in a new thread, even if another instance of the ``specified_version`` is active on the machine. The default is ``False``. This parameter is ignored when @@ -2884,7 +2921,11 @@ class Maxwell2d(Maxwell, FieldAnalysis3D, object): R2 or later. The remote server must be up and running with the command `"ansysedt.exe -grpcsrv portnum"`. aedt_process_id : int, optional Process ID for the instance of AEDT to point PyAEDT at. The default is - ``None``. This parameter is only used when ``new_desktop_session = False``. + ``None``. This parameter is only used when ``new_desktop = False``. + remove_lock : bool, optional + Whether to remove lock to project before opening it or not. + The default is ``False``, which means to not unlock + the existing project if needed and raise an exception. Examples -------- @@ -2923,37 +2964,46 @@ def geometry_mode(self): >>> oDesign.GetGeometryMode""" return self.odesign.GetGeometryMode() + @pyaedt_function_handler( + designname="design", + projectname="project", + specified_version="version", + setup_name="setup", + new_desktop_session="new_desktop", + ) def __init__( self, - projectname=None, - designname=None, + project=None, + design=None, solution_type=None, - setup_name=None, - specified_version=None, + setup=None, + version=None, non_graphical=False, - new_desktop_session=False, + new_desktop=False, close_on_exit=False, student_version=False, machine="", port=0, aedt_process_id=None, + remove_lock=False, ): self.is3d = False FieldAnalysis3D.__init__( self, "Maxwell 2D", - projectname, - designname, + project, + design, solution_type, - setup_name, - specified_version, + setup, + version, non_graphical, - new_desktop_session, + new_desktop, close_on_exit, student_version, machine, port, aedt_process_id, + remove_lock=remove_lock, ) Maxwell.__init__(self) diff --git a/pyaedt/maxwellcircuit.py b/pyaedt/maxwellcircuit.py index cc191e7cea3..2a70a8354b4 100644 --- a/pyaedt/maxwellcircuit.py +++ b/pyaedt/maxwellcircuit.py @@ -1,3 +1,27 @@ +# -*- 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. + """This module contains the ``MaxwellCircuit`` class.""" from __future__ import absolute_import # noreorder @@ -15,25 +39,25 @@ class MaxwellCircuit(AnalysisMaxwellCircuit, object): Parameters ---------- - projectname : str, optional + project : str, optional Name of the project to select or the full path to the project or AEDTZ archive to open. The default is ``None``, in which case an attempt is made to get an active project. If no projects are present, an empty project is created. - designname : str, optional + design : str, optional Name of the design to select. The default is ``None``, in which case an attempt is made to get an active design. If no designs are present, an empty design is created. - specified_version : str, int, float, optional + version : str, int, float, optional Version of AEDT to use. The default is ``None``. If ``None``, the active setup is used or the latest installed version is used. Examples of input values are ``232``, ``23.2``,``2023.2``,``"2023.2"``. - non-graphical : bool, optional + non_graphical : bool, optional Whether to launch AEDT in non-graphical mode. The default is ``False``, in which case AEDT is launched in graphical mode. This parameter is ignored when a script is launched within AEDT. - new_desktop_session : bool, optional + new_desktop : bool, optional Whether to launch an instance of AEDT in a new thread, even if another instance of the ``specified_version`` is active on the machine. The default is ``False``. @@ -52,7 +76,11 @@ class MaxwellCircuit(AnalysisMaxwellCircuit, object): later. The remote server must be up and running with the command `"ansysedt.exe -grpcsrv portnum"`. aedt_process_id : int, optional Process ID for the instance of AEDT to point PyAEDT at. The default is - ``None``. This parameter is only used when ``new_desktop_session = False``. + ``None``. This parameter is only used when ``new_desktop = False``. + remove_lock : bool, optional + Whether to remove lock to project before opening it or not. + The default is ``False``, which means to not unlock + the existing project if needed and raise an exception. Examples -------- @@ -80,34 +108,43 @@ class MaxwellCircuit(AnalysisMaxwellCircuit, object): >>> app = MaxwellCircuit("myfile.aedt") """ + @pyaedt_function_handler( + designname="design", + projectname="project", + specified_version="version", + setup_name="setup", + new_desktop_session="new_desktop", + ) def __init__( self, - projectname=None, - designname=None, + project=None, + design=None, solution_type=None, - specified_version=None, + version=None, non_graphical=False, - new_desktop_session=False, + new_desktop=False, close_on_exit=False, student_version=False, machine="", port=0, aedt_process_id=None, + remove_lock=False, ): """Constructor.""" AnalysisMaxwellCircuit.__init__( self, "Maxwell Circuit", - projectname, - designname, - specified_version, + project, + design, + version, non_graphical, - new_desktop_session, + new_desktop, close_on_exit, student_version, machine, port, aedt_process_id, + remove_lock=remove_lock, ) def _init_from_design(self, *args, **kwargs): diff --git a/pyaedt/mechanical.py b/pyaedt/mechanical.py index 7bd52e6e314..163e4d126b4 100644 --- a/pyaedt/mechanical.py +++ b/pyaedt/mechanical.py @@ -1,3 +1,27 @@ +# -*- 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. + """This module contains the ``Mechanical`` class.""" from __future__ import absolute_import # noreorder @@ -16,23 +40,23 @@ class Mechanical(FieldAnalysis3D, object): Parameters ---------- - projectname : str, optional + project : str, optional Name of the project to select or the full path to the project or AEDTZ archive to open. The default is ``None``, in which case an attempt is made to get an active project. If no projects are present, an empty project is created. - designname : str, optional + design : str, optional Name of the design to select. The default is ``None``, in which case an attempt is made to get an active design. If no designs are present, an empty design is created. solution_type : str, optional Solution type to apply to the design. The default is ``None``, in which case the default type is applied. - setup_name : str, optional + setup : str, optional Name of the setup to use as the nominal. The default is ``None``, in which case the active setup is used or nothing is used. - specified_version : str, int, float, optional + version : str, int, float, optional Version of AEDT to use. The default is ``None``, in which case the active version or latest installed version is used. This parameter is ignored when a script is launched within AEDT. @@ -41,7 +65,7 @@ class Mechanical(FieldAnalysis3D, object): Whether to launch AEDT in the non-graphical mode. The default is ``False``, in which case AEDT is launched in the graphical mode. This parameter is ignored when a script is launched within AEDT. - new_desktop_session : bool, optional + new_desktop : bool, optional Whether to launch an instance of AEDT in a new thread, even if another instance of the ``specified_version`` is active on the machine. The default is ``False``. This parameter is ignored when @@ -62,7 +86,11 @@ class Mechanical(FieldAnalysis3D, object): later. The remote server must be up and running with the command `"ansysedt.exe -grpcsrv portnum"`. aedt_process_id : int, optional Process ID for the instance of AEDT to point PyAEDT at. The default is - ``None``. This parameter is only used when ``new_desktop_session = False``. + ``None``. This parameter is only used when ``new_desktop = False``. + remove_lock : bool, optional + Whether to remove lock to project before opening it or not. + The default is ``False``, which means to not unlock + the existing project if needed and raise an exception. Examples -------- @@ -92,40 +120,49 @@ class Mechanical(FieldAnalysis3D, object): ``Mechanical`` object and open the specified project, which is named ``"myfile.aedt"``. - >>> aedtapp = Mechanical(specified_version=23.2, projectname="myfile.aedt") + >>> aedtapp = Mechanical(version=23.2, project="myfile.aedt") """ + @pyaedt_function_handler( + designname="design", + projectname="project", + specified_version="version", + setup_name="setup", + new_desktop_session="new_desktop", + ) def __init__( self, - projectname=None, - designname=None, + project=None, + design=None, solution_type=None, - setup_name=None, - specified_version=None, + setup=None, + version=None, non_graphical=False, - new_desktop_session=False, + new_desktop=False, close_on_exit=False, student_version=False, machine="", port=0, aedt_process_id=None, + remove_lock=False, ): FieldAnalysis3D.__init__( self, "Mechanical", - projectname, - designname, + project, + design, solution_type, - setup_name, - specified_version, + setup, + version, non_graphical, - new_desktop_session, + new_desktop, close_on_exit, student_version, machine, port, aedt_process_id, + remove_lock=remove_lock, ) def _init_from_design(self, *args, **kwargs): diff --git a/pyaedt/misc/__init__.py b/pyaedt/misc/__init__.py index 0a5470b6bf7..5cbb8146ac5 100644 --- a/pyaedt/misc/__init__.py +++ b/pyaedt/misc/__init__.py @@ -1,3 +1,27 @@ +# -*- 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 pyaedt.misc.misc import current_student_version from pyaedt.misc.misc import current_version from pyaedt.misc.misc import installed_versions diff --git a/pyaedt/misc/create_remote_dir.py b/pyaedt/misc/create_remote_dir.py index 61750cebc7a..2996053836f 100644 --- a/pyaedt/misc/create_remote_dir.py +++ b/pyaedt/misc/create_remote_dir.py @@ -1,3 +1,27 @@ +# -*- 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 sys diff --git a/pyaedt/misc/expression_catalog.toml b/pyaedt/misc/expression_catalog.toml new file mode 100644 index 00000000000..809dd4873ae --- /dev/null +++ b/pyaedt/misc/expression_catalog.toml @@ -0,0 +1,367 @@ +# Voltage + +[voltage_line] +name = "Voltage_Line" +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')", + "Fundamental_Quantity('E')", + "Operation('Imag')", + "Operation('Tangent')", + "Operation('Dot')", + "EnterLine('assignment')", + "Operation('LineValue')", + "Operation('Integrate')", + "Operation('CmplxI')", + "Operation('+')"] +dependent_expressions = [] +report = ["Data Table", "Rectangular Plot"] + +[voltage_line_time] +name = "Voltage_Line" +description = "Voltage drop along a line" +design_type = ["HFSS"] +fields_type = ["Fields"] +solution_type = "Transient" +primary_sweep = "Time" +assignment = "" +assignment_type = ["Line"] +operations = ["Fundamental_Quantity('E_t')", + "Operation('Tangent')", + "Operation('Dot')", + "EnterLine('assignment')", + "Operation('LineValue')", + "Operation('Integrate')" +] +dependent_expressions = [] +report = ["Data Table", "Rectangular Plot"] + +[voltage_line_maxwell] +name = "Voltage_Line" +description = "Voltage drop along a line" +design_type = ["Maxwell 3D"] +fields_type = ["Fields"] +solution_type = "" +primary_sweep = "Freq" +assignment = "" +assignment_type = ["Line"] +operations = ["NameOfExpression('')", + "Operation('Real')", + "Operation('Tangent')", + "Operation('Dot')", + "EnterLine('assignment')", + "Operation('LineValue')", + "Operation('Integrate')", + "Operation('CmplxR')", + "NameOfExpression('')", + "Operation('Imag')", + "Operation('Tangent')", + "Operation('Dot')", + "EnterLine('assignment')", + "Operation('LineValue')", + "Operation('Integrate')", + "Operation('CmplxI')", + "Operation('+')"] +dependent_expressions = [] +report = ["Data Table", "Rectangular Plot"] + +[voltage_drop] +name = "Voltage_Drop" +description = "Voltage drop in Q3D" +design_type = ["Q3D Extractor"] +fields_type = ["DC R/L Fields"] +solution_type = "" +primary_sweep = "Freq" +assignment = "" +assignment_type = ["Line", "Face", "Sheet", "Solid"] +constants = {"vrm"= 3.3} +operations = ["Fundamental_Quantity('dcvPhi')", + "Scalar_Function(FuncValue='vrm')", + "Operation('+')"] +dependent_expressions = [] +report = ["Field_3D"] + +# Current + +[current_line] +name = "Current_Line" +description = "Current along a line" +design_type = ["HFSS", "Q3D Extractor"] +fields_type = ["Fields", "CG Fields"] +solution_type = "" +primary_sweep = "Freq" +assignment = "" +assignment_type = ["Line"] +operations = ["NameOfExpression('')", + "Operation('Real')", + "Operation('Tangent')", + "Operation('Dot')", + "EnterLine('assignment')", + "Operation('LineValue')", + "Operation('Integrate')", + "Operation('CmplxR')", + "NameOfExpression('')", + "Operation('Imag')", + "Operation('Tangent')", + "Operation('Dot')", + "EnterLine('assignment')", + "Operation('LineValue')", + "Operation('Integrate')", + "Operation('CmplxI')", + "Operation('+')"] +dependent_expressions = [] +report = ["Data Table", "Rectangular Plot"] + +[current_line_time] +name = "Current_Line" +description = "Current along a line" +design_type = ["HFSS"] +fields_type = ["Fields"] +solution_type = "Transient" +primary_sweep = "Time" +assignment = "" +assignment_type = ["Line"] +operations = ["Fundamental_Quantity('H_t')", + "Operation('Tangent')", + "Operation('Dot')", + "EnterLine('assignment')", + "Operation('LineValue')", + "Operation('Integrate')"] +dependent_expressions = [] +report = ["Data Table", "Rectangular Plot"] + +# Power + +[power_flow] +name = "Power_Flow" +description = "Power flow through a surface" +design_type = ["HFSS"] +fields_type = ["Fields"] +solution_type = "" +primary_sweep = "Freq" +assignment = "" +assignment_type = ["Sheet", "Solid"] +operations = ["NameOfExpression('Poynting')", + "Operation('Real')", + "Operation('Normal')", + "Operation('Dot')", + "EnterSurface('assignment')", + "Operation('SurfaceValue')", + "Operation('Integrate')"] +dependent_expressions = [] +report = ["Data Table", "Rectangular Plot"] + +# Misc + +[wave_impedance_x] +name = "Wave_Impedance_X" +description = "Wave impedance along a line in X" +design_type = ["HFSS"] +fields_type = ["Fields"] +solution_type = "" +primary_sweep = "Freq" +assignment = "" +assignment_type = ["Line"] +operations = ["Fundamental_Quantity('E')", + "Operation('Smooth')", + "Operation('CmplxMag')", + "Vector_Constant(1, 0, 0)", + "Operation('Cross')", + "Operation('Mag')", + "NameOfExpression('')", + "Operation('Smooth')", + "Operation('CmplxMag')", + "Vector_Constant(1, 0, 0)", + "Operation('Cross')", + "Operation('Mag')", + "Operation('/')" +] +dependent_expressions = [] +report = ["Data Table", "Rectangular Plot"] + +[wave_impedance_y] +name = "Wave_Impedance_Y" +description = "Wave impedance along a line in Y" +design_type = ["HFSS"] +fields_type = ["Fields"] +solution_type = "" +primary_sweep = "Freq" +assignment = "" +assignment_type = ["Line"] +operations = ["Fundamental_Quantity('E')", + "Operation('Smooth')", + "Operation('CmplxMag')", + "Vector_Constant(0, 1, 0)", + "Operation('Cross')", + "Operation('Mag')", + "NameOfExpression('')", + "Operation('Smooth')", + "Operation('CmplxMag')", + "Vector_Constant(0, 1, 0)", + "Operation('Cross')", + "Operation('Mag')", + "Operation('/')" +] +dependent_expressions = [] +report = ["Data Table", "Rectangular Plot"] + +[wave_impedance_z] +name = "Wave_Impedance_Z" +description = "Wave impedance along a line in Z" +design_type = ["HFSS"] +fields_type = ["Fields"] +solution_type = "" +primary_sweep = "Freq" +assignment = "" +assignment_type = ["Line"] +operations = ["Fundamental_Quantity('E')", + "Operation('Smooth')", + "Operation('CmplxMag')", + "Vector_Constant(0, 0, 1)", + "Operation('Cross')", + "Operation('Mag')", + "NameOfExpression('')", + "Operation('Smooth')", + "Operation('CmplxMag')", + "Vector_Constant(0, 0, 1)", + "Operation('Cross')", + "Operation('Mag')", + "Operation('/')" +] +dependent_expressions = [] +report = ["Data Table", "Rectangular Plot"] + +# Electrostatic + +[electric_charge] +name = "Electric_Charge" +description = "Total electric charge on a surface" +design_type = ["Maxwell 3D"] +fields_type = ["Fields"] +solution_type = "" +primary_sweep = "Freq" +assignment = "" +assignment_type = ["Sheet", "Solid"] +operations = ["NameOfExpression('')", + "Operation('Normal')", + "Operation('Dot')", + "EnterSurface('assignment')", + "Operation('SurfaceValue')", + "Operation('Integrate')"] +dependent_expressions = [] +report = ["Data Table", "Rectangular Plot"] + +[e_line] +name = "E_Line" +description = "E field tangential component along a line" +design_type = ["Maxwell 2D"] +fields_type = ["Fields"] +solution_type = "" +primary_sweep = "Distance" +assignment = "" +assignment_type = ["Line"] +operations = ["NameOfExpression('')", + "Operation('Tangent')", + "Operation('Dot')"] +dependent_expressions = [] +report = ["Data Table", "Rectangular Plot"] + +[b_radial] +name = "Radial_Component_Magnetic_Field" +description = "Radial component of magnetic field" +design_type = ["Maxwell 2D"] +fields_type = ["Fields"] +solution_type = "" +primary_sweep = "Distance" +assignment = "" +assignment_type = ["Line"] +operations = ["Fundamental_Quantity('B')", + "Operation('ScalarX')", + "Scalar_Function(FuncValue='PHI')", + "Operation('UMathFunc', 'Cos')", + "Operation('*')", + "Fundamental_Quantity('B')", + "Operation('ScalarY')", + "Scalar_Function(FuncValue='PHI')", + "Operation('UMathFunc', 'Sin')", + "Operation('*')", + "Operation('+')"] +dependent_expressions = [] +report = ["Data Table", "Rectangular Plot"] + +[b_tangential] +name = "Tangential_Component_Magnetic_Field" +description = "Tangential component of magnetic field" +design_type = ["Maxwell 2D"] +fields_type = ["Fields"] +solution_type = "" +primary_sweep = "Distance" +assignment = "" +assignment_type = ["Line"] +operations = ["Fundamental_Quantity('B')", + "Operation('ScalarX')", + "Scalar_Function(FuncValue='PHI')", + "Operation('UMathFunc', 'Sin')", + "Operation('*')", + "Operation('Neg')", + "Fundamental_Quantity('B')", + "Operation('ScalarY')", + "Scalar_Function(FuncValue='PHI')", + "Operation('UMathFunc', 'Cos')", + "Operation('*')", + "Operation('+')"] +dependent_expressions = [] +report = ["Data Table", "Rectangular Plot"] + +[radial_stress_tensor] +name = "Radial_Stress_Tensor" +description = "Radial stress tensor" +design_type = ["Maxwell 2D"] +fields_type = ["Fields"] +solution_type = "" +primary_sweep = "Distance" +assignment = "" +assignment_type = ["Line"] +dependent_expressions = ["b_radial", "b_tangential"] +operations = ["NameOfExpression('b_radial')", + "NameOfExpression('b_radial')", + "Operation('*')", + "NameOfExpression('b_tangential')", + "NameOfExpression('b_tangential')", + "Operation('*')", + "Operation('Neg')", + "Operation('+')", + "Scalar_Constant(1.25664e-06)", + "Operation('/')", + "Scalar_Constant(2)", + "Operation('/')"] +report = ["Data Table", "Rectangular Plot"] + +[tangential_stress_tensor] +name = "Tangential_Stress_Tensor" +description = "Tangential stress tensor" +design_type = ["Maxwell 2D"] +fields_type = ["Fields"] +solution_type = "" +primary_sweep = "Distance" +assignment = "" +assignment_type = ["Line"] +dependent_expressions = ["b_radial", "b_tangential"] +operations = ["NameOfExpression('b_radial')", + "NameOfExpression('b_tangential')", + "Operation('*')", + "Scalar_Constant(1.25664e-06)", + "Operation('/')"] +report = ["Data Table", "Rectangular Plot"] diff --git a/pyaedt/misc/misc.py b/pyaedt/misc/misc.py index e3668e7865c..35d37c070aa 100644 --- a/pyaedt/misc/misc.py +++ b/pyaedt/misc/misc.py @@ -1,3 +1,27 @@ +# -*- 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. + """Miscellaneous Methods for PyAEDT.""" import os @@ -75,3 +99,21 @@ def current_student_version(): if "SV" in version_key: return version_key return "" + + +def is_safe_path(path, allowed_extensions=None): + """Validate if a path is safe to use.""" + # Ensure path is an existing file or directory + if not os.path.exists(path) or not os.path.isfile(path): + return False + + # Restrict to allowed file extensions: + if allowed_extensions: + if not any(path.endswith(extension) for extension in allowed_extensions): + return False + + # Ensure path does not contain dangerous characters + if any(char in path for char in (";", "|", "&", "$", "<", ">", "`")): + return False + + return True diff --git a/pyaedt/misc/spisim_com_configuration_files/__init__.py b/pyaedt/misc/spisim_com_configuration_files/__init__.py index c23e620fcaf..addb0938ec4 100644 --- a/pyaedt/misc/spisim_com_configuration_files/__init__.py +++ b/pyaedt/misc/spisim_com_configuration_files/__init__.py @@ -1,3 +1,27 @@ +# -*- 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 pathlib import Path workdir = Path(__file__).parent diff --git a/pyaedt/misc/spisim_com_configuration_files/com_parameters.py b/pyaedt/misc/spisim_com_configuration_files/com_parameters.py index 7aaeddda5c7..1bec9c5c696 100644 --- a/pyaedt/misc/spisim_com_configuration_files/com_parameters.py +++ b/pyaedt/misc/spisim_com_configuration_files/com_parameters.py @@ -1,9 +1,33 @@ +# -*- 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 enum import Enum import json from pathlib import Path -from pyaedt import pyaedt_function_handler -from pyaedt import settings +from pyaedt.generic.general_methods import pyaedt_function_handler +from pyaedt.generic.settings import settings from pyaedt.misc.spisim_com_configuration_files.com_settings_mapping import spimsim_matlab_keywords_mapping logger = settings.logger diff --git a/pyaedt/misc/spisim_com_configuration_files/com_settings_mapping.py b/pyaedt/misc/spisim_com_configuration_files/com_settings_mapping.py index 942f327492c..7c30eac24ca 100644 --- a/pyaedt/misc/spisim_com_configuration_files/com_settings_mapping.py +++ b/pyaedt/misc/spisim_com_configuration_files/com_settings_mapping.py @@ -1,3 +1,27 @@ +# -*- 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. + spimsim_matlab_keywords_mapping = { # Matlab keyword -> SPIsim keyword # OP_IO_CTRL diff --git a/pyaedt/modeler/__init__.py b/pyaedt/modeler/__init__.py index e69de29bb2d..9c4476773da 100644 --- a/pyaedt/modeler/__init__.py +++ b/pyaedt/modeler/__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/pyaedt/modeler/advanced_cad/__init__.py b/pyaedt/modeler/advanced_cad/__init__.py index e69de29bb2d..9c4476773da 100644 --- a/pyaedt/modeler/advanced_cad/__init__.py +++ b/pyaedt/modeler/advanced_cad/__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/pyaedt/modeler/advanced_cad/actors.py b/pyaedt/modeler/advanced_cad/actors.py index c68f198cbf0..811be43a412 100644 --- a/pyaedt/modeler/advanced_cad/actors.py +++ b/pyaedt/modeler/advanced_cad/actors.py @@ -1,4 +1,28 @@ -from pyaedt import pyaedt_function_handler +# -*- 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 pyaedt.generic.general_methods import pyaedt_function_handler from pyaedt.generic.general_methods import read_json from pyaedt.modeler.advanced_cad.multiparts import Actor from pyaedt.modeler.advanced_cad.multiparts import MultiPartComponent @@ -363,7 +387,7 @@ def speed_expression(self, s): @pyaedt_function_handler() def _add_speed(self, app): app.variable_manager.set_variable( - variable_name=self.speed_name, expression=self.speed_expression, description="radar speed" + name=self.speed_name, expression=self.speed_expression, description="radar speed" ) # Update expressions for x and y position in app: app[self.offset_names[0]] = ( diff --git a/pyaedt/modeler/advanced_cad/multiparts.py b/pyaedt/modeler/advanced_cad/multiparts.py index 7f29aabbbbb..f57bde5199b 100644 --- a/pyaedt/modeler/advanced_cad/multiparts.py +++ b/pyaedt/modeler/advanced_cad/multiparts.py @@ -1,4 +1,27 @@ # -*- 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 from pyaedt.generic.filesystem import get_json_files @@ -401,20 +424,18 @@ def position_in_app(self, app): for m in range(3): # app[self.offset_names[m]] = self.offset[m] app.variable_manager.set_variable( - variable_name=self.offset_names[m], + name=self.offset_names[m], expression=self.offset[m], description=self.name + " " + xyz[m] + "-position", ) - app.variable_manager.set_variable( - variable_name=self.yaw_name, expression=self.yaw, description=self.name + " yaw" - ) + app.variable_manager.set_variable(name=self.yaw_name, expression=self.yaw, description=self.name + " yaw") app.variable_manager.set_variable( - variable_name=self.pitch_name, expression=self.pitch, description=self.name + " pitch" + name=self.pitch_name, expression=self.pitch, description=self.name + " pitch" ) app.variable_manager.set_variable( - variable_name=self.roll_name, expression=self.roll, description=self.name + " roll" + name=self.roll_name, expression=self.roll, description=self.name + " roll" ) cs_origin = self.offset_names @@ -618,7 +639,7 @@ def speed_expression(self, s): # TODO: Add validation of the expression. @pyaedt_function_handler() def _add_speed(self, app): app.variable_manager.set_variable( - variable_name=self.speed_name, expression=self.speed_expression, description="object speed" + name=self.speed_name, expression=self.speed_expression, description="object speed" ) # Update expressions for x and y position in app: app[self.offset_names[0]] = ( diff --git a/pyaedt/modeler/advanced_cad/oms.py b/pyaedt/modeler/advanced_cad/oms.py index 9f230692036..f496b0b56b2 100644 --- a/pyaedt/modeler/advanced_cad/oms.py +++ b/pyaedt/modeler/advanced_cad/oms.py @@ -1,3 +1,27 @@ +# -*- 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 warnings diff --git a/pyaedt/modeler/advanced_cad/parts.py b/pyaedt/modeler/advanced_cad/parts.py index 87f5cbf0dd5..1d5809dd46a 100644 --- a/pyaedt/modeler/advanced_cad/parts.py +++ b/pyaedt/modeler/advanced_cad/parts.py @@ -1,6 +1,30 @@ +# -*- 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 -from pyaedt import pyaedt_function_handler +from pyaedt.generic.general_methods import pyaedt_function_handler from pyaedt.modeler.geometry_operators import GeometryOperators diff --git a/pyaedt/modeler/advanced_cad/stackup_3d.py b/pyaedt/modeler/advanced_cad/stackup_3d.py index b9e9f37ac8e..84ad110bd08 100644 --- a/pyaedt/modeler/advanced_cad/stackup_3d.py +++ b/pyaedt/modeler/advanced_cad/stackup_3d.py @@ -1,7 +1,31 @@ +# -*- 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 collections import OrderedDict import os -from pyaedt import is_ironpython +from pyaedt.generic.general_methods import is_ironpython if not is_ironpython: try: @@ -806,7 +830,7 @@ def add_trace( >>> from pyaedt import Hfss >>> from pyaedt.modeler.stackup_3d import Stackup3D - >>> hfss = Hfss(new_desktop_session=True) + >>> hfss = Hfss(new_desktop=True) >>> my_stackup = Stackup3D(hfss, 2.5e9) >>> gnd = my_stackup.add_ground_layer("gnd") >>> my_stackup.add_dielectric_layer("diel1", thickness=1.5, material="Duroid (tm)") @@ -1232,7 +1256,7 @@ class Stackup3D(object): >>> from pyaedt import Hfss >>> from pyaedt.modeler.stackup_3d import Stackup3D - >>> hfss = Hfss(new_desktop_session=True) + >>> hfss = Hfss(new_desktop=True) >>> my_stackup = Stackup3D(hfss, 2.5e9) """ @@ -2637,7 +2661,7 @@ class Trace(CommonObject, object): -------- >>> from pyaedt import Hfss >>> from pyaedt.modeler.stackup_3d import Stackup3D - >>> hfss = Hfss(new_desktop_session=True) + >>> hfss = Hfss(new_desktop=True) >>> my_stackup = Stackup3D(hfss, 2.5e9) >>> gnd = my_stackup.add_ground_layer("gnd") >>> my_stackup.add_dielectric_layer("diel1", thickness=1.5, material="Duroid (tm)") @@ -3220,7 +3244,7 @@ def create_lumped_port(self, reference_layer, opposite_side=False, port_name=Non -------- >>> from pyaedt import Hfss >>> from pyaedt.modeler.stackup_3d import Stackup3D - >>> hfss = Hfss(new_desktop_session=True) + >>> hfss = Hfss(new_desktop=True) >>> my_stackup = Stackup3D(hfss, 2.5e9) >>> gnd = my_stackup.add_ground_layer("gnd") >>> my_stackup.add_dielectric_layer("diel1", thickness=1.5, material="Duroid (tm)") @@ -3296,7 +3320,7 @@ class Polygon(CommonObject, object): >>> from pyaedt import Hfss >>> from pyaedt.modeler.stackup_3d import Stackup3D - >>> hfss = Hfss(new_desktop_session=True) + >>> hfss = Hfss(new_desktop=True) >>> my_stackup = Stackup3D(hfss, 2.5e9) >>> gnd = my_stackup.add_ground_layer("gnd", thickness=None) >>> my_stackup.add_dielectric_layer("diel1", thickness=1.5, material="Duroid (tm)") diff --git a/pyaedt/modeler/cad/Modeler.py b/pyaedt/modeler/cad/Modeler.py index be58a4ab7c6..848a2325642 100644 --- a/pyaedt/modeler/cad/Modeler.py +++ b/pyaedt/modeler/cad/Modeler.py @@ -1,4 +1,27 @@ # -*- 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. + """ This module contains these classes: `BaseCoordinateSystem`, `FaceCoordinateSystem`, `CoordinateSystem`, `Modeler`, `Position`, and `SweepOptions`. diff --git a/pyaedt/modeler/cad/Primitives.py b/pyaedt/modeler/cad/Primitives.py index f6ab146fa0f..8119b97298d 100644 --- a/pyaedt/modeler/cad/Primitives.py +++ b/pyaedt/modeler/cad/Primitives.py @@ -1,3 +1,27 @@ +# -*- 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. + """ This module contains these Primitives classes: `Polyline` and `Primitives`. """ @@ -584,7 +608,7 @@ def solid_names(self): Returns ------- - List + list """ self._refresh_solids() return self._solids @@ -595,7 +619,7 @@ def sheet_names(self): Returns ------- - str + list """ self._refresh_sheets() return self._sheets @@ -606,7 +630,7 @@ def line_names(self): Returns ------- - str + list """ self._refresh_lines() return self._lines @@ -617,7 +641,7 @@ def unclassified_names(self): Returns ------- - str + list """ self._refresh_unclassified() return self._unclassified @@ -628,7 +652,7 @@ def object_names(self): Returns ------- - str + list """ self._refresh_object_types() return [i for i in self._all_object_names if i not in self._unclassified and i not in self._points] @@ -639,7 +663,7 @@ def point_names(self): Returns ------- - str + list """ self._refresh_points() return self._points @@ -2904,6 +2928,7 @@ def duplicate_around_axis( str(clones), ] vArg3 = ["NAME:Options", "DuplicateAssignments:=", duplicate_assignment] + self.add_new_objects() added_objs = self.oeditor.DuplicateAroundAxis(vArg1, vArg2, vArg3) self._duplicate_added_objects_tuple() if is_3d_comp: @@ -2972,6 +2997,7 @@ def duplicate_along_line( vArg2.append("ZComponent:="), vArg2.append(Zpos) vArg2.append("Numclones:="), vArg2.append(str(clones)) vArg3 = ["NAME:Options", "DuplicateAssignments:=", duplicate_assignment] + self.add_new_objects() self.oeditor.DuplicateAlongLine(vArg1, vArg2, vArg3) if is_3d_comp: return self._duplicate_added_components_tuple() @@ -3678,6 +3704,7 @@ def paste(self): >>> oEditor.Paste """ + self.add_new_objects() self.oeditor.Paste() new_objects = self.add_new_objects() return new_objects @@ -4607,6 +4634,108 @@ def get_vertices_of_line(self, assignment): return position_list + @pyaedt_function_handler( + object_list="assignment_to_export", + removed_objects="assignment_to_remove", + fileName="file_name", + filePath="file_path", + fileFormat="file_format", + ) + def export_3d_model( + self, + file_name="", + file_path="", + file_format=".step", + assignment_to_export=None, + assignment_to_remove=None, + major_version=-1, + minor_version=-1, + ): + """Export the 3D model. + + Parameters + ---------- + file_name : str, optional + Name of the file. + file_path : str, optional + Path for the file. + file_format : str, optional + Format of the file. The default is ``".step"``. + assignment_to_export : list, optional + List of objects to export. The default is ``None``. + assignment_to_remove : list, optional + List of objects to remove. The default is ``None``. + major_version : int, optional + File format major version. The default is -1. + minor_version : int, optional + File format major version. The default is -1. + + Returns + ------- + bool + ``True`` when successful, ``False`` when failed. + + References + ---------- + + >>> oEditor.Export + """ + + if not file_name: + file_name = self.project_name + "_" + self.design_name + if not file_path: + file_path = self.working_directory + if assignment_to_export is None: + assignment_to_export = [] + if assignment_to_remove is None: + assignment_to_remove = [] + + sub_regions = [] + if self._app.settings.aedt_version > "2023.2": + sub_regions = [o for o in self.non_model_objects if self[o].history().command == "CreateSubRegion"] + + if not assignment_to_export: + allObjects = self.object_names + if assignment_to_remove: + for rem in assignment_to_remove: + allObjects.remove(rem) + else: + if "Region" in allObjects: + allObjects.remove("Region") + for o in sub_regions: + allObjects.remove(o) + else: + allObjects = assignment_to_export[:] + + self.logger.debug("Exporting {} objects".format(len(allObjects))) + + # actual version supported by AEDT is 29.0 + if major_version == -1: + if file_format in [".sm3", ".sat", ".sab"]: + major_version = 29 + if minor_version == -1: + if file_format in [".sm3", ".sat", ".sab"]: + minor_version = 0 + stringa = ",".join(allObjects) + arg = [ + "NAME:ExportParameters", + "AllowRegionDependentPartSelectionForPMLCreation:=", + True, + "AllowRegionSelectionForPMLCreation:=", + True, + "Selections:=", + stringa, + "File Name:=", + os.path.join(file_path, file_name + file_format).replace("\\", "/"), + "Major Version:=", + major_version, + "Minor Version:=", + minor_version, + ] + + self.oeditor.Export(arg) + return True + @pyaedt_function_handler(filename="input_file") def import_3d_cad( self, @@ -6568,7 +6697,7 @@ def create_polyline( >>> from pyaedt.modeler.cad.polylines import PolylineSegment >>> from pyaedt import Desktop >>> from pyaedt import Maxwell3d - >>> desktop=Desktop(specified_version="2021.2", new_desktop_session=False) + >>> desktop=Desktop(version="2021.2", new_desktop=False) >>> aedtapp = Maxwell3d() >>> aedtapp.modeler.model_units = "mm" >>> modeler = aedtapp.modeler diff --git a/pyaedt/modeler/cad/Primitives2D.py b/pyaedt/modeler/cad/Primitives2D.py index bec2cae27d6..c2157373ce2 100644 --- a/pyaedt/modeler/cad/Primitives2D.py +++ b/pyaedt/modeler/cad/Primitives2D.py @@ -1,3 +1,27 @@ +# -*- 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 pyaedt.generic.general_methods import pyaedt_function_handler from pyaedt.modeler.cad.Primitives import GeometryModeler diff --git a/pyaedt/modeler/cad/Primitives3D.py b/pyaedt/modeler/cad/Primitives3D.py index e712ba8b18f..59378eddad0 100644 --- a/pyaedt/modeler/cad/Primitives3D.py +++ b/pyaedt/modeler/cad/Primitives3D.py @@ -1,3 +1,27 @@ +# -*- 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 copy import json from math import asin @@ -1469,18 +1493,8 @@ def insert_3d_component( else: is_project_dataset = False dsname = key - self._app.create_dataset( - dsname, - dat["x"], - dat["y"], - dat["z"], - dat["v"], - is_project_dataset, - dat["xunit"], - dat["yunit"], - dat["zunit"], - dat["vunit"], - ) + self._app.create_dataset(dsname, dat["x"], dat["y"], dat["z"], dat["v"], is_project_dataset, + dat["xunit"], dat["yunit"], dat["zunit"], dat["vunit"]) udm_obj = self._create_user_defined_component(new_object_name) if name and not auxiliary_parameters: udm_obj.name = name @@ -1536,7 +1550,7 @@ def insert_3d_component( cs.ref_cs = coordinate_system if aux_dict.get("monitors", None): temp_proj_name = generate_unique_project_name() - ipkapp_temp = Icepak(projectname=os.path.join(self._app.toolkit_directory, temp_proj_name)) + ipkapp_temp = Icepak(project=os.path.join(self._app.toolkit_directory, temp_proj_name)) ipkapp_temp.delete_design(ipkapp_temp.design_name) self._app.oproject.CopyDesign(self._app.design_name) ipkapp_temp.oproject.Paste() diff --git a/pyaedt/modeler/cad/__init__.py b/pyaedt/modeler/cad/__init__.py index e69de29bb2d..9c4476773da 100644 --- a/pyaedt/modeler/cad/__init__.py +++ b/pyaedt/modeler/cad/__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/pyaedt/modeler/cad/component_array.py b/pyaedt/modeler/cad/component_array.py index b0da2e6bd38..f175115721d 100644 --- a/pyaedt/modeler/cad/component_array.py +++ b/pyaedt/modeler/cad/component_array.py @@ -1,12 +1,36 @@ +# -*- 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 __future__ import absolute_import from collections import OrderedDict import os import re -from pyaedt import pyaedt_function_handler from pyaedt.generic.constants import AEDT_UNITS from pyaedt.generic.general_methods import _uname +from pyaedt.generic.general_methods import pyaedt_function_handler from pyaedt.generic.general_methods import read_csv @@ -25,7 +49,7 @@ class ComponentArray(object): Basic usage demonstrated with an HFSS design with an existing array: >>> from pyaedt import Hfss - >>> aedtapp = Hfss(projectname="Array.aedt") + >>> aedtapp = Hfss(project="Array.aedt") >>> array_names = aedtapp.component_array_names[0] >>> array = aedtapp.component_array[array_names[0]] """ @@ -386,7 +410,7 @@ def parse_array_info_from_csv(self, input_file): # pragma: no cover Examples -------- >>> from pyaedt import Hfss - >>> aedtapp = Hfss(projectname="Array.aedt") + >>> aedtapp = Hfss(project="Array.aedt") >>> array_names = aedtapp.component_array_names[0] >>> array = aedtapp.component_array[array_names[0]] >>> array_csv = array.export_array_info() diff --git a/pyaedt/modeler/cad/components_3d.py b/pyaedt/modeler/cad/components_3d.py index 1ed2f3feced..8595dfb1686 100644 --- a/pyaedt/modeler/cad/components_3d.py +++ b/pyaedt/modeler/cad/components_3d.py @@ -1,3 +1,27 @@ +# -*- 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 __future__ import absolute_import from collections import OrderedDict @@ -6,10 +30,10 @@ import re import warnings -from pyaedt import Edb -from pyaedt import pyaedt_function_handler +from pyaedt.edb import Edb from pyaedt.generic.desktop_sessions import _edb_sessions from pyaedt.generic.general_methods import _uname +from pyaedt.generic.general_methods import pyaedt_function_handler from pyaedt.modeler.cad.elements3d import BinaryTreeNode from pyaedt.modeler.cad.elements3d import _dict2arg diff --git a/pyaedt/modeler/cad/elements3d.py b/pyaedt/modeler/cad/elements3d.py index ea55690aa8a..c609c3855f5 100644 --- a/pyaedt/modeler/cad/elements3d.py +++ b/pyaedt/modeler/cad/elements3d.py @@ -1,3 +1,27 @@ +# -*- 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 __future__ import absolute_import from collections import OrderedDict @@ -1116,7 +1140,6 @@ def coordinate_system(self, new_coordinate_system): coordinate_system = ["NAME:Orientation", "Value:=", new_coordinate_system] self._change_property(coordinate_system) self._point_coordinate_system = new_coordinate_system - return True @pyaedt_function_handler() def delete(self): diff --git a/pyaedt/modeler/cad/object3d.py b/pyaedt/modeler/cad/object3d.py index 423a30436b7..26029d9089d 100644 --- a/pyaedt/modeler/cad/object3d.py +++ b/pyaedt/modeler/cad/object3d.py @@ -1,4 +1,27 @@ # -*- 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. + """ This module contains these classes: `Components3DLayout`,`CircuitComponent', `EdgePrimitive`, `EdgeTypePrimitive`, `FacePrimitive`, `Geometries3DLayout`, diff --git a/pyaedt/modeler/cad/polylines.py b/pyaedt/modeler/cad/polylines.py index 3df25284627..c6c23443f13 100644 --- a/pyaedt/modeler/cad/polylines.py +++ b/pyaedt/modeler/cad/polylines.py @@ -1,13 +1,37 @@ +# -*- 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 __future__ import absolute_import import math import warnings -from pyaedt import pyaedt_function_handler from pyaedt.application.Variables import decompose_variable_value from pyaedt.generic.constants import PLANE from pyaedt.generic.constants import unit_converter from pyaedt.generic.general_methods import _dim_arg +from pyaedt.generic.general_methods import pyaedt_function_handler from pyaedt.modeler.cad.object3d import Object3d from pyaedt.modeler.geometry_operators import GeometryOperators diff --git a/pyaedt/modeler/calculators.py b/pyaedt/modeler/calculators.py index 5e802073ac8..621baaa23ab 100644 --- a/pyaedt/modeler/calculators.py +++ b/pyaedt/modeler/calculators.py @@ -1,3 +1,27 @@ +# -*- 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 math from pyaedt import constants diff --git a/pyaedt/modeler/circuits/PrimitivesCircuit.py b/pyaedt/modeler/circuits/PrimitivesCircuit.py index 87dc0caf6c1..098cbcef3eb 100644 --- a/pyaedt/modeler/circuits/PrimitivesCircuit.py +++ b/pyaedt/modeler/circuits/PrimitivesCircuit.py @@ -1,3 +1,27 @@ +# -*- 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 math import os import random @@ -318,7 +342,7 @@ def create_interface_port(self, name, location=None, angle=0): return False @pyaedt_function_handler() - def create_page_port(self, name, location=[], angle=0): + def create_page_port(self, name, location=None, angle=0): """Create a page port. Parameters @@ -326,7 +350,8 @@ def create_page_port(self, name, location=[], angle=0): name : str Name of the port. location : list, optional - Position on the X and Y axis. The default is ``None``. + Position on the X and Y axis. + If not provided the default is ``None``, in which case an empty list is set. angle : optional Angle rotation in degrees. The default is ``0``. @@ -340,6 +365,7 @@ def create_page_port(self, name, location=[], angle=0): >>> oEditor.CreatePagePort """ + location = [] if location is None else location xpos, ypos = self._get_location(location) id = self.create_unique_id() diff --git a/pyaedt/modeler/circuits/PrimitivesEmit.py b/pyaedt/modeler/circuits/PrimitivesEmit.py index 34f65476fce..89063faae70 100644 --- a/pyaedt/modeler/circuits/PrimitivesEmit.py +++ b/pyaedt/modeler/circuits/PrimitivesEmit.py @@ -1,3 +1,27 @@ +# -*- 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 collections import defaultdict from pyaedt.emit_core import emit_constants as emit_consts @@ -764,7 +788,7 @@ def set_band_start_frequency(self, band_node, band_start_freq, units=""): Examples -------- >>> from pyaedt import Emit - >>> aedtapp = Emit(new_desktop_session=False) + >>> aedtapp = Emit(new_desktop=False) >>> radio = aedtapp.modeler.components.create_component("New Radio") >>> band = radio.bands()[0] >>> start_freq = 10 @@ -810,7 +834,7 @@ def set_band_stop_frequency(self, band_node, band_stop_freq, units=""): Examples -------- >>> from pyaedt import Emit - >>> aedtapp = Emit(new_desktop_session=False) + >>> aedtapp = Emit(new_desktop=False) >>> radio = aedtapp.modeler.components.create_component("New Radio") >>> band = radio.bands()[0] >>> stop_freq = 10 diff --git a/pyaedt/modeler/circuits/PrimitivesMaxwellCircuit.py b/pyaedt/modeler/circuits/PrimitivesMaxwellCircuit.py index b01717f0d6a..9fedbb602de 100644 --- a/pyaedt/modeler/circuits/PrimitivesMaxwellCircuit.py +++ b/pyaedt/modeler/circuits/PrimitivesMaxwellCircuit.py @@ -1,3 +1,27 @@ +# -*- 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 pyaedt.generic.general_methods import pyaedt_function_handler from pyaedt.modeler.circuits.PrimitivesCircuit import CircuitComponents diff --git a/pyaedt/modeler/circuits/PrimitivesNexxim.py b/pyaedt/modeler/circuits/PrimitivesNexxim.py index a4e81202ac9..050cff65412 100644 --- a/pyaedt/modeler/circuits/PrimitivesNexxim.py +++ b/pyaedt/modeler/circuits/PrimitivesNexxim.py @@ -1,11 +1,33 @@ # -*- 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 random import re import time import warnings -from pyaedt import settings from pyaedt.application.Variables import decompose_variable_value from pyaedt.generic.LoadAEDTFile import load_keyword_in_aedt_file from pyaedt.generic.constants import AEDT_UNITS @@ -13,6 +35,7 @@ from pyaedt.generic.general_methods import is_linux from pyaedt.generic.general_methods import open_file from pyaedt.generic.general_methods import pyaedt_function_handler +from pyaedt.generic.settings import settings from pyaedt.modeler.circuits.PrimitivesCircuit import CircuitComponents from pyaedt.modeler.circuits.PrimitivesCircuit import ComponentCatalog from pyaedt.modeler.circuits.object3dcircuit import CircuitComponent @@ -1218,8 +1241,8 @@ def create_new_component_from_symbol( time_stamp=1591858313, description="", refbase="x", - parameters=[], - values=[], + parameters=None, + values=None, gref="", ): """Create a component from a symbol. @@ -1237,9 +1260,11 @@ def create_new_component_from_symbol( refbase : str, optional Reference base. The default is ``"U"``. parameters : list - List of parameters. The default is ``[]``. + List of parameters. + If not provided the default is ``None``, in which case an empty list is set. values : list - List of parameter values. The default is ``[]``. + List of parameter values. + If not provided the default is ``None``, in which case an empty list is set. gref : str, optional Global Reference @@ -1254,6 +1279,8 @@ def create_new_component_from_symbol( >>> oModelManager.Add >>> oComponentManager.Add """ + parameters = [] if parameters is None else parameters + values = [] if values is None else values arg = [ "NAME:" + name, "Info:=", @@ -1957,7 +1984,7 @@ def create_component_from_spicemodel( Examples -------- >>> from pyaedt import Circuit - >>> cir = Circuit(specified_version="2023.2") + >>> cir = Circuit(version="2023.2") >>> model = os.path.join("Your path", "test.lib") >>> cir.modeler.schematic.create_component_from_spicemodel(input_file=model,model="GRM1234",symbol="nexx_cap") >>> cir.release_desktop(False, False) diff --git a/pyaedt/modeler/circuits/PrimitivesTwinBuilder.py b/pyaedt/modeler/circuits/PrimitivesTwinBuilder.py index 1a76aa0b9f8..499538aaf40 100644 --- a/pyaedt/modeler/circuits/PrimitivesTwinBuilder.py +++ b/pyaedt/modeler/circuits/PrimitivesTwinBuilder.py @@ -1,3 +1,27 @@ +# -*- 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 pyaedt.generic.general_methods import pyaedt_function_handler from pyaedt.modeler.circuits.PrimitivesCircuit import CircuitComponents from pyaedt.modeler.circuits.PrimitivesCircuit import ComponentCatalog diff --git a/pyaedt/modeler/circuits/__init__.py b/pyaedt/modeler/circuits/__init__.py index e69de29bb2d..9c4476773da 100644 --- a/pyaedt/modeler/circuits/__init__.py +++ b/pyaedt/modeler/circuits/__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/pyaedt/modeler/circuits/object3dcircuit.py b/pyaedt/modeler/circuits/object3dcircuit.py index a6d8dcd3d56..ac3bb1c2888 100644 --- a/pyaedt/modeler/circuits/object3dcircuit.py +++ b/pyaedt/modeler/circuits/object3dcircuit.py @@ -1,15 +1,38 @@ # -*- 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 __future__ import absolute_import from collections import OrderedDict import math import time -from pyaedt import pyaedt_function_handler from pyaedt.application.Variables import decompose_variable_value from pyaedt.generic.constants import AEDT_UNITS from pyaedt.generic.general_methods import _arg2dict from pyaedt.generic.general_methods import _dim_arg +from pyaedt.generic.general_methods import pyaedt_function_handler from pyaedt.modeler.cad.elements3d import _dict2arg from pyaedt.modeler.geometry_operators import GeometryOperators as go diff --git a/pyaedt/modeler/geometry_operators.py b/pyaedt/modeler/geometry_operators.py index d55705d34c7..00aded2db2b 100644 --- a/pyaedt/modeler/geometry_operators.py +++ b/pyaedt/modeler/geometry_operators.py @@ -1,4 +1,27 @@ # -*- 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 math import re import sys @@ -102,7 +125,7 @@ def parse_dim_arg(string, scale_to_unit=None, variable_manager=None): else: if variable_manager: if not variable_manager.set_variable("temp_var", string): - if not variable_manager.set_variable("temp_var", string, postprocessing=True): + if not variable_manager.set_variable("temp_var", string, is_post_processing=True): return string value = variable_manager["temp_var"].value / sunit del variable_manager["temp_var"] diff --git a/pyaedt/modeler/modeler2d.py b/pyaedt/modeler/modeler2d.py index 7698682ad46..009787dd312 100644 --- a/pyaedt/modeler/modeler2d.py +++ b/pyaedt/modeler/modeler2d.py @@ -1,3 +1,27 @@ +# -*- 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 math from warnings import warn diff --git a/pyaedt/modeler/modeler3d.py b/pyaedt/modeler/modeler3d.py index 4be69c3f03e..791e8ae0c1a 100644 --- a/pyaedt/modeler/modeler3d.py +++ b/pyaedt/modeler/modeler3d.py @@ -1,3 +1,27 @@ +# -*- 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 __future__ import absolute_import # noreorder import copy @@ -7,13 +31,13 @@ import warnings from pyaedt.application.Variables import generate_validation_errors -from pyaedt.generic.constants import CSS4_COLORS from pyaedt.generic.general_methods import GrpcApiError from pyaedt.generic.general_methods import generate_unique_name from pyaedt.generic.general_methods import open_file from pyaedt.generic.general_methods import pyaedt_function_handler from pyaedt.modeler.cad.Primitives3D import Primitives3D from pyaedt.modeler.geometry_operators import GeometryOperators +from pyaedt.modules.solutions import nastran_to_stl class Modeler3D(Primitives3D): @@ -992,328 +1016,6 @@ def objects_in_bounding_box(self, bounding_box, check_solids=True, check_lines=T return objects - @pyaedt_function_handler() - def _parse_nastran(self, file_path): - - nas_to_dict = {"Points": [], "PointsId": {}, "Assemblies": {}} - includes = [] - - def parse_lines(input_lines, input_pid=0, in_assembly="Main"): - if in_assembly not in nas_to_dict["Assemblies"]: - nas_to_dict["Assemblies"][in_assembly] = {"Triangles": {}, "Solids": {}, "Lines": {}} - for lk in range(len(input_lines)): - line = input_lines[lk] - line_type = line[:8].strip() - if line.startswith("$") or line.startswith("*"): - continue - elif line_type in ["GRID", "CTRIA3", "CQUAD4"]: - grid_id = int(line[8:16]) - if line_type in ["CTRIA3", "CQUAD4"]: - tria_id = int(line[16:24]) - if tria_id not in nas_to_dict["Assemblies"][in_assembly]["Triangles"]: - nas_to_dict["Assemblies"][in_assembly]["Triangles"][tria_id] = [] - n1 = line[24:32].strip() - if "-" in n1[1:] and "e" not in n1[1:].lower(): - n1 = n1[0] + n1[1:].replace("-", "e-") - n2 = line[32:40].strip() - if "-" in n2[1:] and "e" not in n2[1:].lower(): - n2 = n2[0] + n2[1:].replace("-", "e-") - n3 = line[40:48].strip() - if "-" in n3[1:] and "e" not in n3[1:].lower(): - n3 = n3[0] + n3[1:].replace("-", "e-") - if line_type == "GRID": - nas_to_dict["PointsId"][grid_id] = input_pid - nas_to_dict["Points"].append([float(n1), float(n2), float(n3)]) - input_pid += 1 - elif line_type == "CTRIA3": - tri = [ - nas_to_dict["PointsId"][int(n1)], - nas_to_dict["PointsId"][int(n2)], - nas_to_dict["PointsId"][int(n3)], - ] - nas_to_dict["Assemblies"][in_assembly]["Triangles"][tria_id].append(tri) - elif line_type == "CQUAD4": - n4 = line[48:56].strip() - if "-" in n4[1:] and "e" not in n4[1:].lower(): - n4 = n4[0] + n4[1:].replace("-", "e-") - tri = [ - nas_to_dict["PointsId"][int(n1)], - nas_to_dict["PointsId"][int(n2)], - nas_to_dict["PointsId"][int(n3)], - ] - nas_to_dict["Assemblies"][in_assembly]["Triangles"][tria_id].append(tri) - tri = [ - nas_to_dict["PointsId"][int(n1)], - nas_to_dict["PointsId"][int(n3)], - nas_to_dict["PointsId"][int(n4)], - ] - nas_to_dict["Assemblies"][in_assembly]["Triangles"][tria_id].append(tri) - elif line_type in ["GRID*", "CTRIA3*", "CQUAD4*"]: - grid_id = int(line[8:24]) - if line_type in ["CTRIA3*", "CQUAD4*"]: - tria_id = int(line[24:40]) - if tria_id not in nas_to_dict["Assemblies"][in_assembly]["Triangles"]: - nas_to_dict["Assemblies"][in_assembly]["Triangles"][tria_id] = [] - n1 = line[40:56].strip() - if "-" in n1[1:] and "e" not in n1[1:].lower(): - n1 = n1[0] + n1[1:].replace("-", "e-") - n2 = line[56:72].strip() - if "-" in n2[1:] and "e" not in n2[1:].lower(): - n2 = n2[0] + n2[1:].replace("-", "e-") - - n3 = line[72:88].strip() - idx = 88 - if not n3 or n3.startswith("*"): - lk += 1 - n3 = input_lines[lk][8:24].strip() - idx = 24 - if "-" in n3[1:] and "e" not in n3[1:].lower(): - n3 = n3[0] + n3[1:].replace("-", "e-") - if line_type == "GRID*": - try: - nas_to_dict["Points"].append([float(n1), float(n2), float(n3)]) - except Exception: # nosec - continue - nas_to_dict["PointsId"][grid_id] = input_pid - input_pid += 1 - elif line_type == "CTRIA3*": - tri = [ - nas_to_dict["PointsId"][int(n1)], - nas_to_dict["PointsId"][int(n2)], - nas_to_dict["PointsId"][int(n3)], - ] - nas_to_dict["Assemblies"][in_assembly]["Triangles"][tria_id].append(tri) - elif line_type == "CQUAD4*": - n4 = input_lines[lk][idx : idx + 16].strip() - if not n4 or n4.startswith("*"): - lk += 1 - n4 = input_lines[lk][8:24].strip() - if "-" in n4[1:] and "e" not in n4[1:].lower(): - n4 = n4[0] + n4[1:].replace("-", "e-") - tri = [ - nas_to_dict["PointsId"][int(n1)], - nas_to_dict["PointsId"][int(n2)], - nas_to_dict["PointsId"][int(n3)], - ] - nas_to_dict["Assemblies"][in_assembly]["Triangles"][tria_id].append(tri) - tri = [ - nas_to_dict["PointsId"][int(n1)], - nas_to_dict["PointsId"][int(n3)], - nas_to_dict["PointsId"][int(n4)], - ] - nas_to_dict["Assemblies"][in_assembly]["Triangles"][tria_id].append(tri) - elif line_type in [ - "CTETRA", - "CPYRAM", - "CPYRA", - ]: - # obj_id = line[8:16].strip() - n = [] - el_id = line[16:24].strip() - if el_id not in nas_to_dict["Assemblies"][in_assembly]["Solids"]: - nas_to_dict["Assemblies"][in_assembly]["Solids"][el_id] = [] - - n.append(int(line[24:32])) - n.append(int(line[32:40])) - n.append(int(line[40:48])) - n.append(int(line[48:56])) - if line_type in ["CPYRA", "CPYRAM"]: - n.append(int(line[56:64])) - - from itertools import combinations - - for k in list(combinations(n, 3)): - # tri = [int(k[0]), int(k[1]), int(k[2])] - tri = [ - nas_to_dict["PointsId"][int(k[0])], - nas_to_dict["PointsId"][int(k[1])], - nas_to_dict["PointsId"][int(k[2])], - ] - tri.sort() - tri = tuple(tri) - nas_to_dict["Assemblies"][in_assembly]["Solids"][el_id].append(tri) - - elif line_type in [ - "CTETRA*", - "CPYRAM*", - "CPYRA*", - ]: - # obj_id = line[8:24].strip() - n = [] - el_id = line[24:40].strip() - if el_id not in nas_to_dict["Assemblies"][in_assembly]["Solids"]: - nas_to_dict["Assemblies"][in_assembly]["Solids"][el_id] = [] - # n.append(line[24:40].strip()) - n.append(line[40:56].strip()) - - n.append(line[56:72].strip()) - lk += 1 - n.extend([input_lines[lk][i : i + 16] for i in range(16, len(input_lines[lk]), 16)]) - - from itertools import combinations - - if line_type == "CTETRA*": - for k in list(combinations(n, 3)): - # tri = [int(k[0]), int(k[1]), int(k[2])] - tri = [ - nas_to_dict["PointsId"][int(k[0])], - nas_to_dict["PointsId"][int(k[1])], - nas_to_dict["PointsId"][int(k[2])], - ] - tri.sort() - tri = tuple(tri) - nas_to_dict["Assemblies"][in_assembly]["Solids"][el_id].append(tri) - else: - spli1 = [n[0], n[1], n[2], n[4]] - for k in list(combinations(spli1, 3)): - tri = [ - nas_to_dict["PointsId"][int(k[0])], - nas_to_dict["PointsId"][int(k[1])], - nas_to_dict["PointsId"][int(k[2])], - ] - tri.sort() - tri = tuple(tri) - nas_to_dict["Assemblies"][in_assembly]["Solids"][el_id].append(tri) - spli1 = [n[0], n[2], n[3], n[4]] - for k in list(combinations(spli1, 3)): - tri = [ - nas_to_dict["PointsId"][int(k[0])], - nas_to_dict["PointsId"][int(k[1])], - nas_to_dict["PointsId"][int(k[2])], - ] - tri.sort() - tri = tuple(tri) - nas_to_dict["Assemblies"][in_assembly]["Solids"][el_id].append(tri) - - elif line_type in ["CROD", "CBEAM", "CBAR"]: - obj_id = int(line[16:24]) - n1 = int(line[24:32]) - n2 = int(line[32:40]) - if obj_id in nas_to_dict["Assemblies"][in_assembly]["Lines"]: - nas_to_dict["Assemblies"][in_assembly]["Lines"][obj_id].append( - [nas_to_dict["PointsId"][int(n1)], nas_to_dict["PointsId"][int(n2)]] - ) - else: - nas_to_dict["Assemblies"][in_assembly]["Lines"][obj_id] = [ - [nas_to_dict["PointsId"][int(n1)], nas_to_dict["PointsId"][int(n2)]] - ] - elif line_type in ["CROD*", "CBEAM*", "CBAR*"]: - obj_id = int(line[24:40]) - n1 = int(line[40:56]) - n2 = int(line[56:72]) - if obj_id in nas_to_dict["Assemblies"][in_assembly]["Lines"]: - nas_to_dict["Assemblies"][in_assembly]["Lines"][obj_id].append( - [nas_to_dict["PointsId"][int(n1)], nas_to_dict["PointsId"][int(n2)]] - ) - else: - nas_to_dict["Assemblies"][in_assembly]["Lines"][obj_id] = [ - [nas_to_dict["PointsId"][int(n1)], nas_to_dict["PointsId"][int(n2)]] - ] - return input_pid - - self.logger.reset_timer() - self.logger.info("Loading file") - with open_file(file_path, "r") as f: - lines = f.read().splitlines() - for line in lines: - if line.startswith("INCLUDE"): - includes.append(line.split(" ")[1].replace("'", "").strip()) - pid = parse_lines(lines) - for include in includes: - with open_file(os.path.join(os.path.dirname(file_path), include), "r") as f: - lines = f.read().splitlines() - name = include.split(".")[0] - if name in self.oeditor.GetChildNames("Groups"): - name = generate_unique_name(include.split(".")[0], n=2) - pid = parse_lines(lines, pid, name) - self.logger.info("File loaded") - for assembly in list(nas_to_dict["Assemblies"].keys())[::]: - if ( - nas_to_dict["Assemblies"][assembly]["Triangles"] - == nas_to_dict["Assemblies"][assembly]["Solids"] - == nas_to_dict["Assemblies"][assembly]["Lines"] - == {} - ): - del nas_to_dict["Assemblies"][assembly] - return nas_to_dict - - @pyaedt_function_handler() - def _write_stl(self, nas_to_dict, decimation, enable_planar_merge, pv): - def _write_solid_stl(triangle, pp): - try: - # points = [nas_to_dict["Points"][id] for id in triangle] - points = [pp[i] for i in triangle] - except KeyError: # pragma: no cover - return - fc = GeometryOperators.get_polygon_centroid(points) - v1 = points[0] - v2 = points[1] - cv1 = GeometryOperators.v_points(fc, v1) - cv2 = GeometryOperators.v_points(fc, v2) - if cv2[0] == cv1[0] == 0.0 and cv2[1] == cv1[1] == 0.0: - n = [0, 0, 1] # pragma: no cover - elif cv2[0] == cv1[0] == 0.0 and cv2[2] == cv1[2] == 0.0: - n = [0, 1, 0] # pragma: no cover - elif cv2[1] == cv1[1] == 0.0 and cv2[2] == cv1[2] == 0.0: - n = [1, 0, 0] # pragma: no cover - else: - n = GeometryOperators.v_cross(cv1, cv2) - - normal = GeometryOperators.normalize_vector(n) - if normal: - f.write(" facet normal {} {} {}\n".format(normal[0], normal[1], normal[2])) - f.write(" outer loop\n") - f.write(" vertex {} {} {}\n".format(points[0][0], points[0][1], points[0][2])) - f.write(" vertex {} {} {}\n".format(points[1][0], points[1][1], points[1][2])) - f.write(" vertex {} {} {}\n".format(points[2][0], points[2][1], points[2][2])) - f.write(" endloop\n") - f.write(" endfacet\n") - - self.logger.info("Creating STL file with detected faces") - enable_stl_merge = False if enable_planar_merge == "False" or enable_planar_merge is False else True - - def decimate(points_in, faces_in): - fin = [[3] + list(i) for i in faces_in] - mesh = pv.PolyData(points_in, faces=fin) - new_mesh = mesh.decimate_pro(decimation, preserve_topology=True, boundary_vertex_deletion=False) - points_out = list(new_mesh.points) - faces_out = [i[1:] for i in new_mesh.faces.reshape(-1, 4) if i[0] == 3] - return points_out, faces_out - - output_stls = [] - for assembly_name, assembly in nas_to_dict["Assemblies"].items(): - output_stl = os.path.join(self._app.working_directory, assembly_name + ".stl") - f = open(output_stl, "w") - for tri_id, triangles in assembly["Triangles"].items(): - tri_out = triangles - p_out = nas_to_dict["Points"][::] - if decimation > 0 and len(triangles) > 20: - p_out, tri_out = decimate(nas_to_dict["Points"], tri_out) - f.write("solid Sheet_{}\n".format(tri_id)) - if enable_planar_merge == "Auto" and len(tri_out) > 50000: - enable_stl_merge = False # pragma: no cover - for triangle in tri_out: - _write_solid_stl(triangle, p_out) - f.write("endsolid\n") - for solidid, solid_triangles in assembly["Solids"].items(): - f.write("solid Solid_{}\n".format(solidid)) - import pandas as pd - - df = pd.Series(solid_triangles) - tri_out = df.drop_duplicates(keep=False).to_list() - p_out = nas_to_dict["Points"][::] - if decimation > 0 and len(solid_triangles) > 20: - p_out, tri_out = decimate(nas_to_dict["Points"], tri_out) - if enable_planar_merge == "Auto" and len(tri_out) > 50000: - enable_stl_merge = False # pragma: no cover - for triangle in tri_out: - _write_solid_stl(triangle, p_out) - f.write("endsolid\n") - f.close() - output_stls.append(output_stl) - self.logger.info("STL file created") - return output_stls, enable_stl_merge - @pyaedt_function_handler() def import_nastran( self, @@ -1359,95 +1061,19 @@ def import_nastran( ------- List of :class:`pyaedt.modeler.Object3d.Object3d` """ - pv = None - if decimation > 0 or preview: - try: - import pyvista as pv - except Exception: # pragma: no cover - self.logger.error("Package pyvista is needed to perform model simplification.") - self.logger.error("Please install it using pip.") - decimation = 0 - preview = False autosave = ( True if self._app.odesktop.GetRegistryInt("Desktop/Settings/ProjectOptions/DoAutoSave") == 1 else False ) self._app.odesktop.EnableAutoSave(False) - - nas_to_dict = self._parse_nastran(file_path) - objs_before = [i for i in self.object_names] - empty = True - for assembly in nas_to_dict["Assemblies"].values(): - if assembly["Triangles"] or assembly["Solids"] or assembly["Lines"]: - empty = False - break - if empty: # pragma: no cover - self.logger.error("Failed to import file. Check the model and retry") - return False - output_stls, enable_stl_merge = self._write_stl(nas_to_dict, decimation, enable_planar_merge, pv) - if preview: - if decimation > 0: - pl = pv.Plotter(shape=(1, 2)) - else: # pragma: no cover - pl = pv.Plotter() - dargs = dict(show_edges=True) - css4_colors = list(CSS4_COLORS.values()) - colors = [] - color_by_assembly = True - if len(nas_to_dict["Assemblies"]) == 1: - color_by_assembly = False - - def preview_pyvista(dict_in): - k = 0 - p_out = nas_to_dict["Points"][::] - for assembly in dict_in["Assemblies"].values(): - if color_by_assembly: - h = css4_colors[k].lstrip("#") - colors.append(tuple(int(h[i : i + 2], 16) for i in (0, 2, 4))) - k += 1 - - for triangles in assembly["Triangles"].values(): - tri_out = triangles - fin = [[3] + list(i) for i in tri_out] - if not color_by_assembly: - h = css4_colors[k].lstrip("#") - colors.append(tuple(int(h[i : i + 2], 16) for i in (0, 2, 4))) - k = k + 1 if k < len(css4_colors) - 1 else 0 - pl.add_mesh(pv.PolyData(p_out, faces=fin), color=colors[-1], **dargs) - - for triangles in assembly["Solids"].values(): - import pandas as pd - - df = pd.Series(triangles) - tri_out = df.drop_duplicates(keep=False).to_list() - p_out = nas_to_dict["Points"][::] - fin = [[3] + list(i) for i in tri_out] - if not color_by_assembly: - h = css4_colors[k].lstrip("#") - colors.append(tuple(int(h[i : i + 2], 16) for i in (0, 2, 4))) - k = k + 1 if k < len(css4_colors) - 1 else 0 - - pl.add_mesh(pv.PolyData(p_out, faces=fin), color=colors[-1], **dargs) - - preview_pyvista(nas_to_dict) - pl.add_text("Input mesh", font_size=24) - pl.reset_camera() - if decimation > 0 and output_stls: - k = 0 - pl.reset_camera() - pl.subplot(0, 1) - for output_stl in output_stls: - mesh = pv.read(output_stl) - h = css4_colors[k].lstrip("#") - colors.append(tuple(int(h[i : i + 2], 16) for i in (0, 2, 4))) - pl.add_mesh(mesh, color=colors[-1], **dargs) - k = k + 1 if k < len(css4_colors) - 1 else 0 - pl.add_text("Decimated mesh", font_size=24) - pl.reset_camera() - pl.link_views() - if "PYTEST_CURRENT_TEST" not in os.environ: - pl.show() # pragma: no cover - self.logger.info("STL files created") + + output_stls, nas_to_dict, enable_stl_merge = nastran_to_stl( + input_file=file_path, + decimation=decimation, + output_folder=self._app.working_directory, + enable_planar_merge=enable_planar_merge, + preview=preview, + ) if save_only_stl: return output_stls @@ -1462,10 +1088,14 @@ def preview_pyvista(dict_in): merge_planar_faces=enable_stl_merge, ) self.logger.info("Model {} imported".format(os.path.split(output_stl)[-1])) + self._app.save_project() if group_parts: self.logger.info("Grouping parts...") aedt_objs = self.object_names[::] for assembly, _ in nas_to_dict["Assemblies"].items(): + assembly_group_name = assembly + if assembly in self.oeditor.GetChildNames("Groups"): + assembly_group_name = generate_unique_name(assembly, n=2) new_group = [] for el in nas_to_dict["Assemblies"][assembly]["Solids"].keys(): obj_names = [i for i in aedt_objs if i.startswith("Solid_{}".format(el))] @@ -1477,16 +1107,16 @@ def preview_pyvista(dict_in): ] if obj_names: new_group.append(self.create_group(obj_names, group_name=str(el))) - if assembly in self.oeditor.GetChildNames("Groups"): + if assembly_group_name in self.oeditor.GetChildNames("Groups"): self.oeditor.MoveEntityToGroup( [ "Groups:=", new_group, ], - ["ParentGroup:=", assembly], + ["ParentGroup:=", assembly_group_name], ) else: - new_name = self.create_group(new_group, group_name=assembly) + new_name = self.create_group(new_group, group_name=assembly_group_name) self.oeditor.MoveEntityToGroup( [ "Groups:=", @@ -1495,33 +1125,44 @@ def preview_pyvista(dict_in): ["ParentGroup:=", new_name], ) self.logger.info("Parts grouped") + self._app.save_project() if import_lines: + if lines_thickness: + self._app["x_section_thickness"] = self._arg_with_dim(lines_thickness) self.logger.info("Importing lines. This operation can take time....") for assembly_name, assembly in nas_to_dict["Assemblies"].items(): if assembly["Lines"]: for line_name, lines in assembly["Lines"].items(): - if lines_thickness: - self._app["x_section_{}".format(line_name)] = lines_thickness polys = [] id = 0 for line in lines: try: - points = [nas_to_dict["Points"][line[0]], nas_to_dict["Points"][line[1]]] + # points = [nas_to_dict["Points"][line[0]], nas_to_dict["Points"][line[1]]] + points = [nas_to_dict["Points"][i] for i in line] except KeyError: continue - if lines_thickness: - polys.append( - self.create_polyline( - points, - name="Poly_{}_{}".format(line_name, id), - xsection_type="Circle", - xsection_width="x_section_{}".format(line_name), - xsection_num_seg=6, - ) - ) + p_line = self.create_polyline( + points, + name="Poly_{}_{}".format(line_name, id), + xsection_type="Circle" if lines_thickness else None, + xsection_width="x_section_thickness" if lines_thickness else 1, + ) + + if p_line: + polys.append(p_line) else: - polys.append(self.create_polyline(points, name="Poly_{}_{}".format(line_name, id))) + self.logger.warning("Failed to create Polyline as a union of segments.") + self.logger.warning("Trying to create single segments.") + for i in range(len(points) - 1): + p_line = self.create_polyline( + points[i : i + 2], + name=generate_unique_name("Poly_{}_{}".format(line_name, id)), + xsection_type="Circle" if lines_thickness else None, + xsection_width="x_section_thickness" if lines_thickness else 1, + ) + if p_line: + polys.append(p_line) id += 1 if group_parts: pids = [i.name for i in polys] @@ -1542,11 +1183,6 @@ def preview_pyvista(dict_in): ], ["ParentGroup:=", group_name], ) - - if len(polys) > 1: - out_poly = self.unite(polys, purge=not lines_thickness) - if not lines_thickness and out_poly: - self.generate_object_history(out_poly) self.logger.info("Lines imported") objs_after = [i for i in self.object_names] diff --git a/pyaedt/modeler/modelerpcb.py b/pyaedt/modeler/modelerpcb.py index 4e17524d6c6..aab82cc68a3 100644 --- a/pyaedt/modeler/modelerpcb.py +++ b/pyaedt/modeler/modelerpcb.py @@ -1,3 +1,27 @@ +# -*- 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 re from warnings import warn @@ -402,7 +426,7 @@ def colinear_heal(self, assignment, tolerance=0.1): Examples -------- >>> from pyaedt import Hfss3dLayout - >>> h3d=Hfss3dLayout(specified_version="2021.2") + >>> h3d=Hfss3dLayout(version="2021.2") >>> h3d.modeler.layers.add_layer("TOP") >>> l1=h3d.modeler.create_line("TOP",[[0,0],[100,0]],0.5) >>> l2=h3d.modeler.create_line("TOP",[[100,0],[120,-35]],0.5) @@ -457,7 +481,7 @@ def expand(self, assignment, size=1, expand_type="ROUND", replace_original=False Examples -------- >>> from pyaedt import Hfss3dLayout - >>> h3d=Hfss3dLayout(specified_version="2021.2") + >>> h3d=Hfss3dLayout(version="2021.2") >>> h3d.modeler.layers.add_layer("TOP") >>> h3d.modeler.create_rectangle("TOP", [20,20],[50,50], name="rect_1") >>> h3d.modeler.create_line("TOP",[[25,25],[40,40]]) diff --git a/pyaedt/modeler/pcb/Primitives3DLayout.py b/pyaedt/modeler/pcb/Primitives3DLayout.py index a457a33684d..3833b9ab1ae 100644 --- a/pyaedt/modeler/pcb/Primitives3DLayout.py +++ b/pyaedt/modeler/pcb/Primitives3DLayout.py @@ -1,3 +1,27 @@ +# -*- 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 sys @@ -57,7 +81,7 @@ def __getitem__(self, partname): if partname in self.geometries: return self.geometries[partname] if partname in self.vias: - return self.nets[partname] + return self.vias[partname] if partname in self.nets: return self.nets[partname] if not isinstance(partname, (str, int, float, list, tuple)): diff --git a/pyaedt/modeler/pcb/__init__.py b/pyaedt/modeler/pcb/__init__.py index e69de29bb2d..9c4476773da 100644 --- a/pyaedt/modeler/pcb/__init__.py +++ b/pyaedt/modeler/pcb/__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/pyaedt/modeler/pcb/object3dlayout.py b/pyaedt/modeler/pcb/object3dlayout.py index f6d238370b5..426a44dbc8a 100644 --- a/pyaedt/modeler/pcb/object3dlayout.py +++ b/pyaedt/modeler/pcb/object3dlayout.py @@ -1,4 +1,27 @@ # -*- 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. + """ This module provides methods and data structures for managing all properties of objects (points, lines, sheeets, and solids) within the AEDT 3D Layout Modeler. @@ -9,9 +32,9 @@ import math import re -from pyaedt import pyaedt_function_handler from pyaedt.generic.constants import unit_converter from pyaedt.generic.general_methods import _dim_arg +from pyaedt.generic.general_methods import pyaedt_function_handler from pyaedt.modeler.geometry_operators import GeometryOperators @@ -95,7 +118,11 @@ def set_property_value(self, name, value): >>> oEditor.ChangeProperty """ - vProp = ["NAME:" + name, "Value:=", value] + if "Pt" in name: + coordinates = value.split(",") + vProp = ["NAME:" + name, "X:=", coordinates[0], "Y:=", coordinates[1]] + else: + vProp = ["NAME:" + name, "Value:=", value] return self.change_property(vProp) @property @@ -805,6 +832,18 @@ def components(self): comps[c] = self._primitives.components[c] return comps + @property + def geometry_names(self): + """List of geometry names. + + Returns + ------- + list + Geometries that belong to the selected net.""" + comps = self._primitives._get_names(["component", "pin", "via"]) + geo = [i for i in self._oeditor.FindObjects("Net", self.name) if i not in comps] + return geo + class Pins3DLayout(Object3DLayout, object): """Contains the pins in HFSS 3D Layout.""" diff --git a/pyaedt/modeler/schematic.py b/pyaedt/modeler/schematic.py index c6be0544f93..cc9100ad4b8 100644 --- a/pyaedt/modeler/schematic.py +++ b/pyaedt/modeler/schematic.py @@ -1,15 +1,44 @@ # -*- 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 random import re +import sys import time +import warnings -from pyaedt import settings from pyaedt.generic.constants import AEDT_UNITS from pyaedt.generic.general_methods import is_linux from pyaedt.generic.general_methods import pyaedt_function_handler +from pyaedt.generic.settings import settings from pyaedt.modeler.cad.Modeler import Modeler -from pyaedt.modeler.circuits.PrimitivesEmit import EmitComponent -from pyaedt.modeler.circuits.PrimitivesEmit import EmitComponents + +if (3, 8) < sys.version_info < (3, 12): + from pyaedt.modeler.circuits.PrimitivesEmit import EmitComponent + from pyaedt.modeler.circuits.PrimitivesEmit import EmitComponents +else: # pragma: no cover + warnings.warn("Emit API is only available for Python 3.8+,<3.12.") from pyaedt.modeler.circuits.PrimitivesMaxwellCircuit import MaxwellCircuitComponents from pyaedt.modeler.circuits.PrimitivesNexxim import NexximComponents from pyaedt.modeler.circuits.PrimitivesTwinBuilder import TwinBuilderComponents @@ -436,7 +465,7 @@ def _get_components_selections(self, selections, return_as_list=True): for sel in selections: if isinstance(sel, int): sels.append(self.schematic.components[sel].composed_name) - elif isinstance(sel, (CircuitComponent, EmitComponent)): + elif isinstance(sel, CircuitComponent): sels.append(sel.composed_name) else: for el in list(self.schematic.components.values()): @@ -716,6 +745,24 @@ def __init__(self, app): self.components = EmitComponents(app, self) self.logger.info("ModelerEmit class has been initialized!") + @pyaedt_function_handler() + def _get_components_selections(self, selections, return_as_list=True): # pragma: no cover + sels = [] + if not isinstance(selections, list): + selections = [selections] + for sel in selections: + if isinstance(sel, int): + sels.append(self.schematic.components[sel].composed_name) + elif isinstance(sel, (CircuitComponent, EmitComponent)): + sels.append(sel.composed_name) + else: + for el in list(self.schematic.components.values()): + if sel in [el.InstanceName, el.composed_name, el.name]: + sels.append(el.composed_name) + if not return_as_list: + return ", ".join(sels) + return sels + class ModelerMaxwellCircuit(ModelerCircuit): """ModelerMaxwellCircuit class. diff --git a/pyaedt/modules/AdvancedPostProcessing.py b/pyaedt/modules/AdvancedPostProcessing.py index f8db6690e76..1eeee364356 100644 --- a/pyaedt/modules/AdvancedPostProcessing.py +++ b/pyaedt/modules/AdvancedPostProcessing.py @@ -1,3 +1,27 @@ +# -*- 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. + """ This module contains the `PostProcessor` class. @@ -12,14 +36,15 @@ import warnings from pyaedt import generate_unique_name -from pyaedt import settings from pyaedt.generic.general_methods import is_ironpython from pyaedt.generic.general_methods import open_file from pyaedt.generic.general_methods import pyaedt_function_handler from pyaedt.generic.plot import ModelPlotter +from pyaedt.generic.settings import settings from pyaedt.modules.PostProcessor import FieldSummary from pyaedt.modules.PostProcessor import PostProcessor as Post from pyaedt.modules.PostProcessor import TOTAL_QUANTITIES +from pyaedt.modules.fields_calculator import FieldsCalculator if not is_ironpython: try: @@ -57,6 +82,7 @@ class PostProcessor(Post): def __init__(self, app): Post.__init__(self, app) + self.fields_calculator = FieldsCalculator(app) @pyaedt_function_handler() def nb_display(self, show_axis=True, show_grid=True, show_ruler=True): @@ -814,6 +840,7 @@ def create_3d_plot( primary_sweep="Theta", secondary_sweep="Phi", snapshot_path=None, + show=True, ): """Create a 3D plot using Matplotlib. @@ -832,6 +859,8 @@ def create_3d_plot( snapshot_path : str, optional Full path to image file if a snapshot is needed. The default is ``None``. + show : bool, optional + Whether if show the plot or not. Default is set to `True`. Returns ------- @@ -842,7 +871,9 @@ def create_3d_plot( solution_data.intrinsics[nominal_sweep] = nominal_value if nominal_value: solution_data.primary_sweep = primary_sweep - return solution_data.plot_3d(x_axis=primary_sweep, y_axis=secondary_sweep, snapshot_path=snapshot_path) + return solution_data.plot_3d( + x_axis=primary_sweep, y_axis=secondary_sweep, snapshot_path=snapshot_path, show=show + ) @pyaedt_function_handler(frames_list="frames", output_gif_path="gif_path") def plot_scene( diff --git a/pyaedt/modules/Boundary.py b/pyaedt/modules/Boundary.py index deb84c681ce..b369ec5ceb4 100644 --- a/pyaedt/modules/Boundary.py +++ b/pyaedt/modules/Boundary.py @@ -1,3 +1,27 @@ +# -*- 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. + """ This module contains these classes: ``BoundaryCommon`` and ``BoundaryObject``. """ @@ -7,7 +31,6 @@ import copy import re -from pyaedt import Hfss3dLayout from pyaedt.application.Variables import decompose_variable_value from pyaedt.generic.DataHandlers import _dict2arg from pyaedt.generic.DataHandlers import random_string @@ -373,6 +396,11 @@ def __init__(self, app, component_type, component_name, props): @pyaedt_function_handler() def footprint_filter(self): """Minimum component footprint for filtering.""" + if self.props["NativeComponentDefinitionProvider"]["PartsChoice"] != 1: + self._app.logger.error( + "Device Parts modeling is not active, hence no filtering or override option is available." + ) + return None if self._app.settings.aedt_version < "2024.2": return None return self.filters.get("FootPrint", {}).get("Value", None) @@ -388,8 +416,13 @@ def footprint_filter(self, minimum_footprint): minimum_footprint : str Value with unit of the minimum component footprint for filtering. """ - if self._app.settings.aedt_version < "2024.2": - return False + if self.props["NativeComponentDefinitionProvider"]["PartsChoice"] != 1: + self._app.logger.error( + "Device Parts modeling is not active, hence no filtering or override option is available." + ) + return + if self._app.settings.aedt_version < "2024.2": # pragma : no cover + return new_filters = self.props["NativeComponentDefinitionProvider"].get("Filters", []) if "FootPrint" in new_filters: new_filters.remove("FootPrint") @@ -402,6 +435,11 @@ def footprint_filter(self, minimum_footprint): @pyaedt_function_handler() def power_filter(self): """Minimum component power for filtering.""" + if self.props["NativeComponentDefinitionProvider"]["PartsChoice"] != 1: + self._app.logger.error( + "Device Parts modeling is not active, hence no filtering or override option is available." + ) + return None return self.filters.get("Power", {}).get("Value") @power_filter.setter @@ -415,6 +453,11 @@ def power_filter(self, minimum_power): minimum_power : str Value with unit of the minimum component power for filtering. """ + if self.props["NativeComponentDefinitionProvider"]["PartsChoice"] != 1: + self._app.logger.error( + "Device Parts modeling is not active, hence no filtering or override option is available." + ) + return new_filters = self.props["NativeComponentDefinitionProvider"].get("Filters", []) if "Power" in new_filters: new_filters.remove("Power") @@ -427,6 +470,11 @@ def power_filter(self, minimum_power): @pyaedt_function_handler() def type_filters(self): """Types of component that are filtered.""" + if self.props["NativeComponentDefinitionProvider"]["PartsChoice"] != 1: + self._app.logger.error( + "Device Parts modeling is not active, hence no filtering or override option is available." + ) + return None return self.filters.get("Types") @type_filters.setter @@ -440,6 +488,11 @@ def type_filters(self, object_type): object_type : str or list Types of object to filter. Accepted types are ``"Capacitors"``, ``"Inductors"``, ``"Resistors"``. """ + if self.props["NativeComponentDefinitionProvider"]["PartsChoice"] != 1: + self._app.logger.error( + "Device Parts modeling is not active, hence no filtering or override option is available." + ) + return if not isinstance(object_type, list): object_type = [object_type] if not all(o in self._filter_map2name.values() for o in object_type): @@ -459,6 +512,11 @@ def type_filters(self, object_type): @pyaedt_function_handler() def height_filter(self): """Minimum component height for filtering.""" + if self.props["NativeComponentDefinitionProvider"]["PartsChoice"] != 1: + self._app.logger.error( + "Device Parts modeling is not active, hence no filtering or override option is available." + ) + return None return self.filters.get("Height", {}).get("Value", None) @height_filter.setter @@ -472,6 +530,11 @@ def height_filter(self, minimum_height): minimum_height : str Value with unit of the minimum component power for filtering. """ + if self.props["NativeComponentDefinitionProvider"]["PartsChoice"] != 1: + self._app.logger.error( + "Device Parts modeling is not active, hence no filtering or override option is available." + ) + return new_filters = self.props["NativeComponentDefinitionProvider"].get("Filters", []) if "Height" in new_filters: new_filters.remove("Height") @@ -484,6 +547,11 @@ def height_filter(self, minimum_height): @pyaedt_function_handler() def objects_2d_filter(self): """Whether 2d objects are filtered.""" + if self.props["NativeComponentDefinitionProvider"]["PartsChoice"] != 1: + self._app.logger.error( + "Device Parts modeling is not active, hence no filtering or override option is available." + ) + return None return self.filters.get("Exclude2DObjects", False) @objects_2d_filter.setter @@ -497,6 +565,11 @@ def objects_2d_filter(self, filter): filter : bool Whether 2d objects are filtered """ + if self.props["NativeComponentDefinitionProvider"]["PartsChoice"] != 1: + self._app.logger.error( + "Device Parts modeling is not active, hence no filtering or override option is available." + ) + return new_filters = self.props["NativeComponentDefinitionProvider"].get("Filters", []) if "HeightExclude2D" in new_filters: new_filters.remove("HeightExclude2D") @@ -508,6 +581,11 @@ def objects_2d_filter(self, filter): @pyaedt_function_handler() def filters(self): """All active filters.""" + if self.props["NativeComponentDefinitionProvider"].get("PartsChoice", None) != 1: + self._app.logger.error( + "Device Parts modeling is not active, hence no filtering or override option is available." + ) + return None out_filters = {"Type": {"Capacitors": False, "Inductors": False, "Resistors": False}} filters = self.props["NativeComponentDefinitionProvider"].get("Filters", []) filter_map2type = { @@ -565,6 +643,11 @@ def override_component( bool ``True`` if successful. ``False`` otherwise. """ + if self.props["NativeComponentDefinitionProvider"]["PartsChoice"] != 1: + self._app.logger.error( + "Device Parts modeling is not active, hence no filtering or override option is available." + ) + return False override_component = ( self.props["NativeComponentDefinitionProvider"].get("instanceOverridesMap", {}).get("oneOverrideBlk", []) ) @@ -596,13 +679,24 @@ def override_component( @pyaedt_function_handler() @disable_auto_update - def set_parts(self, parts_choice, simplify_parts=False, surface_material="Steel-oxidised-surface"): - """Set how to include PCB parts. + def disable_device_parts(self): + """Disable PCB parts. + + Returns + ------- + bool + ``True`` if successful. ``False`` otherwise. + """ + self.props["NativeComponentDefinitionProvider"]["PartsChoice"] = 0 + return True + + @pyaedt_function_handler() + @disable_auto_update + def set_device_parts(self, simplify_parts=False, surface_material="Steel-oxidised-surface"): + """Set how to include PCB device parts. Parameters ---------- - parts_choice : str - Parts to include: ``"None"``, ``"Device Parts"`` or ``"Package Parts"``. simplify_parts : bool, optional Whether to simplify parts as cuboid. Default is ``False``. surface_material : str, optional @@ -613,27 +707,88 @@ def set_parts(self, parts_choice, simplify_parts=False, surface_material="Steel- bool ``True`` if successful. ``False`` otherwise. """ - allowed_inputs = ["None", "Device Parts", "Package Parts"] - try: - parts_choice = allowed_inputs.index(parts_choice) - except ValueError: + self.props["NativeComponentDefinitionProvider"]["PartsChoice"] = 1 + self.props["NativeComponentDefinitionProvider"]["ModelDeviceAsRect"] = simplify_parts + self.props["NativeComponentDefinitionProvider"]["DeviceSurfaceMaterial"] = surface_material + return True + + @pyaedt_function_handler() + @disable_auto_update + def set_package_parts( + self, + solderballs=None, + connector=None, + solderbumps_modeling="Boxes", + bondwire_material="Au-Typical", + bondwire_diameter="0.05mm", + ): + """Set how to include PCB device parts. + + Parameters + ---------- + solderballs : str, optional + Specifies whether the solderballs located below the stackup are modeled, + and if so whether they are modeled as ``"Boxes"``, ``"Cylinders"`` or ``"Lumped"``. + connector : str, optional + Specifies whether the connectors located above the stackup are modeled, + and if so whether they are modeled as ``"Solderbump"`` or ``"Bondwire"``. + Default is ``None`` in which case they are not modeled. + solderbumps_modeling : str, optional + Specifies how to model solderbumps if ``connector`` is set to ``"Solderbump"``. + Accepted options are: ``"Boxes"``, ``"Cylinders"`` and ``"Lumped"``. + Default is ``"Boxes"``. + bondwire_material : str, optional + Specifies bondwires material if ``connector`` is set to ``"Bondwire"``. + Default is ``"Au-Typical"``. + + Returns + ------- + bool + ``True`` if successful. ``False`` otherwise. + """ + # sanity check + valid_connectors = ["Solderbump", "Bondwire"] + if connector is not None and connector not in valid_connectors: self._app.logger.error( - "{} is not a valid argument, only allowed input are {}.".format(parts_choice, ", ".join(allowed_inputs)) + "{} option is not supported. Use one of the following: {}".format( + connector, ", ".join(valid_connectors) + ) ) return False - self.props["NativeComponentDefinitionProvider"]["PartsChoice"] = parts_choice - self.props["NativeComponentDefinitionProvider"]["ModelDeviceAsRect"] = simplify_parts - self.props["NativeComponentDefinitionProvider"]["DeviceSurfaceMaterial"] = surface_material + solderbumps_map = {"Lumped": "SbLumped", "Cylinders": "SbCylinder", "Boxes": "SbBlock"} + for arg in [solderbumps_modeling, solderballs]: + if arg is not None and arg not in solderbumps_map: + self._app.logger.error( + "{} option is not supported. Use one of the following: " + "{}".format(arg, ", ".join(list(solderbumps_map.keys()))) + ) + return False + if bondwire_material not in self._app.materials.mat_names_aedt: + self._app.logger.error("{} material is not present in the library.".format(bondwire_material)) + return False + + update_properties = { + "PartsChoice": 2, + "CreateTopSolderballs": connector is not None, + "TopConnectorType": connector, + "TopSolderballsModelType": solderbumps_map[solderbumps_modeling], + "BondwireMaterial": bondwire_material, + "BondwireDiameter": bondwire_diameter, + "CreateBottomSolderballs": solderballs is not None, + "BottomSolderballsModelType": solderbumps_map[solderballs], + } + + self.props["NativeComponentDefinitionProvider"].update(update_properties) return True @pyaedt_function_handler() def identify_extent_poly(self): + from pyaedt import Hfss3dLayout + prj = self.props["NativeComponentDefinitionProvider"]["DefnLink"]["Project"] if prj == "This Project*": prj = self._app.project_name - layout = Hfss3dLayout( - projectname=prj, designname=self.props["NativeComponentDefinitionProvider"]["DefnLink"]["Design"] - ) + layout = Hfss3dLayout(project=prj, design=self.props["NativeComponentDefinitionProvider"]["DefnLink"]["Design"]) layer = [o for o in layout.modeler.stackup.drawing_layers if o.type == "outline"][0] outlines = [p for p in layout.modeler.polygons.values() if p.placement_layer == layer.name] if len(outlines) > 1: @@ -4350,7 +4505,7 @@ def add_boundary_node(self, name, assignment_type, value): >>> app = pyaedt.Icepak() >>> network = pyaedt.modules.Boundary.Network(app) >>> network.add_boundary_node("TestNode", "Temperature", 2) - >>> ds = app.create_dataset1d_design("Test_DataSet", [1, 2, 3], [3, 4, 5]) + >>> ds = app.create_dataset1d_design("Test_DataSet",[1, 2, 3],[3, 4, 5]) >>> network.add_boundary_node("TestNode", "Power", {"Type": "Temp Dep", >>> "Function": "Piecewise Linear", >>> "Values": "Test_DataSet"}) diff --git a/pyaedt/modules/CableModeling.py b/pyaedt/modules/CableModeling.py index ed7fe2a10fd..59e1a0f1664 100644 --- a/pyaedt/modules/CableModeling.py +++ b/pyaedt/modules/CableModeling.py @@ -1,3 +1,27 @@ +# -*- 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 itertools import json import os diff --git a/pyaedt/modules/CircuitTemplates.py b/pyaedt/modules/CircuitTemplates.py index 57859343f3b..7560bd30952 100644 --- a/pyaedt/modules/CircuitTemplates.py +++ b/pyaedt/modules/CircuitTemplates.py @@ -1,3 +1,27 @@ +# -*- 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. + # Power Sinusoidal PowerSinusoidal = [ "NAME:Name", diff --git a/pyaedt/modules/DesignXPloration.py b/pyaedt/modules/DesignXPloration.py index 5472a4fd424..ad144d1fb6b 100644 --- a/pyaedt/modules/DesignXPloration.py +++ b/pyaedt/modules/DesignXPloration.py @@ -1,3 +1,27 @@ +# -*- 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 collections import OrderedDict import copy import csv diff --git a/pyaedt/modules/LayerStackup.py b/pyaedt/modules/LayerStackup.py index 244caa484d4..646ef9c3b84 100644 --- a/pyaedt/modules/LayerStackup.py +++ b/pyaedt/modules/LayerStackup.py @@ -1,3 +1,27 @@ +# -*- 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. + """ This module contains these classes: `Layer` and `Layers`. diff --git a/pyaedt/modules/Material.py b/pyaedt/modules/Material.py index ccbc1d25bd5..7214ce71392 100644 --- a/pyaedt/modules/Material.py +++ b/pyaedt/modules/Material.py @@ -1,3 +1,27 @@ +# -*- 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. + """ This module contains these data classes for creating a material library: @@ -603,7 +627,7 @@ def add_thermal_modifier_free_form(self, formula, index=0): -------- >>> from pyaedt import Hfss - >>> hfss = Hfss(specified_version="2021.2") + >>> hfss = Hfss(version="2021.2") >>> mat1 = hfss.materials.add_material("new_copper2") >>> mat1.add_thermal_modifier_free_form("if(Temp > 1000cel, 1, if(Temp < -273.15cel, 1, 1))") """ @@ -636,7 +660,7 @@ def add_thermal_modifier_dataset(self, dataset, index=0): -------- >>> from pyaedt import Hfss - >>> hfss = Hfss(specified_version="2021.2") + >>> hfss = Hfss(version="2021.2") >>> mat1 = hfss.materials.add_material("new_copper2") >>> mat1.add_thermal_modifier_dataset("$ds1") """ @@ -693,7 +717,7 @@ def add_thermal_modifier_closed_form( -------- >>> from pyaedt import Hfss - >>> hfss = Hfss(specified_version="2021.2") + >>> hfss = Hfss(version="2021.2") >>> mat1 = hfss.materials.add_material("new_copper2") >>> mat1.permittivity.add_thermal_modifier_closed_form(c1 = 1e-3) """ @@ -852,7 +876,7 @@ def _set_non_linear(self, x_unit=None, y_unit=None): Examples -------- >>> from pyaedt import Hfss - >>> hfss = Hfss(specified_version="2023.2") + >>> hfss = Hfss(version="2023.2") >>> B_value = [0.0, 0.1, 0.3, 0.4, 0.48, 0.55, 0.6, 0.61, 0.65] >>> H_value = [0.0, 500.0, 1000.0, 1500.0, 2000.0, 2500.0, 3500.0, 5000.0, 10000.0] >>> mat = hfss.materials.add_material("newMat") @@ -1050,7 +1074,7 @@ def add_spatial_modifier_free_form(self, formula, index=0): -------- >>> from pyaedt import Hfss - >>> hfss = Hfss(specified_version="2021.2") + >>> hfss = Hfss(version="2021.2") >>> mat1 = hfss.materials.add_material("new_copper2") >>> mat1.add_spatial_modifier_free_form("if(X > 1mm, 1, if(X < 1mm, 2, 1))") """ @@ -1083,7 +1107,7 @@ def add_spatial_modifier_dataset(self, dataset, index=0): -------- >>> from pyaedt import Hfss - >>> hfss = Hfss(specified_version="2021.2") + >>> hfss = Hfss(version="2021.2") >>> mat1 = hfss.materials.add_material("new_copper2") >>> mat1.add_spatial_modifier_dataset("$ds1") """ @@ -1384,7 +1408,7 @@ def material_appearance(self): Create a material with color ``[0, 153, 153]`` (darker cyan) and transparency ``0.5``. >>> from pyaedt import Hfss - >>> hfss = Hfss(specified_version="2021.2") + >>> hfss = Hfss(version="2021.2") >>> mat1 = hfss.materials.add_material("new_material") >>> appearance_props = mat1.material_appearance >>> mat1.material_appearance = [0, 153, 153, 0.5] diff --git a/pyaedt/modules/MaterialLib.py b/pyaedt/modules/MaterialLib.py index 58438bb8b2d..8b17ba6140f 100644 --- a/pyaedt/modules/MaterialLib.py +++ b/pyaedt/modules/MaterialLib.py @@ -1,4 +1,27 @@ # -*- 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. + """ This module contains the `Materials` class. """ @@ -12,10 +35,10 @@ import sys import warnings -from pyaedt import is_ironpython from pyaedt.generic.DataHandlers import _arg2dict from pyaedt.generic.LoadAEDTFile import load_entire_aedt_file from pyaedt.generic.general_methods import generate_unique_name +from pyaedt.generic.general_methods import is_ironpython from pyaedt.generic.general_methods import open_file from pyaedt.generic.general_methods import pyaedt_function_handler from pyaedt.generic.general_methods import read_json @@ -829,9 +852,7 @@ def import_materials_from_file(self, input_file=None, **kwargs): if numcol > 2: zunit = val["Coordinates"]["DimUnits"][2] zval = [sublist[2] for sublist in new_list] - self._app.create_dataset( - el[1:], xunit=xunit, yunit=yunit, zunit=zunit, xlist=xval, ylist=yval, zlist=zval - ) + self._app.create_dataset(el[1:], x=xval, y=yval, z=zval, x_unit=xunit, y_unit=yunit) if json_flag: for el, val in data["materials"].items(): if el.lower() in list(self.material_keys.keys()): diff --git a/pyaedt/modules/Mesh.py b/pyaedt/modules/Mesh.py index 588f7c015a2..006ca95d078 100644 --- a/pyaedt/modules/Mesh.py +++ b/pyaedt/modules/Mesh.py @@ -1,3 +1,27 @@ +# -*- 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. + """ This module contains the `Mesh` class. """ diff --git a/pyaedt/modules/Mesh3DLayout.py b/pyaedt/modules/Mesh3DLayout.py index 67b845d223d..f006a3f1c07 100644 --- a/pyaedt/modules/Mesh3DLayout.py +++ b/pyaedt/modules/Mesh3DLayout.py @@ -1,3 +1,27 @@ +# -*- 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. + """ This module contains these classes: `Mesh` and `Mesh3DOperation`. diff --git a/pyaedt/modules/MeshIcepak.py b/pyaedt/modules/MeshIcepak.py index 6eab77ed091..db76e18a2b6 100644 --- a/pyaedt/modules/MeshIcepak.py +++ b/pyaedt/modules/MeshIcepak.py @@ -1,5 +1,29 @@ +# -*- 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 abc import abstractmethod from collections import OrderedDict +import os.path import warnings from pyaedt.generic.DataHandlers import _dict2arg @@ -258,7 +282,7 @@ def object(self): return { "CreateRegion": oo for o, oo in self._app.modeler.objects_by_name.items() - if oo.history().command == "CreateRegion" + if oo.history() and oo.history().command == "CreateRegion" }.get("CreateRegion", None) else: return self._app.modeler.objects_by_name.get(self._name, None) @@ -633,10 +657,21 @@ def __getattr__(self, name): return self.__dict__[name] def __setattr__(self, name, value): - if "settings" in self.__dict__ and name in self.settings: + if ("settings" in self.__dict__) and (name in self.settings): self.settings[name] = value elif name == "UserSpecifiedSettings": self.__dict__["manual_settings"] = value + elif ( + ("settings" in self.__dict__) + and not (name in self.settings) + and name + not in ["manual_settings", "settings", "_name", "_model_units", "_app", "_assignment", "enable", "name"] + ): + self._app.logger.error( + "Setting name {} is not available. Available parameters are: {}.".format( + name, ", ".join(self.settings.keys()) + ) + ) else: super(MeshRegionCommon, self).__setattr__(name, value) @@ -674,6 +709,8 @@ def update(self): args = ["NAME:Settings"] args += self.settings.parse_settings_as_args() args += ["UserSpecifiedSettings:=", self.manual_settings] + if self.global_region.object: + args += ["Objects({})".format(str(self.global_region.object.id))] try: self._app.omeshmodule.EditGlobalMeshRegion(args) return True @@ -712,6 +749,7 @@ def __init__(self, app, objects=None, name=None, **kwargs): app, name, ) + self._assignment = None self.enable = True if settings.aedt_version > "2023.2" and objects is not None: if not isinstance(objects, list): @@ -1600,6 +1638,7 @@ def assign_mesh_level_to_group( for el in self.meshoperations: if el.name == name: name = generate_unique_name(name) + break else: name = generate_unique_name("MeshLevel") props = OrderedDict( @@ -1615,3 +1654,45 @@ def assign_mesh_level_to_group( mop.create() self.meshoperations.append(mop) return mop + + def assign_mesh_reuse(self, assignment, mesh_file, name=None): + """Assign a mesh file to objects. + + Parameters + ---------- + assignment : str or list + Names of objects to which the mesh file is assignment. + mesh_file : str + Path to the mesh file. + name : str, optional + Name of the mesh operation. The default is ``None``, in which case it will be + generated automatically. + + Returns + ------- + :class:`pyaedt.modules.Mesh.MeshOperation` + + References + ---------- + + >>> oModule.AssignMeshOperation + """ + if not os.path.exists(mesh_file): + self._app.logger.error("Mesh file does not exist.") + return False + if name: + for el in self.meshoperations: + if el.name == name: + name = generate_unique_name(name) + break + else: + 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} + ) + mop = MeshOperation(self, name, props, "Icepak") + mop.create() + self.meshoperations.append(mop) + return mop diff --git a/pyaedt/modules/OptimetricsTemplates.py b/pyaedt/modules/OptimetricsTemplates.py index c9b976a16dc..efa3dc5d1a1 100644 --- a/pyaedt/modules/OptimetricsTemplates.py +++ b/pyaedt/modules/OptimetricsTemplates.py @@ -1,3 +1,27 @@ +# -*- 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 collections import OrderedDict defaultparametricSetup = OrderedDict( diff --git a/pyaedt/modules/PostProcessor.py b/pyaedt/modules/PostProcessor.py index 2f30d5cf8a2..3d9488924dd 100644 --- a/pyaedt/modules/PostProcessor.py +++ b/pyaedt/modules/PostProcessor.py @@ -1,3 +1,27 @@ +# -*- 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. + """ This module contains these classes: `FieldPlot`, `PostProcessor`, and `SolutionData`. @@ -17,12 +41,12 @@ import string import tempfile -from pyaedt import is_ironpython from pyaedt.application.Variables import decompose_variable_value from pyaedt.generic.DataHandlers import _dict_items_to_list_items from pyaedt.generic.constants import unit_converter from pyaedt.generic.general_methods import check_and_download_file from pyaedt.generic.general_methods import generate_unique_name +from pyaedt.generic.general_methods import is_ironpython from pyaedt.generic.general_methods import open_file from pyaedt.generic.general_methods import pyaedt_function_handler from pyaedt.generic.general_methods import read_configuration_file @@ -921,23 +945,27 @@ def available_display_types(self, report_category=None): @pyaedt_function_handler() def available_quantities_categories( - self, report_category=None, display_type=None, solution=None, context="", is_siwave_dc=False + self, report_category=None, display_type=None, solution=None, context=None, is_siwave_dc=False ): """Compute the list of all available report categories. Parameters ---------- report_category : str, optional - Report Category. Default is `None` which will take first default category. + Report category. The default is ``None``, in which case the first default category is used. display_type : str, optional - Report Display Type. - Default is `None` which will take first default type which is in most of the case "Rectangular Plot". + Report display type. The default is ``None``, in which case the first default type + is used. In most cases, this default type is ``"Rectangular Plot"``. solution : str, optional - Report Setup. Default is `None` which will take first nominal_adaptive solution. - context : str, optional - Report Category. Default is `""` which will take first default context. + Report setup. The default is ``None``, in which case the first + nominal adaptive solution is used. + context : str, dict, optional + Report category. The default is ``None``, in which case the first default context + is used. For Maxwell 2D/3D eddy current solution types, the report category + can be provided as a dictionary, where the key is the matrix name and the value + the reduced matrix. is_siwave_dc : bool, optional - Whether if the setup is Siwave DCIR or not. Default is ``False``. + Whether the setup is Siwave DCIR. The default is ``False``. Returns ------- @@ -970,7 +998,14 @@ def available_quantities_categories( "SimValueContext:=", [37010, 0, 2, 0, False, False, -1, 1, 0, 1, 1, "", 0, 0, "DCIRID", False, id_, "IDIID", False, "1"], ] - + elif self._app.design_type in ["Maxwell 2D", "Maxwell 3D"] and self._app.solution_type == "EddyCurrent": + if isinstance(context, dict): + for k, v in context.items(): + context = ["Context:=", k, "Matrix:=", v] + elif context and isinstance(context, str): + context = ["Context:=", context] + elif not context: + context = "" elif not context: # pragma: no cover context = "" @@ -985,7 +1020,7 @@ def available_report_quantities( display_type=None, solution=None, quantities_category=None, - context="", + context=None, is_siwave_dc=False, ): """Compute the list of all available report quantities of a given report quantity category. @@ -993,17 +1028,23 @@ def available_report_quantities( Parameters ---------- report_category : str, optional - Report Category. Default is ``None`` which will take first default category. + Report Category. The default is ``None``, in which case the default category is used. display_type : str, optional Report Display Type. - Default is ``None`` which will take first default type which is in most of the case "Rectangular Plot". + The default is ``None``, in which case the default type is used. + In most of the cases the default type is "Rectangular Plot". solution : str, optional - Report Setup. Default is `None` which will take first nominal_adaptive solution. + Report Setup. + The default is ``None``, in which case the first nominal adaptive solution is used. quantities_category : str, optional - The category to which quantities belong. It has to be one of ``available_quantities_categories`` method. - Default is ``None`` which will take first default quantity.". - context : str, optional - Report Context. Default is ``""`` which will take first default context. + The category that the quantities belong to. + It must be one of the ``available_quantities_categories`` method. + The default is ``None``, in which case the first default quantity is used. + context : str, dict, optional + Report Context. + The default is ``None``, in which case the default context is used. + For Maxwell 2D/3D Eddy Current solution types this can be provided as a dictionary + where the key is the matrix name and value the reduced matrix. is_siwave_dc : bool, optional Whether if the setup is Siwave DCIR or not. Default is ``False``. @@ -1014,6 +1055,26 @@ def available_report_quantities( References ---------- >>> oModule.GetAllQuantities + + Examples + -------- + The example shows how to get report expressions for a Maxwell design with Eddy current solution. + The context has to be provided as a dictionary where the key is the name of the original matrix + and the value is the name of the reduced matrix. + >>> from pyaedt import Maxwell3d + >>> m3d = Maxwell3d(solution_type="EddyCurrent") + >>> rectangle1 = m3d.modeler.create_rectangle(0, [0.5, 1.5, 0], [2.5, 5], name="Sheet1") + >>> rectangle2 = m3d.modeler.create_rectangle(0, [9, 1.5, 0], [2.5, 5], name="Sheet2") + >>> rectangle3 = m3d.modeler.create_rectangle(0, [16.5, 1.5, 0], [2.5, 5], name="Sheet3") + >>> m3d.assign_current(rectangle1.faces[0], amplitude=1, name="Cur1") + >>> m3d.assign_current(rectangle2.faces[0], amplitude=1, name="Cur2") + >>> m3d.assign_current(rectangle3.faces[0], amplitude=1, name="Cur3") + >>> L = m3d.assign_matrix(assignment=["Cur1", "Cur2", "Cur3"], matrix_name="Matrix1") + >>> out = L.join_series(sources=["Cur1", "Cur2"], matrix_name="ReducedMatrix1") + >>> expressions = m3d.post.available_report_quantities(report_category="EddyCurrent", + ... display_type="Data Table", + ... context={"Matrix1": "ReducedMatrix1"}) + >>> m3d.release_desktop(False, False) """ if not report_category: report_category = self.available_report_types[0] @@ -1038,7 +1099,14 @@ def available_report_quantities( "SimValueContext:=", [37010, 0, 2, 0, False, False, -1, 1, 0, 1, 1, "", 0, 0, "DCIRID", False, id, "IDIID", False, "1"], ] - + elif self._app.design_type in ["Maxwell 2D", "Maxwell 3D"] and self._app.solution_type == "EddyCurrent": + if isinstance(context, dict): + for k, v in context.items(): + context = ["Context:=", k, "Matrix:=", v] + elif context and isinstance(context, str): + context = ["Context:=", context] + elif not context: + context = "" elif not context: context = "" if not quantities_category: @@ -1063,7 +1131,7 @@ def available_report_solutions(self, report_category=None): Parameters ---------- report_category : str, optional - Report Category. Default is ``None`` which will take first default category. + Report Category. Default is ``None`` which takes default category. Returns ------- @@ -1195,7 +1263,7 @@ def delete_report(self, plot_name=None): Parameters ---------- plot_name : str, optional - Name of the plot to delete. The default value is ``None`` and in this case, all reports will be deleted. + Name of the plot to delete. The default value is ``None`` and in this case, all reports are deleted. Returns ------- @@ -1434,7 +1502,7 @@ def export_report_to_csv( Parameters ---------- project_dir : str - Path to the project directory. The csv file will be plot_name.csv. + Path to the project directory. The CSV file is plot_name.csv. plot_name : str Name of the plot to export. uniform : bool, optional @@ -1703,20 +1771,22 @@ def create_report( secondary_sweep_variable : str, optional Name of the secondary sweep variable in 3D Plots. report_category : str, optional - Category of the Report to be created. If `None` default data Report will be used. + Category of the Report to be created. If `None` default data Report is used. The Report Category can be one of the types available for creating a report depend on the simulation setup. For example for a Far Field Plot in HFSS the UI shows the report category as "Create Far Fields Report". - The report category will be in this case "Far Fields". + The report category is "Far Fields" in this case. Depending on the setup different categories are available. - If `None` default category will be used (the first item in the Results drop down menu in AEDT). + If ``None`` default category is used (the first item in the Results drop down menu in AEDT). plot_type : str, optional The format of Data Visualization. Default is ``Rectangular Plot``. - context : str, optional + context : str, dict, optional The default is ``None``. - For HFSS 3D Layout, options are ``"Bondwires"``, ``"Differential Pairs"``, ``None``, ``"Probes"``, ``"RL"``, ``"Sources"``, and ``"Vias"``. - For Q2D or Q3D, specify the name of a reduced matrix. - For a far fields plot, specify the name of an infinite sphere. + - For Maxwell 2D/3D Eddy Current solution types this can be provided as a dictionary + where the key is the matrix name and value the reduced matrix. plot_name : str, optional Name of the plot. The default is ``None``. polyline_points : int, optional, @@ -1724,7 +1794,6 @@ def create_report( subdesign_id : int, optional Specify a subdesign ID to export a Touchstone file of this subdesign. Valid for Circuit Only. The default value is ``None``. - context : str, optional Returns ------- @@ -1754,8 +1823,8 @@ def create_report( ... report_category="Far Fields", ... plot_type="3D Polar Plot", ... context="3D") - >>> hfss.post.create_report("S(1,1)",hfss.nominal_sweep,variations=variations,plot_type="Smith Chart") + >>> hfss.release_desktop(False, False) >>> from pyaedt import Maxwell2d >>> m2d = Maxwell2d() @@ -1763,6 +1832,27 @@ def create_report( ... domain="Time", ... primary_sweep_variable="Time", ... plot_name="Winding Plot 1") + >>> m2d.release_desktop(False, False) + + >>> from pyaedt import Maxwell3d + >>> m3d = Maxwell3d(solution_type="EddyCurrent") + >>> rectangle1 = m3d.modeler.create_rectangle(0, [0.5, 1.5, 0], [2.5, 5], name="Sheet1") + >>> rectangle2 = m3d.modeler.create_rectangle(0, [9, 1.5, 0], [2.5, 5], name="Sheet2") + >>> rectangle3 = m3d.modeler.create_rectangle(0, [16.5, 1.5, 0], [2.5, 5], name="Sheet3") + >>> m3d.assign_current(rectangle1.faces[0], amplitude=1, name="Cur1") + >>> m3d.assign_current(rectangle2.faces[0], amplitude=1, name="Cur2") + >>> m3d.assign_current(rectangle3.faces[0], amplitude=1, name="Cur3") + >>> L = m3d.assign_matrix(assignment=["Cur1", "Cur2", "Cur3"], matrix_name="Matrix1") + >>> out = L.join_series(sources=["Cur1", "Cur2"], matrix_name="ReducedMatrix1") + >>> expressions = m3d.post.available_report_quantities(report_category="EddyCurrent", + ... display_type="Data Table", + ... context={"Matrix1": "ReducedMatrix1"}) + >>> report = m3d.post.create_report( + ... expressions=expressions, + ... context={"Matrix1": "ReducedMatrix1"}, + ... plot_type="Data Table", + ... plot_name="reduced_matrix") + >>> m3d.release_desktop(False, False) """ if not setup_sweep_name: setup_sweep_name = self._app.nominal_sweep @@ -1836,6 +1926,19 @@ def create_report( ].index(context) elif self._app.design_type in ["Q3D Extractor", "2D Extractor"] and context: report.matrix = context + elif ( + self._app.design_type in ["Maxwell 2D", "Maxwell 3D"] + and self._app.solution_type == "EddyCurrent" + and context + ): + if isinstance(context, dict): + for k, v in context.items(): + report.matrix = k + report.reduced_matrix = v + elif context in self.modeler.line_names or context in self.modeler.point_names: + report.polyline = context + else: + report.matrix = context elif report_category == "Far Fields": if not context and self._app._field_setups: report.far_field_sphere = self._app.field_setups[0].name @@ -1883,7 +1986,7 @@ def get_solution_data( ---------- expressions : str or list, optional One or more formulas to add to the report. Example is value ``"dB(S(1,1))"`` or a list of values. - Default is `None` which will return all traces. + Default is ``None`` which returns all traces. setup_sweep_name : str, optional Name of the setup. The default is ``None``, in which case the ``nominal_adaptive`` setup is used. Be sure to build a setup string in the form of @@ -1893,21 +1996,21 @@ def get_solution_data( Plot Domain. Options are "Sweep" for frequency domain related results and "Time" for transient related data. variations : dict, optional Dictionary of all families including the primary sweep. - The default is ``None`` which will use the nominal variations of the setup. + The default is ``None`` which uses the nominal variations of the setup. primary_sweep_variable : str, optional Name of the primary sweep. The default is ``"None"`` which, depending on the context, - will internally assign the primary sweep to: + internally assigns the primary sweep to: 1. ``Freq`` for frequency domain results, 2. ``Time`` for transient results, 3. ``Theta`` for radiation patterns, 4. ``distance`` for field plot over a polyline. report_category : str, optional - Category of the Report to be created. If `None` default data Report will be used. + Category of the Report to be created. If ``None`` default data Report is used. The Report Category can be one of the types available for creating a report depend on the simulation setup. For example for a Far Field Plot in HFSS the UI shows the report category as "Create Far Fields Report". - The report category will be in this case "Far Fields". + The report category is "Far Fields" in this case. Depending on the setup different categories are available. - If `None` default category will be used (the first item in the Results drop down menu in AEDT). + If ``None`` default category is used (the first item in the Results drop down menu in AEDT). To get the list of available categories user can use method ``available_report_types``. context : str, dict, optional This is the context of the report. @@ -1917,6 +2020,8 @@ def get_solution_data( 3. Reduce Matrix Name for Q2d/Q3d solution 4. Infinite Sphere name for Far Fields Plot. 5. Dictionary. If dictionary is passed, key is the report property name and value is property value. + 6. For Maxwell 2D/3D eddy current solution types, this can be provided as a dictionary, + where the key is the matrix name and value the reduced matrix. subdesign_id : int, optional Subdesign ID for exporting a Touchstone file of this subdesign. This parameter is valid for ``Circuit`` only. @@ -1963,6 +2068,7 @@ def get_solution_data( ... variations=variations, ...) >>> data2.plot() + >>> hfss.release_desktop(False, False) >>> from pyaedt import Maxwell2d >>> m2d = Maxwell2d() @@ -1970,12 +2076,30 @@ def get_solution_data( ... "InputCurrent(PHA)", domain="Time", primary_sweep_variable="Time", ... ) >>> data3.plot("InputCurrent(PHA)") + >>> m2d.release_desktop(False, False) >>> from pyaedt import Circuit >>> circuit = Circuit() >>> context = {"algorithm": "FFT", "max_frequency": "100MHz", "time_stop": "2.5us", "time_start": "0ps"} >>> spectralPlotData = circuit.post.get_solution_data(expressions="V(Vprobe1)", domain="Spectral", ... primary_sweep_variable="Spectrum", context=context) + >>> circuit.release_desktop(False, False) + + >>> from pyaedt import Maxwell3d + >>> m3d = Maxwell3d(solution_type="EddyCurrent") + >>> rectangle1 = m3d.modeler.create_rectangle(0, [0.5, 1.5, 0], [2.5, 5], name="Sheet1") + >>> rectangle2 = m3d.modeler.create_rectangle(0, [9, 1.5, 0], [2.5, 5], name="Sheet2") + >>> rectangle3 = m3d.modeler.create_rectangle(0, [16.5, 1.5, 0], [2.5, 5], name="Sheet3") + >>> m3d.assign_current(rectangle1.faces[0], amplitude=1, name="Cur1") + >>> m3d.assign_current(rectangle2.faces[0], amplitude=1, name="Cur2") + >>> m3d.assign_current(rectangle3.faces[0], amplitude=1, name="Cur3") + >>> L = m3d.assign_matrix(assignment=["Cur1", "Cur2", "Cur3"], matrix_name="Matrix1") + >>> out = L.join_series(sources=["Cur1", "Cur2"], matrix_name="ReducedMatrix1") + >>> expressions = m3d.post.available_report_quantities(report_category="EddyCurrent", + ... display_type="Data Table", + ... context={"Matrix1": "ReducedMatrix1"}) + >>> data = m2d.post.get_solution_data(expressions=expressions, context={"Matrix1": "ReducedMatrix1"}) + >>> m3d.release_desktop(False, False) """ expressions = [expressions] if isinstance(expressions, str) else expressions if not setup_sweep_name: @@ -2027,6 +2151,23 @@ def get_solution_data( report.differential_pairs = True elif self._app.design_type in ["Q3D Extractor", "2D Extractor"] and context: report.matrix = context + elif ( + self._app.design_type in ["Maxwell 2D", "Maxwell 3D"] + and self._app.solution_type == "EddyCurrent" + and context + ): + if isinstance(context, dict): + for k, v in context.items(): + report.matrix = k + report.reduced_matrix = v + elif ( + hasattr(self.modeler, "line_names") + and hasattr(self.modeler, "point_names") + and context in self.modeler.point_names + self.modeler.line_names + ): + report.polyline = context + else: + report.matrix = context elif report_category == "Far Fields": if not context and self._app.field_setups: report.far_field_sphere = self._app.field_setups[0].name @@ -3354,7 +3495,7 @@ def create_fieldplot_layers( # type: (list, str, str, list, bool, dict, str) -> FieldPlot """Create a field plot of stacked layer plot. This plot is valid from AEDT 2023 R2 and later in HFSS 3D Layout. - It will also work when a layout components in 3d modeler is used. + It works when a layout components in 3d modeler is used. In order to plot on signal layers use the method ``create_fieldplot_layers_nets``. Parameters @@ -3362,7 +3503,7 @@ def create_fieldplot_layers( layers : list List of layers to plot. For example: ``["Layer1","Layer2"]``. If empty list is provided - all layers will be considered. + all layers are considered. quantity : str Name of the quantity to plot. setup : str, optional @@ -3449,8 +3590,8 @@ def create_fieldplot_layers_nets( layers_nets : list List of layers and nets to plot. For example: ``[["Layer1", "GND", "PWR"], ["Layer2", "VCC"], ...]``. If ``"no-layer"`` is provided as first argument, - all layers will be considered. If ``"no-net"`` is provided or the list contains only layer name, all the - nets will be automatically considered. + all layers are considered. If ``"no-net"`` is provided or the list contains only layer name, all the + nets are automatically considered. quantity : str Name of the quantity to plot. setup : str, optional @@ -3828,7 +3969,7 @@ def export_model_picture( Parameters ---------- full_name : str, optional - Full Path for exporting the image file. The default is ``None``, in which case working_dir will be used. + Full Path for exporting the image file. The default is ``None``, in which case working_dir is used. show_axis : bool, optional Whether to show the axes. The default is ``True``. show_grid : bool, optional @@ -4118,8 +4259,8 @@ def power_budget(self, units="W", temperature=22, output_type="component"): output_type : str, optional Output data presentation. The default is ``"component"``. The options are ``"component"``, or ``"boundary"``. - ``"component"`` will return the power based on each component. - ``"boundary"`` will return the power based on each boundary. + ``"component"`` returns the power based on each component. + ``"boundary"`` returns the power based on each boundary. Returns ------- @@ -4454,23 +4595,27 @@ def extract_dataset_info(boundary_obj, units_input="W", boundary="Power"): power_dict_obj[group] += power_dict_obj[power_comp] if output_type == "boundary": - for comp in power_dict.keys(): - self.logger.info("The power of {} is {} {}".format(comp, str(round(power_dict[comp], 3)), units)) + for comp, value in power_dict.items(): + if round(value, 3) != 0.0: + self.logger.info("The power of {} is {} {}".format(comp, str(round(value, 3)), units)) self.logger.info("The total power is {} {}".format(str(round(sum(power_dict.values()), 3)), units)) return power_dict, sum(power_dict.values()) elif output_type == "component": # pragma: no cover - for comp in power_dict_obj.keys(): - self.logger.info("The power of {} is {} {}".format(comp, str(round(power_dict_obj[comp], 3)), units)) + for comp, value in power_dict_obj.items(): + if round(value, 3) != 0.0: + self.logger.info("The power of {} is {} {}".format(comp, str(round(value, 3)), units)) self.logger.info("The total power is {} {}".format(str(round(sum(power_dict_obj.values()), 3)), units)) return power_dict_obj, sum(power_dict_obj.values()) else: # pragma: no cover - for comp in power_dict.keys(): - self.logger.info("The power of {} is {} {}".format(comp, str(round(power_dict[comp], 3)), units)) + for comp, value in power_dict.items(): + if round(value, 3) != 0.0: + self.logger.info("The power of {} is {} {}".format(comp, str(round(value, 3)), units)) self.logger.info("The total power is {} {}".format(str(round(sum(power_dict.values()), 3)), units)) - for comp in power_dict_obj.keys(): - self.logger.info("The power of {} is {} {}".format(comp, str(round(power_dict_obj[comp], 3)), units)) + for comp, value in power_dict_obj.items(): + if round(value, 3) != 0.0: + self.logger.info("The power of {} is {} {}".format(comp, str(round(value, 3)), units)) self.logger.info("The total power is {} {}".format(str(round(sum(power_dict_obj.values()), 3)), units)) return power_dict_obj, sum(power_dict_obj.values()), power_dict, sum(power_dict.values()) diff --git a/pyaedt/modules/SetupTemplates.py b/pyaedt/modules/SetupTemplates.py index b55424bb77f..7142009842c 100644 --- a/pyaedt/modules/SetupTemplates.py +++ b/pyaedt/modules/SetupTemplates.py @@ -1,3 +1,27 @@ +# -*- 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 __future__ import absolute_import from collections import OrderedDict diff --git a/pyaedt/modules/SolveSetup.py b/pyaedt/modules/SolveSetup.py index fe6491c725b..c153da6b08a 100644 --- a/pyaedt/modules/SolveSetup.py +++ b/pyaedt/modules/SolveSetup.py @@ -1,3 +1,27 @@ +# -*- 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. + """ This module contains these classes: `Setup`, `Setup3DLayout`, and `SetupCircuit`. @@ -101,7 +125,7 @@ def analyze( that support automatic settings. solve_in_batch : bool, optional Whether to solve the project in batch or not. - If ``True`` the project will be saved, closed, solved and repened. + If ``True`` the project will be saved, closed, and solved. machine : str, optional Name of the machine if remote. The default is ``"localhost"``. run_in_thread : bool, optional @@ -221,6 +245,20 @@ def name(self, name): self._name = name self.props["Name"] = name + @pyaedt_function_handler() + def get_profile(self): + """Solution profile. + + Returns + ------- + dict of :class:pyaedt.modeler.cad.elements3d.BinaryTree when solved setups exist, + ``None`` when no solved setups or no compatible application exists. + """ + profile = self._app.get_profile(self.name) + if not isinstance(profile, dict) or not profile: + profile = None + return profile + @pyaedt_function_handler(sweep_name="sweep") def get_solution_data( self, @@ -865,6 +903,54 @@ def add_mesh_link( self.auto_update = auto_update return False + def _parse_link_parameters(self, map_variables_by_name, parameters): + # parameters + params = OrderedDict({}) + if map_variables_by_name: + parameters = self.p_app.available_variations.nominal_w_values_dict + for k, v in parameters.items(): + params[k] = k + elif parameters is None: + parameters = self.p_app.available_variations.nominal_w_values_dict + for k, v in parameters.items(): + params[k] = v + else: + for k, v in parameters.items(): + if k in list(self._app.available_variations.nominal_w_values_dict.keys()): + params[k] = v + else: + params[k] = parameters[v] + return params + + def _parse_link_solution(self, project, design, solution): + prev_solution = OrderedDict({}) + + # project name + if project != "This Project*": + if os.path.exists(project): + prev_solution["Project"] = project + self.props["PathRelativeTo"] = "SourceProduct" + else: + raise ValueError("Project file path provided does not exist.") + else: + prev_solution["Project"] = project + self.props["PathRelativeTo"] = "TargetProject" + + # design name + if not design or design is None: + raise ValueError("Provide design name to add mesh link to.") + elif design not in self.p_app.design_list: + raise ValueError("Design does not exist in current project.") + else: + prev_solution["Design"] = design + + # solution name + if solution: + prev_solution["Soln"] = solution + else: + raise ValueError("Provide a valid solution name.") + return prev_solution + @pyaedt_function_handler( design_name="design", solution_name="solution", parameters_dict="parameters", project_name="project" ) @@ -884,7 +970,7 @@ def start_continue_from_previous_setup( ---------- design : str Name of the design. - solution : str, optional + solution : str Name of the solution in the format ``"name : solution_name"``. For example, ``"Setup1 : Transient", "MySetup : LastAdaptive"``. map_variables_by_name : bool, optional @@ -924,49 +1010,9 @@ def start_continue_from_previous_setup( try: self.auto_update = False - # parameters - params = OrderedDict({}) - if map_variables_by_name: - parameters = self.p_app.available_variations.nominal_w_values_dict - for k, v in parameters.items(): - params[k] = k - elif parameters is None: - parameters = self.p_app.available_variations.nominal_w_values_dict - for k, v in parameters.items(): - params[k] = v - else: - for k, v in parameters.items(): - if k in list(self._app.available_variations.nominal_w_values_dict.keys()): - params[k] = v - else: - params[k] = parameters[v] - - prev_solution = OrderedDict({}) + params = self._parse_link_parameters(map_variables_by_name, parameters) - # project name - if project != "This Project*": - if os.path.exists(project): - prev_solution["Project"] = project - self.props["PathRelativeTo"] = "SourceProduct" - else: - raise ValueError("Project file path provided does not exist.") - else: - prev_solution["Project"] = project - self.props["PathRelativeTo"] = "TargetProject" - - # design name - if not design or design is None: - raise ValueError("Provide design name to add mesh link to.") - elif design not in self.p_app.design_list: - raise ValueError("Design does not exist in current project.") - else: - prev_solution["Design"] = design - - # solution name - if solution: - prev_solution["Soln"] = solution - else: - raise ValueError("Provide a valid solution name.") + prev_solution = self._parse_link_solution(project, design, solution) self.props["PrevSoln"] = prev_solution @@ -1907,7 +1953,7 @@ def _get_net_names(self, app, file_fullname): lay.name: lay.lower_elevation + lay.thickness / 2 for lay in list(self.p_app.modeler.edb.stackup.signal_layers.values()) } - aedtapp = app(projectname=file_fullname) + aedtapp = app(project=file_fullname) units = aedtapp.modeler.model_units aedt_units = AEDT_UNITS["Length"][units] self._convert_edb_to_aedt_units(input_dict=primitives_3d_pts_per_nets, output_unit=aedt_units) @@ -1964,7 +2010,7 @@ def _get_net_names(self, app, file_fullname): if aedtapp.design_type == "Q3D Extractor": aedtapp.auto_identify_nets() - aedtapp.close_project(save_project=True) + aedtapp.close_project(save=True) @pyaedt_function_handler() def _get_primitives_points_per_net(self): @@ -3845,3 +3891,85 @@ def update(self, properties=None): self.omodule.EditSetup(self.name, arg) return True + + +class SetupIcepak(Setup, object): + def __init__(self, app, solution_type, setup_name, is_new_setup=True): + Setup.__init__(self, app, solution_type, setup_name, is_new_setup) + + def start_continue_from_previous_setup( + self, + design, + solution, + map_variables_by_name=True, + parameters=None, + project="This Project*", + force_source_to_solve=True, + preserve_partner_solution=True, + frozen_flow=False, + ): + """Start or continue from a previously solved setup. + + Parameters + ---------- + design : str + Name of the design. + solution : str + Name of the solution in the format ``"name : solution_name"``. + For example, ``"Setup1 : Transient"``, ``"Setup1 : SteadyState"``. + map_variables_by_name : bool, optional + Whether variables are mapped by name from the source design. The default is + ``True``. + parameters : dict, optional + Dictionary of the parameters. This argument is not considered if + ``map_variables_by_name=True``. If ``None``, the default is + ``appname.available_variations.nominal_w_values_dict``. + project : str, optional + Name of the project with the design. The default is ``"This Project*"``. + However, you can supply the full path and name to another project. + force_source_to_solve : bool, optional + The default is ``True``. + preserve_partner_solution : bool, optional + The default is ``True``. + frozen_flow : bool, optional + Whether to freeze the flow to the previous solution. The default is ``False``. + + Returns + ------- + bool + ``True`` when successful, ``False`` when failed. + + References + ---------- + + >>> oModule.EditSetup + + Examples + -------- + >>> ipk = pyaedt.Icepak() + >>> setup = ipk.get_setup("Setup1") + >>> setup.start_continue_from_previous_setup(design="IcepakDesign1",solution="Setup1 : SteadyState") + + """ + + auto_update = self.auto_update + try: + self.auto_update = False + + params = self._parse_link_parameters(map_variables_by_name, parameters) + + prev_solution = self._parse_link_solution(project, design, solution) + + self.props["RestartSoln"] = prev_solution + + self.props["RestartSoln"]["Params"] = params + self.props["RestartSoln"]["ForceSourceToSolve"] = force_source_to_solve + self.props["RestartSoln"]["PreservePartnerSoln"] = preserve_partner_solution + self.props["Frozen Flow Simulation"] = frozen_flow + + self.update() + self.auto_update = auto_update + return True + except Exception: + self.auto_update = auto_update + return False diff --git a/pyaedt/modules/SolveSweeps.py b/pyaedt/modules/SolveSweeps.py index 6d1e1f0e60e..358fd340a0e 100644 --- a/pyaedt/modules/SolveSweeps.py +++ b/pyaedt/modules/SolveSweeps.py @@ -1,3 +1,27 @@ +# -*- 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 collections import OrderedDict import copy from difflib import SequenceMatcher @@ -6,10 +30,10 @@ import sys import warnings -from pyaedt import pyaedt_function_handler from pyaedt.generic.DataHandlers import _dict2arg from pyaedt.generic.LoadAEDTFile import load_entire_aedt_file from pyaedt.generic.constants import unit_converter +from pyaedt.generic.general_methods import pyaedt_function_handler from pyaedt.generic.settings import settings from pyaedt.modules.SetupTemplates import Sweep3DLayout from pyaedt.modules.SetupTemplates import SweepHfss3D @@ -75,8 +99,8 @@ class SweepHFSS(object): Examples -------- - >>> hfss = Hfss(specified_version=version, projectname=proj, designname=gtemDesign, solution_type=solutiontype, - name=name, new_desktop_session=False, close_on_exit=False) + >>> hfss = Hfss(version=version, project=proj, design=gtemDesign, solution_type=solutiontype, + name=name, new_desktop=False, close_on_exit=False) >>> hfss_setup = hfss.setups[0] >>> hfss_sweep = SweepHFSS(hfss_setup, 'Sweep', sweep_type ='Interpolating', props=None) diff --git a/pyaedt/modules/__init__.py b/pyaedt/modules/__init__.py index e69de29bb2d..9c4476773da 100644 --- a/pyaedt/modules/__init__.py +++ b/pyaedt/modules/__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/pyaedt/modules/fields_calculator.py b/pyaedt/modules/fields_calculator.py new file mode 100644 index 00000000000..f3cff929aa9 --- /dev/null +++ b/pyaedt/modules/fields_calculator.py @@ -0,0 +1,365 @@ +# -*- 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 copy +import os + +import pyaedt +from pyaedt.generic.general_methods import generate_unique_project_name +from pyaedt.generic.general_methods import open_file +from pyaedt.generic.general_methods import pyaedt_function_handler +from pyaedt.generic.general_methods import read_toml + + +class FieldsCalculator: + def __init__(self, app): + self.expression_catalog = read_toml(os.path.join(pyaedt.__path__[0], "misc", "expression_catalog.toml")) + self.__app = app + self.design_type = app.design_type + self.ofieldsreporter = app.ofieldsreporter + + @property + def expression_names(self): + """List of available expressions. + + Returns + ------- + list + """ + return list(self.expression_catalog.keys()) + + @pyaedt_function_handler() + def add_expression(self, calculation, assignment, name=None): + """Add named expression. + + Parameters + ---------- + calculation : + Calculation type. + assignment : int or :class:`pyaedt.modeler.cad.object3d.Object3d` or + :class:`pyaedt.modeler.cad.FacePrimitive + Name of the object to add the named expression from. + name : str, optional + Name of the named expression. The default is ``None``. + + Returns + ------- + str, bool + Named expression when successful, ``False`` when failed. + """ + if assignment is not None: + assignment = self.__app.modeler.convert_to_selections(assignment, return_list=True)[0] + + if calculation not in self.expression_names: + self.__app.logger.error("Calculation is not available.") + return False + + expression_info = copy.deepcopy(self.expression_catalog[calculation]) + + if not name: + name = expression_info["name"] + + expression_info["name"] = name + + if self.is_expression_defined(expression_info["name"]): + self.__app.logger.debug("Named expression already exists.") + return expression_info["name"] + + # Check design type + design_type = self.__app.design_type + if design_type not in expression_info["design_type"]: + self.__app.logger.error("Design type is not compatible.") + return False + design_type_index = expression_info["design_type"].index(design_type) + + # Check assignment type + if assignment and isinstance(assignment, str) and assignment not in self.__app.modeler.object_names: + self.__app.logger.error("Assignment type is not correct.") + return False + + # Check assignment type + if assignment and isinstance(assignment, str): + assignment_type = self.__app.modeler.objects_by_name[assignment].object_type + if assignment_type not in expression_info["assignment_type"]: + self.__app.logger.error("Wrong assignment type.") + return False + elif assignment and isinstance(assignment, int): + if "Face" not in expression_info["assignment_type"]: + self.__app.logger.error("Wrong assignment type.") + return False + else: + assignment = "Face" + str(assignment) + + # Check constants + if "constants" in expression_info: + constants = expression_info["constants"] + if constants: + for k, v in constants.items(): + self.__app.variable_manager.set_variable(k, v, postprocessing=True) + + # Check for dependent expressions + if expression_info["dependent_expressions"]: + for expression in expression_info["dependent_expressions"]: + expression_name = self.add_expression(calculation=expression, assignment=None) + expression_info["operations"] = [ + operation.replace(expression, expression_name) for operation in expression_info["operations"] + ] + + if assignment is not None: + expression_info["assignment"] = assignment + + expression_info["operations"] = [ + operation.replace("assignment", expression_info["assignment"]) + for operation in expression_info["operations"] + ] + + # Create clc file + file_name = self.create_expression_file(expression_info["name"], expression_info["operations"]) + + # Import clc + self.ofieldsreporter.LoadNamedExpressions( + os.path.abspath(file_name), expression_info["fields_type"][design_type_index], [name] + ) + + return expression_info["name"] + + @pyaedt_function_handler() + def create_expression_file(self, name, operations): + """Create a calculator expression file. + + Parameters + ---------- + name : str + Name of the expression. + operations : list + List of operations in the calculator. + + Returns + ------- + str, bool + Path of the calculator expression file when successful, ``False`` when failed. + """ + file_name = generate_unique_project_name( + root_name=self.__app.toolkit_directory, + folder_name=self.__app.design_name, + project_name=name, + project_format="clc", + ) + try: + with open_file(file_name, "w") as file: + file.write("$begin 'Named_Expression'\n") + file.write(f" Name('{name}')\n") + for operation in operations: + file.write(f" {operation}\n") + file.write("$end 'Named_Expression'\n") + except Exception: # pragma: no cover + return False + return os.path.abspath(file_name) + + @pyaedt_function_handler() + def expression_plot(self, calculation, assignment, names, setup=None): + """Add a named expression. + + Parameters + ---------- + calculation : str + Calculation type. + assignment : list + List of assignments to apply the expression to. If the expression is not general, assignment is not needed. + names : list + Name of the expressions to plot. + setup : str + Analysis setup. + + Returns + ------- + list + List of created reports. + """ + if assignment is not None: + assignment = self.__app.modeler.convert_to_selections(assignment, return_list=True) + + for name in names: + if not self.is_expression_defined(name): + self.__app.logger.error("Named expression not available.") + return False + + if calculation not in self.expression_names: + self.__app.logger.error("Calculation is not available.") + return False + + if not setup: + setup = self.__app.existing_analysis_sweeps[0] + + expression_info = self.expression_catalog[calculation] + fields_type = expression_info["fields_type"] + primary_sweep = expression_info["primary_sweep"] + + reports = [] + + for report_type in expression_info["report"]: # pragma: no cover + if report_type in ["Data Table", "Rectangular Plot"]: + assignment_report = assignment + primary_sweep_report = primary_sweep + if self.is_general_expression(calculation): + # General expression to calculate the field over the polyline distance + primary_sweep_report = "Distance" + else: + # Non-general expression does not need assignment + assignment_report = [None] + + if None in assignment_report or ( + not self.__has_integer(assignment_report) and self.__has_lines(assignment_report) + ): + for assign in assignment_report: + if "CG Fields" in fields_type and self.design_type == "Q3D Extractor": + report = self.__app.post.reports_by_category.cg_fields(names, setup, polyline=assign) + elif "DC R/L Fields" in fields_type and self.design_type == "Q3D Extractor": + report = self.__app.post.reports_by_category.dc_fields(names, setup, polyline=assign) + else: + report = self.__app.post.reports_by_category.fields(names, setup, polyline=assign) + report.report_type = report_type + report.primary_sweep = primary_sweep_report + report.create() + reports.append(report) + elif report_type in ["Field_3D"]: + intrinsic = {} + if self.design_type == "Q3D Extractor": + intrinsic = {"Freq": self.__app.setups[0].props["AdaptiveFreq"]} + for assign in assignment: + if isinstance(assign, int) or assign in self.__app.modeler.sheet_names: + report = self.__app.post.create_fieldplot_surface( + quantity=names[0], assignment=assign, field_type=fields_type, intrinsics=intrinsic + ) + reports.append(report) + else: + if assign not in self.__app.modeler.point_names and assign not in self.__app.modeler.line_names: + report = self.__app.post.create_fieldplot_volume( + quantity=names[0], assignment=assign, field_type=fields_type, intrinsics=intrinsic + ) + reports.append(report) + return reports + + @pyaedt_function_handler() + def delete_expression(self, name=None): + """Delete a named expression. + + Parameters + ---------- + name : str, optional + Name of the named expression. The default is ``None``, in which case all named expressions are deleted. + + Returns + ------- + bool + ``True`` when successful, ``False`` when failed. + """ + if not name: + self.ofieldsreporter.ClearAllNamedExpr() + return True + if self.is_expression_defined(name): + self.ofieldsreporter.DeleteNamedExpr(name) + return True + + @pyaedt_function_handler() + def is_expression_defined(self, name): + """Check if a named expression exists. + + Parameters + ---------- + name : str, + Named expression. + + Returns + ------- + bool + ``True`` when exists. + """ + is_defined = self.ofieldsreporter.DoesNamedExpressionExists(name) + if is_defined == 1: + return True + return False + + @pyaedt_function_handler() + def is_general_expression(self, name): + """Check if a named expression is general. + + Parameters + ---------- + name : str, + Named expression. + + Returns + ------- + bool + ``True`` if the named expression is general. + """ + if name not in self.expression_names: + self.__app.logger.error("Named expression not available.") + return False + is_general = True + for operation in self.expression_catalog[name]["operations"]: + if "assignment" in operation: + is_general = False + break + return is_general + + @pyaedt_function_handler() + def load_expression_file(self, input_file): + """Load expressions from a TOML file. + + Parameters + ---------- + input_file : str + Full path to the file. + + Returns + ------- + dict + Dictionary of available expressions. + """ + if not os.path.isfile(input_file): + self.__app.logger.error("File does not exist.") + return False + + new_expression_catalog = read_toml(input_file) + + if new_expression_catalog: + self.expression_catalog.update(new_expression_catalog) + + return self.expression_catalog + + @staticmethod + def __has_integer(lst): # pragma: no cover + """Check if a list has integers.""" + for item in lst: + if isinstance(item, int): + return True + return False + + def __has_lines(self, lst): # pragma: no cover + """Check if a list has lines.""" + for item in lst: + if item not in self.__app.modeler.line_names: + return False + return True diff --git a/pyaedt/modules/monitor_icepak.py b/pyaedt/modules/monitor_icepak.py index 4e3438d5b0d..aa6b933696b 100644 --- a/pyaedt/modules/monitor_icepak.py +++ b/pyaedt/modules/monitor_icepak.py @@ -1,3 +1,27 @@ +# -*- 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 re from pyaedt.generic.DataHandlers import _dict2arg diff --git a/pyaedt/modules/report_templates.py b/pyaedt/modules/report_templates.py index 17d20478ab6..52431ad2114 100644 --- a/pyaedt/modules/report_templates.py +++ b/pyaedt/modules/report_templates.py @@ -1,3 +1,27 @@ +# -*- 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 collections import OrderedDict import copy import os @@ -378,7 +402,7 @@ def differential_pairs(self, value): @property def matrix(self): - """2D or Q3D matrix name. + """Maxwell 2D/3D or Q2D/Q3D matrix name. Returns ------- @@ -391,6 +415,21 @@ def matrix(self): def matrix(self, value): self.props["context"]["matrix"] = value + @property + def reduced_matrix(self): + """Maxwell 2D/3D reduced matrix name for eddy current solvers. + + Returns + ------- + str + Reduced matrix name. + """ + return self.props["context"].get("reduced_matrix", None) + + @reduced_matrix.setter + def reduced_matrix(self, value): + self.props["context"]["reduced_matrix"] = value + @property def polyline(self): """Polyline name for the field report. @@ -2152,6 +2191,16 @@ def _context(self): ctxt = ["Context:=", "Original"] else: ctxt = ["Context:=", self.matrix] + elif ( + self._post._app.design_type in ["Maxwell 2D", "Maxwell 3D"] + and self._post._app.solution_type == "EddyCurrent" + ): + if not self.matrix: + ctxt = ["Context:=", "Original"] + elif not self.reduced_matrix: + ctxt = ["Context:=", self.matrix] + elif self.reduced_matrix: + ctxt = ["Context:=", self.matrix, "Matrix:=", self.reduced_matrix] elif self._post.post_solution_type in ["HFSS3DLayout"]: if self.domain == "DCIR": ctxt = [ @@ -2587,6 +2636,9 @@ def _context(self): "USE_PRI_DIST", False, "0" if not self.enable_jitter_distribution else "1", + "SID", + False, + "0", ] if self.enable_jitter_distribution and str(self.quantity_type) == "3": sim_context = [ @@ -2631,6 +2683,9 @@ def _context(self): "PID", False, "0", + "SID", + False, + "0", "PRIDIST", False, "0", @@ -2656,6 +2711,31 @@ def _context(self): "SimValueContext:=", sim_context, ] + if len(self.expressions) == 1: + sid = 0 + pid = 0 + expr = self.expressions[0] + category = "Eye" + found = False + while not found: + available_quantities = self._post.available_report_quantities( + self.report_category, self.report_type, self.setup, category, arg + ) + if len(available_quantities) == 1 and available_quantities[0].lower() == expr.lower(): + found = True + else: + sid += 1 + pid += 1 + arg[2][arg[2].index("SID") + 2] = str(sid) + arg[2][arg[2].index("PID") + 2] = str(pid) + # Limited maximum iterations to 1000 in While loop (Too many probes to analyze even in a single design) + if sid > 1000: + self._post.logger.error( + "Failed to find right context for expression : {}".format(",".join(self.expressions)) + ) + # arg[2][arg[2].index("SID") + 2] = "0" + # arg[2][arg[2].index("PID") + 2] = "0" + break return arg @property @@ -3178,8 +3258,43 @@ def _context(self): "QTID", False, str(self.quantity_type), + "SCID", + False, + "-1", + "SID", + False, + "0", ], ] + if len(self.expressions) == 1: + sid = 0 + pid = 0 + expr = self.expressions[0] + category = "Wave" + if self.report_category == "Statistical Eye": + category = "Eye" + if self.report_category == "Eye Diagram" and self.report_type == "Rectangular Plot": + category = "Voltage" + found = False + while not found: + available_quantities = self._post.available_report_quantities( + self.report_category, self.report_type, self.setup, category, arg + ) + if len(available_quantities) == 1 and available_quantities[0].lower() == expr.lower(): + found = True + else: + sid += 1 + pid += 1 + arg[2][arg[2].index("SID") + 2] = str(sid) + arg[2][arg[2].index("PID") + 2] = str(pid) + # Limited maximum iterations to 1000 in While loop (Too many probes to analyze even in a single design) + if sid > 1000: + self._post.logger.error( + "Failed to find right context for expression : {}".format(",".join(self.expressions)) + ) + # arg[2][arg[2].index("SID") + 2] = "0" + # arg[2][arg[2].index("PID") + 2] = "0" + break return arg @property diff --git a/pyaedt/modules/solutions.py b/pyaedt/modules/solutions.py index 7a41f7a6b18..76bcea79203 100644 --- a/pyaedt/modules/solutions.py +++ b/pyaedt/modules/solutions.py @@ -1,3 +1,27 @@ +# -*- 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 collections import OrderedDict import itertools import json @@ -8,17 +32,18 @@ import sys import time -from pyaedt import is_ironpython -from pyaedt import pyaedt_function_handler from pyaedt.application.Variables import decompose_variable_value from pyaedt.generic.constants import AEDT_UNITS +from pyaedt.generic.constants import CSS4_COLORS from pyaedt.generic.constants import db10 from pyaedt.generic.constants import db20 from pyaedt.generic.constants import unit_converter from pyaedt.generic.general_methods import check_and_download_file from pyaedt.generic.general_methods import check_and_download_folder from pyaedt.generic.general_methods import conversion_function +from pyaedt.generic.general_methods import is_ironpython from pyaedt.generic.general_methods import open_file +from pyaedt.generic.general_methods import pyaedt_function_handler from pyaedt.generic.general_methods import write_csv from pyaedt.generic.plot import get_structured_mesh from pyaedt.generic.plot import is_notebook @@ -27,6 +52,7 @@ from pyaedt.generic.plot import plot_polar_chart from pyaedt.generic.settings import settings from pyaedt.modeler.cad.elements3d import FacePrimitive +from pyaedt.modeler.geometry_operators import GeometryOperators np = None pd = None @@ -50,6 +76,368 @@ plt = None +@pyaedt_function_handler() +def _parse_nastran(file_path): + logger = logging.getLogger("Global") + nas_to_dict = {"Points": [], "PointsId": {}, "Assemblies": {}} + includes = [] + + def parse_lines(input_lines, input_pid=0, in_assembly="Main"): + if in_assembly not in nas_to_dict["Assemblies"]: + nas_to_dict["Assemblies"][in_assembly] = {"Triangles": {}, "Solids": {}, "Lines": {}} + + def get_point(ll, start, length): + n = ll[start : start + length].strip() + if "-" in n[1:] and "e" not in n[1:].lower(): + n = n[0] + n[1:].replace("-", "e-") + return n + + for lk in range(len(input_lines)): + line = input_lines[lk] + line_type = line[:8].strip() + obj_type = "Triangles" + if line.startswith("$") or line.startswith("*"): + continue + elif line_type in ["GRID", "GRID*"]: + num_points = 3 + obj_type = "Grid" + elif line_type in [ + "CTRIA3", + "CTRIA3*", + ]: + num_points = 3 + obj_type = "Triangles" + elif line_type in ["CROD", "CBEAM", "CBAR", "CROD*", "CBEAM*", "CBAR*"]: + num_points = 2 + obj_type = "Lines" + elif line_type in [ + "CQUAD4", + "CQUAD4*", + ]: + num_points = 4 + obj_type = "Triangles" + elif line_type in ["CTETRA", "CTETRA*"]: + num_points = 4 + obj_type = "Solids" + elif line_type in ["CPYRA", "CPYRAM", "CPYRA*", "CPYRAM*"]: + num_points = 5 + obj_type = "Solids" + else: + continue + + points = [] + start_pointer = 8 + word_length = 8 + if line_type.endswith("*"): + word_length = 16 + grid_id = int(line[start_pointer : start_pointer + word_length]) + pp = 0 + start_pointer = start_pointer + word_length + object_id = line[start_pointer : start_pointer + word_length] + if obj_type != "Grid": + object_id = int(object_id) + if object_id not in nas_to_dict["Assemblies"][in_assembly][obj_type]: + nas_to_dict["Assemblies"][in_assembly][obj_type][object_id] = [] + while pp < num_points: + start_pointer = start_pointer + word_length + if start_pointer >= 72: + lk += 1 + line = input_lines[lk] + start_pointer = 8 + points.append(get_point(line, start_pointer, word_length)) + pp += 1 + + if line_type in ["GRID", "GRID*"]: + nas_to_dict["PointsId"][grid_id] = input_pid + nas_to_dict["Points"].append([float(i) for i in points]) + input_pid += 1 + elif line_type in [ + "CTRIA3", + "CTRIA3*", + ]: + tri = [nas_to_dict["PointsId"][int(i)] for i in points] + nas_to_dict["Assemblies"][in_assembly]["Triangles"][object_id].append(tri) + elif line_type in ["CROD", "CBEAM", "CBAR", "CROD*", "CBEAM*", "CBAR*"]: + tri = [nas_to_dict["PointsId"][int(i)] for i in points] + nas_to_dict["Assemblies"][in_assembly]["Lines"][object_id].append(tri) + elif line_type in ["CQUAD4", "CQUAD4*"]: + tri = [ + nas_to_dict["PointsId"][int(points[0])], + nas_to_dict["PointsId"][int(points[1])], + nas_to_dict["PointsId"][int(points[2])], + ] + nas_to_dict["Assemblies"][in_assembly]["Triangles"][object_id].append(tri) + tri = [ + nas_to_dict["PointsId"][int(points[0])], + nas_to_dict["PointsId"][int(points[2])], + nas_to_dict["PointsId"][int(points[3])], + ] + nas_to_dict["Assemblies"][in_assembly]["Triangles"][object_id].append(tri) + else: + from itertools import combinations + + for k in list(combinations(points, 3)): + tri = [ + nas_to_dict["PointsId"][int(k[0])], + nas_to_dict["PointsId"][int(k[1])], + nas_to_dict["PointsId"][int(k[2])], + ] + tri.sort() + tri = tuple(tri) + nas_to_dict["Assemblies"][in_assembly]["Solids"][object_id].append(tri) + + return input_pid + + logger.info("Loading file") + with open_file(file_path, "r") as f: + lines = f.read().splitlines() + for line in lines: + if line.startswith("INCLUDE"): + includes.append(line.split(" ")[1].replace("'", "").strip()) + pid = parse_lines(lines) + for include in includes: + with open_file(os.path.join(os.path.dirname(file_path), include), "r") as f: + lines = f.read().splitlines() + name = include.split(".")[0] + pid = parse_lines(lines, pid, name) + logger.info("File loaded") + for assembly in list(nas_to_dict["Assemblies"].keys())[::]: + if ( + nas_to_dict["Assemblies"][assembly]["Triangles"] + == nas_to_dict["Assemblies"][assembly]["Solids"] + == nas_to_dict["Assemblies"][assembly]["Lines"] + == {} + ): + del nas_to_dict["Assemblies"][assembly] + for _, assembly_object in nas_to_dict["Assemblies"].items(): + + def domino(segments): + + def check_new_connection(s, polylines, exclude_index=-1): + s = s[:] + polylines = [poly[:] for poly in polylines] + attached = False + p_index = None + for i, p in enumerate(polylines): + if i == exclude_index: + continue + if s[0] == p[-1]: + p.extend(s[1:]) # the new segment attaches to the end + attached = True + elif s[-1] == p[0]: + for item in reversed(s[:-1]): + p.insert(0, item) # the new segment attaches to the beginning + attached = True + elif s[0] == p[0]: + for item in s[1:]: + p.insert(0, item) # the new segment attaches to the beginning in reverse order + attached = True + elif s[-1] == p[-1]: + p.extend(s[-2::-1]) # the new segment attaches to the end in reverse order + attached = True + if attached: + p_index = i + break + if not attached: + polylines.append(s) + return polylines, attached, p_index + + polylines = [] + for segment in segments: + polylines, attached_flag, attached_p_index = check_new_connection(segment, polylines) + if attached_flag: + other_polylines = polylines[:attached_p_index] + polylines[attached_p_index + 1 :] + polylines, _, _ = check_new_connection( + polylines[attached_p_index], other_polylines, attached_p_index + ) + + return polylines + + def remove_self_intersections(polylines): + polylines = [poly[:] for poly in polylines] + new_polylines = [] + for p in polylines: + if p[0] in p[1:]: + new_polylines.append([p[0], p[1]]) + p.pop(0) + if p[-1] in p[:-1]: + new_polylines.append([p[-2], p[-1]]) + p.pop(-1) + new_polylines.append(p) + return new_polylines + + if assembly_object["Lines"]: + for lname, lines in assembly_object["Lines"].items(): + new_lines = lines[::] + new_lines = remove_self_intersections(domino(new_lines)) + assembly_object["Lines"][lname] = new_lines + + return nas_to_dict + + +@pyaedt_function_handler() +def _write_stl(nas_to_dict, decimation, working_directory, enable_planar_merge=True): + logger = logging.getLogger("Global") + + def _write_solid_stl(triangle, pp): + try: + # points = [nas_to_dict["Points"][id] for id in triangle] + points = [pp[i] for i in triangle] + except KeyError: # pragma: no cover + return + fc = GeometryOperators.get_polygon_centroid(points) + v1 = points[0] + v2 = points[1] + cv1 = GeometryOperators.v_points(fc, v1) + cv2 = GeometryOperators.v_points(fc, v2) + if cv2[0] == cv1[0] == 0.0 and cv2[1] == cv1[1] == 0.0: + n = [0, 0, 1] # pragma: no cover + elif cv2[0] == cv1[0] == 0.0 and cv2[2] == cv1[2] == 0.0: + n = [0, 1, 0] # pragma: no cover + elif cv2[1] == cv1[1] == 0.0 and cv2[2] == cv1[2] == 0.0: + n = [1, 0, 0] # pragma: no cover + else: + n = GeometryOperators.v_cross(cv1, cv2) + + normal = GeometryOperators.normalize_vector(n) + if normal: + f.write(" facet normal {} {} {}\n".format(normal[0], normal[1], normal[2])) + f.write(" outer loop\n") + f.write(" vertex {} {} {}\n".format(points[0][0], points[0][1], points[0][2])) + f.write(" vertex {} {} {}\n".format(points[1][0], points[1][1], points[1][2])) + f.write(" vertex {} {} {}\n".format(points[2][0], points[2][1], points[2][2])) + f.write(" endloop\n") + f.write(" endfacet\n") + + logger.info("Creating STL file with detected faces") + enable_stl_merge = False if enable_planar_merge == "False" or enable_planar_merge is False else True + + def decimate(points_in, faces_in): + fin = [[3] + list(i) for i in faces_in] + mesh = pv.PolyData(points_in, faces=fin) + new_mesh = mesh.decimate_pro(decimation, preserve_topology=True, boundary_vertex_deletion=False) + points_out = list(new_mesh.points) + faces_out = [i[1:] for i in new_mesh.faces.reshape(-1, 4) if i[0] == 3] + return points_out, faces_out + + output_stls = [] + for assembly_name, assembly in nas_to_dict["Assemblies"].items(): + output_stl = os.path.join(working_directory, assembly_name + ".stl") + f = open(output_stl, "w") + for tri_id, triangles in assembly["Triangles"].items(): + tri_out = triangles + p_out = nas_to_dict["Points"][::] + if decimation > 0 and len(triangles) > 20: + p_out, tri_out = decimate(nas_to_dict["Points"], tri_out) + f.write("solid Sheet_{}\n".format(tri_id)) + if enable_planar_merge == "Auto" and len(tri_out) > 50000: + enable_stl_merge = False # pragma: no cover + for triangle in tri_out: + _write_solid_stl(triangle, p_out) + f.write("endsolid\n") + for solidid, solid_triangles in assembly["Solids"].items(): + f.write("solid Solid_{}\n".format(solidid)) + import pandas as pd + + df = pd.Series(solid_triangles) + tri_out = df.drop_duplicates(keep=False).to_list() + p_out = nas_to_dict["Points"][::] + if decimation > 0 and len(solid_triangles) > 20: + p_out, tri_out = decimate(nas_to_dict["Points"], tri_out) + if enable_planar_merge == "Auto" and len(tri_out) > 50000: + enable_stl_merge = False # pragma: no cover + for triangle in tri_out: + _write_solid_stl(triangle, p_out) + f.write("endsolid\n") + f.close() + output_stls.append(output_stl) + logger.info("STL file created") + return output_stls, enable_stl_merge + + +def nastran_to_stl(input_file, output_folder=None, decimation=0, enable_planar_merge="True", preview=False): + logger = logging.getLogger("Global") + nas_to_dict = _parse_nastran(input_file) + + empty = True + for assembly in nas_to_dict["Assemblies"].values(): + if assembly["Triangles"] or assembly["Solids"] or assembly["Lines"]: + empty = False + break + if empty: # pragma: no cover + logger.error("Failed to import file. Check the model and retry") + return False + if output_folder is None: + output_folder = os.path.dirname(input_file) + output_stls, enable_stl_merge = _write_stl(nas_to_dict, decimation, output_folder, enable_planar_merge) + if preview: + logger.info("Generating preview...") + if decimation > 0: + pl = pv.Plotter(shape=(1, 2)) + else: # pragma: no cover + pl = pv.Plotter() + dargs = dict(show_edges=True) + colors = [] + color_by_assembly = True + if len(nas_to_dict["Assemblies"]) == 1: + color_by_assembly = False + + def preview_pyvista(dict_in): + css4_colors = list(CSS4_COLORS.values()) + k = 0 + p_out = nas_to_dict["Points"][::] + for assembly in dict_in["Assemblies"].values(): + if color_by_assembly: + h = css4_colors[k].lstrip("#") + colors.append(tuple(int(h[i : i + 2], 16) for i in (0, 2, 4))) + k += 1 + + for triangles in assembly["Triangles"].values(): + tri_out = triangles + fin = [[3] + list(i) for i in tri_out] + if not color_by_assembly: + h = css4_colors[k].lstrip("#") + colors.append(tuple(int(h[i : i + 2], 16) for i in (0, 2, 4))) + k = k + 1 if k < len(css4_colors) - 1 else 0 + pl.add_mesh(pv.PolyData(p_out, faces=fin), color=colors[-1], **dargs) + + for triangles in assembly["Solids"].values(): + import pandas as pd + + df = pd.Series(triangles) + tri_out = df.drop_duplicates(keep=False).to_list() + p_out = nas_to_dict["Points"][::] + fin = [[3] + list(i) for i in tri_out] + if not color_by_assembly: + h = css4_colors[k].lstrip("#") + colors.append(tuple(int(h[i : i + 2], 16) for i in (0, 2, 4))) + k = k + 1 if k < len(css4_colors) - 1 else 0 + + pl.add_mesh(pv.PolyData(p_out, faces=fin), color=colors[-1], **dargs) + + preview_pyvista(nas_to_dict) + pl.add_text("Input mesh", font_size=24) + pl.reset_camera() + if decimation > 0 and output_stls: + k = 0 + pl.reset_camera() + pl.subplot(0, 1) + css4_colors = list(CSS4_COLORS.values()) + for output_stl in output_stls: + mesh = pv.read(output_stl) + h = css4_colors[k].lstrip("#") + colors.append(tuple(int(h[i : i + 2], 16) for i in (0, 2, 4))) + pl.add_mesh(mesh, color=colors[-1], **dargs) + k = k + 1 if k < len(css4_colors) - 1 else 0 + pl.add_text("Decimated mesh", font_size=24) + pl.reset_camera() + pl.link_views() + if "PYTEST_CURRENT_TEST" not in os.environ: + pl.show() # pragma: no cover + logger.info("STL files created") + return output_stls, nas_to_dict, enable_stl_merge + + def simplify_stl(input_file, output_file=None, decimation=0.5, preview=False): """Import and simplify a stl file using pyvista and fast-simplification. @@ -63,7 +451,8 @@ def simplify_stl(input_file, output_file=None, decimation=0.5, preview=False): Fraction of the original mesh to remove before creating the stl file. If set to ``0.9``, this function will try to reduce the data set to 10% of its original size and will remove 90% of the input triangles. - + preview : bool, optional + Whether to preview the model in pyvista or skip it. Returns ------- str @@ -843,6 +1232,8 @@ def plot( Full path to image file if a snapshot is needed. is_polar : bool, optional Set to `True` if this is a polar plot. + show : bool, optional + Whether if show the plot or not. Default is set to `True`. Returns ------- @@ -930,6 +1321,8 @@ def plot_3d( snapshot_path : str, optional Full path to image file if a snapshot is needed. The default is ``None``. + show : bool, optional + Whether if show the plot or not. Default is set to `True`. Returns ------- @@ -1165,7 +1558,7 @@ class FfdSolutionData(object): >>> import pyaedt >>> from pyaedt.modules.solutions import FfdSolutionData - >>> app = pyaedt.Hfss(specified_version="2023.2", designname="Antenna") + >>> app = pyaedt.Hfss(version="2023.2", design="Antenna") >>> setup_name = "Setup1 : LastAdaptive" >>> frequencies = [77e9] >>> sphere = "3D" @@ -1182,7 +1575,7 @@ def __init__( eep_files, frequencies, ): - self.logger = logging.getLogger(__name__) + self.logger = logging.getLogger("Global") self._raw_data = {} self.farfield_data = {} @@ -1640,7 +2033,7 @@ def plot_farfield_contour( Examples -------- >>> import pyaedt - >>> app = pyaedt.Hfss(specified_version="2024.1", designname="Antenna") + >>> app = pyaedt.Hfss(version="2024.1", design="Antenna") >>> setup_name = "Setup1 : LastAdaptive" >>> frequencies = [77e9] >>> sphere = "3D" @@ -1779,7 +2172,7 @@ def plot_2d_cut( Examples -------- >>> import pyaedt - >>> app = pyaedt.Hfss(specified_version="2023.2", designname="Antenna") + >>> app = pyaedt.Hfss(version="2023.2", design="Antenna") >>> setup_name = "Setup1 : LastAdaptive" >>> frequencies = [77e9] >>> sphere = "3D" @@ -1920,7 +2313,7 @@ def polar_plot_3d( Examples -------- >>> import pyaedt - >>> app = pyaedt.Hfss(specified_version="2023.2", designname="Antenna") + >>> app = pyaedt.Hfss(version="2023.2", design="Antenna") >>> setup_name = "Setup1 : LastAdaptive" >>> frequencies = [77e9] >>> sphere = "3D" @@ -2025,7 +2418,7 @@ def polar_plot_3d_pyvista( Examples -------- >>> import pyaedt - >>> app = pyaedt.Hfss(specified_version="2023.2", designname="Antenna") + >>> app = pyaedt.Hfss(version="2023.2", design="Antenna") >>> setup_name = "Setup1 : LastAdaptive" >>> frequencies = [77e9] >>> sphere = "3D" @@ -2543,7 +2936,7 @@ class FfdSolutionDataExporter(FfdSolutionData): Examples -------- >>> import pyaedt - >>> app = pyaedt.Hfss(specified_version="2023.2", designname="Antenna") + >>> app = pyaedt.Hfss(version="2023.2", design="Antenna") >>> setup_name = "Setup1 : LastAdaptive" >>> frequencies = [77e9] >>> sphere = "3D" @@ -2770,29 +3163,29 @@ class FieldPlot: def __init__( self, postprocessor, - objects=[], - surfaces=[], - lines=[], - cutplanes=[], + objects=None, + surfaces=None, + lines=None, + cutplanes=None, solution="", quantity="", - intrinsics={}, - seeding_faces=[], - layer_nets=[], + intrinsics=None, + seeding_faces=None, + layer_nets=None, layer_plot_type="LayerNetsExtFace", ): self._postprocessor = postprocessor self.oField = postprocessor.ofieldsreporter - self.volumes = objects - self.surfaces = surfaces - self.lines = lines - self.cutplanes = cutplanes - self.layer_nets = layer_nets + self.volumes = [] if objects is None else objects + self.surfaces = [] if surfaces is None else surfaces + self.lines = [] if lines is None else lines + self.cutplanes = [] if cutplanes is None else cutplanes + self.layer_nets = [] if layer_nets is None else layer_nets self.layer_plot_type = layer_plot_type - self.seeding_faces = seeding_faces + self.seeding_faces = [] if seeding_faces is None else seeding_faces self.solution = solution self.quantity = quantity - self.intrinsics = intrinsics + self.intrinsics = {} if intrinsics is None else intrinsics self.name = "Field_Plot" self.plot_folder = "Field_Plot" self.Filled = False @@ -2919,21 +3312,11 @@ def intrinsicVar(self): Returns ------- list or dict - List or dictionary of the variables for the field plot. + Variables for the field plot. """ var = "" - if isinstance(self.intrinsics, list): - l = 0 - while l < len(self.intrinsics): - val = self.intrinsics[l + 1] - if ":=" in self.intrinsics[l] and isinstance(self.intrinsics[l + 1], list): - val = self.intrinsics[l + 1][0] - ll = self.intrinsics[l].split(":=") - var += ll[0] + "='" + str(val) + "' " - l += 2 - else: - for a in self.intrinsics: - var += a + "='" + str(self.intrinsics[a]) + "' " + for a in self.intrinsics: + var += a + "='" + str(self.intrinsics[a]) + "' " return var @property @@ -3522,13 +3905,13 @@ def __init__( max_frequency="1GHz", ray_density=2, bounces=5, - intrinsics={}, + intrinsics=None, ): self.is_creeping_wave = is_creeping_wave self._postprocessor = postprocessor self._ofield = postprocessor.ofieldsreporter self.quantity = quantity - self.intrinsics = intrinsics + self.intrinsics = {} if intrinsics is None else intrinsics self.name = "Field_Plot" self.plot_folder = "Field_Plot" self.max_frequency = max_frequency @@ -3560,22 +3943,12 @@ def intrinsicVar(self): Returns ------- - list or dict - List or dictionary of the variables for the field plot. + str + Variables for the field plot. """ var = "" - if isinstance(self.intrinsics, list): - l = 0 - while l < len(self.intrinsics): - val = self.intrinsics[l + 1] - if ":=" in self.intrinsics[l] and isinstance(self.intrinsics[l + 1], list): - val = self.intrinsics[l + 1][0] - ll = self.intrinsics[l].split(":=") - var += ll[0] + "='" + str(val) + "' " - l += 2 - else: - for a in self.intrinsics: - var += a + "='" + str(self.intrinsics[a]) + "' " + for a in self.intrinsics: + var += a + "='" + str(self.intrinsics[a]) + "' " return var @pyaedt_function_handler() diff --git a/pyaedt/q3d.py b/pyaedt/q3d.py index 633c54e0b0f..7189af0c7e8 100644 --- a/pyaedt/q3d.py +++ b/pyaedt/q3d.py @@ -1,3 +1,27 @@ +# -*- 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. + """This module contains these classes: ``Q2d``, ``Q3d``, and ``QExtractor`.""" from __future__ import absolute_import # noreorder @@ -7,12 +31,12 @@ import re import warnings -from pyaedt import is_ironpython from pyaedt.application.Analysis3D import FieldAnalysis3D from pyaedt.application.Variables import decompose_variable_value from pyaedt.generic.constants import MATRIXOPERATIONSQ2D from pyaedt.generic.constants import MATRIXOPERATIONSQ3D from pyaedt.generic.general_methods import generate_unique_name +from pyaedt.generic.general_methods import is_ironpython from pyaedt.generic.general_methods import pyaedt_function_handler from pyaedt.generic.settings import settings from pyaedt.modeler.geometry_operators import GeometryOperators as go @@ -50,34 +74,36 @@ def design_file(self): def __init__( self, Q3DType, - projectname=None, - designname=None, + project=None, + design=None, solution_type=None, setup_name=None, - specified_version=None, + version=None, non_graphical=False, - new_desktop_session=False, + new_desktop=False, close_on_exit=False, student_version=False, machine="", port=0, aedt_process_id=None, + remove_lock=False, ): FieldAnalysis3D.__init__( self, Q3DType, - projectname, - designname, + project, + design, solution_type, setup_name, - specified_version, + version, non_graphical, - new_desktop_session, + new_desktop, close_on_exit, student_version, machine, port, aedt_process_id, + remove_lock=remove_lock, ) self.matrices = [] for el in list(self.omatrix.ListReduceMatrixes()): @@ -1204,23 +1230,23 @@ class Q3d(QExtractor, object): Parameters ---------- - projectname : str, optional + project : str, optional Name of the project to select or the full path to the project or AEDTZ archive to open. The default is ``None``, in which case an attempt is made to get an active project. If no projects are present, an empty project is created. - designname : str, optional + design : str, optional Name of the design to select. The default is ``None``, in which case an attempt is made to get an active design. If no designs are present, an empty design is created. solution_type : str, optional Solution type to apply to the design. The default is ``None``, in which case the default type is applied. - setup_name : str, optional + setup : str, optional Name of the setup to use as the nominal. The default is ``None``, in which case the active setup is used or nothing is used. - specified_version : str, int, float, optional + version : str, int, float, optional Version of AEDT to use. The default is ``None``, in which case the active version or latest installed version is used. This parameter is ignored when Script is launched within AEDT. @@ -1229,7 +1255,7 @@ class Q3d(QExtractor, object): Whether to launch AEDT in non-graphical mode. The default is ``False``, in which case AEDT is launched in graphical mode. This parameter is ignored when a script is launched within AEDT. - new_desktop_session : bool, optional + new_desktop : bool, optional Whether to launch an instance of AEDT in a new thread, even if another instance of the ``specified_version`` is active on the machine. The default is ``False``. This parameter is ignored when @@ -1251,7 +1277,11 @@ class Q3d(QExtractor, object): running with the command `"ansysedt.exe -grpcsrv portnum"`. aedt_process_id : int, optional Process ID for the instance of AEDT to point PyAEDT at. The default is - ``None``. This parameter is only used when ``new_desktop_session = False``. + ``None``. This parameter is only used when ``new_desktop = False``. + remove_lock : bool, optional + Whether to remove lock to project before opening it or not. + The default is ``False``, which means to not unlock + the existing project if needed and raise an exception. Examples -------- @@ -1263,36 +1293,45 @@ class Q3d(QExtractor, object): """ + @pyaedt_function_handler( + designname="design", + projectname="project", + specified_version="version", + setup_name="setup", + new_desktop_session="new_desktop", + ) def __init__( self, - projectname=None, - designname=None, + project=None, + design=None, solution_type=None, - setup_name=None, - specified_version=None, + setup=None, + version=None, non_graphical=False, - new_desktop_session=False, + new_desktop=False, close_on_exit=False, student_version=False, machine="", port=0, aedt_process_id=None, + remove_lock=False, ): QExtractor.__init__( self, "Q3D Extractor", - projectname, - designname, + project, + design, solution_type, - setup_name, - specified_version, + setup, + version, non_graphical, - new_desktop_session, + new_desktop, close_on_exit, student_version, machine, port, aedt_process_id, + remove_lock=remove_lock, ) self.MATRIXOPERATIONS = MATRIXOPERATIONSQ3D() @@ -2041,23 +2080,23 @@ class Q2d(QExtractor, object): Parameters ---------- - projectname : str, optional + project : str, optional Name of the project to select or the full path to the project or AEDTZ archive to open. The default is ``None``, in which case an attempt is made to get an active project. If no projects are present, an empty project is created. - designname : str, optional + design : str, optional Name of the design to select. The default is ``None``, in which case an attempt is made to get an active design. If no designs are present, an empty design is created. solution_type : str, optional Solution type to apply to the design. The default is ``None``, in which case the default type is applied. - setup_name : str, optional + setup : str, optional Name of the setup to use as the nominal. The default is ``None``, in which case the active setup is used or nothing is used. - specified_version : str, int, float, optional + version : str, int, float, optional Version of AEDT to use. The default is ``None``, in which case the active version or latest installed version is used. This parameter is ignored when a script is launched within AEDT. @@ -2066,7 +2105,7 @@ class Q2d(QExtractor, object): Whether to launch AEDT in non-graphical mode. The default is ``False``, in which case AEDT is launched in graphical mode. This parameter is ignored when a script is launched within AEDT. - new_desktop_session : bool, optional + new_desktop : bool, optional Whether to launch an instance of AEDT in a new thread, even if another instance of the ``specified_version`` is active on the machine. The default is ``False``. This parameter is ignored @@ -2087,7 +2126,11 @@ class Q2d(QExtractor, object): The remote server must be up and running with the command `"ansysedt.exe -grpcsrv portnum"`. aedt_process_id : int, optional Process ID for the instance of AEDT to point PyAEDT at. The default is - ``None``. This parameter is only used when ``new_desktop_session = False``. + ``None``. This parameter is only used when ``new_desktop = False``. + remove_lock : bool, optional + Whether to remove lock to project before opening it or not. + The default is ``False``, which means to not unlock + the existing project if needed and raise an exception. Examples -------- @@ -2115,36 +2158,45 @@ def dim(self): """Dimension.""" return self.modeler.dimension + @pyaedt_function_handler( + designname="design", + projectname="project", + specified_version="version", + setup_name="setup", + new_desktop_session="new_desktop", + ) def __init__( self, - projectname=None, - designname=None, + project=None, + design=None, solution_type=None, - setup_name=None, - specified_version=None, + setup=None, + version=None, non_graphical=False, - new_desktop_session=False, + new_desktop=False, close_on_exit=False, student_version=False, machine="", port=0, aedt_process_id=None, + remove_lock=False, ): QExtractor.__init__( self, "2D Extractor", - projectname, - designname, + project, + design, solution_type, - setup_name, - specified_version, + setup, + version, non_graphical, - new_desktop_session, + new_desktop, close_on_exit, student_version, machine, port, aedt_process_id, + remove_lock=remove_lock, ) self.MATRIXOPERATIONS = MATRIXOPERATIONSQ2D() diff --git a/pyaedt/rmxprt.py b/pyaedt/rmxprt.py index 3ed62c4855b..3b7582437ef 100644 --- a/pyaedt/rmxprt.py +++ b/pyaedt/rmxprt.py @@ -1,3 +1,27 @@ +# -*- 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. + """This module contains these classes: ``RMXprtModule`` and ``Rmxprt``.""" from __future__ import absolute_import # noreorder @@ -125,12 +149,12 @@ class Rmxprt(FieldAnalysisRMxprt): Parameters ---------- - projectname : str, optional + project : str, optional Name of the project to select or the full path to the project or AEDTZ archive to open. The default is ``None``, in which case an attempt is made to get an active project. If no projects are present, an empty project is created. - designname : str, optional + design : str, optional Name of the design to select. The default is ``None``, in which case an attempt is made to get an active design. If no designs are present, an empty design is created. @@ -139,11 +163,11 @@ class Rmxprt(FieldAnalysisRMxprt): ``None``, in which case the default type is applied. model_units : str, optional Model units. - setup_name : str, optional + setup : str, optional Name of the setup to use as the nominal. The default is ``None``, in which case the active setup is used or nothing is used. - specified_version : str, int, float, optional + version : str, int, float, optional Version of AEDT to use. The default is ``None``, in which case the active setup is used or the latest installed version is used. @@ -152,7 +176,7 @@ class Rmxprt(FieldAnalysisRMxprt): Whether to launch AEDT in non-graphical mode. The default is ``False``, in which case AEDT is launched in graphical mode. This parameter is ignored when a script is launched within AEDT. - new_desktop_session : bool, optional + new_desktop : bool, optional Whether to launch an instance of AEDT in a new thread, even if another instance of the ``specified_version`` is active on the machine. The default is ``False``. @@ -171,7 +195,11 @@ class Rmxprt(FieldAnalysisRMxprt): The remote server must be up and running with the command `"ansysedt.exe -grpcsrv portnum"`. aedt_process_id : int, optional Process ID for the instance of AEDT to point PyAEDT at. The default is - ``None``. This parameter is only used when ``new_desktop_session = False``. + ``None``. This parameter is only used when ``new_desktop = False``. + remove_lock : bool, optional + Whether to remove lock to project before opening it or not. + The default is ``False``, which means to not unlock + the existing project if needed and raise an exception. Examples -------- @@ -198,37 +226,46 @@ class Rmxprt(FieldAnalysisRMxprt): >>> app = Rmxprt("myfile.aedt") """ + @pyaedt_function_handler( + designname="design", + projectname="project", + specified_version="version", + setup_name="setup", + new_desktop_session="new_desktop", + ) def __init__( self, - projectname=None, - designname=None, + project=None, + design=None, solution_type=None, model_units=None, - setup_name=None, - specified_version=None, + setup=None, + version=None, non_graphical=False, - new_desktop_session=False, + new_desktop=False, close_on_exit=False, student_version=False, machine="", port=0, aedt_process_id=None, + remove_lock=False, ): FieldAnalysisRMxprt.__init__( self, "RMxprtSolution", - projectname, - designname, + project, + design, solution_type, - setup_name, - specified_version, + setup, + version, non_graphical, - new_desktop_session, + new_desktop, close_on_exit, student_version, machine, port, aedt_process_id, + remove_lock=remove_lock, ) if not model_units or model_units == "mm": model_units = "mm" diff --git a/pyaedt/rpc/rpyc_services.py b/pyaedt/rpc/rpyc_services.py index 015fc8c6154..8ce026642bd 100644 --- a/pyaedt/rpc/rpyc_services.py +++ b/pyaedt/rpc/rpyc_services.py @@ -11,14 +11,15 @@ from pyaedt import generate_unique_name from pyaedt.generic.general_methods import env_path -from pyaedt import is_ironpython -from pyaedt import is_linux +from pyaedt.generic.general_methods import is_ironpython +from pyaedt.generic.settings import is_linux from pyaedt import is_windows +from pyaedt.misc.misc import is_safe_path if is_linux and is_ironpython: - import subprocessdotnet as subprocess + import subprocessdotnet as subprocess # nosec else: - import subprocess + import subprocess # nosec if not is_ironpython: import rpyc @@ -270,24 +271,37 @@ def exposed_run_script(self, script, aedt_version="2021.2", ansysem_path=None, n elif os.path.exists(script): script_file = script else: - return "File wrong or wrong commands." + return "Wrong file or wrong commands." + if not is_safe_path(script_file): + return "Script file {} not safe.".format(script_file) executable = "ansysedt.exe" if is_linux and not ansysem_path and not env_path(aedt_version): ansysem_path = os.getenv("PYAEDT_SERVER_AEDT_PATH", "") if env_path(aedt_version) or ansysem_path: if not ansysem_path: ansysem_path = env_path(aedt_version) - - ng_feature = " -features=SF159726_SCRIPTOBJECT" + exe_path = os.path.join(ansysem_path, executable) + if not is_safe_path(exe_path): + return "Ansys EM path not safe." + command = [exe_path] + if non_graphical: + command.append("-ng") + ng_feature = "-features=SF159726_SCRIPTOBJECT" if self._beta_options: for opt in range(self._beta_options.__len__()): if self._beta_options[opt] not in ng_feature: ng_feature += "," + self._beta_options[opt] if non_graphical: - ng_feature += ",SF6694_NON_GRAPHICAL_COMMAND_EXECUTION -ng" - command = os.path.join(ansysem_path, executable) + ng_feature + " -RunScriptAndExit " + script_file - p = subprocess.Popen(command) - p.wait() + ng_feature += ",SF6694_NON_GRAPHICAL_COMMAND_EXECUTION" + command.append(ng_feature) + command = [exe_path, ng_feature, "-RunScriptAndExit", script_file] + try: + p = subprocess.Popen(command) # nosec + p.wait() + except subprocess.CalledProcessError as e: + msg = "Command failed with error: {}".format(e) + logger.error(msg) + return msg return "Script Executed." else: @@ -336,34 +350,34 @@ def exposed_edb( def exposed_hfss( self, - projectname=None, - designname=None, + project=None, + design=None, solution_type=None, - setup_name=None, - specified_version=None, + setup=None, + version=None, non_graphical=True, ): """Starts a new Hfss session. Parameters ---------- - projectname : str, optional + project : str, optional Name of the project to select or the full path to the project or AEDTZ archive to open. The default is ``None``, in which case an attempt is made to get an active project. If no projects are present, an empty project is created. - designname : str, optional + design : str, optional Name of the design to select. The default is ``None``, in which case an attempt is made to get an active design. If no designs are present, an empty design is created. solution_type : str, optional Solution type to apply to the design. The default is ``None``, in which case the default type is applied. - setup_name : str, optional + setup : str, optional Name of the setup to use as the nominal. The default is ``None``, in which case the active setup is used or nothing is used. - specified_version : str, int, float, optional + version : str, int, float, optional Version of AEDT to use. The default is ``None``, in which case the active version or latest installed version is used. non_graphical : bool, optional @@ -376,13 +390,13 @@ def exposed_hfss( """ self._beta() aedtapp = Hfss( - projectname=projectname, - designname=designname, + project=project, + design=design, solution_type=solution_type, - setup_name=setup_name, - specified_version=specified_version, + setup=setup, + version=version, non_graphical=non_graphical, - new_desktop_session=True, + new_desktop=True, close_on_exit=True, student_version=False, ) @@ -391,34 +405,34 @@ def exposed_hfss( def exposed_hfss3dlayout( self, - projectname=None, - designname=None, + project=None, + design=None, solution_type=None, - setup_name=None, - specified_version=None, + setup=None, + version=None, non_graphical=True, ): """Starts a new Hfss3dLayout session. Parameters ---------- - projectname : str, optional + project : str, optional Name of the project to select or the full path to the project or AEDTZ archive to open. The default is ``None``, in which case an attempt is made to get an active project. If no projects are present, an empty project is created. - designname : str, optional + design : str, optional Name of the design to select. The default is ``None``, in which case an attempt is made to get an active design. If no designs are present, an empty design is created. solution_type : str, optional Solution type to apply to the design. The default is ``None``, in which case the default type is applied. - setup_name : str, optional + setup : str, optional Name of the setup to use as the nominal. The default is ``None``, in which case the active setup is used or nothing is used. - specified_version : str, int, float, optional + version : str, int, float, optional Version of AEDT to use. The default is ``None``, in which case the active version or latest installed version is used. non_graphical : bool, optional @@ -431,13 +445,13 @@ def exposed_hfss3dlayout( """ self._beta() aedtapp = Hfss3dLayout( - projectname=projectname, - designname=designname, + project=project, + design=design, solution_type=solution_type, - setup_name=setup_name, - specified_version=specified_version, + setup=setup, + version=version, non_graphical=non_graphical, - new_desktop_session=True, + new_desktop=True, close_on_exit=True, student_version=False, ) @@ -446,34 +460,34 @@ def exposed_hfss3dlayout( def exposed_maxwell3d( self, - projectname=None, - designname=None, + project=None, + design=None, solution_type=None, - setup_name=None, - specified_version=None, + setup=None, + version=None, non_graphical=True, ): """Starts a new Maxwell3d session. Parameters ---------- - projectname : str, optional + project : str, optional Name of the project to select or the full path to the project or AEDTZ archive to open. The default is ``None``, in which case an attempt is made to get an active project. If no projects are present, an empty project is created. - designname : str, optional + design : str, optional Name of the design to select. The default is ``None``, in which case an attempt is made to get an active design. If no designs are present, an empty design is created. solution_type : str, optional Solution type to apply to the design. The default is ``None``, in which case the default type is applied. - setup_name : str, optional + setup : str, optional Name of the setup to use as the nominal. The default is ``None``, in which case the active setup is used or nothing is used. - specified_version : str, int, float, optional + version : str, int, float, optional Version of AEDT to use. The default is ``None``, in which case the active version or latest installed version is used. non_graphical : bool, optional @@ -486,13 +500,13 @@ def exposed_maxwell3d( """ self._beta() aedtapp = Maxwell3d( - projectname=projectname, - designname=designname, + project=project, + design=design, solution_type=solution_type, - setup_name=setup_name, - specified_version=specified_version, + setup=setup, + version=version, non_graphical=non_graphical, - new_desktop_session=True, + new_desktop=True, close_on_exit=True, student_version=False, ) @@ -501,34 +515,34 @@ def exposed_maxwell3d( def exposed_maxwell2d( self, - projectname=None, - designname=None, + project=None, + design=None, solution_type=None, - setup_name=None, - specified_version=None, + setup=None, + version=None, non_graphical=True, ): """Starts a new Maxwell32 session. Parameters ---------- - projectname : str, optional + project : str, optional Name of the project to select or the full path to the project or AEDTZ archive to open. The default is ``None``, in which case an attempt is made to get an active project. If no projects are present, an empty project is created. - designname : str, optional + design : str, optional Name of the design to select. The default is ``None``, in which case an attempt is made to get an active design. If no designs are present, an empty design is created. solution_type : str, optional Solution type to apply to the design. The default is ``None``, in which case the default type is applied. - setup_name : str, optional + setup : str, optional Name of the setup to use as the nominal. The default is ``None``, in which case the active setup is used or nothing is used. - specified_version : str, int, float, optional + version : str, int, float, optional Version of AEDT to use. The default is ``None``, in which case the active version or latest installed version is used. non_graphical : bool, optional @@ -541,13 +555,13 @@ def exposed_maxwell2d( """ self._beta() aedtapp = Maxwell2d( - projectname=projectname, - designname=designname, + project=project, + design=design, solution_type=solution_type, - setup_name=setup_name, - specified_version=specified_version, + setup=setup, + version=version, non_graphical=non_graphical, - new_desktop_session=True, + new_desktop=True, close_on_exit=True, student_version=False, ) @@ -556,34 +570,34 @@ def exposed_maxwell2d( def exposed_icepak( self, - projectname=None, - designname=None, + project=None, + design=None, solution_type=None, - setup_name=None, - specified_version=None, + setup=None, + version=None, non_graphical=True, ): """Starts a new Icepak session. Parameters ---------- - projectname : str, optional + project : str, optional Name of the project to select or the full path to the project or AEDTZ archive to open. The default is ``None``, in which case an attempt is made to get an active project. If no projects are present, an empty project is created. - designname : str, optional + design : str, optional Name of the design to select. The default is ``None``, in which case an attempt is made to get an active design. If no designs are present, an empty design is created. solution_type : str, optional Solution type to apply to the design. The default is ``None``, in which case the default type is applied. - setup_name : str, optional + setup : str, optional Name of the setup to use as the nominal. The default is ``None``, in which case the active setup is used or nothing is used. - specified_version : str, int, float, optional + version : str, int, float, optional Version of AEDT to use. The default is ``None``, in which case the active version or latest installed version is used. non_graphical : bool, optional @@ -596,13 +610,13 @@ def exposed_icepak( """ self._beta() aedtapp = Icepak( - projectname=projectname, - designname=designname, + project=project, + design=design, solution_type=solution_type, - setup_name=setup_name, - specified_version=specified_version, + setup=setup, + version=version, non_graphical=non_graphical, - new_desktop_session=True, + new_desktop=True, close_on_exit=True, student_version=False, ) @@ -611,34 +625,34 @@ def exposed_icepak( def exposed_circuit( self, - projectname=None, - designname=None, + project=None, + design=None, solution_type=None, - setup_name=None, - specified_version=None, + setup=None, + version=None, non_graphical=True, ): """Starts a new Circuit session. Parameters ---------- - projectname : str, optional + project : str, optional Name of the project to select or the full path to the project or AEDTZ archive to open. The default is ``None``, in which case an attempt is made to get an active project. If no projects are present, an empty project is created. - designname : str, optional + design : str, optional Name of the design to select. The default is ``None``, in which case an attempt is made to get an active design. If no designs are present, an empty design is created. solution_type : str, optional Solution type to apply to the design. The default is ``None``, in which case the default type is applied. - setup_name : str, optional + setup : str, optional Name of the setup to use as the nominal. The default is ``None``, in which case the active setup is used or nothing is used. - specified_version : str, int, float, optional + version : str, int, float, optional Version of AEDT to use. The default is ``None``, in which case the active version or latest installed version is used. non_graphical : bool, optional @@ -651,13 +665,13 @@ def exposed_circuit( """ self._beta() aedtapp = Circuit( - projectname=projectname, - designname=designname, + project=project, + design=design, solution_type=solution_type, - setup_name=setup_name, - specified_version=specified_version, + setup=setup, + version=version, non_graphical=non_graphical, - new_desktop_session=True, + new_desktop=True, close_on_exit=True, student_version=False, ) @@ -666,34 +680,34 @@ def exposed_circuit( def exposed_mechanical( self, - projectname=None, - designname=None, + project=None, + design=None, solution_type=None, - setup_name=None, - specified_version=None, + setup=None, + version=None, non_graphical=True, ): """Starts a new Mechanical session. Parameters ---------- - projectname : str, optional + project : str, optional Name of the project to select or the full path to the project or AEDTZ archive to open. The default is ``None``, in which case an attempt is made to get an active project. If no projects are present, an empty project is created. - designname : str, optional + design : str, optional Name of the design to select. The default is ``None``, in which case an attempt is made to get an active design. If no designs are present, an empty design is created. solution_type : str, optional Solution type to apply to the design. The default is ``None``, in which case the default type is applied. - setup_name : str, optional + setup : str, optional Name of the setup to use as the nominal. The default is ``None``, in which case the active setup is used or nothing is used. - specified_version : str, int, float, optional + version : str, int, float, optional Version of AEDT to use. The default is ``None``, in which case the active version or latest installed version is used. non_graphical : bool, optional @@ -706,13 +720,13 @@ def exposed_mechanical( """ self._beta() aedtapp = Mechanical( - projectname=projectname, - designname=designname, + project=project, + design=design, solution_type=solution_type, - setup_name=setup_name, - specified_version=specified_version, + setup=setup, + version=version, non_graphical=non_graphical, - new_desktop_session=True, + new_desktop=True, close_on_exit=True, student_version=False, ) @@ -721,34 +735,34 @@ def exposed_mechanical( def exposed_q3d( self, - projectname=None, - designname=None, + project=None, + design=None, solution_type=None, - setup_name=None, - specified_version=None, + setup=None, + version=None, non_graphical=True, ): """Starts a new Q3d session. Parameters ---------- - projectname : str, optional + project : str, optional Name of the project to select or the full path to the project or AEDTZ archive to open. The default is ``None``, in which case an attempt is made to get an active project. If no projects are present, an empty project is created. - designname : str, optional + design : str, optional Name of the design to select. The default is ``None``, in which case an attempt is made to get an active design. If no designs are present, an empty design is created. solution_type : str, optional Solution type to apply to the design. The default is ``None``, in which case the default type is applied. - setup_name : str, optional + setup : str, optional Name of the setup to use as the nominal. The default is ``None``, in which case the active setup is used or nothing is used. - specified_version : str, int, float, optional + version : str, int, float, optional Version of AEDT to use. The default is ``None``, in which case the active version or latest installed version is used. non_graphical : bool, optional @@ -761,13 +775,13 @@ def exposed_q3d( """ self._beta() aedtapp = Q3d( - projectname=projectname, - designname=designname, + project=project, + design=design, solution_type=solution_type, - setup_name=setup_name, - specified_version=specified_version, + setup=setup, + version=version, non_graphical=non_graphical, - new_desktop_session=True, + new_desktop=True, close_on_exit=True, student_version=False, ) @@ -776,34 +790,34 @@ def exposed_q3d( def exposed_q2d( self, - projectname=None, - designname=None, + project=None, + design=None, solution_type=None, - setup_name=None, - specified_version=None, + setup=None, + version=None, non_graphical=True, ): """Starts a new Q2d session. Parameters ---------- - projectname : str, optional + project : str, optional Name of the project to select or the full path to the project or AEDTZ archive to open. The default is ``None``, in which case an attempt is made to get an active project. If no projects are present, an empty project is created. - designname : str, optional + design : str, optional Name of the design to select. The default is ``None``, in which case an attempt is made to get an active design. If no designs are present, an empty design is created. solution_type : str, optional Solution type to apply to the design. The default is ``None``, in which case the default type is applied. - setup_name : str, optional + setup : str, optional Name of the setup to use as the nominal. The default is ``None``, in which case the active setup is used or nothing is used. - specified_version : str, int, float, optional + version : str, int, float, optional Version of AEDT to use. The default is ``None``, in which case the active version or latest installed version is used. non_graphical : bool, optional @@ -816,13 +830,13 @@ def exposed_q2d( """ self._beta() aedtapp = Q2d( - projectname=projectname, - designname=designname, + project=project, + design=design, solution_type=solution_type, - setup_name=setup_name, - specified_version=specified_version, + setup=setup, + version=version, non_graphical=non_graphical, - new_desktop_session=True, + new_desktop=True, close_on_exit=True, student_version=False, ) @@ -871,7 +885,13 @@ def aedt_grpc(port=None, beta_options=None, use_aedt_relative_path=False, non_gr from pyaedt.generic.general_methods import grpc_active_sessions sessions = grpc_active_sessions() if not port: - port = check_port(random.randint(18500, 20000)) + # TODO: Remove once IronPython is deprecated + if is_ironpython: + port = check_port(random.randint(18500, 20000)) # nosec + else: + import secrets + secure_random = secrets.SystemRandom() + port = check_port(secure_random.randint(18500, 20000)) if port == 0: print("Error. No ports are available.") @@ -1097,7 +1117,7 @@ def on_disconnect(self, connection): try: edb.close_edb() except Exception: - pass + logger.warning("Error when trying to close EDB.") def start_service(self, port): """Connect to remove service manager and run a new server on specified port. @@ -1157,5 +1177,11 @@ def exposed_stop_service(self, port): @staticmethod def exposed_check_port(): - port_number = random.randint(18500, 20000) - return check_port(port_number) + # TODO: Remove once IronPython is deprecated + if is_ironpython: # nosec + port = check_port(random.randint(18500, 20000)) # nosec + else: + import secrets + secure_random = secrets.SystemRandom() + port = check_port(secure_random.randint(18500, 20000)) + return port diff --git a/pyaedt/sbrplus/__init__.py b/pyaedt/sbrplus/__init__.py index e69de29bb2d..9c4476773da 100644 --- a/pyaedt/sbrplus/__init__.py +++ b/pyaedt/sbrplus/__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/pyaedt/sbrplus/hdm_parser.py b/pyaedt/sbrplus/hdm_parser.py index 444ea9b7054..5fe3bec0cc9 100644 --- a/pyaedt/sbrplus/hdm_parser.py +++ b/pyaedt/sbrplus/hdm_parser.py @@ -1,3 +1,28 @@ +# -*- 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 ast import struct import warnings @@ -14,6 +39,8 @@ "Install with \n\npip install numpy\n\nRequires CPython." ) +from pyaedt.aedt_logger import pyaedt_logger + class Parser: """ @@ -37,7 +64,13 @@ def __init__(self, filename): header, binarycontent = binarycontent.split(b"#header end\n") header = header.decode().splitlines()[1:] header = [line for line in header if not line.startswith("#")] - self.header = eval(" ".join(header)) + header = "".join(header) + try: + self.header = ast.literal_eval(header) + except (ValueError, SyntaxError) as e: + pyaedt_logger.error("Header of file '{}' is not a valid dictionary.".format(filename)) + raise e + self._read_header() self.binarycontent = binarycontent @@ -90,7 +123,8 @@ def _parse_list(self, type=None, base=None, size=1): and converted to a NumPy array. A list is converted to a Python list. Only simple base types can be interpreted as a NumPy array. """ - assert base != None + if base is None: # pragma: no cover + pyaedt_logger.warning("Invalid input provided when parsing for vector or list.") res = [] bt = self.parser_types[base] @@ -107,7 +141,7 @@ def _parse_list(self, type=None, base=None, size=1): if type == "vector": res = np.array(res) else: - res = [self._parse(base) for iel in range(size)] + res = [self._parse(base) for _ in range(size)] if len(res) == 1: return res[0] diff --git a/pyaedt/sbrplus/hdm_utils.py b/pyaedt/sbrplus/hdm_utils.py index 2a2934486af..3de0ba527c5 100644 --- a/pyaedt/sbrplus/hdm_utils.py +++ b/pyaedt/sbrplus/hdm_utils.py @@ -1,3 +1,28 @@ +# -*- 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. + + def sort_bundle(bundle, monoPW_attrib="sweep_angle_index"): """ In-place sorting utility for hdm ray exports. diff --git a/pyaedt/sbrplus/plot.py b/pyaedt/sbrplus/plot.py index 9fae5a4b4c3..87675122497 100644 --- a/pyaedt/sbrplus/plot.py +++ b/pyaedt/sbrplus/plot.py @@ -1,3 +1,27 @@ +# -*- 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 collections import defaultdict import math import os @@ -6,8 +30,8 @@ import numpy as np import pyvista as pv -from pyaedt import pyaedt_function_handler from pyaedt.generic.constants import AEDT_UNITS +from pyaedt.generic.general_methods import pyaedt_function_handler from pyaedt.generic.plot import CommonPlotter from pyaedt.generic.plot import ObjClass diff --git a/pyaedt/twinbuilder.py b/pyaedt/twinbuilder.py index 2593b9c6780..251a47e6efd 100644 --- a/pyaedt/twinbuilder.py +++ b/pyaedt/twinbuilder.py @@ -1,3 +1,27 @@ +# -*- 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. + """This module contains the ``TwinBuilder`` class.""" from __future__ import absolute_import # noreorder @@ -19,23 +43,23 @@ class TwinBuilder(AnalysisTwinBuilder, object): Parameters ---------- - projectname : str, optional + project : str, optional Name of the project to select or the full path to the project or AEDTZ archive to open. The default is ``None``, in which case an attempt is made to get an active project. If no projects are present, an empty project is created. - designname : str, optional + design : str, optional Name of the design to select. The default is ``None``, in which case an attempt is made to get an active design. If no designs are present, an empty design is created. solution_type : str, optional Solution type to apply to the design. The default is ``None``, in which case the default type is applied. - setup_name : str, optional + setup : str, optional Name of the setup to use as the nominal. The default is ``None``, in which case the active setup is used or nothing is used. - specified_version : str, int, float, optional + version : str, int, float, optional Version of AEDT to use. The default is ``None``, in which case the active setup or latest installed version is used. @@ -44,7 +68,7 @@ class TwinBuilder(AnalysisTwinBuilder, object): Whether to launch AEDT in non-graphical mode. The default is ``False``, in which case AEDT is launched in graphical mode. This parameter is ignored when a script is launched within AEDT. - new_desktop_session : bool, optional + new_desktop : bool, optional Whether to launch an instance of AEDT in a new thread, even if another instance of the ``specified_version`` is active on the machine. The default is ``False``. @@ -63,7 +87,11 @@ class TwinBuilder(AnalysisTwinBuilder, object): The remote server must be up and running with command `"ansysedt.exe -grpcsrv portnum"`. aedt_process_id : int, optional Process ID for the instance of AEDT to point PyAEDT at. The default is - ``None``. This parameter is only used when ``new_desktop_session = False``. + ``None``. This parameter is only used when ``new_desktop = False``. + remove_lock : bool, optional + Whether to remove lock to project before opening it or not. + The default is ``False``, which means to not unlock + the existing project if needed and raise an exception. Examples -------- @@ -91,37 +119,46 @@ class TwinBuilder(AnalysisTwinBuilder, object): >>> app = TwinBuilder("myfile.aedt") """ + @pyaedt_function_handler( + designname="design", + projectname="project", + specified_version="version", + setup_name="setup", + new_desktop_session="new_desktop", + ) def __init__( self, - projectname=None, - designname=None, + project=None, + design=None, solution_type=None, - setup_name=None, - specified_version=None, + setup=None, + version=None, non_graphical=False, - new_desktop_session=False, + new_desktop=False, close_on_exit=False, student_version=False, machine="", port=0, aedt_process_id=None, + remove_lock=False, ): """Constructor.""" AnalysisTwinBuilder.__init__( self, "Twin Builder", - projectname, - designname, + project, + design, solution_type, - setup_name, - specified_version, + setup, + version, non_graphical, - new_desktop_session, + new_desktop, close_on_exit, student_version, machine, port, aedt_process_id, + remove_lock=remove_lock, ) def _init_from_design(self, *args, **kwargs): @@ -571,7 +608,7 @@ def add_q3d_dynamic_component( component = self.modeler.schematic.create_component(component_library="", component_name=component_name) if component: if is_loaded: - app.close_project(save_project=False) + app.close_project(save=False) return component else: # pragma: no cover raise ValueError("Error in creating the component.") diff --git a/pyaedt/workflows/__init__.py b/pyaedt/workflows/__init__.py index 3bc3c8e5b19..f10103137e9 100644 --- a/pyaedt/workflows/__init__.py +++ b/pyaedt/workflows/__init__.py @@ -1,6 +1,7 @@ -# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates. -# SPDX-License-Identifier: MIT +# -*- 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 diff --git a/pyaedt/workflows/circuit/__init__.py b/pyaedt/workflows/circuit/__init__.py index 3bc3c8e5b19..f10103137e9 100644 --- a/pyaedt/workflows/circuit/__init__.py +++ b/pyaedt/workflows/circuit/__init__.py @@ -1,6 +1,7 @@ -# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates. -# SPDX-License-Identifier: MIT +# -*- 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 diff --git a/pyaedt/workflows/customize_automation_tab.py b/pyaedt/workflows/customize_automation_tab.py index c3309d2ae98..9cc9f384d3d 100644 --- a/pyaedt/workflows/customize_automation_tab.py +++ b/pyaedt/workflows/customize_automation_tab.py @@ -1,6 +1,7 @@ -# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates. -# SPDX-License-Identifier: MIT +# -*- 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 @@ -36,8 +37,8 @@ from defusedxml.ElementTree import ParseError from defusedxml.minidom import parseString -from pyaedt import is_linux from pyaedt.generic.general_methods import read_toml +from pyaedt.generic.settings import is_linux import pyaedt.workflows import pyaedt.workflows.templates diff --git a/pyaedt/workflows/emit/__init__.py b/pyaedt/workflows/emit/__init__.py index 3bc3c8e5b19..f10103137e9 100644 --- a/pyaedt/workflows/emit/__init__.py +++ b/pyaedt/workflows/emit/__init__.py @@ -1,6 +1,7 @@ -# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates. -# SPDX-License-Identifier: MIT +# -*- 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 diff --git a/pyaedt/workflows/hfss/__init__.py b/pyaedt/workflows/hfss/__init__.py index 3bc3c8e5b19..f10103137e9 100644 --- a/pyaedt/workflows/hfss/__init__.py +++ b/pyaedt/workflows/hfss/__init__.py @@ -1,6 +1,7 @@ -# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates. -# SPDX-License-Identifier: MIT +# -*- 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 diff --git a/pyaedt/workflows/hfss/push_excitation_from_file.py b/pyaedt/workflows/hfss/push_excitation_from_file.py index 3dbe6147de8..ebef439fad4 100644 --- a/pyaedt/workflows/hfss/push_excitation_from_file.py +++ b/pyaedt/workflows/hfss/push_excitation_from_file.py @@ -1,6 +1,7 @@ -# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates. -# SPDX-License-Identifier: MIT +# -*- 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 @@ -52,8 +53,8 @@ def frontend(): # pragma: no cover # Get ports app = pyaedt.Desktop( - new_desktop_session=False, - specified_version=version, + new_desktop=False, + version=version, port=port, aedt_process_id=aedt_process_id, student_version=is_student, @@ -153,8 +154,8 @@ def main(extension_args): file_path = extension_args["file_path"] app = pyaedt.Desktop( - new_desktop_session=False, - specified_version=version, + new_desktop=False, + version=version, port=port, aedt_process_id=aedt_process_id, student_version=is_student, @@ -171,11 +172,7 @@ def main(extension_args): if not os.path.isfile(file_path): # pragma: no cover app.logger.error("File does not exist.") elif choice: - hfss.edit_source_from_file( - choice, - file_path, - is_time_domain=True, - ) + hfss.edit_source_from_file(choice, file_path, is_time_domain=True) app.logger.info("Excitation assigned correctly.") else: app.logger.error("Failed to select a port.") diff --git a/pyaedt/workflows/hfss3dlayout/__init__.py b/pyaedt/workflows/hfss3dlayout/__init__.py index 3bc3c8e5b19..f10103137e9 100644 --- a/pyaedt/workflows/hfss3dlayout/__init__.py +++ b/pyaedt/workflows/hfss3dlayout/__init__.py @@ -1,6 +1,7 @@ -# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates. -# SPDX-License-Identifier: MIT +# -*- 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 diff --git a/pyaedt/workflows/hfss3dlayout/cutout.py b/pyaedt/workflows/hfss3dlayout/cutout.py new file mode 100644 index 00000000000..217e1451f78 --- /dev/null +++ b/pyaedt/workflows/hfss3dlayout/cutout.py @@ -0,0 +1,251 @@ +# -*- 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 + +from pyedb import Edb + +import pyaedt +from pyaedt import Hfss3dLayout +from pyaedt import generate_unique_name +import pyaedt.workflows.hfss3dlayout +from pyaedt.workflows.misc import get_aedt_version +from pyaedt.workflows.misc import get_arguments +from pyaedt.workflows.misc import get_port +from pyaedt.workflows.misc import get_process_id +from pyaedt.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 = { + "choice": "ConvexHull", + "signals": [], + "reference": [], + "expansion_factor": 3, + "fix_disjoints": True, +} +extension_description = "Layout Cutout" + + +def frontend(): # pragma: no cover + app = pyaedt.Desktop( + new_desktop=False, + version=version, + port=port, + aedt_process_id=aedt_process_id, + student_version=is_student, + ) + h3d = Hfss3dLayout() + objs_net = {} + for net in h3d.oeditor.GetNets(): + objs_net[net] = h3d.modeler.objects_by_net(net) + import tkinter + from tkinter import ttk + + import PIL.Image + import PIL.ImageTk + + master = tkinter.Tk() + + master.geometry("700x450") + + master.title("Advanced Cutout") + + # Load the logo for the main window + icon_path = os.path.join(os.path.dirname(pyaedt.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)) + + var = tkinter.StringVar() + label = tkinter.Label(master, textvariable=var) + var.set("Cutout Type:") + label.grid(row=0, column=0, pady=10) + combo = ttk.Combobox(master, width=40) # Set the width of the combobox + combo["values"] = ("ConvexHull", "Bounding", "Conforming") + combo.current(0) + combo.grid(row=0, column=1, pady=10) + + combo.focus_set() + master.signal_ui = [i for i in h3d.modeler.signal_nets.keys()] + master.reference_ui = [i for i in h3d.modeler.power_nets.keys()] + + def get_selection(): + sels = h3d.oeditor.GetSelections() + selection = [] + for sel in sels: + for net, net_list in objs_net.items(): + if sel in net_list: + selection.append(net) + break + return selection + + def apply_signal(): + selection = get_selection() + master.signal_ui = list(set(selection)) + if selection: + var2.set("OK") + else: + var2.set("Empty selection. Select nets from layout and retry.") + + def apply_reference(): + selection = get_selection() + master.reference_ui = list(set(selection)) + if selection: + var3.set("OK") + else: + var3.set("Empty selection. Select nets from layout and retry.") + + var2 = tkinter.StringVar() + label2 = tkinter.Label(master, textvariable=var2, relief=tkinter.RAISED) + var2.set("Select") + label2.grid(row=1, column=2, pady=10) + b_sig = tkinter.Button(master, text="Select signal nets in layout and Apply", width=40, command=apply_signal) + b_sig.grid(row=1, column=1, pady=10) + var3 = tkinter.StringVar() + label3 = tkinter.Label(master, textvariable=var3, relief=tkinter.RAISED) + var3.set("Select") + label3.grid(row=2, column=2, pady=10) + b_ref = tkinter.Button(master, text="Apply Reference Nets", width=40, command=apply_reference) + b_ref.grid(row=2, column=1, pady=10) + + var_exp = tkinter.StringVar() + label_exp = tkinter.Label(master, textvariable=var_exp) + var_exp.set("Expansion factor(mm):") + label_exp.grid(row=3, column=0, pady=10) + expansion = tkinter.Text(master, width=20, height=1) + expansion.insert(tkinter.END, "3") + expansion.grid(row=3, column=1, pady=10, padx=5) + var_disj = tkinter.StringVar() + label_disj = tkinter.Label(master, textvariable=var_disj) + var_disj.set("Fix disjoint nets:") + label_disj.grid(row=4, column=0, pady=10) + disjoint_check = tkinter.IntVar() + check2 = tkinter.Checkbutton(master, width=30, variable=disjoint_check) + check2.grid(row=4, column=1, pady=10, padx=5) + + def callback(): + master.choice_ui = combo.get() + master.disjoints_ui = True if disjoint_check.get() == 1 else False + master.expansion_ui = expansion.get("1.0", tkinter.END).strip() + master.destroy() + + b = tkinter.Button(master, text="Create Cutout", width=40, command=callback) + b.grid(row=6, column=1, pady=10) + + tkinter.mainloop() + + choice_ui = getattr(master, "choice_ui", extension_arguments["choice"]) + disjoints_ui = getattr(master, "disjoints_ui", extension_arguments["fix_disjoints"]) + expansion_ui = getattr(master, "expansion_ui", extension_arguments["expansion_factor"]) + signal_ui = getattr(master, "signal_ui", extension_arguments["signals"]) + reference_ui = getattr(master, "reference_ui", extension_arguments["reference"]) + + output_dict = { + "choice": choice_ui, + "signals": signal_ui, + "reference": reference_ui, + "expansion_factor": expansion_ui, + "fix_disjoints": disjoints_ui, + } + app.release_desktop(False, False) + return output_dict + + +def main(extension_args): + choice = extension_args["choice"] + signal = extension_args["signals"] + reference = extension_args["reference"] + expansion = extension_args["expansion_factor"] + disjoint = extension_args["fix_disjoints"] + app = pyaedt.Desktop( + new_desktop=False, + version=version, + port=port, + aedt_process_id=aedt_process_id, + student_version=is_student, + ) + + active_project = app.active_project() + active_design = app.active_design() + aedb_path = os.path.join(active_project.GetPath(), active_project.GetName() + ".aedb") + new_path = aedb_path[:-5] + generate_unique_name("_cutout", n=2) + ".aedb" + edb = Edb(aedb_path, active_design.GetName().split(";")[1], edbversion=version) + edb.save_edb_as(new_path) + edb.cutout( + signal_list=signal, + reference_list=reference, + extent_type=choice, + expansion_size=float(expansion) / 1000, + use_round_corner=False, + output_aedb_path=new_path, + open_cutout_at_end=True, + use_pyaedt_cutout=True, + number_of_threads=4, + use_pyaedt_extent_computing=True, + extent_defeature=0, + remove_single_pin_components=True if disjoint else False, + custom_extent=None, + custom_extent_units="mm", + include_partial_instances=False, + keep_voids=True, + check_terminals=False, + include_pingroups=False, + expansion_factor=0, + maximum_iterations=10, + preserve_components_with_model=False, + simple_pad_check=True, + keep_lines_as_path=False, + ) + if disjoint: + edb.nets.find_and_fix_disjoint_nets(reference) + edb.close_edb() + h3d = Hfss3dLayout(new_path) + if not extension_args["is_test"]: # pragma: no cover + app.logger.info("Project generated correctly.") + 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/pyaedt/workflows/hfss3dlayout/export_layout.py b/pyaedt/workflows/hfss3dlayout/export_layout.py new file mode 100644 index 00000000000..e417cf8fb8e --- /dev/null +++ b/pyaedt/workflows/hfss3dlayout/export_layout.py @@ -0,0 +1,164 @@ +# -*- 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 + +from pyedb import Edb + +import pyaedt +import pyaedt.workflows.hfss3dlayout +from pyaedt.workflows.misc import get_aedt_version +from pyaedt.workflows.misc import get_arguments +from pyaedt.workflows.misc import get_port +from pyaedt.workflows.misc import get_process_id +from pyaedt.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 = {"export_ipc": True, "export_configuration": True, "export_bom": True} +extension_description = "Layout Exporter" + + +def frontend(): # pragma: no cover + import tkinter + from tkinter import ttk + + import PIL.Image + import PIL.ImageTk + + master = tkinter.Tk() + + master.geometry("700x450") + + master.title("Layout exporter") + + # Load the logo for the main window + icon_path = os.path.join(os.path.dirname(pyaedt.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)) + + var = tkinter.StringVar() + label = tkinter.Label(master, textvariable=var) + var.set("Export IPC2581:") + label.grid(row=0, column=0, pady=10) + ipc_check = tkinter.IntVar() + check = tkinter.Checkbutton(master, width=30, variable=ipc_check) + check.grid(row=0, column=1, pady=10, padx=5) + ipc_check.set(1) + + var2 = tkinter.StringVar() + label2 = tkinter.Label(master, textvariable=var2) + var2.set("Export Configuration file:") + label2.grid(row=1, column=0, pady=10) + configuration_check = tkinter.IntVar() + check2 = tkinter.Checkbutton(master, width=30, variable=configuration_check) + check2.grid(row=1, column=1, pady=10, padx=5) + configuration_check.set(1) + + var3 = tkinter.StringVar() + label3 = tkinter.Label(master, textvariable=var3) + var3.set("Export BOM file:") + label3.grid(row=2, column=0, pady=10) + bom_check = tkinter.IntVar() + check3 = tkinter.Checkbutton(master, width=30, variable=bom_check) + check3.grid(row=2, column=1, pady=10, padx=5) + bom_check.set(1) + + def callback(): + master.ipc_ui = True if ipc_check.get() == 1 else False + master.confg_ui = True if configuration_check.get() == 1 else False + master.bom_ui = True if bom_check.get() == 1 else False + master.destroy() + + b = tkinter.Button(master, text="Export", width=40, command=callback) + b.grid(row=3, column=1, pady=10) + + tkinter.mainloop() + + ipc_ui = getattr(master, "ipc_ui", extension_arguments["export_ipc"]) + confg_ui = getattr(master, "confg_ui", extension_arguments["export_configuration"]) + bom_ui = getattr(master, "bom_ui", extension_arguments["export_bom"]) + + output_dict = { + "export_ipc": ipc_ui, + "export_configuration": confg_ui, + "export_bom": bom_ui, + } + return output_dict + + +def main(extension_args): + ipc = extension_args["export_ipc"] + bom = extension_args["export_bom"] + config = extension_args["export_configuration"] + app = pyaedt.Desktop( + new_desktop=False, + version=version, + port=port, + aedt_process_id=aedt_process_id, + student_version=is_student, + ) + + active_project = app.active_project() + active_design = app.active_design() + aedb_path = os.path.join(active_project.GetPath(), active_project.GetName() + ".aedb") + edb = Edb(aedb_path, active_design.GetName().split(";")[1], edbversion=version) + if ipc: + ipc_file = aedb_path[:-5] + "_ipc2581.xml" + edb.export_to_ipc2581(ipc_file) + if bom: + bom_file = aedb_path[:-5] + "_bom.csv" + edb.components.export_bom(bom_file) + if config: + config_file = aedb_path[:-5] + "_config.json" + edb.configuration.export(config_file) + + if not extension_args["is_test"]: # pragma: no cover + app.logger.info("Project generated correctly.") + 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/pyaedt/workflows/hfss3dlayout/export_to_3d.py b/pyaedt/workflows/hfss3dlayout/export_to_3d.py index c51c7b83eea..7e8d4ee9bb5 100644 --- a/pyaedt/workflows/hfss3dlayout/export_to_3d.py +++ b/pyaedt/workflows/hfss3dlayout/export_to_3d.py @@ -1,6 +1,7 @@ -# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates. -# SPDX-License-Identifier: MIT +# -*- 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 @@ -100,8 +101,8 @@ def main(extension_args): choice = extension_args["choice"] app = pyaedt.Desktop( - new_desktop_session=False, - specified_version=version, + new_desktop=False, + version=version, port=port, aedt_process_id=aedt_process_id, student_version=is_student, @@ -119,7 +120,7 @@ def main(extension_args): app.release_desktop(False, False) raise Exception("Hfss 3D Layout project is needed.") - h3d = pyaedt.Hfss3dLayout(projectname=project_name, designname=design_name) + h3d = pyaedt.Hfss3dLayout(project=project_name, design=design_name) setup = h3d.create_setup() suffix = suffixes[choice] @@ -133,21 +134,16 @@ def main(extension_args): h3d.save_project() if choice == "Export to Q3D": - _ = pyaedt.Q3d(projectname=h3d.project_file[:-5] + f"_{suffix}.aedt") + _ = pyaedt.Q3d(project=h3d.project_file[:-5] + f"_{suffix}.aedt") else: - aedtapp = pyaedt.Hfss(projectname=h3d.project_file[:-5] + f"_{suffix}.aedt") + aedtapp = pyaedt.Hfss(project=h3d.project_file[:-5] + f"_{suffix}.aedt") aedtapp2 = None if choice == "Export to Maxwell 3D": - aedtapp2 = pyaedt.Maxwell3d(projectname=aedtapp.project_name) + aedtapp2 = pyaedt.Maxwell3d(project=aedtapp.project_name) elif choice == "Export to Icepak": - aedtapp2 = pyaedt.Icepak(projectname=aedtapp.project_name) + aedtapp2 = pyaedt.Icepak(project=aedtapp.project_name) if aedtapp2: - aedtapp2.copy_solid_bodies_from( - aedtapp, - no_vacuum=False, - no_pec=False, - include_sheets=True, - ) + aedtapp2.copy_solid_bodies_from(aedtapp, no_vacuum=False, no_pec=False, include_sheets=True) aedtapp2.delete_design(aedtapp.design_name) aedtapp2.save_project() diff --git a/pyaedt/workflows/hfss3dlayout/images/large/cutout.png b/pyaedt/workflows/hfss3dlayout/images/large/cutout.png new file mode 100644 index 00000000000..996169b4e13 Binary files /dev/null and b/pyaedt/workflows/hfss3dlayout/images/large/cutout.png differ diff --git a/pyaedt/workflows/hfss3dlayout/images/large/export.png b/pyaedt/workflows/hfss3dlayout/images/large/export.png new file mode 100644 index 00000000000..820c5ce2392 Binary files /dev/null and b/pyaedt/workflows/hfss3dlayout/images/large/export.png differ diff --git a/pyaedt/workflows/hfss3dlayout/push_excitation_from_file_3dl.py b/pyaedt/workflows/hfss3dlayout/push_excitation_from_file_3dl.py new file mode 100644 index 00000000000..f0f8db4819a --- /dev/null +++ b/pyaedt/workflows/hfss3dlayout/push_excitation_from_file_3dl.py @@ -0,0 +1,212 @@ +# -*- 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.path + +import pyaedt +from pyaedt import Hfss3dLayout +import pyaedt.workflows +from pyaedt.workflows.misc import get_aedt_version +from pyaedt.workflows.misc import get_arguments +from pyaedt.workflows.misc import get_port +from pyaedt.workflows.misc import get_process_id +from pyaedt.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 = {"file_path": "", "choice": ""} +extension_description = "Push excitation from file" + + +def frontend(): # pragma: no cover + + import tkinter + from tkinter import filedialog + from tkinter import ttk + + import PIL.Image + import PIL.ImageTk + + # Get ports + app = pyaedt.Desktop( + new_desktop=False, + version=version, + port=port, + aedt_process_id=aedt_process_id, + student_version=is_student, + ) + + active_project = app.active_project() + active_design = app.active_design() + + project_name = active_project.GetName() + + if active_design.GetDesignType() in ["HFSS 3D Layout Design"]: + design_name = active_design.GetName().split(";")[1] + else: # pragma: no cover + app.logger.debug("Hfss 3D Layout project is needed.") + app.release_desktop(False, False) + raise Exception("Hfss 3D Layout project is needed.") + + hfss_3dl = Hfss3dLayout(project_name, design_name) + + port_selection = hfss_3dl.excitations + + if not port_selection: + app.logger.error("No ports found.") + hfss_3dl.release_desktop(False, False) + output_dict = {"choice": "", "file_path": ""} + return output_dict + + # Create UI + master = tkinter.Tk() + + master.geometry("700x150") + + master.title("Assign push excitation to port from transient data") + + # Load the logo for the main window + icon_path = os.path.join(pyaedt.workflows.__path__[0], "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", 8)) + + var = tkinter.StringVar() + label = tkinter.Label(master, textvariable=var) + var.set("Choose a port:") + label.grid(row=0, column=0, pady=10) + combo = ttk.Combobox(master, width=30) + combo["values"] = port_selection + combo.current(0) + combo.grid(row=0, column=1, pady=10, padx=5) + combo.focus_set() + var2 = tkinter.StringVar() + label2 = tkinter.Label(master, textvariable=var2) + var2.set("Browse file:") + label2.grid(row=1, column=0, pady=10) + text = tkinter.Text(master, width=50, height=1) + text.grid(row=1, column=1, pady=10, padx=5) + + def browseFiles(): + filename = filedialog.askopenfilename( + initialdir="/", + title="Select a Transient File", + filetypes=(("Transient curve", "*.csv*"), ("all files", "*.*")), + ) + text.insert(tkinter.END, filename) + + b1 = tkinter.Button(master, text="...", width=10, command=browseFiles) + b1.grid(row=3, column=0) + b1.grid(row=1, column=2, pady=10) + + def callback(): + master.choice_ui = combo.get() + master.file_path_ui = text.get("1.0", tkinter.END).strip() + master.destroy() + + b = tkinter.Button(master, text="Ok", width=40, command=callback) + b.grid(row=2, column=1, pady=10) + + tkinter.mainloop() + + file_path_ui = getattr(master, "file_path_ui", extension_arguments["file_path"]) + choice_ui = getattr(master, "choice_ui", extension_arguments["choice"]) + + if not file_path_ui or not os.path.isfile(file_path_ui): + app.logger.error("File does not exist.") + + if not choice_ui: + app.logger.error("Excitation not found.") + + hfss_3dl.release_desktop(False, False) + + output_dict = {"choice": choice_ui, "file_path": file_path_ui} + + return output_dict + + +def main(extension_args): + choice = extension_args["choice"] + file_path = extension_args["file_path"] + + app = pyaedt.Desktop( + new_desktop=False, + version=version, + port=port, + aedt_process_id=aedt_process_id, + student_version=is_student, + ) + + active_project = app.active_project() + active_design = app.active_design() + + project_name = active_project.GetName() + + if active_design.GetDesignType() in ["HFSS 3D Layout Design"]: + design_name = active_design.GetName().split(";")[1] + else: # pragma: no cover + app.logger.debug("Hfss 3D Layout project is needed.") + app.release_desktop(False, False) + raise Exception("Hfss 3D Layout project is needed.") + + hfss_3dl = Hfss3dLayout(project_name, design_name) + + if not os.path.isfile(file_path): # pragma: no cover + app.logger.error("File does not exist.") + elif choice: + hfss_3dl.edit_source_from_file( + choice, + file_path, + is_time_domain=True, + ) + app.logger.info("Excitation assigned correctly.") + else: + app.logger.error("Failed to select a port.") + + 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/pyaedt/workflows/hfss3dlayout/toolkits_catalog.toml b/pyaedt/workflows/hfss3dlayout/toolkits_catalog.toml index 4bbf3a28f65..58893164913 100644 --- a/pyaedt/workflows/hfss3dlayout/toolkits_catalog.toml +++ b/pyaedt/workflows/hfss3dlayout/toolkits_catalog.toml @@ -4,3 +4,24 @@ script = "export_to_3d.py" icon = "images/large/cad3d.png" template = "run_pyaedt_toolkit_script" pip = "" + +[PushfromTransient] +name = "Push Excitation from transient data" +script = "push_excitation_from_file_3dl.py" +icon = "images/large/push.png" +template = "run_pyaedt_toolkit_script" +pip = "" + +[ExportFiles] +name = "Export Layout info" +script = "export_layout.py" +icon = "images/large/export.png" +template = "run_pyedb_toolkit_script" +pip = "" + +[Cutout] +name = "Advanced cutout" +script = "cutout.py" +icon = "images/large/cutout.png" +template = "run_pyedb_toolkit_script" +pip = "" \ No newline at end of file diff --git a/pyaedt/workflows/icepak/__init__.py b/pyaedt/workflows/icepak/__init__.py index 3bc3c8e5b19..f10103137e9 100644 --- a/pyaedt/workflows/icepak/__init__.py +++ b/pyaedt/workflows/icepak/__init__.py @@ -1,6 +1,7 @@ -# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates. -# SPDX-License-Identifier: MIT +# -*- 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 diff --git a/pyaedt/workflows/installer/__init__.py b/pyaedt/workflows/installer/__init__.py index 3bc3c8e5b19..f10103137e9 100644 --- a/pyaedt/workflows/installer/__init__.py +++ b/pyaedt/workflows/installer/__init__.py @@ -1,6 +1,7 @@ -# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates. -# SPDX-License-Identifier: MIT +# -*- 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 diff --git a/pyaedt/workflows/installer/console_setup.py b/pyaedt/workflows/installer/console_setup.py index b32f3273fa1..0ea19672ce0 100644 --- a/pyaedt/workflows/installer/console_setup.py +++ b/pyaedt/workflows/installer/console_setup.py @@ -1,3 +1,27 @@ +# -*- 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. + """ Launches an interactive shell with an instance of HFSS @@ -64,18 +88,18 @@ def release(d): error = False if port: desktop = Desktop( - specified_version=version, + version=version, port=port, - new_desktop_session=False, + new_desktop=False, non_graphical=False, close_on_exit=False, student_version=student_version, ) elif is_windows: desktop = Desktop( - specified_version=version, + version=version, aedt_process_id=aedt_process_id, - new_desktop_session=False, + new_desktop=False, non_graphical=False, close_on_exit=False, student_version=student_version, diff --git a/pyaedt/workflows/installer/extension_manager.py b/pyaedt/workflows/installer/extension_manager.py index f07cfd6ce82..d90a781474c 100644 --- a/pyaedt/workflows/installer/extension_manager.py +++ b/pyaedt/workflows/installer/extension_manager.py @@ -1,6 +1,7 @@ -# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates. -# SPDX-License-Identifier: MIT +# -*- 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 @@ -240,9 +241,9 @@ def button_is_clicked( name = toolkit_name.get() desktop = Desktop( - specified_version=version, + version=version, port=port, - new_desktop_session=False, + new_desktop=False, non_graphical=False, close_on_exit=False, student_version=student_version, @@ -293,6 +294,9 @@ def button_is_clicked( if not file: file = os.path.join(os.path.dirname(pyaedt.workflows.templates.__file__), "extension_template.py") if os.path.isfile(executable_interpreter): + template_file = "run_pyaedt_toolkit_script" + if selected_toolkit_info: + template_file = selected_toolkit_info.get("template") add_script_to_menu( name=name, script_file=file, @@ -301,6 +305,7 @@ def button_is_clicked( executable_interpreter=executable_interpreter, personal_lib=desktop.personallib, aedt_version=desktop.aedt_version_id, + template_file=template_file, ) desktop.logger.info("{} installed".format(name)) else: diff --git a/pyaedt/workflows/installer/pyaedt_installer.py b/pyaedt/workflows/installer/pyaedt_installer.py index 8d7a5ef0d63..29959a4b6c1 100644 --- a/pyaedt/workflows/installer/pyaedt_installer.py +++ b/pyaedt/workflows/installer/pyaedt_installer.py @@ -1,6 +1,7 @@ -# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates. -# SPDX-License-Identifier: MIT +# -*- 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 diff --git a/pyaedt/workflows/maxwell2d/__init__.py b/pyaedt/workflows/maxwell2d/__init__.py index 3bc3c8e5b19..f10103137e9 100644 --- a/pyaedt/workflows/maxwell2d/__init__.py +++ b/pyaedt/workflows/maxwell2d/__init__.py @@ -1,6 +1,7 @@ -# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates. -# SPDX-License-Identifier: MIT +# -*- 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 diff --git a/pyaedt/workflows/maxwell3d/__init__.py b/pyaedt/workflows/maxwell3d/__init__.py index 3bc3c8e5b19..f10103137e9 100644 --- a/pyaedt/workflows/maxwell3d/__init__.py +++ b/pyaedt/workflows/maxwell3d/__init__.py @@ -1,6 +1,7 @@ -# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates. -# SPDX-License-Identifier: MIT +# -*- 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 diff --git a/pyaedt/workflows/mechanical/__init__.py b/pyaedt/workflows/mechanical/__init__.py index 3bc3c8e5b19..f10103137e9 100644 --- a/pyaedt/workflows/mechanical/__init__.py +++ b/pyaedt/workflows/mechanical/__init__.py @@ -1,6 +1,7 @@ -# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates. -# SPDX-License-Identifier: MIT +# -*- 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 diff --git a/pyaedt/workflows/misc.py b/pyaedt/workflows/misc.py index 687620ba188..89ba7b998a6 100644 --- a/pyaedt/workflows/misc.py +++ b/pyaedt/workflows/misc.py @@ -1,6 +1,7 @@ -# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates. -# SPDX-License-Identifier: MIT +# -*- 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 diff --git a/pyaedt/workflows/project/__init__.py b/pyaedt/workflows/project/__init__.py index 3bc3c8e5b19..f10103137e9 100644 --- a/pyaedt/workflows/project/__init__.py +++ b/pyaedt/workflows/project/__init__.py @@ -1,6 +1,7 @@ -# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates. -# SPDX-License-Identifier: MIT +# -*- 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 diff --git a/pyaedt/workflows/project/advanced_fields_calculator.py b/pyaedt/workflows/project/advanced_fields_calculator.py new file mode 100644 index 00000000000..e60709d2746 --- /dev/null +++ b/pyaedt/workflows/project/advanced_fields_calculator.py @@ -0,0 +1,274 @@ +# -*- 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.path + +import pyaedt +from pyaedt import get_pyaedt_app +from pyaedt.generic.general_methods import generate_unique_name +from pyaedt.modeler.cad.elements3d import FacePrimitive +import pyaedt.workflows +from pyaedt.workflows.misc import get_aedt_version +from pyaedt.workflows.misc import get_arguments +from pyaedt.workflows.misc import get_port +from pyaedt.workflows.misc import get_process_id +from pyaedt.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 = {"setup": "", "calculation": "", "assignment": []} +extension_description = "Simplified use of Fields Calculator" + + +def frontend(): # pragma: no cover + + import tkinter + from tkinter import ttk + + import PIL.Image + import PIL.ImageTk + + # Get ports + app = pyaedt.Desktop( + new_desktop=False, + specified_version=version, + port=port, + aedt_process_id=aedt_process_id, + student_version=is_student, + ) + + active_project = app.active_project() + active_design = app.active_design() + + project_name = active_project.GetName() + if active_design.GetDesignType() == "HFSS 3D Layout Design": + design_name = active_design.GetDesignName() + else: + design_name = active_design.GetName() + + aedtapp = get_pyaedt_app(project_name, design_name) + + # Load new expressions from file + current_directory = os.getcwd() + all_files = os.listdir(current_directory) + toml_files = [f for f in all_files if f.endswith(".toml")] + for toml_file in toml_files: + aedtapp.post.fields_calculator.load_expression_file(toml_file) + + # Personal Lib directory + all_files = os.listdir(aedtapp.personallib) + toml_files = [os.path.join(aedtapp.personallib, f) for f in all_files if f.endswith(".toml")] + for toml_file in toml_files: + aedtapp.post.fields_calculator.load_expression_file(toml_file) + + # Available fields calculator expressions + available_expressions = aedtapp.post.fields_calculator.expression_catalog + available_descriptions = {} + for expression, expression_info in available_expressions.items(): + if "design_type" in expression_info and aedtapp.design_type in expression_info["design_type"]: + if "Transient" in aedtapp.solution_type and "Transient" in expression_info["solution_type"]: + available_descriptions[expression] = expression_info["description"] + elif "Transient" not in aedtapp.solution_type and "Transient" not in expression_info["solution_type"]: + available_descriptions[expression] = expression_info["description"] + + available_setups = aedtapp.existing_analysis_sweeps + + if not available_setups: + app.logger.error("No setups defined.") + aedtapp.release_desktop(False, False) + output_dict = {"setup": "", "calculation": "", "assignment": []} + return output_dict + + # Create UI + master = tkinter.Tk() + + master.geometry("700x150") + + master.title("Advanced fields calculator") + + # Load the logo for the main window + icon_path = os.path.join(pyaedt.workflows.__path__[0], "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", 8)) + + var = tkinter.StringVar() + label = tkinter.Label(master, textvariable=var) + var.set("Solved setup:") + label.grid(row=0, column=0, pady=10, padx=15) + combo_setup = ttk.Combobox(master, width=30) + combo_setup["values"] = available_setups + combo_setup.current(0) + combo_setup.grid(row=0, column=1, pady=10, padx=10) + combo_setup.focus_set() + + var = tkinter.StringVar() + label = tkinter.Label(master, textvariable=var) + var.set("Calculations:") + label.grid(row=1, column=0, pady=10, padx=15) + combo_calculation = ttk.Combobox(master, width=30) + combo_calculation["values"] = list(available_descriptions.values()) + combo_calculation.current(0) + combo_calculation.grid(row=1, column=1, pady=10, padx=10) + combo_calculation.focus_set() + + def callback(): + master.setup = combo_setup.get() + master.calculation = combo_calculation.get() + master.destroy() + + b = tkinter.Button(master, text="Ok", width=40, command=callback) + b.grid(row=2, column=1, pady=10) + + tkinter.mainloop() + + setup_ui = getattr(master, "setup", extension_arguments["setup"]) + if getattr(master, "setup"): + setup = setup_ui + else: + setup = extension_arguments["setup"] + + calculation_ui = getattr(master, "calculation", extension_arguments["calculation"]) + calculation = extension_arguments["setup"] + + if getattr(master, "setup"): + calculation_description = calculation_ui + for k, v in available_descriptions.items(): + if calculation_description == v: + calculation = k + break + + assignments = aedtapp.modeler.convert_to_selections(aedtapp.modeler.selections, True) + + app.release_desktop(False, False) + + output_dict = {"setup": setup, "calculation": calculation, "assignment": assignments} + + return output_dict + + +def main(extension_args): + setup = extension_args["setup"] + calculation = extension_args["calculation"] + assignment_selection = extension_args["assignment"] + + app = pyaedt.Desktop( + new_desktop=False, + version=version, + port=port, + aedt_process_id=aedt_process_id, + student_version=is_student, + ) + + active_project = app.active_project() + active_design = app.active_design() + + project_name = active_project.GetName() + if active_design.GetDesignType() == "HFSS 3D Layout Design": # pragma: no cover + design_name = active_design.GetDesignName() + else: + design_name = active_design.GetName() + + aedtapp = get_pyaedt_app(project_name, design_name) + + if not calculation: + aedtapp.logger.warning("No calculation selected.") + if not extension_args["is_test"]: # pragma: no cover + app.release_desktop(False, False) + return False + + assignments = [] + for assignment in assignment_selection: + if assignment not in aedtapp.modeler.object_names and "Face" in assignment: + assignments.append(aedtapp.modeler.get_face_by_id(int(assignment[4:]))) + else: + assignments.append(assignment) + + # Load new expressions from file + # Current directory + current_directory = os.getcwd() + all_files = os.listdir(current_directory) + toml_files = [f for f in all_files if f.endswith(".toml")] + for toml_file in toml_files: + aedtapp.post.fields_calculator.load_expression_file(toml_file) + + # Personal Lib directory + all_files = os.listdir(aedtapp.personallib) + toml_files = [os.path.join(aedtapp.personallib, f) for f in all_files if f.endswith(".toml")] + for toml_file in toml_files: + aedtapp.post.fields_calculator.load_expression_file(toml_file) + + names = [] + + if not aedtapp.post.fields_calculator.is_general_expression(calculation): + for assignment in assignments: + assignment_str = assignment + if isinstance(assignment_str, FacePrimitive): + assignment_str = str(assignment.id) + elif not isinstance(assignment_str, str): # pragma: no cover + assignment_str = generate_unique_name(calculation) + name = aedtapp.post.fields_calculator.add_expression( + calculation, assignment, calculation + "_" + assignment_str + ) + if name: + names.append(name) + else: + aedtapp.logger.error("Wrong assignment.") + if not extension_args["is_test"]: # pragma: no cover + app.release_desktop(False, False) + return False + else: + names.append(aedtapp.post.fields_calculator.add_expression(calculation, None)) + + if not aedtapp.post.fields_calculator.is_general_expression(calculation): + _ = aedtapp.post.fields_calculator.expression_plot(calculation, None, names, setup) + else: + _ = aedtapp.post.fields_calculator.expression_plot(calculation, assignments, names, setup) + + 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/pyaedt/workflows/project/configure_edb.py b/pyaedt/workflows/project/configure_edb.py new file mode 100644 index 00000000000..1934e746b3d --- /dev/null +++ b/pyaedt/workflows/project/configure_edb.py @@ -0,0 +1,187 @@ +# -*- 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.path + +from pyedb import Edb + +import pyaedt +from pyaedt import Hfss3dLayout +from pyaedt import generate_unique_name +from pyaedt.generic.filesystem import search_files +import pyaedt.workflows +from pyaedt.workflows.misc import get_aedt_version +from pyaedt.workflows.misc import get_arguments +from pyaedt.workflows.misc import get_port +from pyaedt.workflows.misc import get_process_id +from pyaedt.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 = {"aedb_path": "", "configuration_path": ""} +extension_description = "Configure project from aedb file" + + +def frontend(): # pragma: no cover + + import tkinter + from tkinter import filedialog + from tkinter import ttk + + import PIL.Image + import PIL.ImageTk + + master = tkinter.Tk() + + master.geometry("750x250") + + master.title(extension_description) + + # Load the logo for the main window + icon_path = os.path.join(pyaedt.workflows.__path__[0], "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", 8)) + + var2 = tkinter.StringVar() + label2 = tkinter.Label(master, textvariable=var2) + var2.set("Browse file:") + label2.grid(row=0, column=0, pady=10) + text = tkinter.Text(master, width=40, height=1) + text.grid(row=0, column=1, pady=10, padx=5) + + def browse_aedb(): + filename = filedialog.askopenfilename( + initialdir="/", + title="Select a layout folder or file", + filetypes=(("aedb file", "*.def"), ("brd", "*.brd"), ("all files", "*.*")), + ) + if filename.endswith(".def"): + filename = os.path.dirname(filename) + text.insert(tkinter.END, filename) + + b1 = tkinter.Button(master, text="...", width=10, command=browse_aedb) + b1.grid(row=0, column=2, pady=10) + + var3 = tkinter.StringVar() + label3 = tkinter.Label(master, textvariable=var3) + var3.set("Browse configuration file or folder:") + label3.grid(row=1, column=0, pady=10) + text2 = tkinter.Text(master, width=40, height=1) + text2.grid(row=1, column=1, pady=10, padx=5) + + def browse_config(): + inital_dir = text.get("1.0", tkinter.END).strip() + filename = filedialog.askopenfilename( + initialdir=os.path.dirname(inital_dir) if inital_dir else "/", + title="Select configuration file", + filetypes=(("Configuration file", "*.json"), ("Configuration file", "*.toml")), + ) + text2.insert(tkinter.END, filename) + + b2 = tkinter.Button(master, text="...", width=10, command=browse_config) + b2.grid(row=1, column=2, pady=10) + + def callback(): + master.aedb_path_ui = text.get("1.0", tkinter.END).strip() + master.configuration_path_ui = text2.get("1.0", tkinter.END).strip() + master.destroy() + + b3 = tkinter.Button(master, text="Ok", width=40, command=callback) + b3.grid(row=25, column=1, pady=10, padx=10) + + tkinter.mainloop() + + aedb_path_ui = getattr(master, "aedb_path_ui", extension_arguments["aedb_path"]) + + configuration_path_ui = getattr(master, "configuration_path_ui", extension_arguments["configuration_path"]) + + output_dict = { + "configuration_path": configuration_path_ui, + "aedb_path": aedb_path_ui, + } + return output_dict + + +def main(extension_args): + aedb_path = extension_args["aedb_path"] + config = extension_args["configuration_path"] + if os.path.isdir(config): + configs = search_files(config, "*.json") + configs += search_files(config, "*.toml") + else: + configs = [config] + app = pyaedt.Desktop( + new_desktop_session=False, + specified_version=version, + port=port, + aedt_process_id=aedt_process_id, + student_version=is_student, + ) + if aedb_path == "": + project_name = app.active_project().GetName() + aedb_path = os.path.join(app.active_project().GetPath(), project_name + ".aedb") + else: + project_name = os.path.splitext(os.path.split(aedb_path)[-1])[0] + if project_name in app.project_list(): + app.odesktop.CloseProject(project_name) + for config in configs: + edbapp = Edb(aedb_path, edbversion=version) + config_name = os.path.splitext(os.path.split(config)[-1])[0] + output_path = aedb_path[:-5] + f"_{config_name}.aedb" + if os.path.exists(output_path): + new_name = generate_unique_name(config_name, n=2) + output_path = aedb_path[:-5] + f"_{new_name}.aedb" + edbapp.configuration.load(config_file=config) + edbapp.configuration.run() + edbapp.save_edb_as(output_path) + edbapp.close() + h3d = Hfss3dLayout(output_path) + h3d.save_project() + if not extension_args["is_test"]: # pragma: no cover + app.release_desktop(False, False) + return True + + +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/pyaedt/workflows/project/create_report.py b/pyaedt/workflows/project/create_report.py index ed8fe38d95c..a2b7e1a1e42 100644 --- a/pyaedt/workflows/project/create_report.py +++ b/pyaedt/workflows/project/create_report.py @@ -1,6 +1,7 @@ -# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates. -# SPDX-License-Identifier: MIT +# -*- 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 @@ -44,8 +45,8 @@ def main(extension_args): app = pyaedt.Desktop( - new_desktop_session=False, - specified_version=version, + new_desktop=False, + version=version, port=port, aedt_process_id=aedt_process_id, student_version=is_student, diff --git a/pyaedt/workflows/project/images/large/aedb.png b/pyaedt/workflows/project/images/large/aedb.png new file mode 100644 index 00000000000..380c40ca09e Binary files /dev/null and b/pyaedt/workflows/project/images/large/aedb.png differ diff --git a/pyaedt/workflows/project/images/large/fields.png b/pyaedt/workflows/project/images/large/fields.png new file mode 100644 index 00000000000..ec44b53d34f Binary files /dev/null and b/pyaedt/workflows/project/images/large/fields.png differ diff --git a/pyaedt/workflows/project/import_nastran.py b/pyaedt/workflows/project/import_nastran.py index d728cf204bf..9bfc0968727 100644 --- a/pyaedt/workflows/project/import_nastran.py +++ b/pyaedt/workflows/project/import_nastran.py @@ -1,6 +1,7 @@ -# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates. -# SPDX-License-Identifier: MIT +# -*- 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 @@ -23,8 +24,8 @@ import os.path import pyaedt -from pyaedt import generate_unique_name from pyaedt import get_pyaedt_app +from pyaedt.modules.solutions import nastran_to_stl import pyaedt.workflows from pyaedt.workflows.misc import get_aedt_version from pyaedt.workflows.misc import get_arguments @@ -69,47 +70,47 @@ def frontend(): # pragma: no cover style = ttk.Style() style.configure("Toolbutton.TButton", padding=6, font=("Helvetica", 8)) + var2 = tkinter.StringVar() + label2 = tkinter.Label(master, textvariable=var2) + var2.set("Browse file:") + label2.grid(row=0, column=0, pady=10) + text = tkinter.Text(master, width=40, height=1) + text.grid(row=0, column=1, pady=10, padx=5) + + def browseFiles(): + filename = filedialog.askopenfilename( + initialdir="/", + title="Select a Nastran or stl File", + filetypes=(("Nastran", "*.nas"), ("STL", "*.stl"), ("all files", "*.*")), + ) + text.insert(tkinter.END, filename) + + b1 = tkinter.Button(master, text="...", width=10, command=browseFiles) + b1.grid(row=0, column=2, pady=10) + var = tkinter.StringVar() label = tkinter.Label(master, textvariable=var) var.set("Decimation factor (0-0.9). It may affect results:") - label.grid(row=0, column=0, pady=10) + label.grid(row=1, column=0, pady=10) check = tkinter.Text(master, width=20, height=1) check.insert(tkinter.END, "0.0") - check.grid(row=0, column=1, pady=10, padx=5) + check.grid(row=1, column=1, pady=10, padx=5) var = tkinter.StringVar() label = tkinter.Label(master, textvariable=var) var.set("Import as lightweight (only HFSS):") - label.grid(row=1, column=0, pady=10) + label.grid(row=2, column=0, pady=10) light = tkinter.IntVar() check2 = tkinter.Checkbutton(master, width=30, variable=light) - check2.grid(row=1, column=1, pady=10, padx=5) + check2.grid(row=2, column=1, pady=10, padx=5) var = tkinter.StringVar() label = tkinter.Label(master, textvariable=var) var.set("Enable planar merge:") - label.grid(row=2, column=0, pady=10) + label.grid(row=3, column=0, pady=10) planar = tkinter.IntVar(value=1) check3 = tkinter.Checkbutton(master, width=30, variable=planar) - check3.grid(row=2, column=1, pady=10, padx=5) - - var2 = tkinter.StringVar() - label2 = tkinter.Label(master, textvariable=var2) - var2.set("Browse file:") - label2.grid(row=3, column=0, pady=10) - text = tkinter.Text(master, width=40, height=1) - text.grid(row=3, column=1, pady=10, padx=5) - - def browseFiles(): - filename = filedialog.askopenfilename( - initialdir="/", - title="Select a Nastran or stl File", - filetypes=(("Nastran", "*.nas"), ("STL", "*.stl"), ("all files", "*.*")), - ) - text.insert(tkinter.END, filename) - - b1 = tkinter.Button(master, text="...", width=10, command=browseFiles) - b1.grid(row=3, column=2, pady=10) + check3.grid(row=3, column=1, pady=10, padx=5) def callback(): master.decimate_ui = float(check.get("1.0", tkinter.END).strip()) @@ -125,21 +126,7 @@ def preview(): master.file_path_ui = text.get("1.0", tkinter.END).strip() if master.file_path_ui.endswith(".nas"): - design_name = generate_unique_name("Preview", n=2) - - app = pyaedt.Hfss( - new_desktop_session=False, - specified_version=version, - port=port, - aedt_process_id=aedt_process_id, - student_version=is_student, - designname=design_name, - ) - - app.modeler.import_nastran( - master.file_path_ui, decimation=master.decimate_ui, save_only_stl=True, preview=True - ) - app.release_desktop(False, False) + nastran_to_stl(input_file=master.file_path_ui, decimation=master.decimate_ui, preview=True) else: from pyaedt.modules.solutions import simplify_stl @@ -175,8 +162,8 @@ def main(extension_args): if os.path.exists(file_path): app = pyaedt.Desktop( - new_desktop_session=False, - specified_version=version, + new_desktop=False, + version=version, port=port, aedt_process_id=aedt_process_id, student_version=is_student, @@ -204,8 +191,8 @@ def main(extension_args): app.logger.info("Geometry imported correctly.") else: app = pyaedt.Desktop( - new_desktop_session=False, - specified_version=version, + new_desktop=False, + version=version, port=port, aedt_process_id=aedt_process_id, student_version=is_student, diff --git a/pyaedt/workflows/project/toolkits_catalog.toml b/pyaedt/workflows/project/toolkits_catalog.toml index 60ece1bdd81..6974adca284 100644 --- a/pyaedt/workflows/project/toolkits_catalog.toml +++ b/pyaedt/workflows/project/toolkits_catalog.toml @@ -11,3 +11,17 @@ script = "import_nastran.py" icon = "images/large/cad3d.png" template = "run_pyaedt_toolkit_script" pip = "" + +[ConfigureEdb] +name = "Configure layout" +script = "configure_edb.py" +icon = "images/large/aedb.png" +template = "run_pyedb_toolkit_script" +pip = "" + +[FieldsCalculator] +name = "Advanced Fields Calculator" +script = "advanced_fields_calculator.py" +icon = "images/large/fields.png" +template = "run_pyaedt_toolkit_script" +pip = "" diff --git a/pyaedt/workflows/q2d/__init__.py b/pyaedt/workflows/q2d/__init__.py index 3bc3c8e5b19..f10103137e9 100644 --- a/pyaedt/workflows/q2d/__init__.py +++ b/pyaedt/workflows/q2d/__init__.py @@ -1,6 +1,7 @@ -# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates. -# SPDX-License-Identifier: MIT +# -*- 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 diff --git a/pyaedt/workflows/q3d/__init__.py b/pyaedt/workflows/q3d/__init__.py index 3bc3c8e5b19..f10103137e9 100644 --- a/pyaedt/workflows/q3d/__init__.py +++ b/pyaedt/workflows/q3d/__init__.py @@ -1,6 +1,7 @@ -# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates. -# SPDX-License-Identifier: MIT +# -*- 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 diff --git a/pyaedt/workflows/templates/__init__.py b/pyaedt/workflows/templates/__init__.py index 3bc3c8e5b19..f10103137e9 100644 --- a/pyaedt/workflows/templates/__init__.py +++ b/pyaedt/workflows/templates/__init__.py @@ -1,6 +1,7 @@ -# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates. -# SPDX-License-Identifier: MIT +# -*- 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 diff --git a/pyaedt/workflows/templates/extension_template.py b/pyaedt/workflows/templates/extension_template.py index 81beff8b5ae..7cfb4586fbf 100644 --- a/pyaedt/workflows/templates/extension_template.py +++ b/pyaedt/workflows/templates/extension_template.py @@ -1,6 +1,7 @@ -# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates. -# SPDX-License-Identifier: MIT +# -*- 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 @@ -42,8 +43,8 @@ def main(extension_args): app = pyaedt.Desktop( - new_desktop_session=False, - specified_version=version, + new_desktop=False, + version=version, port=port, aedt_process_id=aedt_process_id, student_version=is_student, diff --git a/pyaedt/workflows/templates/pyaedt_utils.py b/pyaedt/workflows/templates/pyaedt_utils.py index 7e26a366cf0..108b8f7941f 100644 --- a/pyaedt/workflows/templates/pyaedt_utils.py +++ b/pyaedt/workflows/templates/pyaedt_utils.py @@ -1,6 +1,7 @@ -# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates. -# SPDX-License-Identifier: MIT +# -*- 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 diff --git a/pyaedt/workflows/templates/run_pyedb_toolkit_script.py_build b/pyaedt/workflows/templates/run_pyedb_toolkit_script.py_build new file mode 100644 index 00000000000..37ac2d0db09 --- /dev/null +++ b/pyaedt/workflows/templates/run_pyedb_toolkit_script.py_build @@ -0,0 +1,76 @@ +# Copyright (C) 2023 - 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. + +""" +* * * This script is meant to run in IronPython within AEDT. * * * + +The script executes the PyAEDT workflow. + +""" +import os +import sys + +is_linux = os.name == "posix" + +if is_linux: + import subprocessdotnet as subprocess +else: + import subprocess + +toolkits_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')) + +sys.path.append(toolkits_dir) + +import pyaedt_utils + + +def main(): + try: + # Get AEDT version + short_version = oDesktop.GetVersion()[2:6].replace(".", "") + oDesktop.AddMessage("", "", 0, "Toolkit launched. Wait.") + # CPython interpreter + python_exe = r"##PYTHON_EXE##" + # Python script + pyaedt_script = r"##PYTHON_SCRIPT##" + # Check if CPython interpreter and AEDT release match + python_exe = pyaedt_utils.sanitize_interpreter_path(python_exe, short_version) + # Check python executable + python_exe_flag = pyaedt_utils.check_file(python_exe, oDesktop) + if not python_exe_flag: + return + # Check script file + pyaedt_script_flag = pyaedt_utils.check_file(pyaedt_script, oDesktop) + if not pyaedt_script_flag: + return + # Add environment variables + pyaedt_utils.environment_variables(oDesktop) + # Run workflow + my_env = dict(os.environ.copy()) + command = [python_exe, pyaedt_script] + subprocess.Popen(command, env=my_env) + except Exception as e: + pyaedt_utils.show_error(str(e), oDesktop) + + +if __name__ == "__main__": + main() diff --git a/pyaedt/workflows/twinbuilder/__init__.py b/pyaedt/workflows/twinbuilder/__init__.py index 3bc3c8e5b19..f10103137e9 100644 --- a/pyaedt/workflows/twinbuilder/__init__.py +++ b/pyaedt/workflows/twinbuilder/__init__.py @@ -1,6 +1,7 @@ -# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates. -# SPDX-License-Identifier: MIT +# -*- 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 diff --git a/pyaedt/workflows/twinbuilder/convert_to_circuit.py b/pyaedt/workflows/twinbuilder/convert_to_circuit.py index 1a1aa2e9b51..2a7e2c6d255 100644 --- a/pyaedt/workflows/twinbuilder/convert_to_circuit.py +++ b/pyaedt/workflows/twinbuilder/convert_to_circuit.py @@ -1,6 +1,7 @@ -# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates. -# SPDX-License-Identifier: MIT +# -*- 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 @@ -25,8 +26,8 @@ import sys import pyaedt -from pyaedt import is_linux from pyaedt.generic.general_methods import read_toml +from pyaedt.generic.settings import is_linux import pyaedt.workflows from pyaedt.workflows.misc import get_aedt_version from pyaedt.workflows.misc import get_arguments @@ -47,8 +48,8 @@ def main(extension_args): app = pyaedt.Desktop( - new_desktop_session=False, - specified_version=version, + new_desktop=False, + version=version, port=port, aedt_process_id=aedt_process_id, student_version=is_student, @@ -67,14 +68,14 @@ def main(extension_args): if active_design.GetDesignType() in ["Twin Builder"]: design_name = active_design.GetName().split(";")[1] - tb = pyaedt.TwinBuilder(designname=design_name, projectname=project_name) + tb = pyaedt.TwinBuilder(design=design_name, project=project_name) else: # pragma: no cover app.logger.error("An active TwinBuilder Design is needed.") sys.exit() catalog = read_toml(os.path.join(pyaedt.__path__[0], "misc", "tb_nexxim_mapping.toml")) scale = catalog["General"]["scale"] - cir = pyaedt.Circuit(designname=tb.design_name + "_Translated") + cir = pyaedt.Circuit(design=tb.design_name + "_Translated") from pyaedt.generic.constants import unit_converter diff --git a/pyproject.toml b/pyproject.toml index 65ff3a1b2b1..9b165f845ab 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,9 +26,8 @@ classifiers = [ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", - "Topic :: Scientific/Engineering :: Libraries", - "Topic :: Scientific/Engineering :: Scientific/Engineering", - "Topic :: Scientific/Engineering :: Scientific/Engineering :: Electronic Design Automation (EDA)", + "Topic :: Software Development :: Libraries", + "Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)", "Topic :: Scientific/Engineering :: Information Analysis", # Additional specific classifiers "Operating System :: OS Independent", @@ -39,7 +38,7 @@ dependencies = [ "jsonschema", "psutil", "pyedb>=0.4.0", - "pytomlpp; python_version < '3.12'", + "pytomlpp", "rpyc>=6.0.0,<6.1", ] @@ -60,10 +59,10 @@ tests = [ "pyvista>=0.38.0,<0.44", # 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.1", + "scikit-rf>=0.30.0,<1.2", "SRTM.py", "utm", - "vtk==9.2.6", + "vtk==9.2.6; python_version < '3.12'", ] dotnet = [ "ansys-pythonnet>=3.1.0rc3", @@ -90,7 +89,7 @@ doc = [ #"pytest-sphinx", "pyvista>=0.38.0,<0.44", "recommonmark", - "scikit-rf>=0.30.0,<1.1", + "scikit-rf>=0.30.0,<1.2", "Sphinx==5.3.0; python_version == '3.7'", "Sphinx>=7.1.0,<7.4; python_version > '3.7'", "sphinx-autobuild==2021.3.14; python_version == '3.7'", @@ -104,7 +103,7 @@ doc = [ #"sphinxcontrib-websupport", "SRTM.py", "utm", - "vtk==9.2.6", + "vtk==9.2.6; python_version < '3.12'", ] doc-no-examples = [ "ansys-sphinx-theme>=0.10.0,<0.17", @@ -135,10 +134,10 @@ 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.1", + "scikit-rf>=0.30.0,<1.2", "SRTM.py", "utm", - "vtk==9.2.6", + "vtk==9.2.6; python_version < '3.12'", ] installer = [ "imageio>=2.30.0,<2.35", @@ -150,10 +149,10 @@ installer = [ "pyvista>=0.38.0,<0.44", # 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.1", + "scikit-rf>=0.30.0,<1.2", "SRTM.py", "utm", - "vtk==9.2.6", + "vtk==9.2.6; python_version < '3.12'", "jupyterlab>=3.6.0,<4.3", "ipython>=7.30.0,<8.26", "ipyvtklink>=0.2.0,<0.2.4", @@ -193,6 +192,7 @@ source = ["pyaedt"] [tool.coverage.report] show_missing = true +omit = ["pyaedt/rpc/*.py"] [tool.pytest.ini_options] minversion = "7.1"