diff --git a/doc/changelog.d/7053.added.md b/doc/changelog.d/7053.added.md new file mode 100644 index 00000000000..0b77d98cc30 --- /dev/null +++ b/doc/changelog.d/7053.added.md @@ -0,0 +1 @@ +Wrap AssignFarFieldWave diff --git a/src/ansys/aedt/core/hfss.py b/src/ansys/aedt/core/hfss.py index 291f39b7863..243646b0c33 100644 --- a/src/ansys/aedt/core/hfss.py +++ b/src/ansys/aedt/core/hfss.py @@ -6720,6 +6720,114 @@ def plane_wave( inc_wave_args.update(props) return self._create_boundary(name, inc_wave_args, "Plane Incident Wave") + @pyaedt_function_handler() + def far_field_wave( + self, + assignment: Union[str, "Hfss"], + setup: Optional[str] = None, + simulate_source: bool = True, + preserve_source_solution: bool = True, + coordinate_system: str = "Global", + name: Optional[str] = None, + ) -> BoundaryObject: + """Create a far field wave excitation. + + Parameters + ---------- + assignment : ansys.aedt.core.Hfss or str + Source HFSS object from which to link the far field data, or path to an external + far field data file (.ffd file). + setup : optional + Name of the setup. The default is ``None``, in which + case a name is automatically assigned. + This parameter is only used when ``assignment`` is an HFSS object. + simulate_source : bool, optional + Whether to force the source design to solve. The default is ``True``. + This parameter is only used when ``assignment`` is an HFSS object. + preserve_source_solution : bool, optional + Whether to preserve the source solution. The default is ``True``. + This parameter is only used when ``assignment`` is an HFSS object. + coordinate_system : str, optional + Coordinate system to use for the source. The default is ``"Global"``. + name : str, optional + Name of the excitation. The default is ``None``, in which + case a name is automatically assigned. + + Returns + ------- + :class:`ansys.aedt.core.modules.boundary.common.BoundaryObject` + Far field boundary object. + + References + ---------- + >>> oModule.AssignFarFieldWave + + Examples + -------- + Create a far field wave excitation from another design in the same project. + + >>> from ansys.aedt.core import Hfss + >>> target = Hfss(project="target_project.aedt") + >>> source = Hfss(project="target_project.aedt", design="Source_Design") + >>> setup = source.create_setup("Setup1", Frequency="10GHz") + >>> far_field_wave_src = target.far_field_wave(assignment=source, setup=setup) + + Create a far field wave excitation from an external project. + + >>> target = Hfss(project="target_project.aedt") + >>> source = Hfss(project="source_project.aedt", design="Array_Design") + >>> setup = source.create_setup("Setup1", Frequency="10GHz") + >>> far_field_wave_src = target.far_field_wave(assignment=source, setup=setup) + + Create a far field wave excitation from an external data file. + + >>> target = Hfss(project="target_project.aedt") + >>> far_field_wave_src = target.far_field_wave(assignment="/path/to/farfield.ffd") + """ + name = self._get_unique_source_name(name, "IncFFWave") + + if isinstance(assignment, str): + # Use external data file + props = { + "IsFarField": True, + "UseDataLink": False, + "ExternalDataFile": assignment, + "SourceCoordSystem": coordinate_system, + } + else: + # Use data link to another design + if assignment.project_name == self.project_name: + project_name = "This Project*" + else: + project_name = Path(assignment.project_path) / (assignment.project_name + ".aedt") + + design_name = assignment.design_name + + if not setup.get_sweep(): + setup = assignment.nominal_adaptive + + params = {} + pars = assignment.available_variations.get_independent_nominal_values() + for el in pars: + params[el] = pars[el] + + props = { + "IsFarField": True, + "UseDataLink": True, + "ExternalDataFile": "", + "Project": str(project_name), + "Product": "HFSS", + "Design": design_name, + "Soln": setup, + "Params": params, + "ForceSourceToSolve": simulate_source, + "PreservePartnerSoln": preserve_source_solution, + "PathRelativeTo": "TargetProject", + "SourceCoordSystem": coordinate_system, + } + + return self._create_boundary(name, props, "Far Field Wave") + @pyaedt_function_handler() def hertzian_dipole_wave( self, diff --git a/src/ansys/aedt/core/modules/boundary/common.py b/src/ansys/aedt/core/modules/boundary/common.py index 00dca3553a5..cfa27f3638e 100644 --- a/src/ansys/aedt/core/modules/boundary/common.py +++ b/src/ansys/aedt/core/modules/boundary/common.py @@ -550,6 +550,8 @@ def create(self): self._app.oboundary.AssignFluxTangential(self._get_args()) elif bound_type == "Plane Incident Wave": self._app.oboundary.AssignPlaneWave(self._get_args()) + elif bound_type == "Far Field Wave": + self._app.oboundary.AssignFarFieldWave(self._get_args()) elif bound_type == "Hertzian Dipole Wave": self._app.oboundary.AssignHertzianDipoleWave(self._get_args()) elif bound_type == "ResistiveSheet": diff --git a/tests/system/general/test_hfss.py b/tests/system/general/test_hfss.py index 2f4df296743..b80847e081c 100644 --- a/tests/system/general/test_hfss.py +++ b/tests/system/general/test_hfss.py @@ -1992,6 +1992,65 @@ def test_plane_wave(aedt_app): assert new_plane_wave.name in aedt_app.excitation_names +def test_far_field(aedt_app, add_app, test_tmp_dir): + # Create simple geometry in target design + _ = aedt_app.modeler.create_box([0, 0, 0], [10, 10, 10], "TargetBox") + + # Create a source design in the same project + source_design = add_app(application=Hfss, design="FarFieldSource", close_projects=False) + source_design.solution_type = "Modal" + + setup = source_design.create_setup("Setup1", Frequency="10GHz") + setup.props["MaximumPasses"] = 2 + + # Test far field with assignment from same project + far_field_boundary = aedt_app.far_field_wave( + assignment=source_design, setup=setup, coordinate_system="Global", name="FarField1" + ) + assert far_field_boundary is not None + assert far_field_boundary.name == "FarField1" + assert far_field_boundary.name in aedt_app.excitation_names + assert far_field_boundary.type == "Far Field Wave" + + # Test far field with external data file + ffd_file_original = TESTS_GENERAL_PATH / "example_models" / "T04" / "test.ffd" + ffd_file = shutil.copy2(ffd_file_original, test_tmp_dir / "test.ffd") + + far_field_ext = aedt_app.far_field_wave( + assignment=str(ffd_file), coordinate_system="Global", name="FarFieldExternal" + ) + assert far_field_ext is not None + assert far_field_ext.name == "FarFieldExternal" + assert far_field_ext.name in aedt_app.excitation_names + + # Test with different properties + far_field_boundary2 = aedt_app.far_field_wave( + assignment=source_design, + setup=setup, + coordinate_system="Global", + simulate_source=False, + preserve_source_solution=False, + ) + assert far_field_boundary2 is not None + assert far_field_boundary2.name in aedt_app.excitation_names + + # Test far field with external project + external_source = add_app( + application=Hfss, project="ExternalProject", design="ExternalSource", close_projects=False + ) + external_source.solution_type = "Modal" + external_setup = external_source.create_setup("Setup1", Frequency="10GHz") + external_setup.props["MaximumPasses"] = 2 + + far_field_external_project = aedt_app.far_field_wave( + assignment=external_source, setup=external_setup, coordinate_system="Global", name="FarFieldExternalProject" + ) + external_source.close_project() + assert far_field_external_project is not None + assert far_field_external_project.name == "FarFieldExternalProject" + assert far_field_external_project.name in aedt_app.excitation_names + + def test_export_on_completion(aedt_app, test_tmp_dir): assert aedt_app.export_touchstone_on_completion() assert aedt_app.export_touchstone_on_completion(export=True, output_dir=test_tmp_dir)