From 2c116d8af8798fcffaed55558e47ff11821f1a62 Mon Sep 17 00:00:00 2001 From: Hui Zhou Date: Wed, 17 Apr 2024 18:48:02 +0200 Subject: [PATCH 01/13] FEATURE: add new class SiwaveDCIRSettings (#383) * add new class SiwaveDCIRSettings * MISC: Auto fixes from pre-commit.com hooks For more information, see https://pre-commit.ci --------- Co-authored-by: ring630 <@gmail.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- src/pyedb/dotnet/edb_core/configuration.py | 7 +++ .../edb_data/siwave_simulation_setup_data.py | 6 +++ .../sim_setup_data/data/siw_dc_ir_settings.py | 46 +++++++++++++++++ src/pyedb/siwave.py | 51 ++++++++++++++++++- .../edb_config_json/setups_siwave_dc.json | 5 +- tests/legacy/system/conftest.py | 7 ++- tests/legacy/system/test_edb_config_json.py | 4 ++ tests/legacy/system/test_siwave.py | 5 +- 8 files changed, 126 insertions(+), 5 deletions(-) create mode 100644 src/pyedb/dotnet/sim_setup_data/data/siw_dc_ir_settings.py diff --git a/src/pyedb/dotnet/edb_core/configuration.py b/src/pyedb/dotnet/edb_core/configuration.py index 967fdabf69..c77a28264e 100644 --- a/src/pyedb/dotnet/edb_core/configuration.py +++ b/src/pyedb/dotnet/edb_core/configuration.py @@ -401,6 +401,13 @@ def _load_setups(self): self._pedb.logger.warning("Setup {} already existing. Editing it.".format(name)) edb_setup = self._pedb.setups[name] edb_setup.set_dc_slider(setup["dc_slider_position"]) + dc_ir_settings = setup.get("dc_ir_settings", None) + if dc_ir_settings: + for k, v in dc_ir_settings.items(): + if k not in dir(edb_setup.dc_ir_settings): + self._pedb.logger.error(f"Invalid keyword {k}") + else: + setattr(edb_setup.dc_ir_settings, k, v) else: if setup_type.lower() == "hfss": if name not in self._pedb.setups: diff --git a/src/pyedb/dotnet/edb_core/edb_data/siwave_simulation_setup_data.py b/src/pyedb/dotnet/edb_core/edb_data/siwave_simulation_setup_data.py index 28e1a738af..a9bb935193 100644 --- a/src/pyedb/dotnet/edb_core/edb_data/siwave_simulation_setup_data.py +++ b/src/pyedb/dotnet/edb_core/edb_data/siwave_simulation_setup_data.py @@ -27,6 +27,7 @@ convert_pydict_to_netdict, ) from pyedb.dotnet.edb_core.utilities.simulation_setup import BaseSimulationSetup +from pyedb.dotnet.sim_setup_data.data.siw_dc_ir_settings import SiwaveDCIRSettings from pyedb.generic.general_methods import is_linux, pyedb_function_handler @@ -1144,6 +1145,11 @@ def create(self, name=None): self.set_dc_slider(1) return self + @property + def dc_ir_settings(self): + """DC IR settings.""" + return SiwaveDCIRSettings(self) + @pyedb_function_handler def get_configurations(self): """Get SIwave DC simulation settings. diff --git a/src/pyedb/dotnet/sim_setup_data/data/siw_dc_ir_settings.py b/src/pyedb/dotnet/sim_setup_data/data/siw_dc_ir_settings.py new file mode 100644 index 0000000000..f0f1f0c3c2 --- /dev/null +++ b/src/pyedb/dotnet/sim_setup_data/data/siw_dc_ir_settings.py @@ -0,0 +1,46 @@ +# 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. + + +class SiwaveDCIRSettings: + """Class for DC IR settings.""" + + def __init__(self, parent): + self._parent = parent + + @property + def export_dc_thermal_data(self): + """Export DC Thermal Data. + + Returns + ------- + bool + ``True`` when activated, ``False`` deactivated. + """ + return self._parent.get_sim_setup_info.SimulationSettings.DCIRSettings.ExportDCThermalData + + @export_dc_thermal_data.setter + def export_dc_thermal_data(self, value): + edb_setup_info = self._parent.get_sim_setup_info + edb_setup_info.SimulationSettings.DCIRSettings.ExportDCThermalData = value + self._parent._edb_object = self._parent._set_edb_setup_info(edb_setup_info) + self._parent._update_setup() diff --git a/src/pyedb/siwave.py b/src/pyedb/siwave.py index f7725fde4c..0b491425f8 100644 --- a/src/pyedb/siwave.py +++ b/src/pyedb/siwave.py @@ -14,6 +14,7 @@ import time from pyedb.dotnet.clr_module import _clr +from pyedb.edb_logger import pyedb_logger from pyedb.generic.general_methods import ( _pythonver, is_ironpython, @@ -65,6 +66,7 @@ def current_version(self): return self.version_keys[0] def __init__(self, specified_version=None): + self._logger = pyedb_logger if is_ironpython: _com = "pythonnet" import System @@ -327,7 +329,6 @@ def export_siwave_report(self, simulation_name, file_path, bkground_color="White bkground_color : str, optional Color of the report's background. The default is ``"White"``. - Returns ------- bool @@ -339,3 +340,51 @@ def export_siwave_report(self, simulation_name, file_path, bkground_color="White while not os.path.exists(file_path): time.sleep(0.1) return True + + @pyedb_function_handler + def run_dc_simulation(self): + """Run DC simulation.""" + self._logger.info("Running DC simulation.") + return self.oproject.ScrRunDcSimulation(1) + + @pyedb_function_handler + def export_icepak_project(self, file_path, dc_simulation_name): + """Exports an Icepak project for standalone use. + + Parameters + ---------- + file_path : str, + Path of the Icepak project. + dc_simulation_name : str + Name of the DC simulation. + + Returns + ------- + bool + ``True`` when successful, ``False`` when failed. + + """ + + self.oproject.ScrExportDcPowerDataToIcepak(True) + self._logger.info("Exporting Icepak project.") + code = self.oproject.ScrExportIcepakProject(file_path, dc_simulation_name) + return True if code == 0 else False + + @pyedb_function_handler + def run_icepak_simulation(self, icepak_simulation_name, dc_simulation_name): + """Runs an Icepak simulation. + + Parameters + ---------- + icepak_simulation_name : str + Name of the Icepak simulation. + dc_simulation_name : str + Name of the DC simulation. + + Returns + ------- + bool + ``True`` when successful, ``False`` when failed. + + """ + return self.oproject.ScrRunIcepakSimulation(icepak_simulation_name, dc_simulation_name) diff --git a/tests/example_models/TEDB/edb_config_json/setups_siwave_dc.json b/tests/example_models/TEDB/edb_config_json/setups_siwave_dc.json index 24d3b47f3e..741ba98d3c 100644 --- a/tests/example_models/TEDB/edb_config_json/setups_siwave_dc.json +++ b/tests/example_models/TEDB/edb_config_json/setups_siwave_dc.json @@ -3,7 +3,10 @@ { "name": "siwave_dc", "type": "siwave_dc", - "dc_slider_position": 1 + "dc_slider_position": 1, + "dc_ir_settings": { + "export_dc_thermal_data": true + } } ] } \ No newline at end of file diff --git a/tests/legacy/system/conftest.py b/tests/legacy/system/conftest.py index d7d97358b4..00bb34978a 100644 --- a/tests/legacy/system/conftest.py +++ b/tests/legacy/system/conftest.py @@ -59,9 +59,12 @@ def _get_folder(self, name): dst = self.local_scratch.copyfolder(src, os.path.join(self._local_folder, os.path.split(src)[-1])) return dst - def get_si_verse(self): + def get_si_verse(self, edbapp=True): aedb = self._get_folder("TEDB/ANSYS-HSD_V1.aedb") - return Edb(aedb, edbversion=desktop_version) + if edbapp: + return Edb(aedb, edbversion=desktop_version) + else: + return aedb def get_multizone_pcb(self): aedb = self._get_folder("multi_zone_project.aedb") diff --git a/tests/legacy/system/test_edb_config_json.py b/tests/legacy/system/test_edb_config_json.py index abd2545dda..2529667e6a 100644 --- a/tests/legacy/system/test_edb_config_json.py +++ b/tests/legacy/system/test_edb_config_json.py @@ -162,3 +162,7 @@ def test_11_package_definitions(self, edb_examples): assert edbapp.definitions.package["package_1"].heatsink.fin_spacing == 0.001 assert edbapp.definitions.package["package_1"].heatsink.fin_thickness == 0.004 edbapp.close() + + def test_12_setup_siwave_dc(self, edb_examples): + edbapp = edb_examples.get_si_verse() + assert edbapp.configuration.load(str(self.local_input_folder / "setups_siwave_dc.json"), apply_file=True) diff --git a/tests/legacy/system/test_siwave.py b/tests/legacy/system/test_siwave.py index 9fe664f624..fc04a0d70e 100644 --- a/tests/legacy/system/test_siwave.py +++ b/tests/legacy/system/test_siwave.py @@ -39,6 +39,7 @@ def init(self, local_scratch): def test_siwave(self): """Create Siwave.""" + siw = Siwave(desktop_version) time.sleep(10) example_project = os.path.join(local_path, "example_models", "siwave", "siw_dc.siw") @@ -47,9 +48,11 @@ def test_siwave(self): assert siw assert siw.close_project() siw.open_project(target_path) - siw.oproject.ScrRunDcSimulation(1) + siw.run_dc_simulation() export_report = os.path.join(siw.results_directory, "test.htm") assert siw.export_siwave_report("DC IR Sim 3", export_report) export_data = os.path.join(siw.results_directory, "test.txt") assert siw.export_element_data("DC IR Sim 3", export_data) + export_icepak = os.path.join(siw.results_directory, "icepak.aedt") + assert siw.export_icepak_project(export_icepak, "DC IR Sim 3") assert siw.quit_application() From e8614823f55300fd316bb8c110ad39faafc07ae9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Apr 2024 08:29:09 +0200 Subject: [PATCH 02/13] MAINT: Update sphinx requirement from <7.3,>=7.1.0 to >=7.1.0,<7.4 (#381) Updates the requirements on [sphinx](https://github.com/sphinx-doc/sphinx) to permit the latest version. - [Release notes](https://github.com/sphinx-doc/sphinx/releases) - [Changelog](https://github.com/sphinx-doc/sphinx/blob/master/CHANGES.rst) - [Commits](https://github.com/sphinx-doc/sphinx/compare/v7.1.0...v7.3.5) --- updated-dependencies: - dependency-name: sphinx dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index c0afbc2eb8..8c3c2b221e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,7 +54,7 @@ doc = [ "pypandoc>=1.10.0,<1.14", # NOTE: Remove recommonmark once examples are reworked. "recommonmark", - "Sphinx>=7.1.0,<7.3", + "Sphinx>=7.1.0,<7.4", "sphinx-autobuild==2024.2.4; python_version == '3.8'", "sphinx-autobuild==2024.2.4; python_version > '3.8'", "sphinx-copybutton>=0.5.0,<0.6", From 5b82b9b03c80a49dc3d3ff0d6e0abb730bf19a3d Mon Sep 17 00:00:00 2001 From: Hui Zhou Date: Thu, 18 Apr 2024 09:13:43 +0200 Subject: [PATCH 03/13] FEATURE: support list of nets, group all pins (#385) Co-authored-by: ring630 <@gmail.com> --- src/pyedb/dotnet/edb_core/configuration.py | 11 ++++++++++- .../TEDB/edb_config_json/pin_groups.json | 9 +++++++++ tests/legacy/system/test_edb_config_json.py | 4 ++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/pyedb/dotnet/edb_core/configuration.py b/src/pyedb/dotnet/edb_core/configuration.py index c77a28264e..85c1060c99 100644 --- a/src/pyedb/dotnet/edb_core/configuration.py +++ b/src/pyedb/dotnet/edb_core/configuration.py @@ -383,6 +383,7 @@ def _load_sources(self): elif src_type == "current": src_obj = self._pedb.create_current_source(pos_terminal, neg_terminal) src_obj.magnitude = src["magnitude"] + src_obj.name = name @pyedb_function_handler def _load_setups(self): @@ -560,13 +561,21 @@ def _load_spice_models(self): @pyedb_function_handler def _load_pin_groups(self): """Imports pin groups information from JSON.""" + comps = self._pedb.components.components for pg in self.data["pin_groups"]: name = pg["name"] ref_designator = pg["reference_designator"] if "pins" in pg: self._pedb.siwave.create_pin_group(ref_designator, pg["pins"], name) elif "net" in pg: - self._pedb.siwave.create_pin_group_on_net(ref_designator, pg["net"], name) + nets = pg["net"] + nets = nets if isinstance(nets, list) else [nets] + comp = comps[ref_designator] + pins = [p for p, obj in comp.pins.items() if obj.net_name in nets] + self._pedb.siwave.create_pin_group(ref_designator, pins, name) + else: + pins = [i for i in comps[ref_designator].pins.keys()] + self._pedb.siwave.create_pin_group(ref_designator, pins, name) @pyedb_function_handler def _load_nets(self): diff --git a/tests/example_models/TEDB/edb_config_json/pin_groups.json b/tests/example_models/TEDB/edb_config_json/pin_groups.json index d7e4c9aa9f..acd987d82a 100644 --- a/tests/example_models/TEDB/edb_config_json/pin_groups.json +++ b/tests/example_models/TEDB/edb_config_json/pin_groups.json @@ -17,6 +17,15 @@ "name": "U9_AVDD_PLL", "reference_designator": "U9", "pins": ["44"] + }, + { + "name": "U6_ALL_PINS", + "reference_designator": "U6" + }, + { + "name": "J5_TWO_NETS", + "reference_designator": "J5", + "net": ["SFPA_VCCR", "SFPA_VCCT"] } ], "ports": [ diff --git a/tests/legacy/system/test_edb_config_json.py b/tests/legacy/system/test_edb_config_json.py index 2529667e6a..54dc185042 100644 --- a/tests/legacy/system/test_edb_config_json.py +++ b/tests/legacy/system/test_edb_config_json.py @@ -71,6 +71,10 @@ def test_01_create_edb(self): def test_02_pin_groups(self): edbapp = Edb(str(self.local_edb), desktop_version) assert edbapp.configuration.load(str(self.local_input_folder / "pin_groups.json"), apply_file=True) + assert len(edbapp.siwave.pin_groups["U6_ALL_PINS"].pins.keys()) == 96 + assert len(edbapp.siwave.pin_groups["J5_TWO_NETS"].pins.keys()) == 2 + assert edbapp.sources["U9_pin_group_source"] + assert edbapp.ports["U9_pin_group_port"] edbapp.close() def test_03_spice_models(self): From 0cb8d4c700a88a77946380cb5fa4e3607e6bffb2 Mon Sep 17 00:00:00 2001 From: svandenb-dev <74993647+svandenb-dev@users.noreply.github.com> Date: Thu, 18 Apr 2024 16:25:52 +0200 Subject: [PATCH 04/13] FIX_zwro_value_solder_ball_height (#389) --- src/pyedb/dotnet/edb_core/edb_data/components_data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pyedb/dotnet/edb_core/edb_data/components_data.py b/src/pyedb/dotnet/edb_core/edb_data/components_data.py index 16303de972..24fc3627f3 100644 --- a/src/pyedb/dotnet/edb_core/edb_data/components_data.py +++ b/src/pyedb/dotnet/edb_core/edb_data/components_data.py @@ -329,7 +329,7 @@ def solder_ball_height(self): @solder_ball_height.setter def solder_ball_height(self, value): - if "GetSolderBallProperty" in dir(self.component_property) and value: + if "GetSolderBallProperty" in dir(self.component_property): sball_height = round(self._edb.utility.Value(value).ToDouble(), 9) cmp_property = self.component_property solder_ball_prop = cmp_property.GetSolderBallProperty().Clone() From b44d7fa3b5d9ce8cfded742b166f4c5e44a46246 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Morais?= <146729917+SMoraisAnsys@users.noreply.github.com> Date: Thu, 18 Apr 2024 15:08:14 +0000 Subject: [PATCH 05/13] CI: Check title with ansys action (#350) * CI: Check title with ansys action Note: Leverage https://github.com/ansys/actions/issues/446 * CI: Use ansys/actions v6 --- .github/workflows/ci_cd.yml | 28 +++++----------------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/.github/workflows/ci_cd.yml b/.github/workflows/ci_cd.yml index 1dc1c271b4..5e5020b49c 100644 --- a/.github/workflows/ci_cd.yml +++ b/.github/workflows/ci_cd.yml @@ -27,33 +27,15 @@ concurrency: jobs: check_title: - name: Check PR title if: github.event_name == 'pull_request' + name: Check the title of the pull request runs-on: ubuntu-latest steps: - - name: Get PR title - env: - REPOSITORY_OWNER: ${{ github.repository_owner }} - REPOSITORY_NAME: ${{ github.event.repository.name }} - PULL_REQUEST_NUMBER: ${{ github.event.number }} - uses: actions/github-script@v7 + - name: Check commit name + uses: ansys/actions/commit-style@v6 with: - script: | - const response = await github.graphql(`query { - repository(owner: "${{ env.REPOSITORY_OWNER }}", name: "${{ env.REPOSITORY_NAME }}") { - pullRequest(number: ${{ env.PULL_REQUEST_NUMBER }}) { - title - } - } - }`) - const title = response.repository.pullRequest.title; - core.exportVariable('PR_TITLE', title); - - name: Check PR title format - run: | - if ! [[ "${{ env.PR_TITLE }}" =~ ^(FEATURE:|REFACT:|IMPROVE:|TEST:|DOC:|MAINT:|FIX:|CHORE:|CI:).* ]]; then - echo "ERROR: Pull Request title does not start with one of the valid prefixes: FEATURE:, REFACT:, IMPROVE:, TEST:, DOC:, MAINT:, FIX:, CHORE:, or CI:" - exit 1 - fi + token: ${{ secrets.GITHUB_TOKEN }} + use-upper-case: true doc-style: name: Documentation style check From 3e32c15f1af3b2b269a3987ddfe787165c362b40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Morais?= <146729917+SMoraisAnsys@users.noreply.github.com> Date: Fri, 19 Apr 2024 13:57:09 +0000 Subject: [PATCH 06/13] TEST: Materials load_material method (#387) * TESTS: Extend tests with load_material * CHORE: Remove cover of loss_tangent * MISC: Auto fixes from pre-commit.com hooks For more information, see https://pre-commit.ci * TESTS: Load dieletric or conductor * MISC: Auto fixes from pre-commit.com hooks For more information, see https://pre-commit.ci * TESTS: Fix test expected value --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- src/pyedb/dotnet/edb_core/materials.py | 16 ++++++++-------- tests/legacy/system/test_edb_materials.py | 23 +++++++++++++++++++++++ 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/pyedb/dotnet/edb_core/materials.py b/src/pyedb/dotnet/edb_core/materials.py index 98f1ef3942..73a35808ae 100644 --- a/src/pyedb/dotnet/edb_core/materials.py +++ b/src/pyedb/dotnet/edb_core/materials.py @@ -413,7 +413,7 @@ def update(self, input_dict: dict): for attribute in ATTRIBUTES: if attribute in input_dict: setattr(self, attribute, input_dict[attribute]) - if "loss_tangent" in input_dict: + if "loss_tangent" in input_dict: # pragma: no cover setattr(self, "loss_tangent", input_dict["loss_tangent"]) # Update DS model @@ -534,7 +534,7 @@ def add_material(self, name: str, **kwargs): material_def = self.__edb_definition.MaterialDef.Create(self.__edb.active_db, name) material = Material(self.__edb, material_def) attributes_input_dict = {key: val for (key, val) in kwargs.items() if key in ATTRIBUTES + DC_ATTRIBUTES} - if "loss_tangent" in kwargs: + if "loss_tangent" in kwargs: # pragma: no cover warnings.warn( "This key is deprecated in versions >0.7.0 and will soon be removed. " "Use key dielectric_loss_tangent instead.", @@ -637,7 +637,7 @@ def add_djordjevicsarkar_dielectric( material = self.__add_dielectric_material_model(name, material_model) for key, value in kwargs.items(): setattr(material, key, value) - if "loss_tangent" in kwargs: + if "loss_tangent" in kwargs: # pragma: no cover warnings.warn( "This key is deprecated in versions >0.7.0 and will soon be removed. " "Use key dielectric_loss_tangent instead.", @@ -703,7 +703,7 @@ def add_debye_material( material = self.__add_dielectric_material_model(name, material_model) for key, value in kwargs.items(): setattr(material, key, value) - if "loss_tangent" in kwargs: + if "loss_tangent" in kwargs: # pragma: no cover warnings.warn( "This key is deprecated in versions >0.7.0 and will soon be removed. " "Use key dielectric_loss_tangent instead.", @@ -766,7 +766,7 @@ def add_multipole_debye_material( material = self.__add_dielectric_material_model(name, material_model) for key, value in kwargs.items(): setattr(material, key, value) - if "loss_tangent" in kwargs: + if "loss_tangent" in kwargs: # pragma: no cover warnings.warn( "This key is deprecated in versions >0.7.0 and will soon be removed. " "Use key dielectric_loss_tangent instead.", @@ -842,7 +842,7 @@ def update_material(self, material_name, input_dict): material = self[material_name] attributes_input_dict = {key: val for (key, val) in input_dict.items() if key in ATTRIBUTES + DC_ATTRIBUTES} - if "loss_tangent" in input_dict: + if "loss_tangent" in input_dict: # pragma: no cover warnings.warn( "This key is deprecated in versions >0.7.0 and will soon be removed. " "Use key dielectric_loss_tangent instead.", @@ -864,7 +864,7 @@ def load_material(self, material): self.add_conductor_material(material_name, material_conductivity) else: material_permittivity = material["permittivity"] - if "loss_tangent" in material: + if "loss_tangent" in material: # pragma: no cover warnings.warn( "This key is deprecated in versions >0.7.0 and will soon be removed. " "Use key dielectric_loss_tangent instead.", @@ -938,7 +938,7 @@ def load_amat(self, amat_file): if "tangent_delta" in material_properties: material_properties["dielectric_loss_tangent"] = material_properties["tangent_delta"] del material_properties["tangent_delta"] - elif "loss_tangent" in material_properties: + elif "loss_tangent" in material_properties: # pragma: no cover warnings.warn( "This key is deprecated in versions >0.7.0 and will soon be removed. " "Use key dielectric_loss_tangent instead.", diff --git a/tests/legacy/system/test_edb_materials.py b/tests/legacy/system/test_edb_materials.py index 4c25cf3567..3d2590582a 100644 --- a/tests/legacy/system/test_edb_materials.py +++ b/tests/legacy/system/test_edb_materials.py @@ -86,6 +86,7 @@ def test_material_properties(self): for value in VALUES: setattr(material, property, value) assert float(value) == getattr(material, property) + assert 12 == material.loss_tangent def test_material_dc_properties(self): """Evaluate material DC properties.""" @@ -289,3 +290,25 @@ def test_materials_read_materials(self): assert name_to_material[key]["mass_density"] == 8055 assert name_to_material[key]["specific_heat"] == 480 assert name_to_material[key]["thermal_expansion_coefficient"] == 1.08e-005 + + def test_materials_load_conductor_material(self): + """Load conductor material.""" + materials = Materials(self.edbapp) + conductor_material_properties = {"name": MATERIAL_NAME, "conductivity": 2e4} + + assert MATERIAL_NAME not in materials + materials.load_material(conductor_material_properties) + material = materials[MATERIAL_NAME] + assert 2e4 == material.conductivity + + def test_materials_load_dielectric_material(self): + """Load dielectric material.""" + materials = Materials(self.edbapp) + dielectric_material_properties = {"name": MATERIAL_NAME, "permittivity": 12, "loss_tangent": 0.00045} + + assert MATERIAL_NAME not in materials + materials.load_material(dielectric_material_properties) + material = materials[MATERIAL_NAME] + assert 0.00045 == material.loss_tangent + assert 0.00045 == material.dielectric_loss_tangent + assert 12 == material.permittivity From 7a5c4e9a2bcaec43db8c81f2e178ff1abb1a5240 Mon Sep 17 00:00:00 2001 From: Massimo Capodiferro <77293250+maxcapodi78@users.noreply.github.com> Date: Fri, 19 Apr 2024 16:08:53 +0200 Subject: [PATCH 07/13] FIX: Logger (#392) * Fix duplication of logger when Pyaedt logger is initialized. * Fix duplication of logger when Pyaedt logger is initialized. * MISC: Auto fixes from pre-commit.com hooks For more information, see https://pre-commit.ci * Fix duplication of logger when Pyaedt logger is initialized. * MISC: Auto fixes from pre-commit.com hooks For more information, see https://pre-commit.ci * Fix duplication of logger when Pyaedt logger is initialized. * MISC: Auto fixes from pre-commit.com hooks For more information, see https://pre-commit.ci --------- Co-authored-by: maxcapodi78 Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- src/pyedb/dotnet/edb_core/dotnet/database.py | 9 ++++--- src/pyedb/edb_logger.py | 16 ++++++++++- src/pyedb/generic/settings.py | 28 ++++++++++++++------ 3 files changed, 40 insertions(+), 13 deletions(-) diff --git a/src/pyedb/dotnet/edb_core/dotnet/database.py b/src/pyedb/dotnet/edb_core/dotnet/database.py index b2ba29945c..0fef1ecca0 100644 --- a/src/pyedb/dotnet/edb_core/dotnet/database.py +++ b/src/pyedb/dotnet/edb_core/dotnet/database.py @@ -721,10 +721,11 @@ def __init__(self, edbversion, student_version=False): """Initialize DLLs.""" from pyedb.dotnet.clr_module import _clr, edb_initialized - if settings.enable_screen_logs: - self._logger.enable_stdout_log() - else: # pragma: no cover - self._logger.disable_stdout_log() + if not settings.use_pyaedt_log: + if settings.enable_screen_logs: + self._logger.enable_stdout_log() + else: # pragma: no cover + self._logger.disable_stdout_log() if not edb_initialized: # pragma: no cover self._logger.error("Failed to initialize Dlls.") return diff --git a/src/pyedb/edb_logger.py b/src/pyedb/edb_logger.py index 608d2f9d1b..9e821e2949 100644 --- a/src/pyedb/edb_logger.py +++ b/src/pyedb/edb_logger.py @@ -415,4 +415,18 @@ def glb(self): return self._global -pyedb_logger = EdbLogger(to_stdout=settings.enable_screen_logs) +logger = logging.getLogger("Global") +if any("aedt_logger" in str(i) for i in logger.filters): + from pyaedt.generic.settings import settings as pyaedt_settings + + from pyedb.generic.settings import settings as pyaedb_settings + + pyedb_logger = pyaedt_settings.logger + pyaedb_settings.use_pyaedt_log = True + pyaedb_settings.logger = pyedb_logger + +else: + pyedb_logger = EdbLogger(to_stdout=settings.enable_screen_logs) + from pyedb.generic.settings import settings as pyaedb_settings + + pyaedb_settings.logger = pyedb_logger diff --git a/src/pyedb/generic/settings.py b/src/pyedb/generic/settings.py index 064d9ac225..4c1f151a7c 100644 --- a/src/pyedb/generic/settings.py +++ b/src/pyedb/generic/settings.py @@ -59,6 +59,26 @@ def __init__(self): self._global_log_file_size = 10 self._lsf_queue = None self._edb_environment_variables = {} + self._use_pyaedt_log = False + self._logger = None + + @property + def logger(self): + """Active logger.""" + return self._logger + + @logger.setter + def logger(self, val): + self._logger = val + + @property + def use_pyaedt_log(self): + """Flag that disable Edb log when PyAEDT is used.""" + return self._use_pyaedt_log + + @use_pyaedt_log.setter + def use_pyaedt_log(self, value): + self._use_pyaedt_log = value @property def edb_environment_variables(self): @@ -130,14 +150,6 @@ def enable_debug_methods_argument_logger(self): def enable_debug_methods_argument_logger(self, val): self._enable_debug_methods_argument_logger = val - @property - def logger(self): - """Active logger.""" - try: - return logging.getLogger("Global") - except: # pragma: no cover - return logging.getLogger(__name__) - @property def enable_error_handler(self): """Flag for enabling and disabling the internal PyEDB error handling.""" From 31057900da8ff6199fe7de9791e144cabf9ed15b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Morais?= <146729917+SMoraisAnsys@users.noreply.github.com> Date: Mon, 22 Apr 2024 11:18:57 +0000 Subject: [PATCH 08/13] FIX: Precommit by removing unused import (#397) --- src/pyedb/generic/settings.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pyedb/generic/settings.py b/src/pyedb/generic/settings.py index 4c1f151a7c..336944b303 100644 --- a/src/pyedb/generic/settings.py +++ b/src/pyedb/generic/settings.py @@ -20,7 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -import logging import os import time From 85f7233c3387fd28fae543cc35315d4a7819b115 Mon Sep 17 00:00:00 2001 From: svandenb-dev <74993647+svandenb-dev@users.noreply.github.com> Date: Mon, 22 Apr 2024 15:21:13 +0200 Subject: [PATCH 09/13] release 0.9.dev0 (#394) --- src/pyedb/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pyedb/__init__.py b/src/pyedb/__init__.py index d58f041682..6bbbfad487 100644 --- a/src/pyedb/__init__.py +++ b/src/pyedb/__init__.py @@ -44,7 +44,7 @@ def custom_show_warning(message, category, filename, lineno, file=None, line=Non # pyedb_path = os.path.dirname(__file__) -__version__ = "0.8.dev0" +__version__ = "0.9.dev0" version = __version__ # From 9c4cebb6ef1157613c66f4447f88b497f900e633 Mon Sep 17 00:00:00 2001 From: gkorompi <156683163+gkorompi@users.noreply.github.com> Date: Tue, 23 Apr 2024 15:59:33 +0300 Subject: [PATCH 10/13] FIX: add types create_pingroup_from_pins (#391) * FEATURE: add types create_pingroup_from_pins * Update components.py * Update components.py --- src/pyedb/dotnet/edb_core/components.py | 11 +++++++++-- tests/legacy/system/test_edb_components.py | 10 ++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/pyedb/dotnet/edb_core/components.py b/src/pyedb/dotnet/edb_core/components.py index ac699c30fe..f5e9bde2eb 100644 --- a/src/pyedb/dotnet/edb_core/components.py +++ b/src/pyedb/dotnet/edb_core/components.py @@ -879,7 +879,7 @@ def create_port_on_component( Type of port to create. ``CoaxPort`` generates solder balls. ``CircuitPort`` generates circuit ports on pins belonging to the net list. do_pingroup : bool - True activate pingroup during port creation (only used with combination of CoaxPort), + True activate pingroup during port creation (only used with combination of CircPort), False will take the closest reference pin and generate one port per signal pin. refnet : string or list of string. list of the reference net. @@ -1335,7 +1335,7 @@ def add_rlc_boundary(self, component=None, circuit_type=True): return True @pyedb_function_handler() - def _create_pin_group_terminal(self, pingroup, isref=False, term_name=None): + def _create_pin_group_terminal(self, pingroup, isref=False, term_name=None, term_type="circuit"): """Creates an EDB pin group terminal from a given EDB pin group. Parameters @@ -1343,10 +1343,13 @@ def _create_pin_group_terminal(self, pingroup, isref=False, term_name=None): pingroup : Edb pin group. isref : bool + Specify if this terminal a reference terminal. term_name : Terminal name (Optional). If not provided default name is Component name, Pin name, Net name. str. + term_type: Type of terminal, gap, circuit or auto. + str. Returns ------- Edb pin group terminal. @@ -1360,6 +1363,10 @@ def _create_pin_group_terminal(self, pingroup, isref=False, term_name=None): pingroup_term = self._edb.cell.terminal.PinGroupTerminal.Create( self._active_layout, pingroup.GetNet(), term_name, pingroup, isref ) + if term_type == "circuit": + pingroup_term.SetIsCircuitPort(True) + elif term_type == "auto": + pingroup_term.SetIsAutoPort(True) return pingroup_term @pyedb_function_handler() diff --git a/tests/legacy/system/test_edb_components.py b/tests/legacy/system/test_edb_components.py index 0eb87f0f7a..71afbdb542 100644 --- a/tests/legacy/system/test_edb_components.py +++ b/tests/legacy/system/test_edb_components.py @@ -569,3 +569,13 @@ def test_solder_ball_getter_setter(self): diam1, diam2 = cmp.solder_ball_diameter assert round(diam1, 6) == 100e-6 assert round(diam2, 6) == 100e-6 + + def test_create_pingroup_from_pins_types(self): + example_folder = os.path.join(local_path, "example_models", test_subfolder) + source_path_edb = os.path.join(example_folder, "ANSYS-HSD_V1.aedb") + target_path_edb = os.path.join(self.local_scratch.path, "test_component", "test.aedb") + self.local_scratch.copyfolder(source_path_edb, target_path_edb) + edbapp = Edb(target_path_edb, desktop_version) + assert edbapp.components.create_pingroup_from_pins([*edbapp.components.components["Q1"].pins.values()]) + assert edbapp.components._create_pin_group_terminal(edbapp.padstacks.pingroups[0], term_type="circuit") + edbapp.close() From 5d672a92755073d9568f6944a5870ba9661eadee Mon Sep 17 00:00:00 2001 From: gkorompi <156683163+gkorompi@users.noreply.github.com> Date: Wed, 24 Apr 2024 14:59:47 +0300 Subject: [PATCH 11/13] FIX: comment fix (#409) --- src/pyedb/dotnet/edb_core/stackup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pyedb/dotnet/edb_core/stackup.py b/src/pyedb/dotnet/edb_core/stackup.py index 49a0609d82..74bac3cf86 100644 --- a/src/pyedb/dotnet/edb_core/stackup.py +++ b/src/pyedb/dotnet/edb_core/stackup.py @@ -2264,7 +2264,7 @@ def import_stackup(self, file_path): >>> edb.stackup.import_stackup("stackup.xml") """ - self._logger.warning("Method export_stackup is deprecated. Use .export.") + self._logger.warning("Method import_stackup is deprecated. Use .load") return self.load(file_path) @pyedb_function_handler() From d135483cd94cb87d8c27c2ae67de302718430f4b Mon Sep 17 00:00:00 2001 From: Hui Zhou Date: Wed, 24 Apr 2024 14:29:52 +0200 Subject: [PATCH 12/13] FEAT: Siwave icepak settings (#404) * FEATURE: add icepak property siwave.py * FEATURE: update edb_example class. * FEATURE: add unittest * MISC: Auto fixes from pre-commit.com hooks For more information, see https://pre-commit.ci * Fix PR tittle --------- Co-authored-by: ring630 <@gmail.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- src/pyedb/dotnet/edb_core/siwave.py | 31 + .../siwave/icepak_component.pwrd | 854 ++++++++++++++++++ tests/legacy/system/conftest.py | 41 +- tests/legacy/system/test_edb.py | 10 + 4 files changed, 925 insertions(+), 11 deletions(-) create mode 100644 tests/example_models/siwave/icepak_component.pwrd diff --git a/src/pyedb/dotnet/edb_core/siwave.py b/src/pyedb/dotnet/edb_core/siwave.py index 31f6210c0a..56695a478c 100644 --- a/src/pyedb/dotnet/edb_core/siwave.py +++ b/src/pyedb/dotnet/edb_core/siwave.py @@ -1454,3 +1454,34 @@ def place_voltage_probe( p_terminal = self._pedb.get_point_terminal(name, positive_net_name, positive_location, positive_layer) n_terminal = self._pedb.get_point_terminal(name + "_ref", negative_net_name, negative_location, negative_layer) return self._pedb.create_voltage_probe(p_terminal, n_terminal) + + @property + def icepak_use_minimal_comp_defaults(self): + """Icepak default setting. If "True", only resistor are active in Icepak simulation. + The power dissipation of the resistors are calculated from DC results. + """ + siwave_id = self._pedb.edb_api.ProductId.SIWave + cell = self._pedb.active_cell._active_cell + _, value = cell.GetProductProperty(siwave_id, 422, "") + return bool(value) + + @icepak_use_minimal_comp_defaults.setter + def icepak_use_minimal_comp_defaults(self, value): + value = "True" if bool(value) else "" + siwave_id = self._pedb.edb_api.ProductId.SIWave + cell = self._pedb.active_cell._active_cell + cell.SetProductProperty(siwave_id, 422, value) + + @property + def icepak_component_file(self): + """Icepak component file path.""" + siwave_id = self._pedb.edb_api.ProductId.SIWave + cell = self._pedb.active_cell._active_cell + _, value = cell.GetProductProperty(siwave_id, 420, "") + return value + + @icepak_component_file.setter + def icepak_component_file(self, value): + siwave_id = self._pedb.edb_api.ProductId.SIWave + cell = self._pedb.active_cell._active_cell + cell.SetProductProperty(siwave_id, 420, value) diff --git a/tests/example_models/siwave/icepak_component.pwrd b/tests/example_models/siwave/icepak_component.pwrd new file mode 100644 index 0000000000..0a424fee9b --- /dev/null +++ b/tests/example_models/siwave/icepak_component.pwrd @@ -0,0 +1,854 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/legacy/system/conftest.py b/tests/legacy/system/conftest.py index 00bb34978a..228ebd3700 100644 --- a/tests/legacy/system/conftest.py +++ b/tests/legacy/system/conftest.py @@ -49,25 +49,44 @@ class EdbExamples: def __init__(self, local_scratch): self.local_scratch = local_scratch - - @property - def _local_folder(self): - return os.path.join(self.local_scratch.path, generate_random_string(6)) - - def _get_folder(self, name): - src = os.path.join(example_models_path, name) - dst = self.local_scratch.copyfolder(src, os.path.join(self._local_folder, os.path.split(src)[-1])) + self.example_models_path = example_models_path + self._test_folder = "" + + def get_local_file_folder(self, name): + return os.path.join(self.local_scratch.path, name) + + def _create_test_folder(self): + """Create a local folder under `local_scratch`.""" + self._test_folder = os.path.join(self.local_scratch.path, generate_random_string(6)) + return self._test_folder + + def _copy_file_folder_into_local_folder(self, file_folder_path): + src = os.path.join(self.example_models_path, file_folder_path) + local_folder = self._create_test_folder() + file_folder_name = os.path.join(local_folder, os.path.split(src)[-1]) + dst = self.local_scratch.copyfolder(src, file_folder_name) return dst - def get_si_verse(self, edbapp=True): - aedb = self._get_folder("TEDB/ANSYS-HSD_V1.aedb") + def get_si_verse(self, edbapp=True, additional_files_folders=""): + aedb = self._copy_file_folder_into_local_folder("TEDB/ANSYS-HSD_V1.aedb") + if additional_files_folders: + files = ( + additional_files_folders if isinstance(additional_files_folders, list) else [additional_files_folders] + ) + for f in files: + src = os.path.join(self.example_models_path, f) + file_folder_name = os.path.join(self._test_folder, os.path.split(src)[-1]) + if os.path.isfile(src): + self.local_scratch.copyfile(src, file_folder_name) + else: + self.local_scratch.copyfolder(src, file_folder_name) if edbapp: return Edb(aedb, edbversion=desktop_version) else: return aedb def get_multizone_pcb(self): - aedb = self._get_folder("multi_zone_project.aedb") + aedb = self._copy_file_folder_into_local_folder("multi_zone_project.aedb") return Edb(aedb, edbversion=desktop_version) diff --git a/tests/legacy/system/test_edb.py b/tests/legacy/system/test_edb.py index 949e8ba3b3..7185e6e28c 100644 --- a/tests/legacy/system/test_edb.py +++ b/tests/legacy/system/test_edb.py @@ -1732,3 +1732,13 @@ def test_multizone(self, edb_examples): assert defined_ports assert project_connexions edbapp.close_edb() + + def test_icepak(self, edb_examples): + edbapp = edb_examples.get_si_verse(additional_files_folders=["siwave/icepak_component.pwrd"]) + edbapp.siwave.icepak_use_minimal_comp_defaults = True + assert edbapp.siwave.icepak_use_minimal_comp_defaults + edbapp.siwave.icepak_use_minimal_comp_defaults = False + assert not edbapp.siwave.icepak_use_minimal_comp_defaults + edbapp.siwave.icepak_component_file = edb_examples.get_local_file_folder("siwave/icepak_component.pwrd") + assert edbapp.siwave.icepak_component_file == edb_examples.get_local_file_folder("siwave/icepak_component.pwrd") + edbapp.close() From 0f0518d753f7bfb828a9f3cee9d59565ac963f21 Mon Sep 17 00:00:00 2001 From: gkorompi <156683163+gkorompi@users.noreply.github.com> Date: Wed, 24 Apr 2024 15:47:04 +0300 Subject: [PATCH 13/13] FIX: do_pingroup (#406) --- src/pyedb/dotnet/edb_core/components.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/pyedb/dotnet/edb_core/components.py b/src/pyedb/dotnet/edb_core/components.py index f5e9bde2eb..fff4829809 100644 --- a/src/pyedb/dotnet/edb_core/components.py +++ b/src/pyedb/dotnet/edb_core/components.py @@ -1016,17 +1016,10 @@ def create_port_on_component( else: self._logger.info("No pins found on component {} for the net {}".format(component, net)) else: - ref_pin_group = self.create_pingroup_from_pins(ref_pins) - if not ref_pin_group: - self._logger.warning("failed to create reference pin group") - return False - ref_pin_group_term = self._create_pin_group_terminal(ref_pin_group, isref=True) for net in net_list: pins = [pin for pin in cmp_pins if pin.GetNet().GetName() == net] for pin in pins: - pin_group = self.create_pingroup_from_pins([pin]) - pin_group_term = self._create_pin_group_terminal(pin_group, isref=False) - pin_group_term.SetReferenceTerminal(ref_pin_group_term) + self.create_port_on_pins(component, pin, ref_pins) return True @pyedb_function_handler() @@ -2302,7 +2295,7 @@ def get_pin_from_component(self, component, netName=None, pinName=None): Filter on the net name as an alternative to ``pinName``. The default is ``None``. pinName : str, optional - Filter on the pin name an an alternative to + Filter on the pin name an alternative to ``netName``. The default is ``None``. Returns