Skip to content

FEAT: EM fields in Q3D #6421

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Jul 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/changelog.d/6421.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Em fields in q3d
2 changes: 2 additions & 0 deletions src/ansys/aedt/core/application/aedt_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ def oradfield(self):
"""
if self.design_type == "HFSS" and self._odesign.GetSolutionType() not in ["EigenMode", "Characteristic Mode"]:
return self._odesign.GetModule("RadField")
if self.desktop_class.aedt_version_id >= "2025.1" and self.design_type == "Q3D Extractor":
return self._odesign.GetModule("RadField")
return None

@pyaedt_function_handler()
Expand Down
135 changes: 70 additions & 65 deletions src/ansys/aedt/core/hfss.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import math
from pathlib import Path
import tempfile
from typing import Optional
from typing import Union
import warnings

Expand Down Expand Up @@ -236,6 +237,28 @@ def __init__(
def _init_from_design(self, *args, **kwargs):
self.__init__(*args, **kwargs)

@pyaedt_function_handler
# NOTE: Extend Mixin behaviour to handle near field setups
def _create_boundary(self, name, props, boundary_type):
# No-near field cases
if boundary_type not in (
"NearFieldSphere",
"NearFieldBox",
"NearFieldRectangle",
"NearFieldLine",
"NearFieldPoints",
):
return super()._create_boundary(name, props, boundary_type)

# Near field setup
bound = NearFieldSetup(self, name, props, boundary_type)
result = bound.create()
if result:
self.field_setups.append(bound)
self.logger.info(f"Field setup {boundary_type} {name} has been created.")
return bound
raise AEDTRuntimeError(f"Failed to create near field setup {boundary_type} {name}")

@property
def field_setups(self):
"""List of AEDT radiation fields.
Expand Down Expand Up @@ -5574,19 +5597,19 @@ def insert_infinite_sphere(
@pyaedt_function_handler()
def insert_near_field_sphere(
self,
radius=20,
radius: Union[float, int, str] = 20,
radius_units="mm",
x_start=0,
x_stop=180,
x_step=10,
y_start=0,
y_stop=180,
y_step=10,
angle_units="deg",
custom_radiation_faces=None,
custom_coordinate_system=None,
name=None,
):
x_start: Union[float, int, str] = 0,
x_stop: Union[float, int, str] = 180,
x_step: Union[float, int, str] = 10,
y_start: Union[float, int, str] = 0,
y_stop: Union[float, int, str] = 180,
y_step: Union[float, int, str] = 10,
angle_units: str = "deg",
custom_radiation_faces: Optional[str] = None,
custom_coordinate_system: Optional[str] = None,
name: Optional[str] = None,
) -> NearFieldSetup:
"""Create a near field sphere.

.. note::
Expand Down Expand Up @@ -5648,26 +5671,22 @@ def insert_near_field_sphere(
props["CoordSystem"] = custom_coordinate_system
else:
props["CoordSystem"] = ""
bound = NearFieldSetup(self, name, props, "NearFieldSphere")
if bound.create():
self.field_setups.append(bound)
return bound
return False
return self._create_boundary(name, props, "NearFieldSphere")

@pyaedt_function_handler()
def insert_near_field_box(
self,
u_length=20,
u_samples=21,
v_length=20,
v_samples=21,
w_length=20,
w_samples=21,
units="mm",
custom_radiation_faces=None,
custom_coordinate_system=None,
name=None,
):
u_length: Union[float, int, str] = 20,
u_samples: Union[float, int, str] = 21,
v_length: Union[float, int, str] = 20,
v_samples: Union[float, int, str] = 21,
w_length: Union[float, int, str] = 20,
w_samples: Union[float, int, str] = 21,
units: str = "mm",
custom_radiation_faces: Optional[str] = None,
custom_coordinate_system: Optional[str] = None,
name: Optional[str] = None,
) -> NearFieldSetup:
"""Create a near field box.

.. note::
Expand Down Expand Up @@ -5723,24 +5742,20 @@ def insert_near_field_box(
props["CoordSystem"] = custom_coordinate_system
else:
props["CoordSystem"] = "Global"
bound = NearFieldSetup(self, name, props, "NearFieldBox")
if bound.create():
self.field_setups.append(bound)
return bound
return False
return self._create_boundary(name, props, "NearFieldBox")

@pyaedt_function_handler()
def insert_near_field_rectangle(
self,
u_length=20,
u_samples=21,
v_length=20,
v_samples=21,
units="mm",
custom_radiation_faces=None,
custom_coordinate_system=None,
name=None,
):
u_length: Union[float, int, str] = 20,
u_samples: Union[float, int, str] = 21,
v_length: Union[float, int, str] = 20,
v_samples: Union[float, int, str] = 21,
units: str = "mm",
custom_radiation_faces: Optional[str] = None,
custom_coordinate_system: Optional[str] = None,
name: Optional[str] = None,
) -> NearFieldSetup:
"""Create a near field rectangle.

.. note::
Expand Down Expand Up @@ -5790,20 +5805,17 @@ def insert_near_field_rectangle(
props["CoordSystem"] = custom_coordinate_system
else:
props["CoordSystem"] = "Global"
bound = NearFieldSetup(self, name, props, "NearFieldRectangle")
if bound.create():
self.field_setups.append(bound)
return bound
return False

return self._create_boundary(name, props, "NearFieldRectangle")

@pyaedt_function_handler(line="assignment")
def insert_near_field_line(
self,
assignment,
points=1000,
custom_radiation_faces=None,
name=None,
):
assignment: str,
points: Union[float, str] = 1000,
custom_radiation_faces: Optional[str] = None,
name: str = None,
) -> NearFieldSetup:
"""Create a near field line.

.. note::
Expand All @@ -5830,6 +5842,7 @@ def insert_near_field_line(
name = generate_unique_name("Line")

props = dict({"UseCustomRadiationSurface": custom_radiation_faces is not None})

if custom_radiation_faces:
props["CustomRadiationSurface"] = custom_radiation_faces
else:
Expand All @@ -5838,19 +5851,15 @@ def insert_near_field_line(
props["NumPts"] = points
props["Line"] = assignment

bound = NearFieldSetup(self, name, props, "NearFieldLine")
if bound.create():
self.field_setups.append(bound)
return bound
return False
return self._create_boundary(name, props, "NearFieldLine")

@pyaedt_function_handler()
def insert_near_field_points(
self,
input_file: Union[str, Path] = None,
coordinate_system="Global",
name=None,
):
coordinate_system: str = "Global",
name: Optional[str] = None,
) -> NearFieldSetup:
"""Create a near field line.

.. note::
Expand Down Expand Up @@ -5880,11 +5889,7 @@ def insert_near_field_points(
props["CoordSystem"] = coordinate_system
props["PointListFile"] = str(point_file)

bound = NearFieldSetup(self, name, props, "NearFieldPoints")
if bound.create():
self.field_setups.append(bound)
return bound
return False
return self._create_boundary(name, props, "NearFieldPoints")

@pyaedt_function_handler()
def set_sbr_current_sources_options(self, conformance=False, thin_sources=False, power_fraction=0.95):
Expand Down
13 changes: 8 additions & 5 deletions src/ansys/aedt/core/modules/boundary/hfss_boundary.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,14 @@ def _child_object(self):
child_object = None
design_childs = self._app.get_oo_name(self._app.odesign)

if "Radiation" in design_childs:
cc = self._app.get_oo_object(self._app.odesign, "Radiation")
cc_names = self._app.get_oo_name(cc)
if self._name in cc_names:
child_object = cc.GetChildObject(self._name)
for category in ["Radiation", "EM Fields"]:
if category in design_childs:
cc = self._app.get_oo_object(self._app.odesign, category)
cc_names = self._app.get_oo_name(cc)
if self._name in cc_names:
child_object = cc.GetChildObject(self._name)
break

return child_object

@property
Expand Down
Loading