From bc6ea47e4680347fd56105870174fd496497ec2c Mon Sep 17 00:00:00 2001 From: Sebastien Morais Date: Sun, 26 Jan 2025 12:04:55 +0100 Subject: [PATCH 01/12] WIP --- src/ansys/aedt/core/maxwell.py | 788 +++++++++++++++--------------- src/ansys/aedt/core/mechanical.py | 51 +- tests/unit/test_mechanical.py | 95 ++++ 3 files changed, 509 insertions(+), 425 deletions(-) create mode 100644 tests/unit/test_mechanical.py diff --git a/src/ansys/aedt/core/maxwell.py b/src/ansys/aedt/core/maxwell.py index 03335c48024..0b475193527 100644 --- a/src/ansys/aedt/core/maxwell.py +++ b/src/ansys/aedt/core/maxwell.py @@ -34,6 +34,7 @@ from ansys.aedt.core.application.analysis_3d import FieldAnalysis3D from ansys.aedt.core.application.variables import decompose_variable_value from ansys.aedt.core.generic.constants import SOLUTIONS +from ansys.aedt.core.generic.errors import AEDTRuntimeError from ansys.aedt.core.generic.general_methods import generate_unique_name from ansys.aedt.core.generic.general_methods import is_linux from ansys.aedt.core.generic.general_methods import open_file @@ -169,15 +170,12 @@ def apply_skew( bool ``True`` when successful, ``False`` when failed. """ - if skew_type not in ["Continuous", "Step", "V-Shape", "User Defined"]: - self.logger.error("Invalid skew type.") - return False - if skew_part not in ["Rotor", "Stator"]: - self.logger.error("Invalid skew part.") - return False - if skew_angle_unit not in ["deg", "rad", "degsec", "degmin"]: - self.logger.error("Invalid skew angle unit.") - return False + if skew_type not in ("Continuous", "Step", "V-Shape", "User Defined"): + raise ValueError("Invalid skew type.") + if skew_part not in ("Rotor", "Stator"): + raise ValueError("Invalid skew part.") + if skew_angle_unit not in ("deg", "rad", "degsec", "degmin"): + raise ValueError("Invalid skew angle unit.") if skew_type != "User Defined": arg = { "UseSkewModel": True, @@ -189,8 +187,7 @@ def apply_skew( return self.change_design_settings(arg) else: if not custom_slices_skew_angles or len(custom_slices_skew_angles) != int(number_of_slices): - self.logger.error("Please provide skew angles for each slice.") - return False + raise ValueError("Please provide skew angles for each slice.") arg_slice_table = {"NAME:SkewSliceTable": []} slice_length = decompose_variable_value(self.design_properties["ModelDepth"])[0] / int(number_of_slices) for i in range(int(number_of_slices)): @@ -245,14 +242,16 @@ def set_core_losses(self, assignment, core_loss_on_field=False): >>> m3d.set_core_losses(assignment=["PQ_Core_Bottom", "PQ_Core_Top"],core_loss_on_field=True) >>> m3d.release_desktop(True, True) """ - if self.solution_type in ["EddyCurrent", "Transient"]: - assignment = self.modeler.convert_to_selections(assignment, True) - self.oboundary.SetCoreLoss(assignment, core_loss_on_field) - return True - else: - raise Exception("Core losses is only available with `EddyCurrent` and `Transient` solutions.") - return False + if self.solution_type not in (SOLUTIONS.Maxwell3d.EddyCurrent, SOLUTIONS.Maxwell3d.Transient): + raise AEDTRuntimeError("Solution type does not have matrix parameters")( + "Core losses is only available with `EddyCurrent` and `Transient` solutions." + ) + + assignment = self.modeler.convert_to_selections(assignment, True) + self.oboundary.SetCoreLoss(assignment, core_loss_on_field) + return True + # TODO: Check this method @pyaedt_function_handler(sources="assignment") def assign_matrix( self, @@ -323,7 +322,11 @@ def assign_matrix( """ assignment = self.modeler.convert_to_selections(assignment, True) - if self.solution_type in ["Electrostatic", "ACConduction", "DCConduction"]: + if self.solution_type in ( + SOLUTIONS.Maxwell3d.Electrostatic, + SOLUTIONS.Maxwell3d.ACConduction, + SOLUTIONS.Maxwell3d.DCConduction, + ): turns = ["1"] * len(assignment) branches = None if self.design_type == "Maxwell 2D": @@ -334,47 +337,43 @@ def assign_matrix( self.logger.warning("First Ground is selected") group_sources = self.modeler.convert_to_selections(group_sources, True) if any(item in group_sources for item in assignment): - self.logger.error("Ground must be different than selected sources") - return False + raise AEDTRuntimeError("Ground must be different than selected sources") else: group_sources = None - elif self.solution_type in ["EddyCurrent", "Magnetostatic"]: - if self.solution_type == "Magnetostatic": - if group_sources: - if isinstance(group_sources, dict): - new_group = group_sources.copy() - for element in new_group: - if not all(item in assignment for item in group_sources[element]): - self.logger.warning("Sources in group " + element + " are not selected") - group_sources.pop(element) - if not branches or len(group_sources) != len( - self.modeler.convert_to_selections(branches, True) - ): - if branches: - branches = self.modeler.convert_to_selections(branches, True) - num = abs(len(group_sources) - len(self.modeler.convert_to_selections(branches, True))) - if len(group_sources) < len(self.modeler.convert_to_selections(branches, True)): - branches = branches[:-num] - else: - new_element = [branches[0]] * num - branches.extend(new_element) + elif self.solution_type == SOLUTIONS.Maxwell3d.Magnetostatic: + if group_sources: + if isinstance(group_sources, dict): + new_group = group_sources.copy() + for element in new_group: + if not all(item in assignment for item in group_sources[element]): + self.logger.warning("Sources in group " + element + " are not selected") + group_sources.pop(element) + if not branches or len(group_sources) != len(self.modeler.convert_to_selections(branches, True)): + if branches: + branches = self.modeler.convert_to_selections(branches, True) + num = abs(len(group_sources) - len(self.modeler.convert_to_selections(branches, True))) + if len(group_sources) < len(self.modeler.convert_to_selections(branches, True)): + branches = branches[:-num] else: - branches = [1] * len(group_sources) - elif isinstance(group_sources, list): - group_name = generate_unique_name("Group") - group_sources = {group_name: group_sources} - else: - self.logger.warning("Group of sources is not a dictionary") - group_sources = None - else: - group_sources = None - branches = None - turns = ["1"] * len(assignment) - self.logger.info("Infinite is the only return path option in EddyCurrent.") - return_path = ["infinite"] * len(assignment) + new_element = [branches[0]] * num + branches.extend(new_element) + else: + branches = [1] * len(group_sources) + elif isinstance(group_sources, list): + group_name = generate_unique_name("Group") + group_sources = {group_name: group_sources} + else: + self.logger.warning("Group of sources is not a dictionary") + group_sources = None + elif self.solution_type == SOLUTIONS.Maxwell3d.EddyCurrent: + group_sources = None + branches = None + turns = ["1"] * len(assignment) + self.logger.info("Infinite is the only return path option in EddyCurrent.") + return_path = ["infinite"] * len(assignment) - if self.solution_type not in ["Transient", "ElectricTransient"]: + if self.solution_type not in (SOLUTIONS.Maxwell3d.Transient, SOLUTIONS.Maxwell3d.ElectricTransient): if not matrix_name: matrix_name = generate_unique_name("Matrix") if not turns or len(assignment) != len(self.modeler.convert_to_selections(turns, True)): @@ -395,8 +394,7 @@ def assign_matrix( else: return_path = self.modeler.convert_to_selections(return_path, True) if any(item in return_path for item in assignment): - self.logger.error("Return path specified must not be included in sources") - return False + raise AEDTRuntimeError("Return path specified must not be included in sources") if group_sources and self.solution_type in ["EddyCurrent", "Magnetostatic"]: props = dict({"MatrixEntry": dict({"MatrixEntry": []}), "MatrixGroup": dict({"MatrixGroup": []})}) @@ -404,7 +402,7 @@ def assign_matrix( props = dict({"MatrixEntry": dict({"MatrixEntry": []}), "MatrixGroup": []}) for element in range(len(assignment)): - if self.solution_type == "Magnetostatic" and self.design_type == "Maxwell 2D": + if self.solution_type == SOLUTIONS.Maxwell3d.Magnetostatic and self.design_type == "Maxwell 2D": prop = dict( { "Source": assignment[element], @@ -412,14 +410,18 @@ def assign_matrix( "ReturnPath": return_path[element], } ) - elif self.solution_type == "EddyCurrent": + elif self.solution_type == SOLUTIONS.Maxwell3d.EddyCurrent: prop = dict({"Source": assignment[element], "ReturnPath": return_path[element]}) else: prop = dict({"Source": assignment[element], "NumberOfTurns": turns[element]}) props["MatrixEntry"]["MatrixEntry"].append(prop) if group_sources: - if self.solution_type in ["Electrostatic", "ACConduction", "DCConduction"]: + if self.solution_type in ( + SOLUTIONS.Maxwell3d.Electrostatic, + SOLUTIONS.Maxwell3d.ACConduction, + SOLUTIONS.Maxwell3d.DCConduction, + ): source_list = ",".join(group_sources) props["GroundSources"] = source_list else: @@ -432,8 +434,7 @@ def assign_matrix( cont += 1 return self._create_boundary_object(matrix_name, props, "Matrix") else: - self.logger.error("Solution type does not have matrix parameters") - return False + raise AEDTRuntimeError("Solution type does not have matrix parameters") @pyaedt_function_handler() def setup_ctrlprog( @@ -465,9 +466,8 @@ def setup_ctrlprog( bool ``True`` when successful and ``False`` when failed. """ - if self.solution_type not in ["Transient"]: - self.logger.error("Control Program is only available in Maxwell 2D and 3D Transient solutions.") - return False + if self.solution_type != SOLUTIONS.Maxwell3d.Transient: + raise AEDTRuntimeError("Control Program is only available in Maxwell 2D and 3D Transient solutions.") self._py_file = setupname + ".py" ctl_file_path = os.path.join(self.working_directory, self._py_file) @@ -497,7 +497,8 @@ def setup_ctrlprog( if file_str is not None: with io.open(ctl_file_path, "w", newline="\n") as fo: fo.write(file_str) - assert os.path.exists(ctl_file_path), "Control program file could not be created." + if not os.path.exists(ctl_file_path): + raise FileNotFoundError("Control program file could not be created.") self.oanalysis.EditSetup( setupname, @@ -548,8 +549,7 @@ def eddy_effects_on(self, assignment, enable_eddy_effects=True, enable_displacem """ solid_objects_names = self.get_all_conductors_names() if not solid_objects_names: - self.logger.error("No conductors defined in active design.") - return False + raise AEDTRuntimeError("No conductors defined in active design.") assignment = self.modeler.convert_to_selections(assignment, True) EddyVector = ["NAME:EddyEffectVector"] @@ -557,7 +557,7 @@ def eddy_effects_on(self, assignment, enable_eddy_effects=True, enable_displacem if not enable_eddy_effects: enable_displacement_current = False for obj in solid_objects_names: - if self.solution_type == "EddyCurrent": + if self.solution_type == SOLUTIONS.Maxwell3d.EddyCurrent: if obj in assignment: EddyVector.append( [ @@ -582,7 +582,7 @@ def eddy_effects_on(self, assignment, enable_eddy_effects=True, enable_displacem bool(self.oboundary.GetDisplacementCurrent(obj)), ] ) - if self.solution_type == "Transient": + if self.solution_type == SOLUTIONS.Maxwell3d.Transient: if obj in assignment: EddyVector.append( [ @@ -659,9 +659,8 @@ def setup_y_connection(self, assignment=None): >>> m2d.release_desktop(True, True) """ - if self.solution_type not in ["Transient"]: - self.logger.error("Y connections only available for Transient solutions.") - return False + if self.solution_type != SOLUTIONS.Maxwell3d.Transient: + raise AEDTRuntimeError("Y connections only available for Transient solutions.") if assignment: connection = ["NAME:YConnection", "Windings:=", ",".join(assignment)] @@ -735,23 +734,26 @@ def assign_current(self, assignment, amplitude=1, phase="0deg", solid=True, swap "Current": amplitude, } ) - if self.solution_type not in [ - "Magnetostatic", - "DCConduction", - "ElectricTransient", - "TransientAPhiFormulation", - "ElectroDCConduction", - ]: + if self.solution_type not in ( + SOLUTIONS.Maxwell3d.Magnetostatic, + SOLUTIONS.Maxwell3d.DCConduction, + SOLUTIONS.Maxwell3d.ElectricTransient, + SOLUTIONS.Maxwell3d.TransientAPhiFormulation, + SOLUTIONS.Maxwell3d.ElectroDCConduction, + ): props["Phase"] = phase - if self.solution_type not in ["DCConduction", "ElectricTransient", "ElectroDCConduction"]: + if self.solution_type not in ( + SOLUTIONS.Maxwell3d.DCConduction, + SOLUTIONS.Maxwell3d.ElectricTransient, + SOLUTIONS.Maxwell3d.ElectroDCConduction, + ): props["IsSolid"] = solid props["Point out of terminal"] = swap_direction else: if type(assignment[0]) is str: props = dict({"Objects": assignment, "Current": amplitude, "IsPositive": swap_direction}) else: - self.logger.warning("Input must be a 2D object.") - return False + raise ValueError("Input must be a 2D object.") return self._create_boundary_object(name, props, "Current") @pyaedt_function_handler(band_object="assignment") @@ -824,7 +826,9 @@ def assign_translate_motion( ---------- >>> oModule.AssignBand """ - assert self.solution_type == SOLUTIONS.Maxwell3d.Transient, "Motion applies only to the Transient setup." + if self.solution_type != SOLUTIONS.Maxwell3d.Transient: + raise AEDTRuntimeError("Motion applies only to the Transient setup.") + if not motion_name: motion_name = generate_unique_name("Motion") object_list = self.modeler.convert_to_selections(assignment, True) @@ -917,7 +921,9 @@ def assign_rotate_motion( ---------- >>> oModule.AssignBand """ - assert self.solution_type == SOLUTIONS.Maxwell3d.Transient, "Motion applies only to the Transient setup." + if self.solution_type != SOLUTIONS.Maxwell3d.Transient: + raise AEDTRuntimeError("Motion applies only to the Transient setup.") + names = list(self.omodelsetup.GetMotionSetupNames()) motion_name = "MotionSetup" + str(len(names) + 1) object_list = self.modeler.convert_to_selections(assignment, True) @@ -1075,11 +1081,10 @@ def assign_floating(self, assignment, charge_value=0, name=None): >>> floating1 = m3d.assign_floating(assignment=[box.faces[0], box.faces[1]], charge_value=3) >>> m3d.release_desktop(True, True) """ - if self.solution_type not in ["Electrostatic", "ElectricTransient"]: # pragma : no cover - self.logger.error( + if self.solution_type not in (SOLUTIONS.Maxwell3d.Electrostatic, SOLUTIONS.Maxwell3d.ElectricTransient): + raise AEDTRuntimeError( "Assign floating excitation is only valid for electrostatic or electric transient solvers." ) - return False if not isinstance(assignment, list): assignment = [assignment] @@ -1270,8 +1275,7 @@ def assign_coil(self, assignment, conductors_number=1, polarity="Positive", name ) bound_type = "CoilTerminal" else: - self.logger.warning("Face Selection is not allowed in Maxwell 2D. Provide a 2D object.") - return False + raise AEDTRuntimeError("Face Selection is not allowed in Maxwell 2D. Provide a 2D object.") return self._create_boundary_object(name, props, bound_type) @@ -1328,31 +1332,30 @@ def assign_force(self, assignment, coordinate_system="Global", is_virtual=True, >>> m3d.assign_force("conductor1",is_virtual=False,force_name="force_copper") # conductor, use Lorentz force >>> m3d.release_desktop(True, True) """ - if self.solution_type not in ["ACConduction", "DCConduction"]: - assignment = self.modeler.convert_to_selections(assignment, True) - if not force_name: - force_name = generate_unique_name("Force") - if self.design_type == "Maxwell 3D": - prop = dict( - { - "Name": force_name, - "Reference CS": coordinate_system, - "Is Virtual": is_virtual, - "Objects": assignment, - } - ) - else: - prop = dict( - { - "Name": force_name, - "Reference CS": coordinate_system, - "Objects": assignment, - } - ) - return self._create_boundary_object(force_name, prop, "Force") + if self.solution_type in (SOLUTIONS.Maxwell3d.ACConduction, SOLUTIONS.Maxwell3d.DCConduction): + raise AEDTRuntimeError("Solution type has no 'Matrix' parameter.") + + assignment = self.modeler.convert_to_selections(assignment, True) + if not force_name: + force_name = generate_unique_name("Force") + if self.design_type == "Maxwell 3D": + prop = dict( + { + "Name": force_name, + "Reference CS": coordinate_system, + "Is Virtual": is_virtual, + "Objects": assignment, + } + ) else: - self.logger.error("Solution type has no 'Matrix' parameter.") - return False + prop = dict( + { + "Name": force_name, + "Reference CS": coordinate_system, + "Objects": assignment, + } + ) + return self._create_boundary_object(force_name, prop, "Force") @pyaedt_function_handler(input_object="assignment", reference_cs="coordinate_system") def assign_torque( @@ -1391,36 +1394,35 @@ def assign_torque( ---------- >>> oModule.AssignTorque """ - if self.solution_type not in ["ACConduction", "DCConduction"]: - if self.solution_type == "Transient": - is_virtual = True - assignment = self.modeler.convert_to_selections(assignment, True) - if not torque_name: - torque_name = generate_unique_name("Torque") - if self.design_type == "Maxwell 3D": - prop = dict( - { - "Name": torque_name, - "Is Virtual": is_virtual, - "Coordinate System": coordinate_system, - "Axis": axis, - "Is Positive": is_positive, - "Objects": assignment, - } - ) - else: - prop = dict( - { - "Name": torque_name, - "Coordinate System": coordinate_system, - "Is Positive": is_positive, - "Objects": assignment, - } - ) - return self._create_boundary_object(torque_name, prop, "Torque") + if self.solution_type in (SOLUTIONS.Maxwell3d.ACConduction, SOLUTIONS.Maxwell3d.DCConduction): + raise AEDTRuntimeError("Solution Type has not Matrix Parameter") + + if self.solution_type == SOLUTIONS.Maxwell3d.Transient: + is_virtual = True + assignment = self.modeler.convert_to_selections(assignment, True) + if not torque_name: + torque_name = generate_unique_name("Torque") + if self.design_type == "Maxwell 3D": + prop = dict( + { + "Name": torque_name, + "Is Virtual": is_virtual, + "Coordinate System": coordinate_system, + "Axis": axis, + "Is Positive": is_positive, + "Objects": assignment, + } + ) else: - self.logger.error("Solution Type has not Matrix Parameter") - return False + prop = dict( + { + "Name": torque_name, + "Coordinate System": coordinate_system, + "Is Positive": is_positive, + "Objects": assignment, + } + ) + return self._create_boundary_object(torque_name, prop, "Torque") @pyaedt_function_handler() def solve_inside(self, name, activate=True): @@ -1463,9 +1465,9 @@ def analyze_from_zero(self): ---------- >>> oModule.ResetSetupToTimeZero """ - if self.solution_type != "Transient": - self.logger.error("This methods work only with Maxwell Transient Analysis.") - return False + if self.solution_type != SOLUTIONS.Maxwell3d.Transient: + raise AEDTRuntimeError("This methods work only with Maxwell Transient Analysis.") + self.oanalysis.ResetSetupToTimeZero(self._setup) self.analyze() return True @@ -1530,24 +1532,21 @@ def assign_symmetry(self, assignment, symmetry_name=None, is_odd=True): ---------- >>> oModule.AssignSymmetry """ - try: - if symmetry_name is None: - symmetry_name = generate_unique_name("Symmetry") - - prop = {} - if assignment: - if self.design_type == "Maxwell 2D": - assignment = self.modeler.convert_to_selections(assignment, True) - prop = dict({"Name": symmetry_name, "Edges": assignment, "IsOdd": is_odd}) - else: - assignment = self.modeler.convert_to_selections(assignment, True) - prop = dict({"Name": symmetry_name, "Faces": assignment, "IsOdd": is_odd}) + if symmetry_name is None: + symmetry_name = generate_unique_name("Symmetry") + + prop = {} + if assignment: + if self.design_type == "Maxwell 2D": + assignment = self.modeler.convert_to_selections(assignment, True) + prop = dict({"Name": symmetry_name, "Edges": assignment, "IsOdd": is_odd}) else: - msg = "At least one edge must be provided." - ValueError(msg) - return self._create_boundary_object(symmetry_name, prop, "Symmetry") - except Exception: - return False + assignment = self.modeler.convert_to_selections(assignment, True) + prop = dict({"Name": symmetry_name, "Faces": assignment, "IsOdd": is_odd}) + else: + msg = "At least one edge must be provided." + ValueError(msg) + return self._create_boundary_object(symmetry_name, prop, "Symmetry") @pyaedt_function_handler( entities="assignment", @@ -1606,83 +1605,81 @@ def assign_current_density( bool ``True`` when successful, ``False`` when failed. """ - if self.solution_type in ["EddyCurrent", "Magnetostatic", "Transient"]: - if current_density_name is None: - current_density_name = generate_unique_name("CurrentDensity") - if re.compile(r"(\d+)\s*(\w+)").match(phase).groups()[1] not in ["deg", "degmin", "degsec", "rad"]: - self.logger.error("Invalid phase unit.") - return False - if coordinate_system_type not in ["Cartesian", "Cylindrical", "Spherical"]: - self.logger.error("Invalid coordinate system.") - return False + if self.solution_type not in ( + SOLUTIONS.Maxwell3d.EddyCurrent, + SOLUTIONS.Maxwell3d.Magnetostatic, + SOLUTIONS.Maxwell3d.Transient, + ): + raise AEDTRuntimeError( + "Current density can only be applied to Eddy Current, Magnetostatic and 2D Transient solution types." + ) + if re.compile(r"(\d+)\s*(\w+)").match(phase).groups()[1] not in ["deg", "degmin", "degsec", "rad"]: + raise ValueError("Invalid phase unit.") + if coordinate_system_type not in ("Cartesian", "Cylindrical", "Spherical"): + raise ValueError("Invalid coordinate system.") - objects_list = self.modeler.convert_to_selections(assignment, True) + if current_density_name is None: + current_density_name = generate_unique_name("CurrentDensity") + objects_list = self.modeler.convert_to_selections(assignment, True) - try: - if self.modeler._is3d: - if self.solution_type == "Transient": - self.logger.error( - "Current density can only be applied to Eddy Current or Magnetostatic " "solution types." - ) - return False - - common_props = { - "Objects": objects_list, - "CurrentDensityX": current_density_x, - "CurrentDensityY": current_density_y, - "CurrentDensityZ": current_density_z, - "CoordinateSystem Name": coordinate_system, - "CoordinateSystem Type": coordinate_system_type, - } + try: + if self.modeler._is3d: + if self.solution_type == SOLUTIONS.Maxwell3d.Transient: + raise AEDTRuntimeError( + "Current density can only be applied to Eddy Current or Magnetostatic solution types." + ) - if len(objects_list) > 1: - current_density_group_names = [] - for x in range(0, len(objects_list)): - current_density_group_names.append(current_density_name + f"_{str(x + 1)}") - bound_props = {"items": current_density_group_names} - if self.solution_type == "EddyCurrent": - common_props["Phase"] = phase - bound_props[current_density_group_names[0]] = common_props.copy() - bound_name = current_density_group_names[0] - bound_type = "CurrentDensityGroup" - else: - if self.solution_type == "EddyCurrent": - common_props["Phase"] = phase - bound_props = common_props - bound_name = current_density_name - bound_type = "CurrentDensity" + common_props = { + "Objects": objects_list, + "CurrentDensityX": current_density_x, + "CurrentDensityY": current_density_y, + "CurrentDensityZ": current_density_z, + "CoordinateSystem Name": coordinate_system, + "CoordinateSystem Type": coordinate_system_type, + } + + if len(objects_list) > 1: + current_density_group_names = [] + for x in range(0, len(objects_list)): + current_density_group_names.append(current_density_name + f"_{str(x + 1)}") + bound_props = {"items": current_density_group_names} + if self.solution_type == SOLUTIONS.Maxwell3d.EddyCurrent: + common_props["Phase"] = phase + bound_props[current_density_group_names[0]] = common_props.copy() + bound_name = current_density_group_names[0] + bound_type = "CurrentDensityGroup" else: - common_props = { - "Objects": objects_list, - "Value": current_density_2d, - "CoordinateSystem": "", - } - if len(objects_list) > 1: - current_density_group_names = [] - for x in range(0, len(objects_list)): - current_density_group_names.append(current_density_name + f"_{str(x + 1)}") - bound_props = {"items": current_density_group_names} - if self.solution_type == "EddyCurrent": - common_props["Phase"] = phase - bound_props[current_density_group_names[0]] = common_props.copy() - bound_name = current_density_group_names[0] - bound_type = "CurrentDensityGroup" - else: - if self.solution_type == "EddyCurrent": - common_props["Phase"] = phase - bound_props = common_props - bound_name = current_density_name - bound_type = "CurrentDensity" - - return self._create_boundary_object(bound_name, bound_props, bound_type) - except Exception: - self.logger.error("Couldn't assign current density to desired list of objects.") - return False - else: - self.logger.error( - "Current density can only be applied to Eddy Current, Magnetostatic and 2D Transient " "solution types." - ) - return False + if self.solution_type == SOLUTIONS.Maxwell3d.EddyCurrent: + common_props["Phase"] = phase + bound_props = common_props + bound_name = current_density_name + bound_type = "CurrentDensity" + else: + common_props = { + "Objects": objects_list, + "Value": current_density_2d, + "CoordinateSystem": "", + } + if len(objects_list) > 1: + current_density_group_names = [] + for x in range(0, len(objects_list)): + current_density_group_names.append(current_density_name + f"_{str(x + 1)}") + bound_props = {"items": current_density_group_names} + if self.solution_type == SOLUTIONS.Maxwell3d.EddyCurrent: + common_props["Phase"] = phase + bound_props[current_density_group_names[0]] = common_props.copy() + bound_name = current_density_group_names[0] + bound_type = "CurrentDensityGroup" + else: + if self.solution_type == SOLUTIONS.Maxwell3d.EddyCurrent: + common_props["Phase"] = phase + bound_props = common_props + bound_name = current_density_name + bound_type = "CurrentDensity" + + return self._create_boundary_object(bound_name, bound_props, bound_type) + except Exception: + raise AEDTRuntimeError("Couldn't assign current density to desired list of objects.") @pyaedt_function_handler(input_object="assignment", radiation_name="radiation") def assign_radiation(self, assignment, radiation=None): @@ -1720,22 +1717,21 @@ def assign_radiation(self, assignment, radiation=None): >>> m3d.assign_radiation([box1, box2.faces[0]]) >>> m3d.release_desktop(True, True) """ - if self.solution_type == "EddyCurrent": - if not radiation: - radiation = generate_unique_name("Radiation") - elif radiation in self.modeler.get_boundaries_name(): - radiation = generate_unique_name(radiation) - - listobj = self.modeler.convert_to_selections(assignment, True) - props = {"Objects": [], "Faces": []} - for sel in listobj: - if isinstance(sel, str): - props["Objects"].append(sel) - elif isinstance(sel, int): - props["Faces"].append(sel) - return self._create_boundary_object(radiation, props, "Radiation") - self.logger.error("Excitation applicable only to Eddy Current.") - return False + if self.solution_type != SOLUTIONS.Maxwell3d.EddyCurrent: + raise AEDTRuntimeError("Excitation applicable only to Eddy Current.") + if not radiation: + radiation = generate_unique_name("Radiation") + elif radiation in self.modeler.get_boundaries_name(): + radiation = generate_unique_name(radiation) + + listobj = self.modeler.convert_to_selections(assignment, True) + props = {"Objects": [], "Faces": []} + for sel in listobj: + if isinstance(sel, str): + props["Objects"].append(sel) + elif isinstance(sel, int): + props["Faces"].append(sel) + return self._create_boundary_object(radiation, props, "Radiation") @pyaedt_function_handler(objects="assignment") def enable_harmonic_force( @@ -1774,9 +1770,9 @@ def enable_harmonic_force( ``True`` when successful, ``False`` when failed. """ - if self.solution_type != "Transient": - self.logger.error("This methods work only with Maxwell Transient Analysis.") - return False + if self.solution_type != SOLUTIONS.Maxwell3d.Transient: + raise AEDTRuntimeError("This methods work only with Maxwell Transient Analysis.") + assignment = self.modeler.convert_to_selections(assignment, True) self.odesign.EnableHarmonicForceCalculation( [ @@ -1861,9 +1857,9 @@ def enable_harmonic_force_on_layout_component( bool ``True`` when successful, ``False`` when failed. """ - if self.solution_type != "TransientAPhiFormulation": - self.logger.error("This methods work only with Maxwell TransientAPhiFormulation Analysis.") - return False + if self.solution_type != SOLUTIONS.Maxwell3d.TransientAPhiFormulation: + raise AEDTRuntimeError("This methods work only with Maxwell TransientAPhiFormulation Analysis.") + args = [ "ForceType:=", force_type, @@ -1933,9 +1929,9 @@ def export_element_based_harmonic_force( str Path to the export directory. """ - if self.solution_type != "Transient" and self.solution_type != "TransientAPhiFormulation": - self.logger.error("This methods work only with Maxwell Transient Analysis.") - return False + if self.solution_type not in (SOLUTIONS.Maxwell3d.Transient, SOLUTIONS.Maxwell3d.TransientAPhiFormulation): + raise AEDTRuntimeError("This methods work only with Maxwell Transient Analysis.") + if not output_directory: output_directory = self.working_directory if not setup: @@ -1979,11 +1975,10 @@ def create_external_circuit(self, circuit_design=None): >>> cir = m2d.create_external_circuit() >>> m2d.release_desktop(True, True) """ - if self.solution_type not in ["EddyCurrent", "Transient"]: - self.logger.error( + if self.solution_type not in (SOLUTIONS.Maxwell3d.EddyCurrent, SOLUTIONS.Maxwell3d.Transient): + raise AEDTRuntimeError( "External circuit excitation for windings is available only for Eddy Current or Transient solutions." ) - return False if not circuit_design: circuit_design = self.design_name + "_ckt" @@ -1998,8 +1993,7 @@ def create_external_circuit(self, circuit_design=None): if wdg_key in self.excitations_by_type.keys(): [wdgs.append(w) for w in self.excitations_by_type[wdg_key]] if not wdgs: - self.logger.error("No windings in the Maxwell design.") - return False + raise AEDTRuntimeError("No windings in the Maxwell design.") external_wdgs = [w for w in wdgs if w.props["Type"] == "External"] @@ -2033,7 +2027,8 @@ def edit_external_circuit(self, netlist_file_path, schematic_design_name, parame ``True`` when successful, ``False`` when failed. """ if schematic_design_name not in self.design_list: - return False + raise AEDTRuntimeError(f"Schematic design '{schematic_design_name}' is not in design list.") + odesign = self.desktop_class.active_design(self.oproject, schematic_design_name) oeditor = odesign.SetActiveEditor("SchematicEditor") if is_linux and settings.aedt_version == "2024.1": # pragma: no cover @@ -2134,8 +2129,7 @@ def _create_boundary_object(self, name, props, boundary_type): self.logger.info(f"Boundary {name} has been correctly created.") self._boundaries[bound.name] = bound return bound - self.logger.error(f"Boundary {name} was not created.") - return False + raise AEDTRuntimeError(f"Boundary {name} was not created.") class Maxwell3d(Maxwell, FieldAnalysis3D, object): @@ -2304,29 +2298,30 @@ def assign_insulating(self, assignment, insulation=None): >>> m3d.release_desktop(True, True) """ - if self.solution_type in [ - "Magnetostatic", - "EddyCurrent", - "Transient", - "TransientAPhiFormulation", - "DCConduction", - "ACConduction", - "ElectroDCConduction", - ]: - if not insulation: - insulation = generate_unique_name("Insulation") - elif insulation in self.modeler.get_boundaries_name(): - insulation = generate_unique_name(insulation) - - listobj = self.modeler.convert_to_selections(assignment, True) - props = {"Objects": [], "Faces": []} - for sel in listobj: - if isinstance(sel, str): - props["Objects"].append(sel) - elif isinstance(sel, int): - props["Faces"].append(sel) - return self._create_boundary_object(insulation, props, "Insulating") - return False + if self.solution_type not in ( + SOLUTIONS.Maxwell3d.Magnetostatic, + SOLUTIONS.Maxwell3d.EddyCurrent, + SOLUTIONS.Maxwell3d.Transient, + SOLUTIONS.Maxwell3d.TransientAPhiFormulation, + SOLUTIONS.Maxwell3d.DCConduction, + SOLUTIONS.Maxwell3d.ACConduction, + SOLUTIONS.Maxwell3d.ElectroDCConduction, + ): + raise AEDTRuntimeError(f"This method does not work with solution type '{self.solution_type}'") + + if not insulation: + insulation = generate_unique_name("Insulation") + elif insulation in self.modeler.get_boundaries_name(): + insulation = generate_unique_name(insulation) + + listobj = self.modeler.convert_to_selections(assignment, True) + props = {"Objects": [], "Faces": []} + for sel in listobj: + if isinstance(sel, str): + props["Objects"].append(sel) + elif isinstance(sel, int): + props["Faces"].append(sel) + return self._create_boundary_object(insulation, props, "Insulating") @pyaedt_function_handler(geometry_selection="assignment", impedance_name="impedance") def assign_impedance( @@ -2381,35 +2376,33 @@ def assign_impedance( >>> impedance_assignment = m3d.assign_impedance(assignment=shield_faces,impedance="ShieldImpedance") >>> m3d.release_desktop(True, True) """ - if self.solution_type in [ - "EddyCurrent", - "Transient", - ]: - if not impedance: - impedance = generate_unique_name("Impedance") - elif impedance in self.modeler.get_boundaries_name(): - impedance = generate_unique_name(impedance) - - listobj = self.modeler.convert_to_selections(assignment, True) - props = {"Objects": [], "Faces": []} - for sel in listobj: - if isinstance(sel, str): - props["Objects"].append(sel) - elif isinstance(sel, int): - props["Faces"].append(sel) - - if material_name is not None: - props["UseMaterial"] = True - props["MaterialName"] = material_name - props["IsPermeabilityNonlinear"] = non_linear_permeability - if conductivity is not None: - props["Conductivity"] = conductivity - else: - props["UseMaterial"] = False - props["Permeability"] = permeability + if self.solution_type not in (SOLUTIONS.Maxwell3d.Transient, SOLUTIONS.Maxwell3d.EddyCurrent): + raise AEDTRuntimeError(f"This method does not work with solution type '{self.solution_type}'") + + if not impedance: + impedance = generate_unique_name("Impedance") + elif impedance in self.modeler.get_boundaries_name(): + impedance = generate_unique_name(impedance) + + listobj = self.modeler.convert_to_selections(assignment, True) + props = {"Objects": [], "Faces": []} + for sel in listobj: + if isinstance(sel, str): + props["Objects"].append(sel) + elif isinstance(sel, int): + props["Faces"].append(sel) + + if material_name is not None: + props["UseMaterial"] = True + props["MaterialName"] = material_name + props["IsPermeabilityNonlinear"] = non_linear_permeability + if conductivity is not None: props["Conductivity"] = conductivity - return self._create_boundary_object(impedance, props, "Impedance") - return False + else: + props["UseMaterial"] = False + props["Permeability"] = permeability + props["Conductivity"] = conductivity + return self._create_boundary_object(impedance, props, "Impedance") @pyaedt_function_handler(entities="assignment") def assign_current_density_terminal(self, assignment, current_density_name=None): @@ -2428,35 +2421,33 @@ def assign_current_density_terminal(self, assignment, current_density_name=None) bool ``True`` when successful, ``False`` when failed. """ - if self.solution_type in ["EddyCurrent", "Magnetostatic"]: + if self.solution_type in (SOLUTIONS.Maxwell3d.EddyCurrent, SOLUTIONS.Maxwell3d.Magnetostatic): if current_density_name is None: current_density_name = generate_unique_name("CurrentDensity") objects_list = self.modeler.convert_to_selections(assignment, True) - try: - if self.modeler._is3d: - bound_objects = {"Faces": objects_list} - else: - bound_objects = {"Objects": objects_list} - if len(objects_list) > 1: - current_density_group_names = [] - for x in range(0, len(objects_list)): - current_density_group_names.append(current_density_name + f"_{str(x + 1)}") - bound_name = current_density_group_names[0] - props = {"items": current_density_group_names, bound_name: bound_objects} - bound_type = "CurrentDensityTerminalGroup" - else: - props = bound_objects - bound_name = current_density_name - bound_type = "CurrentDensityTerminal" + if self.modeler._is3d: + bound_objects = {"Faces": objects_list} + else: + bound_objects = {"Objects": objects_list} + if len(objects_list) > 1: + current_density_group_names = [] + for x in range(0, len(objects_list)): + current_density_group_names.append(current_density_name + f"_{str(x + 1)}") + bound_name = current_density_group_names[0] + props = {"items": current_density_group_names, bound_name: bound_objects} + bound_type = "CurrentDensityTerminalGroup" + else: + props = bound_objects + bound_name = current_density_name + bound_type = "CurrentDensityTerminal" - return self._create_boundary_object(bound_name, props, bound_type) - except Exception: - return False + return self._create_boundary_object(bound_name, props, bound_type) else: - self.logger.error("Current density can only be applied to Eddy Current or Magnetostatic solution types.") - return False + raise AEDTRuntimeError( + "Current density can only be applied to Eddy Current or Magnetostatic solution types." + ) @pyaedt_function_handler() def get_conduction_paths(self): @@ -2544,15 +2535,12 @@ def assign_master_slave( u_vector_pos_coordinates_slave, ] if any(not isinstance(coordinates, list) for coordinates in list_coordinates): - self.logger.error("Please provide a list of coordinates for U vectors.") - return False + raise ValueError("Please provide a list of coordinates for U vectors.") for coordinates in list_coordinates: if any(not isinstance(x, str) for x in coordinates): - self.logger.error("Elements of coordinates system must be strings in the form of ``value+unit``.") - return False + raise ValueError("Elements of coordinates system must be strings in the form of ``value+unit``.") if any(len(coordinates) != 3 for coordinates in list_coordinates): - self.logger.error("Vector must contain 3 elements for x, y, and z coordinates.") - return False + raise ValueError("Vector must contain 3 elements for x, y, and z coordinates.") u_master_vector_coordinates = dict( { "Coordinate System": "Global", @@ -2585,9 +2573,7 @@ def assign_master_slave( slave = self._create_boundary_object(bound_name_s, slave_props, "Dependent") if slave: return master, slave - else: - self.logger.error("Slave boundary could not be created.") - return False + raise AEDTRuntimeError("Slave boundary could not be created.") return False @pyaedt_function_handler(objects_list="assignment") @@ -2622,9 +2608,8 @@ def assign_flux_tangential(self, assignment, flux_name=None): >>> flux_tangential = m3d.assign_flux_tangential(box.faces[0],"FluxExample") >>> m3d.release_desktop(True, True) """ - if self.solution_type != "TransientAPhiFormulation": - self.logger.error("Flux tangential boundary can only be assigned to a transient APhi solution type.") - return False + if self.solution_type != SOLUTIONS.Maxwell3d.TransientAPhiFormulation: + raise AEDTRuntimeError("Flux tangential boundary can only be assigned to a transient APhi solution type.") assignment = self.modeler.convert_to_selections(assignment, True) @@ -2685,14 +2670,13 @@ def assign_layout_force( >>> m3d.assign_layout_force(net_layers=nets_layers,component_name="LC1_1") >>> m3d.release_desktop(True, True) """ + if component_name not in self.modeler.user_defined_component_names: + raise AEDTRuntimeError("Provided component name doesn't exist in current design.") + for key in net_layers.keys(): if not isinstance(net_layers[key], list): net_layers[key] = list(net_layers[key]) - if component_name not in self.modeler.user_defined_component_names: - self.logger.error("Provided component name doesn't exist in current design.") - return False - if not force_name: force_name = generate_unique_name("Layout_Force") @@ -2765,9 +2749,9 @@ def assign_tangential_h_field( ---------- >>> oModule.AssignTangentialHField """ - if self.solution_type not in ["EddyCurrent", "Magnetostatic"]: - self.logger.error("Tangential H Field is applicable only to Eddy Current.") - return False + if self.solution_type not in (SOLUTIONS.Maxwell3d.EddyCurrent, SOLUTIONS.Maxwell3d.Magnetostatic): + raise AEDTRuntimeError("Tangential H Field is applicable only to Eddy Current.") + assignment = self.modeler.convert_to_selections(assignment, True) if not bound_name: bound_name = generate_unique_name("TangentialHField") @@ -2783,10 +2767,10 @@ def assign_tangential_h_field( } ) props["ComponentXReal"] = x_component_real - if self.solution_type == "EddyCurrent": + if self.solution_type == SOLUTIONS.Maxwell3d.EddyCurrent: props["ComponentXImag"] = x_component_imag props["ComponentYReal"] = y_component_real - if self.solution_type == "EddyCurrent": + if self.solution_type == SOLUTIONS.Maxwell3d.EddyCurrent: props["ComponentYImag"] = y_component_imag if not origin and isinstance(assignment[0], int): edges = self.modeler.get_face_edges(assignment[0]) @@ -2819,9 +2803,9 @@ def assign_zero_tangential_h_field(self, assignment, boundary=None): ---------- >>> oModule.AssignZeroTangentialHField """ - if self.solution_type not in ["EddyCurrent"]: - self.logger.error("Tangential H Field is applicable only to Eddy Current.") - return False + if self.solution_type != SOLUTIONS.Maxwell3d.EddyCurrent: + raise AEDTRuntimeError("Tangential H Field is applicable only to Eddy Current.") + assignment = self.modeler.convert_to_selections(assignment, True) if not boundary: boundary = generate_unique_name("ZeroTangentialHField") @@ -2922,11 +2906,14 @@ def assign_resistive_sheet( >>> bound = m3d.assign_resistive_sheet(assignment=resistive_face, non_linear=True) >>> m3d.release_desktop() """ - if self.solution_type not in ["EddyCurrent", "Transient", "Magnetostatic"]: - self.logger.error( + if self.solution_type not in ( + SOLUTIONS.Maxwell3d.EddyCurrent, + SOLUTIONS.Maxwell3d.Transient, + SOLUTIONS.Maxwell3d.Magnetostatic, + ): + raise AEDTRuntimeError( "Resistive sheet is applicable only to Eddy Current, transient and magnetostatic solvers." ) - return False assignment = self.modeler.convert_to_selections(assignment, True) @@ -2942,9 +2929,9 @@ def assign_resistive_sheet( elif isinstance(sel, int): props["Faces"].append(sel) - if self.solution_type in ["EddyCurrent", "Transient"]: + if self.solution_type in (SOLUTIONS.Maxwell3d.EddyCurrent, SOLUTIONS.Maxwell3d.Transient): props["Resistance"] = resistance - elif self.solution_type == "Magnetostatic": + elif self.solution_type == SOLUTIONS.Maxwell3d.Magnetostatic: props["Nonlinear"] = non_linear props["AnodeParA"] = anode_a props["AnodeParB"] = anode_b @@ -3309,33 +3296,29 @@ def assign_master_slave( >>> oModule.AssignIndependent >>> oModule.AssignDependent """ - try: - independent = self.modeler.convert_to_selections(independent, True) - dependent = self.modeler.convert_to_selections(dependent, True) - if not boundary: - bound_name_m = generate_unique_name("Independent") - bound_name_s = generate_unique_name("Dependent") - else: - bound_name_m = boundary - bound_name_s = boundary + "_dep" - master_props = dict({"Edges": independent, "ReverseV": reverse_master}) - master = self._create_boundary_object(bound_name_m, master_props, "Independent") - if master: - slave_props = dict( - { - "Edges": dependent, - "ReverseU": reverse_slave, - "Independent": bound_name_m, - "SameAsMaster": same_as_master, - } - ) - slave = self._create_boundary_object(bound_name_s, slave_props, "Dependent") - if slave: - return master, slave - else: - return False - except Exception: - return False + independent = self.modeler.convert_to_selections(independent, True) + dependent = self.modeler.convert_to_selections(dependent, True) + if not boundary: + bound_name_m = generate_unique_name("Independent") + bound_name_s = generate_unique_name("Dependent") + else: + bound_name_m = boundary + bound_name_s = boundary + "_dep" + master_props = dict({"Edges": independent, "ReverseV": reverse_master}) + master = self._create_boundary_object(bound_name_m, master_props, "Independent") + if master: + slave_props = dict( + { + "Edges": dependent, + "ReverseU": reverse_slave, + "Independent": bound_name_m, + "SameAsMaster": same_as_master, + } + ) + slave = self._create_boundary_object(bound_name_s, slave_props, "Dependent") + if slave: + return master, slave + raise AEDTRuntimeError("Slave boundary could not be created.") @pyaedt_function_handler(objects="assignment", bound_name="boundary") def assign_end_connection(self, assignment, resistance=0, inductance=0, boundary=None): @@ -3364,12 +3347,11 @@ def assign_end_connection(self, assignment, resistance=0, inductance=0, boundary ---------- >>> oModule.AssignEndConnection """ - if self.solution_type not in ["EddyCurrent", "Transient"]: - self.logger.error("Excitation applicable only to Eddy Current or Transient Solver.") - return False + if self.solution_type not in (SOLUTIONS.Maxwell3d.EddyCurrent, SOLUTIONS.Maxwell3d.Transient): + raise AEDTRuntimeError("Excitation applicable only to Eddy Current or Transient Solver.") if len(assignment) < 2: - self.logger.error("At least 2 objects are needed.") - return False + raise AEDTRuntimeError("At least 2 objects are needed.") + assignment = self.modeler.convert_to_selections(assignment, True) if not boundary: boundary = generate_unique_name("EndConnection") diff --git a/src/ansys/aedt/core/mechanical.py b/src/ansys/aedt/core/mechanical.py index cd27f361fa3..3ba5e060b0a 100644 --- a/src/ansys/aedt/core/mechanical.py +++ b/src/ansys/aedt/core/mechanical.py @@ -27,6 +27,8 @@ from __future__ import absolute_import # noreorder from ansys.aedt.core.application.analysis_3d import FieldAnalysis3D +from ansys.aedt.core.generic.constants import SOLUTIONS +from ansys.aedt.core.generic.errors import AEDTRuntimeError from ansys.aedt.core.generic.general_methods import generate_unique_name from ansys.aedt.core.generic.general_methods import pyaedt_function_handler from ansys.aedt.core.modules.boundary.common import BoundaryObject @@ -215,6 +217,9 @@ def assign_em_losses( ---------- >>> oModule.AssignEMLoss """ + if self.solution_type != SOLUTIONS.Mechanical.Thermal: + raise AEDTRuntimeError("This method works only in a Mechanical Thermal analysis.") + if surface_objects is None: surface_objects = [] if parameters is None: @@ -222,8 +227,6 @@ def assign_em_losses( if assignment is None: assignment = [] - assert "Thermal" in self.solution_type, "This method works only in a Mechanical Thermal analysis." - self.logger.info("Mapping HFSS EM Loss") oName = self.project_name if oName == source_project_name or source_project_name is None: @@ -283,7 +286,7 @@ def assign_em_losses( ) def assign_thermal_map( self, - object_list, + assignment, design="IcepakDesign1", setup="Setup1", sweep="SteadyState", @@ -297,7 +300,7 @@ def assign_thermal_map( Parameters ---------- - object_list : list + assignment : list design : str, optional Name of the design with the source mapping. The default is ``"IcepakDesign1"``. @@ -320,11 +323,12 @@ def assign_thermal_map( ---------- >>> oModule.AssignThermalCondition """ + if self.solution_type != SOLUTIONS.Mechanical.Structural: + raise AEDTRuntimeError("This method works only in a Mechanical Structural analysis.") + if parameters is None: parameters = [] - assert self.solution_type == "Structural", "This method works only in a Mechanical Structural analysis." - self.logger.info("Mapping HFSS EM Loss") oName = self.project_name if oName == source_project_name or source_project_name is None: @@ -334,11 +338,11 @@ def assign_thermal_map( # # Generate a list of model objects from the lists made previously and use to map the HFSS losses into Icepak. # - object_list = self.modeler.convert_to_selections(object_list, True) - if not object_list: - allObjects = self.modeler.object_names + assignment = self.modeler.convert_to_selections(assignment, True) + if not assignment: + all_objects = self.modeler.object_names else: - allObjects = object_list[:] + all_objects = assignment[:] argparam = {} for el in self.available_variations.nominal_w_values_dict: argparam[el] = self.available_variations.nominal_w_values_dict[el] @@ -347,7 +351,7 @@ def assign_thermal_map( argparam[el] = el props = { - "Objects": allObjects, + "Objects": all_objects, "Uniform": False, "Project": projname, "Product": "ElectronicsDesktop", @@ -402,7 +406,8 @@ def assign_uniform_convection( ---------- >>> oModule.AssignConvection """ - assert "Thermal" in self.solution_type, "This method works only in a Mechanical Thermal analysis." + if self.solution_type != SOLUTIONS.Mechanical.Thermal: + raise AEDTRuntimeError("This method works only in a Mechanical Thermal analysis.") props = {} assignment = self.modeler.convert_to_selections(assignment, True) @@ -450,7 +455,8 @@ def assign_uniform_temperature(self, assignment, temperature="AmbientTemp", name ---------- >>> oModule.AssignTemperature """ - assert "Thermal" in self.solution_type, "This method works only in a Mechanical Thermal analysis." + if self.solution_type != SOLUTIONS.Mechanical.Thermal: + raise AEDTRuntimeError("This method works only in a Mechanical Thermal analysis.") props = {} assignment = self.modeler.convert_to_selections(assignment, True) @@ -495,12 +501,11 @@ def assign_frictionless_support(self, assignment, name=""): ---------- >>> oModule.AssignFrictionlessSupport """ - if not (self.solution_type == "Structural" or "Modal" in self.solution_type): - self.logger.error("This method works only in Mechanical Structural analysis.") - return False + if self.solution_type not in (SOLUTIONS.Mechanical.Structural, SOLUTIONS.Mechanical.Modal): + raise AEDTRuntimeError("This method works only in Mechanical Structural analysis.") + props = {} assignment = self.modeler.convert_to_selections(assignment, True) - if type(assignment) is list: if type(assignment[0]) is str: props["Objects"] = assignment @@ -539,9 +544,9 @@ def assign_fixed_support(self, assignment, name=""): ---------- >>> oModule.AssignFixedSupport """ - if not (self.solution_type == "Structural" or "Modal" in self.solution_type): - self.logger.error("This method works only in a Mechanical Structural analysis.") - return False + if self.solution_type not in (SOLUTIONS.Mechanical.Structural, SOLUTIONS.Mechanical.Modal): + raise AEDTRuntimeError("This method works only in a Mechanical Structural analysis.") + props = {} assignment = self.modeler.convert_to_selections(assignment, True) @@ -600,7 +605,8 @@ def assign_heat_flux(self, assignment, heat_flux_type, value, name=""): ---------- >>> oModule.AssignHeatFlux """ - assert "Thermal" in self.solution_type, "This method works only in a Mechanical Thermal analysis." + if self.solution_type != SOLUTIONS.Mechanical.Thermal: + raise AEDTRuntimeError("This method works only in a Mechanical Thermal analysis.") props = {} assignment = self.modeler.convert_to_selections(assignment, True) @@ -647,7 +653,8 @@ def assign_heat_generation(self, assignment, value, name=""): ---------- >>> oModule.AssignHeatGeneration """ - assert "Thermal" in self.solution_type, "This method works only in a Mechanical Thermal analysis." + if self.solution_type != SOLUTIONS.Mechanical.Thermal: + raise AEDTRuntimeError("This method works only in a Mechanical Thermal analysis.") props = {} assignment = self.modeler.convert_to_selections(assignment, True) diff --git a/tests/unit/test_mechanical.py b/tests/unit/test_mechanical.py new file mode 100644 index 00000000000..f1028e09534 --- /dev/null +++ b/tests/unit/test_mechanical.py @@ -0,0 +1,95 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2021 - 2025 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.mock import MagicMock +from unittest.mock import patch + +from ansys.aedt.core.generic.errors import AEDTRuntimeError +from ansys.aedt.core.mechanical import Mechanical +import pytest + + +@pytest.fixture +def mechanical_setup(): + """Fixture used to mock the creation of a Mechanical instance.""" + with patch("ansys.aedt.core.mechanical.Mechanical.__init__", lambda x: None): + mock_instance = MagicMock(spec=Mechanical) + yield mock_instance + + +@patch.object(Mechanical, "solution_type", "Dummy") +def test_assign_em_losses_failure_with_wrong_solution_type(mechanical_setup): + mechanical = Mechanical() + + with pytest.raises(AEDTRuntimeError): + assert not mechanical.assign_em_losses() + + +@patch.object(Mechanical, "solution_type", "Dummy") +def test_assign_uniform_convection_failure_with_wrong_solution_type(mechanical_setup): + mechanical = Mechanical() + mock_assignment = MagicMock() + + with pytest.raises(AEDTRuntimeError): + assert not mechanical.assign_uniform_convection(mock_assignment) + + +@patch.object(Mechanical, "solution_type", "Dummy") +def test_assign_uniform_temperature_failure_with_wrong_solution_type(mechanical_setup): + mechanical = Mechanical() + mock_assignment = MagicMock() + + with pytest.raises(AEDTRuntimeError): + assert not mechanical.assign_uniform_temperature(mock_assignment) + + +@patch.object(Mechanical, "solution_type", "Dummy") +def test_assign_heat_flux_failure_with_wrong_solution_type(mechanical_setup): + mechanical = Mechanical() + mock_assignment = MagicMock() + mock_heat_flux_type = MagicMock() + mock_value = MagicMock() + + with pytest.raises(AEDTRuntimeError): + assert not mechanical.assign_heat_flux(mock_assignment, mock_heat_flux_type, mock_value) + + +@patch.object(Mechanical, "solution_type", "Dummy") +def test_assign_heat_generation_failure_with_wrong_solution_type(mechanical_setup): + mechanical = Mechanical() + mock_assignment = MagicMock() + mock_value = MagicMock() + + with pytest.raises(AEDTRuntimeError): + assert not mechanical.assign_heat_generation(mock_assignment, mock_value) + + +@patch.object(Mechanical, "solution_type", "Dummy") +def test_assign_thermal_map_failure_with_wrong_solution_type(mechanical_setup): + mechanical = Mechanical() + mock_assignment = MagicMock() + mock_value = MagicMock() + + with pytest.raises(AEDTRuntimeError): + assert not mechanical.assign_thermal_map(mock_assignment, mock_value) From 896e95547cca62a6236c412659459dcc50597844 Mon Sep 17 00:00:00 2001 From: Samuel Lopez <85613111+Samuelopez-ansys@users.noreply.github.com> Date: Tue, 28 Jan 2025 09:27:52 +0100 Subject: [PATCH 02/12] Update src/ansys/aedt/core/maxwell.py --- src/ansys/aedt/core/maxwell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/aedt/core/maxwell.py b/src/ansys/aedt/core/maxwell.py index 0b475193527..baf0ca891cb 100644 --- a/src/ansys/aedt/core/maxwell.py +++ b/src/ansys/aedt/core/maxwell.py @@ -243,7 +243,7 @@ def set_core_losses(self, assignment, core_loss_on_field=False): >>> m3d.release_desktop(True, True) """ if self.solution_type not in (SOLUTIONS.Maxwell3d.EddyCurrent, SOLUTIONS.Maxwell3d.Transient): - raise AEDTRuntimeError("Solution type does not have matrix parameters")( + raise AEDTRuntimeError( "Core losses is only available with `EddyCurrent` and `Transient` solutions." ) From 5ddb80c6845d29e177676e3dfffaf4dec3418d2f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 28 Jan 2025 08:29:11 +0000 Subject: [PATCH 03/12] CHORE: Auto fixes from pre-commit.com hooks For more information, see https://pre-commit.ci --- src/ansys/aedt/core/maxwell.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ansys/aedt/core/maxwell.py b/src/ansys/aedt/core/maxwell.py index baf0ca891cb..c122b59cd3f 100644 --- a/src/ansys/aedt/core/maxwell.py +++ b/src/ansys/aedt/core/maxwell.py @@ -243,9 +243,7 @@ def set_core_losses(self, assignment, core_loss_on_field=False): >>> m3d.release_desktop(True, True) """ if self.solution_type not in (SOLUTIONS.Maxwell3d.EddyCurrent, SOLUTIONS.Maxwell3d.Transient): - raise AEDTRuntimeError( - "Core losses is only available with `EddyCurrent` and `Transient` solutions." - ) + raise AEDTRuntimeError("Core losses is only available with `EddyCurrent` and `Transient` solutions.") assignment = self.modeler.convert_to_selections(assignment, True) self.oboundary.SetCoreLoss(assignment, core_loss_on_field) From 6f49bae605525261b97dd7a8ec7360452e10c123 Mon Sep 17 00:00:00 2001 From: Sebastien Morais Date: Wed, 29 Jan 2025 08:17:15 +0100 Subject: [PATCH 04/12] TESTS: Fix test --- tests/unit/test_maxwell_3d.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/unit/test_maxwell_3d.py b/tests/unit/test_maxwell_3d.py index b04fd31051e..33956b4418c 100644 --- a/tests/unit/test_maxwell_3d.py +++ b/tests/unit/test_maxwell_3d.py @@ -25,7 +25,9 @@ from unittest.mock import MagicMock from unittest.mock import patch +from ansys.aedt.core.generic.errors import AEDTRuntimeError from ansys.aedt.core.maxwell import Maxwell3d +import pytest @patch.object(Maxwell3d, "solution_type", "Transient") @@ -38,4 +40,5 @@ def test_maxwell_3d_assign_resistive_sheet_failure(mock_boundary_object, maxwell maxwell._modeler = MagicMock() maxwell._logger = MagicMock() - assert not maxwell.assign_resistive_sheet(None, None) + with pytest.raises(AEDTRuntimeError, match=r"Boundary ResistiveSheet_\w+ was not created\."): + maxwell.assign_resistive_sheet(None, None) From 1bf6dcc3036419922bf50c7eedccbe301158a276 Mon Sep 17 00:00:00 2001 From: Sebastien Morais Date: Wed, 29 Jan 2025 11:34:58 +0100 Subject: [PATCH 05/12] FIX: Tests and constat ref --- src/ansys/aedt/core/maxwell.py | 6 +- tests/system/general/test_27_Maxwell2D.py | 41 ++++++--- tests/system/general/test_28_Maxwell3D.py | 100 ++++++++++++---------- 3 files changed, 86 insertions(+), 61 deletions(-) diff --git a/src/ansys/aedt/core/maxwell.py b/src/ansys/aedt/core/maxwell.py index c122b59cd3f..a3ff8532aab 100644 --- a/src/ansys/aedt/core/maxwell.py +++ b/src/ansys/aedt/core/maxwell.py @@ -321,7 +321,7 @@ def assign_matrix( assignment = self.modeler.convert_to_selections(assignment, True) if self.solution_type in ( - SOLUTIONS.Maxwell3d.Electrostatic, + SOLUTIONS.Maxwell3d.ElectroStatic, SOLUTIONS.Maxwell3d.ACConduction, SOLUTIONS.Maxwell3d.DCConduction, ): @@ -416,7 +416,7 @@ def assign_matrix( if group_sources: if self.solution_type in ( - SOLUTIONS.Maxwell3d.Electrostatic, + SOLUTIONS.Maxwell3d.ElectroStatic, SOLUTIONS.Maxwell3d.ACConduction, SOLUTIONS.Maxwell3d.DCConduction, ): @@ -1079,7 +1079,7 @@ def assign_floating(self, assignment, charge_value=0, name=None): >>> floating1 = m3d.assign_floating(assignment=[box.faces[0], box.faces[1]], charge_value=3) >>> m3d.release_desktop(True, True) """ - if self.solution_type not in (SOLUTIONS.Maxwell3d.Electrostatic, SOLUTIONS.Maxwell3d.ElectricTransient): + if self.solution_type not in (SOLUTIONS.Maxwell3d.ElectroStatic, SOLUTIONS.Maxwell3d.ElectricTransient): raise AEDTRuntimeError( "Assign floating excitation is only valid for electrostatic or electric transient solvers." ) diff --git a/tests/system/general/test_27_Maxwell2D.py b/tests/system/general/test_27_Maxwell2D.py index fdd9c77259a..6ef09667cf0 100644 --- a/tests/system/general/test_27_Maxwell2D.py +++ b/tests/system/general/test_27_Maxwell2D.py @@ -29,6 +29,7 @@ import ansys.aedt.core from ansys.aedt.core.generic.constants import SOLUTIONS +from ansys.aedt.core.generic.errors import AEDTRuntimeError import pytest from tests import TESTS_GENERAL_PATH @@ -170,7 +171,8 @@ def test_assign_current_source(self, aedtapp): position=[0, 0, 0], radius=5, num_sides="8", is_covered=True, name="Coil", material="Copper" ) assert aedtapp.assign_current([coil]) - assert not aedtapp.assign_current([coil.faces[0].id]) + with pytest.raises(ValueError, "Input must be a 2D object."): + aedtapp.assign_current([coil.faces[0].id]) def test_assign_master_slave(self, aedtapp): aedtapp.modeler.create_rectangle([1, 1, 1], [3, 1], name="Rectangle1", material="copper") @@ -201,14 +203,14 @@ def test_model_depth(self, aedtapp): def test_apply_skew(self, aedtapp): assert aedtapp.apply_skew() - assert not aedtapp.apply_skew(skew_type="Invalid") - assert not aedtapp.apply_skew(skew_part="Invalid") - assert not aedtapp.apply_skew( - skew_type="Continuous", skew_part="Stator", skew_angle="0.5", skew_angle_unit="Invalid" - ) - assert not aedtapp.apply_skew( - skew_type="User Defined", number_of_slices="4", custom_slices_skew_angles=["1", "2", "3"] - ) + with pytest.raises(ValueError, "Invalid coordinate system."): + assert not aedtapp.apply_skew(skew_type="Invalid") + with pytest.raises(ValueError, "Invalid skew angle unit."): + aedtapp.apply_skew(skew_type="Continuous", skew_part="Stator", skew_angle="0.5", skew_angle_unit="Invalid") + with pytest.raises(ValueError, "Please provide skew angles for each slice."): + aedtapp.apply_skew( + skew_type="User Defined", number_of_slices="4", custom_slices_skew_angles=["1", "2", "3"] + ) assert aedtapp.apply_skew( skew_type="User Defined", number_of_slices="4", custom_slices_skew_angles=["1", "2", "3", "4"] ) @@ -239,9 +241,11 @@ def test_assign_end_connection(self, aedtapp): assert bound.props["ResistanceValue"] == "0ohm" bound.props["InductanceValue"] = "5H" assert bound.props["InductanceValue"] == "5H" - assert not aedtapp.assign_end_connection([rect]) + with pytest.raises(AEDTRuntimeError, "At least 2 objects are needed."): + aedtapp.assign_end_connection([rect]) aedtapp.solution_type = SOLUTIONS.Maxwell2d.MagnetostaticXY - assert not aedtapp.assign_end_connection([rect, rect2]) + with pytest.raises(AEDTRuntimeError, "Excitation applicable only to Eddy Current or Transient Solver."): + aedtapp.assign_end_connection([rect, rect2]) def test_setup_y_connection(self, aedtapp): aedtapp.set_active_design("Y_Connections") @@ -312,7 +316,8 @@ def test_assign_current_density(self, aedtapp): assert bound_group.props[bound_group.props["items"][0]]["Objects"] == ["Coil", "Coil_1"] assert bound_group.props[bound_group.props["items"][0]]["Value"] == "0" assert bound_group.props[bound_group.props["items"][0]]["CoordinateSystem"] == "" - assert not aedtapp.assign_current_density("Circle_inner", "CurrentDensity_1") + with pytest.raises(AEDTRuntimeError, "Couldn't assign current density to desired list of objects."): + aedtapp.assign_current_density("Circle_inner", "CurrentDensity_1") def test_set_variable(self, aedtapp): aedtapp.variable_manager.set_variable("var_test", expression="123") @@ -595,9 +600,17 @@ def test_create_external_circuit(self, local_scratch, m2d_app): assert m2d_app.create_external_circuit() assert m2d_app.create_external_circuit(circuit_design="test_cir") m2d_app.solution_type = SOLUTIONS.Maxwell2d.MagnetostaticXY - assert not m2d_app.create_external_circuit() + with pytest.raises( + AEDTRuntimeError, + "External circuit excitation for windings is available only for Eddy Current or Transient solutions.", + ): + m2d_app.create_external_circuit() m2d_app.solution_type = SOLUTIONS.Maxwell2d.EddyCurrentXY for w in m2d_app.excitations_by_type["Winding"]: w.delete() m2d_app.save_project() - assert not m2d_app.create_external_circuit() + with pytest.raises( + AEDTRuntimeError, + "External circuit excitation for windings is available only for Eddy Current or Transient solutions.", + ): + m2d_app.create_external_circuit() diff --git a/tests/system/general/test_28_Maxwell3D.py b/tests/system/general/test_28_Maxwell3D.py index 3dbe5bb8e98..4ede0da7192 100644 --- a/tests/system/general/test_28_Maxwell3D.py +++ b/tests/system/general/test_28_Maxwell3D.py @@ -27,6 +27,7 @@ from ansys.aedt.core import Maxwell3d from ansys.aedt.core.generic.constants import SOLUTIONS +from ansys.aedt.core.generic.errors import AEDTRuntimeError from ansys.aedt.core.generic.general_methods import generate_unique_name from ansys.aedt.core.generic.general_methods import is_linux from ansys.aedt.core.modeler.geometry_operators import GeometryOperators @@ -156,7 +157,8 @@ def test_create_air_region(self, m3d_app): def test_eddy_effects_on(self, m3d_app): m3d_app.solution_type = SOLUTIONS.Maxwell3d.EddyCurrent plate_vacuum = m3d_app.modeler.create_box([-3, -3, 0], [1.5, 1.5, 0.4], name="Plate_vaccum") - assert not m3d_app.eddy_effects_on(plate_vacuum, enable_eddy_effects=True) + with pytest.raises(AEDTRuntimeError, "No conductors defined in active design."): + m3d_app.eddy_effects_on(plate_vacuum, enable_eddy_effects=True) plate = m3d_app.modeler.create_box([-1, -1, 0], [1.5, 1.5, 0.4], name="Plate", material="copper") assert m3d_app.eddy_effects_on(plate, enable_eddy_effects=True) assert m3d_app.oboundary.GetEddyEffect("Plate") @@ -689,8 +691,10 @@ def test_assign_current_density(self, m3d_app): assert bound.props[bound.name]["CurrentDensityZ"] == "0" assert bound.props[bound.name]["CoordinateSystem Name"] == "Global" - assert not m3d_app.assign_current_density(box.name, "current_density_3", coordinate_system_type="test") - assert not m3d_app.assign_current_density(box.name, "current_density_4", phase="5ang") + with pytest.raises(AEDTRuntimeError, "Invalid coordinate system."): + m3d_app.assign_current_density(box.name, "current_density_3", coordinate_system_type="test") + with pytest.raises(AEDTRuntimeError, "Invalid phase unit."): + m3d_app.assign_current_density(box.name, "current_density_4", phase="5ang") def test_assign_current_density_terminal(self, m3d_app): box = m3d_app.modeler.create_box([50, 0, 50], [294, 294, 19], name="box") @@ -757,46 +761,51 @@ def test_assign_independent_dependent(self, m3d_app): ) assert independent assert dependent - assert not m3d_app.assign_master_slave( - master_entity=box.faces[1], - slave_entity=box.faces[5], - u_vector_origin_coordinates_master=[0, "0mm", "0mm"], - u_vector_pos_coordinates_master=["10mm", "0mm", "0mm"], - u_vector_origin_coordinates_slave=["10mm", "0mm", "0mm"], - u_vector_pos_coordinates_slave=["10mm", "10mm", "0mm"], - ) - assert not m3d_app.assign_master_slave( - master_entity=box.faces[1], - slave_entity=box.faces[5], - u_vector_origin_coordinates_master=["0mm", "0mm", "0mm"], - u_vector_pos_coordinates_master=[10, "0mm", "0mm"], - u_vector_origin_coordinates_slave=["10mm", "0mm", "0mm"], - u_vector_pos_coordinates_slave=["10mm", "10mm", "0mm"], - ) - assert not m3d_app.assign_master_slave( - master_entity=box.faces[1], - slave_entity=box.faces[5], - u_vector_origin_coordinates_master=["0mm", "0mm", "0mm"], - u_vector_pos_coordinates_master=["10mm", "0mm", "0mm"], - u_vector_origin_coordinates_slave=[10, "0mm", "0mm"], - u_vector_pos_coordinates_slave=["10mm", "10mm", "0mm"], - ) - assert not m3d_app.assign_master_slave( - master_entity=box.faces[1], - slave_entity=box.faces[5], - u_vector_origin_coordinates_master=["0mm", "0mm", "0mm"], - u_vector_pos_coordinates_master=["10mm", "0mm", "0mm"], - u_vector_origin_coordinates_slave=["10mm", "0mm", "0mm"], - u_vector_pos_coordinates_slave=[10, "10mm", "0mm"], - ) - assert not m3d_app.assign_master_slave( - master_entity=box.faces[1], - slave_entity=box.faces[5], - u_vector_origin_coordinates_master="0mm", - u_vector_pos_coordinates_master=["10mm", "0mm", "0mm"], - u_vector_origin_coordinates_slave=["10mm", "0mm", "0mm"], - u_vector_pos_coordinates_slave=["10mm", "10mm", "0mm"], - ) + with pytest.raises(ValueError, "Elements of coordinates system must be strings in the form of ``value+unit``."): + m3d_app.assign_master_slave( + master_entity=box.faces[1], + slave_entity=box.faces[5], + u_vector_origin_coordinates_master=[0, "0mm", "0mm"], + u_vector_pos_coordinates_master=["10mm", "0mm", "0mm"], + u_vector_origin_coordinates_slave=["10mm", "0mm", "0mm"], + u_vector_pos_coordinates_slave=["10mm", "10mm", "0mm"], + ) + with pytest.raises(ValueError, "Elements of coordinates system must be strings in the form of ``value+unit``."): + m3d_app.assign_master_slave( + master_entity=box.faces[1], + slave_entity=box.faces[5], + u_vector_origin_coordinates_master=["0mm", "0mm", "0mm"], + u_vector_pos_coordinates_master=[10, "0mm", "0mm"], + u_vector_origin_coordinates_slave=["10mm", "0mm", "0mm"], + u_vector_pos_coordinates_slave=["10mm", "10mm", "0mm"], + ) + with pytest.raises(ValueError, "Elements of coordinates system must be strings in the form of ``value+unit``."): + m3d_app.assign_master_slave( + master_entity=box.faces[1], + slave_entity=box.faces[5], + u_vector_origin_coordinates_master=["0mm", "0mm", "0mm"], + u_vector_pos_coordinates_master=["10mm", "0mm", "0mm"], + u_vector_origin_coordinates_slave=[10, "0mm", "0mm"], + u_vector_pos_coordinates_slave=["10mm", "10mm", "0mm"], + ) + with pytest.raises(ValueError, "Elements of coordinates system must be strings in the form of ``value+unit``."): + m3d_app.assign_master_slave( + master_entity=box.faces[1], + slave_entity=box.faces[5], + u_vector_origin_coordinates_master=["0mm", "0mm", "0mm"], + u_vector_pos_coordinates_master=["10mm", "0mm", "0mm"], + u_vector_origin_coordinates_slave=["10mm", "0mm", "0mm"], + u_vector_pos_coordinates_slave=[10, "10mm", "0mm"], + ) + with pytest.raises(ValueError, "Please provide a list of coordinates for U vectors."): + m3d_app.assign_master_slave( + master_entity=box.faces[1], + slave_entity=box.faces[5], + u_vector_origin_coordinates_master="0mm", + u_vector_pos_coordinates_master=["10mm", "0mm", "0mm"], + u_vector_origin_coordinates_slave=["10mm", "0mm", "0mm"], + u_vector_pos_coordinates_slave=["10mm", "10mm", "0mm"], + ) def test_add_mesh_link(self, m3d_app, local_scratch): m3d_app.solution_type = SOLUTIONS.Maxwell3d.Transient @@ -911,7 +920,10 @@ def test_import_dxf(self, m3d_app): def test_assign_flux_tangential(self, m3d_app): box = m3d_app.modeler.create_box([50, 0, 50], [294, 294, 19], name="Box") - assert not m3d_app.assign_flux_tangential(box.faces[0]) + with pytest.raises( + AEDTRuntimeError, "Flux tangential boundary can only be assigned to a transient APhi solution type." + ): + m3d_app.assign_flux_tangential(box.faces[0]) m3d_app.solution_type = "TransientAPhiFormulation" assert m3d_app.assign_flux_tangential(box.faces[0], "FluxExample") assert m3d_app.assign_flux_tangential(box.faces[0].id, "FluxExample") From cf9662ddf165ab59ccf0d80aa97795c2fa3e45dc Mon Sep 17 00:00:00 2001 From: Sebastien Morais Date: Wed, 29 Jan 2025 15:31:07 +0100 Subject: [PATCH 06/12] FIX: Add missing option name --- tests/system/general/test_27_Maxwell2D.py | 34 ++++++++++------- tests/system/general/test_28_Maxwell3D.py | 46 +++++++++++++++-------- 2 files changed, 50 insertions(+), 30 deletions(-) diff --git a/tests/system/general/test_27_Maxwell2D.py b/tests/system/general/test_27_Maxwell2D.py index 6ef09667cf0..84d110c565a 100644 --- a/tests/system/general/test_27_Maxwell2D.py +++ b/tests/system/general/test_27_Maxwell2D.py @@ -171,7 +171,7 @@ def test_assign_current_source(self, aedtapp): position=[0, 0, 0], radius=5, num_sides="8", is_covered=True, name="Coil", material="Copper" ) assert aedtapp.assign_current([coil]) - with pytest.raises(ValueError, "Input must be a 2D object."): + with pytest.raises(ValueError, match="Input must be a 2D object."): aedtapp.assign_current([coil.faces[0].id]) def test_assign_master_slave(self, aedtapp): @@ -203,11 +203,11 @@ def test_model_depth(self, aedtapp): def test_apply_skew(self, aedtapp): assert aedtapp.apply_skew() - with pytest.raises(ValueError, "Invalid coordinate system."): + with pytest.raises(ValueError, match="Invalid coordinate system."): assert not aedtapp.apply_skew(skew_type="Invalid") - with pytest.raises(ValueError, "Invalid skew angle unit."): + with pytest.raises(ValueError, match="Invalid skew angle unit."): aedtapp.apply_skew(skew_type="Continuous", skew_part="Stator", skew_angle="0.5", skew_angle_unit="Invalid") - with pytest.raises(ValueError, "Please provide skew angles for each slice."): + with pytest.raises(ValueError, match="Please provide skew angles for each slice."): aedtapp.apply_skew( skew_type="User Defined", number_of_slices="4", custom_slices_skew_angles=["1", "2", "3"] ) @@ -241,10 +241,10 @@ def test_assign_end_connection(self, aedtapp): assert bound.props["ResistanceValue"] == "0ohm" bound.props["InductanceValue"] = "5H" assert bound.props["InductanceValue"] == "5H" - with pytest.raises(AEDTRuntimeError, "At least 2 objects are needed."): + with pytest.raises(AEDTRuntimeError, match="At least 2 objects are needed."): aedtapp.assign_end_connection([rect]) aedtapp.solution_type = SOLUTIONS.Maxwell2d.MagnetostaticXY - with pytest.raises(AEDTRuntimeError, "Excitation applicable only to Eddy Current or Transient Solver."): + with pytest.raises(AEDTRuntimeError, match="Excitation applicable only to Eddy Current or Transient Solver."): aedtapp.assign_end_connection([rect, rect2]) def test_setup_y_connection(self, aedtapp): @@ -316,7 +316,7 @@ def test_assign_current_density(self, aedtapp): assert bound_group.props[bound_group.props["items"][0]]["Objects"] == ["Coil", "Coil_1"] assert bound_group.props[bound_group.props["items"][0]]["Value"] == "0" assert bound_group.props[bound_group.props["items"][0]]["CoordinateSystem"] == "" - with pytest.raises(AEDTRuntimeError, "Couldn't assign current density to desired list of objects."): + with pytest.raises(AEDTRuntimeError, match="Couldn't assign current density to desired list of objects."): aedtapp.assign_current_density("Circle_inner", "CurrentDensity_1") def test_set_variable(self, aedtapp): @@ -449,8 +449,11 @@ def test_assign_floating(self, m2d_app): assert floating.props["Objects"][0] == rect.name assert floating.props["Value"] == "3" m2d_app.solution_type = SOLUTIONS.Maxwell2d.MagnetostaticXY - floating = m2d_app.assign_floating(assignment=rect, charge_value=3, name="floating_test1") - assert not floating + with pytest.raises( + AEDTRuntimeError, + match="Assign floating excitation is only valid for electrostatic or electric transient solvers.", + ): + m2d_app.assign_floating(assignment=rect, charge_value=3, name="floating_test1") def test_matrix(self, m2d_app): m2d_app.solution_type = SOLUTIONS.Maxwell2d.MagnetostaticXY @@ -473,10 +476,13 @@ def test_matrix(self, m2d_app): assignment=["Current1", "Current2"], matrix_name="Test2", turns=[2, 1], return_path=["Current3", "Current4"] ) assert matrix.props["MatrixEntry"]["MatrixEntry"][1]["ReturnPath"] == "Current4" - matrix = m2d_app.assign_matrix( - assignment=["Current1", "Current2"], matrix_name="Test3", turns=[2, 1], return_path=["Current1", "Current1"] - ) - assert not matrix + with pytest.raises(AEDTRuntimeError, match="Return path specified must not be included in sources"): + m2d_app.assign_matrix( + assignment=["Current1", "Current2"], + matrix_name="Test3", + turns=[2, 1], + return_path=["Current1", "Current1"], + ) group_sources = {"Group1_Test": ["Current3", "Current2"]} matrix = m2d_app.assign_matrix( assignment=["Current3", "Current2"], @@ -602,7 +608,7 @@ def test_create_external_circuit(self, local_scratch, m2d_app): m2d_app.solution_type = SOLUTIONS.Maxwell2d.MagnetostaticXY with pytest.raises( AEDTRuntimeError, - "External circuit excitation for windings is available only for Eddy Current or Transient solutions.", + match="External circuit excitation for windings is available only for Eddy Current or Transient solutions.", ): m2d_app.create_external_circuit() m2d_app.solution_type = SOLUTIONS.Maxwell2d.EddyCurrentXY diff --git a/tests/system/general/test_28_Maxwell3D.py b/tests/system/general/test_28_Maxwell3D.py index 4ede0da7192..04d916d5976 100644 --- a/tests/system/general/test_28_Maxwell3D.py +++ b/tests/system/general/test_28_Maxwell3D.py @@ -157,7 +157,7 @@ def test_create_air_region(self, m3d_app): def test_eddy_effects_on(self, m3d_app): m3d_app.solution_type = SOLUTIONS.Maxwell3d.EddyCurrent plate_vacuum = m3d_app.modeler.create_box([-3, -3, 0], [1.5, 1.5, 0.4], name="Plate_vaccum") - with pytest.raises(AEDTRuntimeError, "No conductors defined in active design."): + with pytest.raises(AEDTRuntimeError, match="No conductors defined in active design."): m3d_app.eddy_effects_on(plate_vacuum, enable_eddy_effects=True) plate = m3d_app.modeler.create_box([-1, -1, 0], [1.5, 1.5, 0.4], name="Plate", material="copper") assert m3d_app.eddy_effects_on(plate, enable_eddy_effects=True) @@ -440,8 +440,8 @@ def test_assign_matrix(self, m3d_app): assert matrix.props["MatrixEntry"]["MatrixEntry"][1]["NumberOfTurns"] == "1" m3d_app.solution_type = SOLUTIONS.Maxwell3d.Transient m3d_app.assign_winding("Sheet1", name="Current1") - matrix = m3d_app.assign_matrix(assignment="Current1") - assert not matrix + with pytest.raises(AEDTRuntimeError, match="Solution type does not have matrix parameters"): + m3d_app.assign_matrix(assignment="Current1") def test_available_quantities_categories(self, m3d_app): m3d_app.solution_type = SOLUTIONS.Maxwell3d.ElectroStatic @@ -691,9 +691,9 @@ def test_assign_current_density(self, m3d_app): assert bound.props[bound.name]["CurrentDensityZ"] == "0" assert bound.props[bound.name]["CoordinateSystem Name"] == "Global" - with pytest.raises(AEDTRuntimeError, "Invalid coordinate system."): + with pytest.raises(AEDTRuntimeError, match="Invalid coordinate system."): m3d_app.assign_current_density(box.name, "current_density_3", coordinate_system_type="test") - with pytest.raises(AEDTRuntimeError, "Invalid phase unit."): + with pytest.raises(AEDTRuntimeError, match="Invalid phase unit."): m3d_app.assign_current_density(box.name, "current_density_4", phase="5ang") def test_assign_current_density_terminal(self, m3d_app): @@ -761,7 +761,9 @@ def test_assign_independent_dependent(self, m3d_app): ) assert independent assert dependent - with pytest.raises(ValueError, "Elements of coordinates system must be strings in the form of ``value+unit``."): + with pytest.raises( + ValueError, match="Elements of coordinates system must be strings in the form of ``value+unit``." + ): m3d_app.assign_master_slave( master_entity=box.faces[1], slave_entity=box.faces[5], @@ -770,7 +772,9 @@ def test_assign_independent_dependent(self, m3d_app): u_vector_origin_coordinates_slave=["10mm", "0mm", "0mm"], u_vector_pos_coordinates_slave=["10mm", "10mm", "0mm"], ) - with pytest.raises(ValueError, "Elements of coordinates system must be strings in the form of ``value+unit``."): + with pytest.raises( + ValueError, match="Elements of coordinates system must be strings in the form of ``value+unit``." + ): m3d_app.assign_master_slave( master_entity=box.faces[1], slave_entity=box.faces[5], @@ -779,7 +783,9 @@ def test_assign_independent_dependent(self, m3d_app): u_vector_origin_coordinates_slave=["10mm", "0mm", "0mm"], u_vector_pos_coordinates_slave=["10mm", "10mm", "0mm"], ) - with pytest.raises(ValueError, "Elements of coordinates system must be strings in the form of ``value+unit``."): + with pytest.raises( + ValueError, match="Elements of coordinates system must be strings in the form of ``value+unit``." + ): m3d_app.assign_master_slave( master_entity=box.faces[1], slave_entity=box.faces[5], @@ -788,7 +794,9 @@ def test_assign_independent_dependent(self, m3d_app): u_vector_origin_coordinates_slave=[10, "0mm", "0mm"], u_vector_pos_coordinates_slave=["10mm", "10mm", "0mm"], ) - with pytest.raises(ValueError, "Elements of coordinates system must be strings in the form of ``value+unit``."): + with pytest.raises( + ValueError, match="Elements of coordinates system must be strings in the form of ``value+unit``." + ): m3d_app.assign_master_slave( master_entity=box.faces[1], slave_entity=box.faces[5], @@ -797,7 +805,7 @@ def test_assign_independent_dependent(self, m3d_app): u_vector_origin_coordinates_slave=["10mm", "0mm", "0mm"], u_vector_pos_coordinates_slave=[10, "10mm", "0mm"], ) - with pytest.raises(ValueError, "Please provide a list of coordinates for U vectors."): + with pytest.raises(ValueError, match="Please provide a list of coordinates for U vectors."): m3d_app.assign_master_slave( master_entity=box.faces[1], slave_entity=box.faces[5], @@ -921,7 +929,7 @@ def test_import_dxf(self, m3d_app): def test_assign_flux_tangential(self, m3d_app): box = m3d_app.modeler.create_box([50, 0, 50], [294, 294, 19], name="Box") with pytest.raises( - AEDTRuntimeError, "Flux tangential boundary can only be assigned to a transient APhi solution type." + AEDTRuntimeError, match="Flux tangential boundary can only be assigned to a transient APhi solution type." ): m3d_app.assign_flux_tangential(box.faces[0]) m3d_app.solution_type = "TransientAPhiFormulation" @@ -936,11 +944,13 @@ def test_assign_tangential_h_field(self, m3d_app): m3d_app.solution_type = SOLUTIONS.Maxwell3d.EddyCurrent assert m3d_app.assign_tangential_h_field(box.bottom_face_x, 1, 0, 2, 0) m3d_app.solution_type = SOLUTIONS.Maxwell3d.Transient - assert not m3d_app.assign_tangential_h_field(box.bottom_face_x, 1, 0, 2, 0) + with pytest.raises(AEDTRuntimeError, match="Tangential H Field is applicable only to Eddy Current."): + m3d_app.assign_tangential_h_field(box.bottom_face_x, 1, 0, 2, 0) def test_assign_zero_tangential_h_field(self, m3d_app): box = m3d_app.modeler.create_box([0, 0, 0], [10, 10, 10]) - assert not m3d_app.assign_zero_tangential_h_field(box.top_face_z) + with pytest.raises(AEDTRuntimeError, match="Tangential H Field is applicable only to Eddy Current."): + m3d_app.assign_zero_tangential_h_field(box.top_face_z) m3d_app.solution_type = SOLUTIONS.Maxwell3d.EddyCurrent assert m3d_app.assign_zero_tangential_h_field(box.top_face_z) @@ -949,7 +959,8 @@ def test_assign_radiation(self, m3d_app): rect2 = m3d_app.modeler.create_rectangle(0, [15, 20, 0], [5, 5], material="aluminum") box = m3d_app.modeler.create_box([15, 20, 0], [5, 5, 5], material="aluminum") box2 = m3d_app.modeler.create_box([150, 20, 0], [50, 5, 10], material="aluminum") - assert not m3d_app.assign_radiation([rect, rect2, box, box2.faces[0]]) + with pytest.raises(AEDTRuntimeError, match="Excitation applicable only to Eddy Current."): + m3d_app.assign_radiation([rect, rect2, box, box2.faces[0]]) m3d_app.solution_type = SOLUTIONS.Maxwell3d.EddyCurrent bound = m3d_app.assign_radiation([rect, rect2, box, box2.faces[0]]) assert bound @@ -997,8 +1008,11 @@ def test_solution_types_setup(self, m3d_app): def test_assign_floating(self, m3d_app): box = m3d_app.modeler.create_box([0, 0, 0], [10, 10, 10], name="Box1") - floating = m3d_app.assign_floating(assignment=box, charge_value=3) - assert not floating + with pytest.raises( + AEDTRuntimeError, + match="Assign floating excitation is only valid for electrostatic or electric transient solvers.", + ): + m3d_app.assign_floating(assignment=box, charge_value=3) m3d_app.solution_type = SOLUTIONS.Maxwell3d.ElectroStatic floating = m3d_app.assign_floating(assignment=box, charge_value=3) assert floating From 352dd266e6e1dba1552526137b32ee25095a32dd Mon Sep 17 00:00:00 2001 From: Sebastien Morais Date: Thu, 30 Jan 2025 12:03:05 +0100 Subject: [PATCH 07/12] FIX: Add new constant and fix tests --- src/ansys/aedt/core/generic/constants.py | 2 +- src/ansys/aedt/core/maxwell.py | 150 +++++++++++----------- src/ansys/aedt/core/mechanical.py | 10 +- tests/system/general/test_27_Maxwell2D.py | 13 +- tests/system/general/test_28_Maxwell3D.py | 15 ++- 5 files changed, 101 insertions(+), 89 deletions(-) diff --git a/src/ansys/aedt/core/generic/constants.py b/src/ansys/aedt/core/generic/constants.py index b016e872991..adbaa39b003 100644 --- a/src/ansys/aedt/core/generic/constants.py +++ b/src/ansys/aedt/core/generic/constants.py @@ -867,7 +867,7 @@ class Circuit(object): class Mechanical(object): """Provides Mechanical solution types.""" - (Thermal, Structural, Modal) = ("Thermal", "Structural", "Modal") + (Thermal, Structural, Modal, SteadyStateThermal) = ("Thermal", "Structural", "Modal", "Steady-State Thermal") class SETUPS(object): diff --git a/src/ansys/aedt/core/maxwell.py b/src/ansys/aedt/core/maxwell.py index a3ff8532aab..5f7c0e5a835 100644 --- a/src/ansys/aedt/core/maxwell.py +++ b/src/ansys/aedt/core/maxwell.py @@ -35,6 +35,7 @@ from ansys.aedt.core.application.variables import decompose_variable_value from ansys.aedt.core.generic.constants import SOLUTIONS from ansys.aedt.core.generic.errors import AEDTRuntimeError +from ansys.aedt.core.generic.errors import GrpcApiError from ansys.aedt.core.generic.general_methods import generate_unique_name from ansys.aedt.core.generic.general_methods import is_linux from ansys.aedt.core.generic.general_methods import open_file @@ -2518,60 +2519,62 @@ def assign_master_slave( >>> oModule.AssignIndependent >>> oModule.AssignDependent """ - independent = self.modeler.convert_to_selections(independent, True) - dependent = self.modeler.convert_to_selections(dependent, True) - if not bound_name: - bound_name_m = generate_unique_name("Independent") - bound_name_s = generate_unique_name("Dependent") - else: - bound_name_m = bound_name - bound_name_s = bound_name + "_dep" - list_coordinates = [ - u_vector_origin_coordinates_master, - u_vector_origin_coordinates_slave, - u_vector_pos_coordinates_master, - u_vector_pos_coordinates_slave, - ] - if any(not isinstance(coordinates, list) for coordinates in list_coordinates): - raise ValueError("Please provide a list of coordinates for U vectors.") - for coordinates in list_coordinates: - if any(not isinstance(x, str) for x in coordinates): - raise ValueError("Elements of coordinates system must be strings in the form of ``value+unit``.") - if any(len(coordinates) != 3 for coordinates in list_coordinates): - raise ValueError("Vector must contain 3 elements for x, y, and z coordinates.") - u_master_vector_coordinates = dict( - { - "Coordinate System": "Global", - "Origin": u_vector_origin_coordinates_master, - "UPos": u_vector_pos_coordinates_master, - } - ) - master_props = dict( - {"Faces": independent, "CoordSysVector": u_master_vector_coordinates, "ReverseV": reverse_master} - ) - master = self._create_boundary_object(bound_name_m, master_props, "Independent") - if master: - u_slave_vector_coordinates = dict( + try: + independent = self.modeler.convert_to_selections(independent, True) + dependent = self.modeler.convert_to_selections(dependent, True) + if not bound_name: + bound_name_m = generate_unique_name("Independent") + bound_name_s = generate_unique_name("Dependent") + else: + bound_name_m = bound_name + bound_name_s = bound_name + "_dep" + list_coordinates = [ + u_vector_origin_coordinates_master, + u_vector_origin_coordinates_slave, + u_vector_pos_coordinates_master, + u_vector_pos_coordinates_slave, + ] + if any(not isinstance(coordinates, list) for coordinates in list_coordinates): + raise ValueError("Please provide a list of coordinates for U vectors.") + for coordinates in list_coordinates: + if any(not isinstance(x, str) for x in coordinates): + raise ValueError("Elements of coordinates system must be strings in the form of ``value+unit``.") + if any(len(coordinates) != 3 for coordinates in list_coordinates): + raise ValueError("Vector must contain 3 elements for x, y, and z coordinates.") + u_master_vector_coordinates = dict( { "Coordinate System": "Global", - "Origin": u_vector_origin_coordinates_slave, - "UPos": u_vector_pos_coordinates_slave, + "Origin": u_vector_origin_coordinates_master, + "UPos": u_vector_pos_coordinates_master, } ) - - slave_props = dict( - { - "Faces": dependent, - "CoordSysVector": u_slave_vector_coordinates, - "ReverseU": reverse_slave, - "Independent": bound_name_m, - "RelationIsSame": same_as_master, - } + master_props = dict( + {"Faces": independent, "CoordSysVector": u_master_vector_coordinates, "ReverseV": reverse_master} ) - slave = self._create_boundary_object(bound_name_s, slave_props, "Dependent") - if slave: - return master, slave - raise AEDTRuntimeError("Slave boundary could not be created.") + master = self._create_boundary_object(bound_name_m, master_props, "Independent") + if master: + u_slave_vector_coordinates = dict( + { + "Coordinate System": "Global", + "Origin": u_vector_origin_coordinates_slave, + "UPos": u_vector_pos_coordinates_slave, + } + ) + + slave_props = dict( + { + "Faces": dependent, + "CoordSysVector": u_slave_vector_coordinates, + "ReverseU": reverse_slave, + "Independent": bound_name_m, + "RelationIsSame": same_as_master, + } + ) + slave = self._create_boundary_object(bound_name_s, slave_props, "Dependent") + if slave: + return master, slave + except GrpcApiError as e: + raise AEDTRuntimeError("Slave boundary could not be created.") from e return False @pyaedt_function_handler(objects_list="assignment") @@ -3294,29 +3297,32 @@ def assign_master_slave( >>> oModule.AssignIndependent >>> oModule.AssignDependent """ - independent = self.modeler.convert_to_selections(independent, True) - dependent = self.modeler.convert_to_selections(dependent, True) - if not boundary: - bound_name_m = generate_unique_name("Independent") - bound_name_s = generate_unique_name("Dependent") - else: - bound_name_m = boundary - bound_name_s = boundary + "_dep" - master_props = dict({"Edges": independent, "ReverseV": reverse_master}) - master = self._create_boundary_object(bound_name_m, master_props, "Independent") - if master: - slave_props = dict( - { - "Edges": dependent, - "ReverseU": reverse_slave, - "Independent": bound_name_m, - "SameAsMaster": same_as_master, - } - ) - slave = self._create_boundary_object(bound_name_s, slave_props, "Dependent") - if slave: - return master, slave - raise AEDTRuntimeError("Slave boundary could not be created.") + try: + independent = self.modeler.convert_to_selections(independent, True) + dependent = self.modeler.convert_to_selections(dependent, True) + if not boundary: + bound_name_m = generate_unique_name("Independent") + bound_name_s = generate_unique_name("Dependent") + else: + bound_name_m = boundary + bound_name_s = boundary + "_dep" + master_props = dict({"Edges": independent, "ReverseV": reverse_master}) + master = self._create_boundary_object(bound_name_m, master_props, "Independent") + if master: + slave_props = dict( + { + "Edges": dependent, + "ReverseU": reverse_slave, + "Independent": bound_name_m, + "SameAsMaster": same_as_master, + } + ) + slave = self._create_boundary_object(bound_name_s, slave_props, "Dependent") + if slave: + return master, slave + except GrpcApiError as e: + raise AEDTRuntimeError("Slave boundary could not be created.") from e + return False @pyaedt_function_handler(objects="assignment", bound_name="boundary") def assign_end_connection(self, assignment, resistance=0, inductance=0, boundary=None): diff --git a/src/ansys/aedt/core/mechanical.py b/src/ansys/aedt/core/mechanical.py index 3ba5e060b0a..a1a3ed4bfda 100644 --- a/src/ansys/aedt/core/mechanical.py +++ b/src/ansys/aedt/core/mechanical.py @@ -217,7 +217,7 @@ def assign_em_losses( ---------- >>> oModule.AssignEMLoss """ - if self.solution_type != SOLUTIONS.Mechanical.Thermal: + if self.solution_type not in (SOLUTIONS.Mechanical.Thermal, SOLUTIONS.Mechanical.SteadyStateThermal): raise AEDTRuntimeError("This method works only in a Mechanical Thermal analysis.") if surface_objects is None: @@ -406,7 +406,7 @@ def assign_uniform_convection( ---------- >>> oModule.AssignConvection """ - if self.solution_type != SOLUTIONS.Mechanical.Thermal: + if self.solution_type not in (SOLUTIONS.Mechanical.Thermal, SOLUTIONS.Mechanical.SteadyStateThermal): raise AEDTRuntimeError("This method works only in a Mechanical Thermal analysis.") props = {} @@ -455,7 +455,7 @@ def assign_uniform_temperature(self, assignment, temperature="AmbientTemp", name ---------- >>> oModule.AssignTemperature """ - if self.solution_type != SOLUTIONS.Mechanical.Thermal: + if self.solution_type not in (SOLUTIONS.Mechanical.Thermal, SOLUTIONS.Mechanical.SteadyStateThermal): raise AEDTRuntimeError("This method works only in a Mechanical Thermal analysis.") props = {} @@ -605,7 +605,7 @@ def assign_heat_flux(self, assignment, heat_flux_type, value, name=""): ---------- >>> oModule.AssignHeatFlux """ - if self.solution_type != SOLUTIONS.Mechanical.Thermal: + if self.solution_type not in (SOLUTIONS.Mechanical.Thermal, SOLUTIONS.Mechanical.SteadyStateThermal): raise AEDTRuntimeError("This method works only in a Mechanical Thermal analysis.") props = {} @@ -653,7 +653,7 @@ def assign_heat_generation(self, assignment, value, name=""): ---------- >>> oModule.AssignHeatGeneration """ - if self.solution_type != SOLUTIONS.Mechanical.Thermal: + if self.solution_type not in (SOLUTIONS.Mechanical.Thermal, SOLUTIONS.Mechanical.SteadyStateThermal): raise AEDTRuntimeError("This method works only in a Mechanical Thermal analysis.") props = {} diff --git a/tests/system/general/test_27_Maxwell2D.py b/tests/system/general/test_27_Maxwell2D.py index 84d110c565a..b874d73ffff 100644 --- a/tests/system/general/test_27_Maxwell2D.py +++ b/tests/system/general/test_27_Maxwell2D.py @@ -189,10 +189,11 @@ def test_assign_master_slave(self, aedtapp): ) assert mas.name == "my_bound" assert slave.name == "my_bound_dep" - assert not aedtapp.assign_master_slave( - aedtapp.modeler["Rectangle1"].edges[0].id, - aedtapp.modeler["Rectangle1"].edges[1].id, - ) + with pytest.raises(AEDTRuntimeError, match="Slave boundary could not be created."): + aedtapp.assign_master_slave( + aedtapp.modeler["Rectangle1"].edges[0].id, + aedtapp.modeler["Rectangle1"].edges[1].id, + ) def test_check_design_preview_image(self, local_scratch, aedtapp): jpg_file = os.path.join(local_scratch.path, "file.jpg") @@ -203,7 +204,7 @@ def test_model_depth(self, aedtapp): def test_apply_skew(self, aedtapp): assert aedtapp.apply_skew() - with pytest.raises(ValueError, match="Invalid coordinate system."): + with pytest.raises(ValueError, match="Invalid skew type."): assert not aedtapp.apply_skew(skew_type="Invalid") with pytest.raises(ValueError, match="Invalid skew angle unit."): aedtapp.apply_skew(skew_type="Continuous", skew_part="Stator", skew_angle="0.5", skew_angle_unit="Invalid") @@ -617,6 +618,6 @@ def test_create_external_circuit(self, local_scratch, m2d_app): m2d_app.save_project() with pytest.raises( AEDTRuntimeError, - "External circuit excitation for windings is available only for Eddy Current or Transient solutions.", + match="External circuit excitation for windings is available only for Eddy Current or Transient solutions.", ): m2d_app.create_external_circuit() diff --git a/tests/system/general/test_28_Maxwell3D.py b/tests/system/general/test_28_Maxwell3D.py index 04d916d5976..2ac4d15aec5 100644 --- a/tests/system/general/test_28_Maxwell3D.py +++ b/tests/system/general/test_28_Maxwell3D.py @@ -23,6 +23,7 @@ # SOFTWARE. import os +import re import shutil from ansys.aedt.core import Maxwell3d @@ -691,9 +692,9 @@ def test_assign_current_density(self, m3d_app): assert bound.props[bound.name]["CurrentDensityZ"] == "0" assert bound.props[bound.name]["CoordinateSystem Name"] == "Global" - with pytest.raises(AEDTRuntimeError, match="Invalid coordinate system."): + with pytest.raises(ValueError, match="Invalid coordinate system."): m3d_app.assign_current_density(box.name, "current_density_3", coordinate_system_type="test") - with pytest.raises(AEDTRuntimeError, match="Invalid phase unit."): + with pytest.raises(ValueError, match="Invalid phase unit."): m3d_app.assign_current_density(box.name, "current_density_4", phase="5ang") def test_assign_current_density_terminal(self, m3d_app): @@ -762,7 +763,7 @@ def test_assign_independent_dependent(self, m3d_app): assert independent assert dependent with pytest.raises( - ValueError, match="Elements of coordinates system must be strings in the form of ``value+unit``." + ValueError, match=re.escape("Elements of coordinates system must be strings in the form of ``value+unit``.") ): m3d_app.assign_master_slave( master_entity=box.faces[1], @@ -1037,7 +1038,10 @@ def test_assign_resistive_sheet(self, m3d_app): assert bound.props["Nonlinear"] assert bound.props["Objects"][0] == my_rectangle.name m3d_app.solution_type = SOLUTIONS.Maxwell3d.ACConduction - assert not m3d_app.assign_resistive_sheet(assignment=my_rectangle, resistance="3ohm") + with pytest.raises( + TypeError, match="Resistive sheet is applicable only to Eddy Current, transient and magnetostatic solvers." + ): + m3d_app.assign_resistive_sheet(assignment=my_rectangle, resistance="3ohm") def test_assign_layout_force(self, layout_comp): nets_layers = { @@ -1046,7 +1050,8 @@ def test_assign_layout_force(self, layout_comp): "V3P3_S5": ["LYR_1", "LYR_2", "UNNAMED_006", "UNNAMED_008"], } assert layout_comp.assign_layout_force(nets_layers, "LC1_1") - assert not layout_comp.assign_layout_force(nets_layers, "LC1_3") + with pytest.raises(AEDTRuntimeError, match="Provided component name doesn't exist in current design."): + layout_comp.assign_layout_force(nets_layers, "LC1_3") nets_layers = {"1V0": "Bottom Solder"} assert layout_comp.assign_layout_force(nets_layers, "LC1_1") From 89f2b97e24ea187eec0364805d379c8a5ba94dcf Mon Sep 17 00:00:00 2001 From: Sebastien Morais Date: Thu, 30 Jan 2025 13:57:54 +0100 Subject: [PATCH 08/12] FIX: Typos --- src/ansys/aedt/core/maxwell.py | 21 +++++++++++++-------- tests/system/general/test_27_Maxwell2D.py | 8 +++----- tests/system/general/test_28_Maxwell3D.py | 18 ++++++++++++------ tests/system/general/test_29_Mechanical.py | 7 +++++-- 4 files changed, 33 insertions(+), 21 deletions(-) diff --git a/src/ansys/aedt/core/maxwell.py b/src/ansys/aedt/core/maxwell.py index 5f7c0e5a835..73c0fc92188 100644 --- a/src/ansys/aedt/core/maxwell.py +++ b/src/ansys/aedt/core/maxwell.py @@ -1543,8 +1543,7 @@ def assign_symmetry(self, assignment, symmetry_name=None, is_odd=True): assignment = self.modeler.convert_to_selections(assignment, True) prop = dict({"Name": symmetry_name, "Faces": assignment, "IsOdd": is_odd}) else: - msg = "At least one edge must be provided." - ValueError(msg) + raise ValueError("At least one edge must be provided.") return self._create_boundary_object(symmetry_name, prop, "Symmetry") @pyaedt_function_handler( @@ -2420,7 +2419,12 @@ def assign_current_density_terminal(self, assignment, current_density_name=None) bool ``True`` when successful, ``False`` when failed. """ - if self.solution_type in (SOLUTIONS.Maxwell3d.EddyCurrent, SOLUTIONS.Maxwell3d.Magnetostatic): + if self.solution_type not in (SOLUTIONS.Maxwell3d.EddyCurrent, SOLUTIONS.Maxwell3d.Magnetostatic): + raise AEDTRuntimeError( + "Current density can only be applied to Eddy Current or Magnetostatic solution types." + ) + + try: if current_density_name is None: current_density_name = generate_unique_name("CurrentDensity") @@ -2442,11 +2446,12 @@ def assign_current_density_terminal(self, assignment, current_density_name=None) bound_name = current_density_name bound_type = "CurrentDensityTerminal" - return self._create_boundary_object(bound_name, props, bound_type) - else: - raise AEDTRuntimeError( - "Current density can only be applied to Eddy Current or Magnetostatic solution types." - ) + boundary = self._create_boundary_object(bound_name, props, bound_type) + if boundary: + return True + except GrpcApiError as e: + raise AEDTRuntimeError("Current density terminal could not be assigned.") from e + return False @pyaedt_function_handler() def get_conduction_paths(self): diff --git a/tests/system/general/test_27_Maxwell2D.py b/tests/system/general/test_27_Maxwell2D.py index b874d73ffff..c08f62f3d8b 100644 --- a/tests/system/general/test_27_Maxwell2D.py +++ b/tests/system/general/test_27_Maxwell2D.py @@ -270,7 +270,8 @@ def test_assign_symmetry(self, aedtapp): assert aedtapp.assign_symmetry([region[0].edges[0], band[0].edges[0]]) assert aedtapp.assign_symmetry([region[0].edges[0], band[0].edges[0]], "Symmetry_Test_IsEven", False) assert aedtapp.assign_symmetry([9556, 88656]) - assert not aedtapp.assign_symmetry([]) + with pytest.raises(ValueError, match="At least one edge must be provided."): + aedtapp.assign_symmetry([]) for bound in aedtapp.boundaries: if bound.name == "Symmetry_Test_IsOdd": assert bound.type == "Symmetry" @@ -607,10 +608,7 @@ def test_create_external_circuit(self, local_scratch, m2d_app): assert m2d_app.create_external_circuit() assert m2d_app.create_external_circuit(circuit_design="test_cir") m2d_app.solution_type = SOLUTIONS.Maxwell2d.MagnetostaticXY - with pytest.raises( - AEDTRuntimeError, - match="External circuit excitation for windings is available only for Eddy Current or Transient solutions.", - ): + with pytest.raises(AEDTRuntimeError, match="No windings in the Maxwell design."): m2d_app.create_external_circuit() m2d_app.solution_type = SOLUTIONS.Maxwell2d.EddyCurrentXY for w in m2d_app.excitations_by_type["Winding"]: diff --git a/tests/system/general/test_28_Maxwell3D.py b/tests/system/general/test_28_Maxwell3D.py index 2ac4d15aec5..5abc8027f6c 100644 --- a/tests/system/general/test_28_Maxwell3D.py +++ b/tests/system/general/test_28_Maxwell3D.py @@ -700,10 +700,15 @@ def test_assign_current_density(self, m3d_app): def test_assign_current_density_terminal(self, m3d_app): box = m3d_app.modeler.create_box([50, 0, 50], [294, 294, 19], name="box") assert m3d_app.assign_current_density_terminal(box.faces[0], "current_density_t_1") - assert not m3d_app.assign_current_density_terminal(box.faces[0], "current_density_t_1") + with pytest.raises(AEDTRuntimeError, match="Current density terminal could not be assigned."): + m3d_app.assign_current_density_terminal(box.faces[0], "current_density_t_1") assert m3d_app.assign_current_density_terminal([box.faces[0], box.faces[1]], "current_density_t_2") m3d_app.solution_type = SOLUTIONS.Maxwell3d.Transient - assert not m3d_app.assign_current_density_terminal(box.faces[0], "current_density_t_3") + with pytest.raises( + AEDTRuntimeError, + match="Current density can only be applied to Eddy Current or Magnetostatic solution types.", + ): + m3d_app.assign_current_density_terminal(box.faces[0], "current_density_t_3") def test_assign_impedance(self, m3d_app): m3d_app.solution_type = SOLUTIONS.Maxwell3d.Transient @@ -774,7 +779,7 @@ def test_assign_independent_dependent(self, m3d_app): u_vector_pos_coordinates_slave=["10mm", "10mm", "0mm"], ) with pytest.raises( - ValueError, match="Elements of coordinates system must be strings in the form of ``value+unit``." + ValueError, match=re.escape("Elements of coordinates system must be strings in the form of ``value+unit``.") ): m3d_app.assign_master_slave( master_entity=box.faces[1], @@ -785,7 +790,7 @@ def test_assign_independent_dependent(self, m3d_app): u_vector_pos_coordinates_slave=["10mm", "10mm", "0mm"], ) with pytest.raises( - ValueError, match="Elements of coordinates system must be strings in the form of ``value+unit``." + ValueError, match=re.escape("Elements of coordinates system must be strings in the form of ``value+unit``.") ): m3d_app.assign_master_slave( master_entity=box.faces[1], @@ -796,7 +801,7 @@ def test_assign_independent_dependent(self, m3d_app): u_vector_pos_coordinates_slave=["10mm", "10mm", "0mm"], ) with pytest.raises( - ValueError, match="Elements of coordinates system must be strings in the form of ``value+unit``." + ValueError, match=re.escape("Elements of coordinates system must be strings in the form of ``value+unit``.") ): m3d_app.assign_master_slave( master_entity=box.faces[1], @@ -1039,7 +1044,8 @@ def test_assign_resistive_sheet(self, m3d_app): assert bound.props["Objects"][0] == my_rectangle.name m3d_app.solution_type = SOLUTIONS.Maxwell3d.ACConduction with pytest.raises( - TypeError, match="Resistive sheet is applicable only to Eddy Current, transient and magnetostatic solvers." + AEDTRuntimeError, + match="Resistive sheet is applicable only to Eddy Current, transient and magnetostatic solvers.", ): m3d_app.assign_resistive_sheet(assignment=my_rectangle, resistance="3ohm") diff --git a/tests/system/general/test_29_Mechanical.py b/tests/system/general/test_29_Mechanical.py index ebb37e3f59c..deb786cff24 100644 --- a/tests/system/general/test_29_Mechanical.py +++ b/tests/system/general/test_29_Mechanical.py @@ -28,6 +28,7 @@ from ansys.aedt.core import Hfss from ansys.aedt.core import Icepak from ansys.aedt.core import Mechanical +from ansys.aedt.core.generic.errors import AEDTRuntimeError import pytest from tests.system.general.conftest import config @@ -113,8 +114,10 @@ def test_07_assign_mechanical_boundaries(self): self.aedtapp.oproject.InsertDesign("Mechanical", "MechanicalDesign3", "Thermal", "") self.aedtapp.set_active_design("MechanicalDesign3") self.aedtapp.modeler.create_cylinder(self.aedtapp.PLANE.XY, udp, 3, coax_dimension, 0, "MyCylinder", "brass") - assert not self.aedtapp.assign_fixed_support(self.aedtapp.modeler["MyCylinder"].faces[0].id) - assert not self.aedtapp.assign_frictionless_support(self.aedtapp.modeler["MyCylinder"].faces[0].id) + with pytest.raises(AEDTRuntimeError, match="This method works only in a Mechanical Structural analysis."): + self.aedtapp.assign_fixed_support(self.aedtapp.modeler["MyCylinder"].faces[0].id) + with pytest.raises(AEDTRuntimeError, match="This method works only in a Mechanical Structural analysis."): + self.aedtapp.assign_frictionless_support(self.aedtapp.modeler["MyCylinder"].faces[0].id) def test_08_mesh_settings(self): assert self.aedtapp.mesh.initial_mesh_settings From 50bd03f86d017b2cc05fd53308a66668bb07328f Mon Sep 17 00:00:00 2001 From: Sebastien Morais Date: Fri, 31 Jan 2025 09:01:42 +0100 Subject: [PATCH 09/12] FIX: Test failure --- src/ansys/aedt/core/mechanical.py | 2 +- tests/system/general/test_27_Maxwell2D.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ansys/aedt/core/mechanical.py b/src/ansys/aedt/core/mechanical.py index a1a3ed4bfda..5c86de07185 100644 --- a/src/ansys/aedt/core/mechanical.py +++ b/src/ansys/aedt/core/mechanical.py @@ -502,7 +502,7 @@ def assign_frictionless_support(self, assignment, name=""): >>> oModule.AssignFrictionlessSupport """ if self.solution_type not in (SOLUTIONS.Mechanical.Structural, SOLUTIONS.Mechanical.Modal): - raise AEDTRuntimeError("This method works only in Mechanical Structural analysis.") + raise AEDTRuntimeError("This method works only in a Mechanical Structural analysis.") props = {} assignment = self.modeler.convert_to_selections(assignment, True) diff --git a/tests/system/general/test_27_Maxwell2D.py b/tests/system/general/test_27_Maxwell2D.py index c08f62f3d8b..72ecb8e4212 100644 --- a/tests/system/general/test_27_Maxwell2D.py +++ b/tests/system/general/test_27_Maxwell2D.py @@ -608,7 +608,7 @@ def test_create_external_circuit(self, local_scratch, m2d_app): assert m2d_app.create_external_circuit() assert m2d_app.create_external_circuit(circuit_design="test_cir") m2d_app.solution_type = SOLUTIONS.Maxwell2d.MagnetostaticXY - with pytest.raises(AEDTRuntimeError, match="No windings in the Maxwell design."): + with pytest.raises(AEDTRuntimeError, match="External circuit excitation for windings is available only for Eddy Current or Transient solutions."): m2d_app.create_external_circuit() m2d_app.solution_type = SOLUTIONS.Maxwell2d.EddyCurrentXY for w in m2d_app.excitations_by_type["Winding"]: From 3b189fd5839cb44f25c2f7f36f4fa6da8523f9f5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 31 Jan 2025 08:03:14 +0000 Subject: [PATCH 10/12] CHORE: Auto fixes from pre-commit.com hooks For more information, see https://pre-commit.ci --- tests/system/general/test_27_Maxwell2D.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/system/general/test_27_Maxwell2D.py b/tests/system/general/test_27_Maxwell2D.py index 72ecb8e4212..3c7eb771bec 100644 --- a/tests/system/general/test_27_Maxwell2D.py +++ b/tests/system/general/test_27_Maxwell2D.py @@ -608,7 +608,10 @@ def test_create_external_circuit(self, local_scratch, m2d_app): assert m2d_app.create_external_circuit() assert m2d_app.create_external_circuit(circuit_design="test_cir") m2d_app.solution_type = SOLUTIONS.Maxwell2d.MagnetostaticXY - with pytest.raises(AEDTRuntimeError, match="External circuit excitation for windings is available only for Eddy Current or Transient solutions."): + with pytest.raises( + AEDTRuntimeError, + match="External circuit excitation for windings is available only for Eddy Current or Transient solutions.", + ): m2d_app.create_external_circuit() m2d_app.solution_type = SOLUTIONS.Maxwell2d.EddyCurrentXY for w in m2d_app.excitations_by_type["Winding"]: From b8137e30cca8aed6816ecac3f356528bcd654a08 Mon Sep 17 00:00:00 2001 From: Sebastien Morais Date: Fri, 31 Jan 2025 11:33:49 +0100 Subject: [PATCH 11/12] FIX: Typos --- tests/system/general/test_27_Maxwell2D.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/general/test_27_Maxwell2D.py b/tests/system/general/test_27_Maxwell2D.py index 3c7eb771bec..b42df73b00d 100644 --- a/tests/system/general/test_27_Maxwell2D.py +++ b/tests/system/general/test_27_Maxwell2D.py @@ -619,6 +619,6 @@ def test_create_external_circuit(self, local_scratch, m2d_app): m2d_app.save_project() with pytest.raises( AEDTRuntimeError, - match="External circuit excitation for windings is available only for Eddy Current or Transient solutions.", + match="No windings in the Maxwell design.", ): m2d_app.create_external_circuit() From 4c9d11240a08c7ea71fadeb66141e96064ccbb8a Mon Sep 17 00:00:00 2001 From: Sebastien Morais Date: Fri, 31 Jan 2025 14:45:06 +0100 Subject: [PATCH 12/12] TESTS: Fix last windows test --- tests/system/general/test_28_Maxwell3D.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/system/general/test_28_Maxwell3D.py b/tests/system/general/test_28_Maxwell3D.py index 5abc8027f6c..6f80e0b1064 100644 --- a/tests/system/general/test_28_Maxwell3D.py +++ b/tests/system/general/test_28_Maxwell3D.py @@ -1080,6 +1080,9 @@ def test_enable_harmonic_force_layout(self, layout_comp): number_of_cycles_for_stop_time=1, ) layout_comp.solution_type = "Magnetostatic" - assert not layout_comp.enable_harmonic_force_on_layout_component( - comp.name, {nets[0]: layers[1::2], nets[1]: layers[1::2]} - ) + with pytest.raises( + AEDTRuntimeError, match="This methods work only with Maxwell TransientAPhiFormulation Analysis." + ): + layout_comp.enable_harmonic_force_on_layout_component( + comp.name, {nets[0]: layers[1::2], nets[1]: layers[1::2]} + )