diff --git a/doc/changelog.d/7264.added.md b/doc/changelog.d/7264.added.md new file mode 100644 index 00000000000..fed1ec5eeab --- /dev/null +++ b/doc/changelog.d/7264.added.md @@ -0,0 +1 @@ +Improve consistency diff --git a/src/ansys/aedt/core/application/design.py b/src/ansys/aedt/core/application/design.py index 7eff49a2cb5..e5219fdb8b9 100644 --- a/src/ansys/aedt/core/application/design.py +++ b/src/ansys/aedt/core/application/design.py @@ -2854,37 +2854,40 @@ def import_dataset1d( >>> oProject.AddDataset >>> oDesign.AddDataset """ - input_file = Path(input_file) - with open_file(input_file, "r") as f: - lines = f.read().splitlines() - header = lines[0] - points = lines[1:] - - header_list = header.split("\t") - units = ["", ""] - cont = 0 - for h in header_list: - result = re.search(r"\[([A-Za-z0-9_]+)\]", h) - if result: - units[cont] = result.group(1) - cont += 1 + in_file = Path(input_file) + if in_file.is_file(): + with in_file.open(encoding="utf-8") as f: + lines = f.read().splitlines() + header = lines[0] + points = lines[1:] - xlist = [] - ylist = [] - for item in points: - xlist.append(float(item.split()[0])) - ylist.append(float(item.split()[1])) + header_list = header.split("\t") + units = ["", ""] + cont = 0 + for h in header_list: + result = re.search(r"\[([A-Za-z0-9_]+)\]", h) + if result: + units[cont] = result.group(1) + cont += 1 - if not name: - name = input_file.stem + xlist = [] + ylist = [] + for item in points: + xlist.append(float(item.split()[0])) + ylist.append(float(item.split()[1])) - if name[0] == "$": - name = name[1:] - is_project_dataset = True + if not name: + name = input_file.stem - return self.create_dataset( - name, xlist, ylist, is_project_dataset=is_project_dataset, x_unit=units[0], y_unit=units[1], sort=sort - ) + if name[0] == "$": + name = name[1:] + is_project_dataset = True + + return self.create_dataset( + name, xlist, ylist, is_project_dataset=is_project_dataset, x_unit=units[0], y_unit=units[1], sort=sort + ) + else: + raise FileNotFoundError(f"Input file '{in_file}' does not exist.") @pyaedt_function_handler() def import_dataset3d( diff --git a/src/ansys/aedt/core/modeler/cad/primitives.py b/src/ansys/aedt/core/modeler/cad/primitives.py index fa86a8200ab..095b8c164e7 100644 --- a/src/ansys/aedt/core/modeler/cad/primitives.py +++ b/src/ansys/aedt/core/modeler/cad/primitives.py @@ -27,6 +27,7 @@ from __future__ import annotations import copy +import fnmatch import math import os from pathlib import Path @@ -4496,9 +4497,11 @@ def create_faceted_bondwire_from_true_surface( str Name of the bondwire created. """ - old_bondwire = self.get_object_from_name(assignment) - if not old_bondwire: - return False + objects = self.get_objects_by_name(assignment) + if objects: + old_bondwire = objects[0] + else: + raise ValueError(f"Assignment {assignment} does not match an object.") edges = old_bondwire.edges faces = old_bondwire.faces centers = [] @@ -7601,7 +7604,57 @@ def get_obj_id(self, assignment: str) -> int | None: return None @pyaedt_function_handler() - def get_object_from_name(self, assignment: str) -> Object3d: + def get_objects_by_name( + self, + assignment: str, + case_sensitive: bool = True, + ) -> list[Object3d]: + """Return the objects whose names match a wildcard pattern. + + The ``*`` character acts as a wildcard that matches any sequence of + characters (including none). The matching mode is inferred + automatically from the position of ``*`` in ``assignment``: + + Parameters + ---------- + assignment : str + Wildcard pattern to match against object names. + Use ``*`` as a wildcard for any sequence of characters. + case_sensitive : bool, optional + Whether the match is case-sensitive. The default is ``True``. + + Returns + ------- + list of :class:`ansys.aedt.core.modeler.cad.object_3d.Object3d` + Objects whose names satisfy the pattern. + + Examples + -------- + # Exact match + >>> objs = modeler.get_objects_by_name("Patch_1") + + # All objects whose name starts with "Substrate" + >>> objs = modeler.get_objects_by_name("Substrate*") + + # All objects whose name ends with "_gnd" + >>> objs = modeler.get_objects_by_name("*_gnd") + + # All objects whose name contains "patch" + >>> objs = modeler.get_objects_by_name("*patch*", case_sensitive=False) + + # Mid-string wildcard: names like "Sub_1", "Sub_gnd_1". + >>> objs = modeler.get_objects_by_name("Sub*_1") + """ + names = list(self.objects_by_name.keys()) + if case_sensitive: + matched = [n for n in names if fnmatch.fnmatchcase(n, assignment)] + else: + pat = assignment.lower() + matched = [n for n in names if fnmatch.fnmatchcase(n.lower(), pat)] + return [self.objects_by_name[n] for n in matched] + + @pyaedt_function_handler() + def get_object_from_name(self, assignment: str) -> Object3d | None: """Return the object from an object name. Parameters @@ -7616,7 +7669,6 @@ def get_object_from_name(self, assignment: str) -> Object3d: """ if assignment in self.object_names: - # object_id = self.get_obj_id(objname) return self.objects[assignment] @pyaedt_function_handler() diff --git a/src/ansys/aedt/core/modules/material.py b/src/ansys/aedt/core/modules/material.py index 07e72dce532..084e448b4cc 100644 --- a/src/ansys/aedt/core/modules/material.py +++ b/src/ansys/aedt/core/modules/material.py @@ -38,6 +38,8 @@ """ import copy +import csv +from pathlib import Path from ansys.aedt.core.base import PyAedtBase from ansys.aedt.core.generic.constants import CSS4_COLORS @@ -430,7 +432,7 @@ def value(self) -> list[float] | float: return [i.value for i in self._property_value] @value.setter - def value(self, val: list[float] | float) -> None: + def value(self, val: str | list | Path | float | int) -> None: if isinstance(val, list) and isinstance(val[0], list): self._property_value[0].value = val self.set_non_linear() @@ -452,6 +454,22 @@ def value(self, val: list[float] | float) -> None: if len(val) == 4: self._property_value[0].value = val self._material._update_props(self.name, val, update_aedt=self._material._material_update) + elif isinstance(val, Path) and val.suffix in [".csv", ".tab"]: + val = Path(val) + if not val.is_file(): + raise FileNotFoundError(f"Argument {val} is not a file.") + datalist = [] + with open(val) as f: + reader = csv.reader(f, delimiter="\t") + next(reader) + for row in reader: + if len(row) != 2: + raise ValueError(f"Expected 2 columns, got {len(row)}") + if not (is_number(row[0]) and is_number(row[1])): + raise ValueError(f"Expected numeric values, got {row[0]} and {row[1]}") + datalist.append([float(row[0]), float(row[1])]) + self.value = datalist + else: self.type = "simple" self._property_value[0].value = val @@ -2777,27 +2795,29 @@ def __init__(self, materiallib, name: str, props=None, material_update: bool = T else: self.physics_type = ["Thermal"] self._props["PhysicsTypes"] = dict({"set": ["Thermal"]}) - for property in SurfMatProperties.aedtname: - if property in self._props: + for surface_property in SurfMatProperties.aedtname: + if surface_property in self._props: mods = None if "ModifierData" in self._props: modifiers = self._props["ModifierData"]["ThermalModifierData"]["all_thermal_modifiers"] for mod in modifiers: if isinstance(modifiers[mod], list): for one_tm in modifiers[mod]: - if one_tm["Property:"] == property: + if one_tm["Property:"] == surface_property: if mods: mods = [mods] mods.append(one_tm) else: mods = one_tm else: - if modifiers[mod]["Property:"] == property: + if modifiers[mod]["Property:"] == surface_property: mods = modifiers[mod] - self.__dict__["_" + property] = MatProperty(self, property, self._props[property], mods) + self.__dict__["_" + surface_property] = MatProperty( + self, surface_property, self._props[surface_property], mods + ) else: - self.__dict__["_" + property] = MatProperty( - self, property, SurfMatProperties.get_defaultvalue(aedtname=property) + self.__dict__["_" + surface_property] = MatProperty( + self, surface_property, SurfMatProperties.get_defaultvalue(aedtname=surface_property) ) @property diff --git a/tests/system/general/example_models/T03/ds_1d_invalid.tab b/tests/system/general/example_models/T03/ds_1d_invalid.tab new file mode 100644 index 00000000000..dc63c9ebdb7 --- /dev/null +++ b/tests/system/general/example_models/T03/ds_1d_invalid.tab @@ -0,0 +1,4 @@ +"X [cel]" "Y" +1.5 "hola" +2 3.5 +2 5 diff --git a/tests/system/general/test_3d_modeler.py b/tests/system/general/test_3d_modeler.py index 2c963cd5b40..a3606970e22 100644 --- a/tests/system/general/test_3d_modeler.py +++ b/tests/system/general/test_3d_modeler.py @@ -1298,6 +1298,18 @@ def test_project_sheet_success_with_single_object(aedt_app) -> None: assert sorted(EXPECTED_POSITIONS) == sorted(positions), "Object has not the expected vertices positions" aedt_app.modeler.delete(aedt_app.modeler.object_names) + box = aedt_app.modeler.create_box([-10, -10, -10], [20, 20, 20], "box_project_operation") + name = box.name + assert aedt_app.modeler.get_objects_by_name(name.upper(), case_sensitive=False) + assert not aedt_app.modeler.get_objects_by_name(name.upper(), case_sensitive=True) + + assert aedt_app.modeler.get_objects_by_name("box_*", case_sensitive=True) + assert aedt_app.modeler.get_objects_by_name("box_*", case_sensitive=False) + assert aedt_app.modeler.get_objects_by_name("*_project_*", case_sensitive=False) + assert aedt_app.modeler.get_objects_by_name("*_operation", case_sensitive=False) + assert not aedt_app.modeler.get_objects_by_name("Box_*", case_sensitive=True) + assert not aedt_app.modeler.get_objects_by_name("plane_*", case_sensitive=False) + def test_project_sheet_success_with_multiple_objects(aedt_app) -> None: """Test project sheet method with multiple objects.""" diff --git a/tests/system/general/test_design.py b/tests/system/general/test_design.py index 3977e227a08..dc8338207cb 100644 --- a/tests/system/general/test_design.py +++ b/tests/system/general/test_design.py @@ -316,6 +316,8 @@ def test_import_dataset1d(aedt_app) -> None: assert ds4.delete() assert aedt_app.import_dataset1d(filename) assert ds5.delete() + with pytest.raises(FileNotFoundError): + aedt_app.import_dataset1d(TESTS_GENERAL_PATH / "example_models" / TEST_SUBFOLDER / "dummy.tab") def test_import_dataset3d(aedt_app) -> None: diff --git a/tests/system/general/test_materials.py b/tests/system/general/test_materials.py index b985bf0d55a..0a8e1ba18f3 100644 --- a/tests/system/general/test_materials.py +++ b/tests/system/general/test_materials.py @@ -164,6 +164,27 @@ def test_create_material(aedt_app) -> None: mat1.material_appearance = [11, 22] +def test_material_value_file(aedt_app) -> None: + mat1 = aedt_app.materials.add_material("new_copper") + filename = Path(TESTS_GENERAL_PATH) / "example_models" / TEST_SUBFOLDER / "ds_1d.tab" + + with pytest.raises(FileNotFoundError): + aedt_app.materials["new_copper"].permittivity = Path("invented.tab") + + with pytest.raises(ValueError): + filename2 = Path(TESTS_GENERAL_PATH) / "example_models" / TEST_SUBFOLDER / "ds_3d.tab" + aedt_app.materials["new_copper"].permittivity = Path(filename2) + + with pytest.raises(ValueError): + filename3 = Path(TESTS_GENERAL_PATH) / "example_models" / TEST_SUBFOLDER / "ds_1d_invalid.tab" + aedt_app.materials["new_copper"].permittivity = Path(filename3) + + mat1.permittivity = filename + + assert len(mat1.permittivity.value) == 3 + assert isinstance(mat1.permittivity.value, list) + + def test_create_modifiers(aedt_app) -> None: aedt_app.materials.add_material("new_copper") assert aedt_app.materials["new_copper"].mass_density.add_thermal_modifier_free_form(