Field expression builder#

The AEDT Fields Calculator is driven by a stack of string operations in reverse Polish notation. Assembling those strings by hand is error-prone and hides which operations are valid for a given quantity. The field expression builder wraps that operation grammar with four strongly typed expression classes (ScalarReal, ScalarComplex, VectorReal, VectorComplex) so that an editor or type checker guides you, and a readable Python chain replaces the raw operation list.

It does not read any raw binary field data; it is purely a typed front end for the calculator’s own operation stack and reuses the existing FieldsCalculator to register, evaluate, and export expressions.

Getting started#

Obtain the builder through hfss.post.fields_calculator.expressions:

from ansys.aedt.core import Hfss
from ansys.aedt.core.visualization.post.field_calculator_expressions import (
    Line,
    Surface,
    Volume,
    cross,
    dot,
)

hfss = Hfss()
fx = hfss.post.fields_calculator.expressions

e = fx.vector("E")  # VectorComplex
mag_e = e.magnitude()  # ScalarReal
peak = mag_e.maximum(Volume("MySolid"))  # ScalarReal over a volume
value = peak.evaluate(setup="Setup1 : LastAdaptive")

Unary operations are .method() calls whose return type tells you what comes next; binary operations are the Python operators (+ - * /) and the free functions dot and cross. Geometry is referenced with Line, Surface, and Volume. Nothing is sent to AEDT until you call add(), evaluate(), or export().

Catalog cookbook#

Every expression shipped in expression_catalog.toml can be written with the builder, and each compiles to the same operation stack the catalog uses (the unit tests assert this exactly). The examples below show the typed form next to the previous operation list to highlight the difference. In the previous form, 'assignment' is the object name filled in at registration time; with the builder you pass the geometry directly to the reduction.

Power flow through a surface#

Field expression builder

poynting = fx.named_expression("Poynting", is_vector=True)
power = dot(poynting.real(), fx.normal()).integrate(Surface("MySheet"))

Previous operation stack

operations = [
    "NameOfExpression('Poynting')",
    "Operation('Real')",
    "Operation('Normal')",
    "Operation('Dot')",
    "EnterSurface('assignment')",
    "Operation('SurfaceValue')",
    "Operation('Integrate')",
]

fx.normal() pushes the surface’s unit normal vector so that dot projects the field onto it.

Voltage drop along a line#

The complex line voltage integrates the real and imaginary tangential projections separately and recombines them.

Field expression builder

e = fx.vector("E")
line = Line("MyLine")
real_part = dot(e.real(), fx.tangent()).integrate(line).as_complex_real()
imag_part = dot(e.imaginary(), fx.tangent()).integrate(line).as_complex_imag()
voltage = real_part + imag_part

Previous operation stack

operations = [
    "Fundamental_Quantity('E')",
    "Operation('Real')",
    "Operation('Tangent')",
    "Operation('Dot')",
    "EnterLine('assignment')",
    "Operation('LineValue')",
    "Operation('Integrate')",
    "Operation('CmplxR')",
    "Fundamental_Quantity('E')",
    "Operation('Imag')",
    "Operation('Tangent')",
    "Operation('Dot')",
    "EnterLine('assignment')",
    "Operation('LineValue')",
    "Operation('Integrate')",
    "Operation('CmplxI')",
    "Operation('+')",
]

Wave impedance along a line#

Field expression builder

unit = fx.vector_constant(1, 0, 0)
e = fx.vector("E").smooth().component_magnitude()
h = fx.named_expression("<Hx,Hy,Hz>", is_vector=True).smooth().component_magnitude()
impedance = cross(e, unit).magnitude() / cross(h, unit).magnitude()

Previous operation stack

operations = [
    "Fundamental_Quantity('E')",
    "Operation('Smooth')",
    "Operation('CmplxMag')",
    "Vector_Constant(1, 0, 0)",
    "Operation('Cross')",
    "Operation('Mag')",
    "NameOfExpression('<Hx,Hy,Hz>')",
    "Operation('Smooth')",
    "Operation('CmplxMag')",
    "Vector_Constant(1, 0, 0)",
    "Operation('Cross')",
    "Operation('Mag')",
    "Operation('/')",
]

H-field minimum position#

Field expression builder

h = fx.named_expression("<Hx,Hy,Hz>", is_vector=True)
x_position = h.magnitude().min_position(Surface("MySheet")).scalar_x()

Previous operation stack

operations = [
    "NameOfExpression('<Hx,Hy,Hz>')",
    "Operation('Mag')",
    "EnterSurface('assignment')",
    "Operation('SurfaceValue')",
    "Operation('MinPos')",
    "Operation('ScalarX')",
]

Radial component of the magnetic field (Maxwell)#

Field expression builder

b = fx.vector("B")
phi = fx.function("PHI")  # a design variable
b_radial = b.scalar_x() * phi.cos() + b.scalar_y() * phi.sin()

Previous operation stack

operations = [
    "Fundamental_Quantity('B')",
    "Operation('ScalarX')",
    "Scalar_Function(FuncValue='PHI')",
    "Operation('UMathFunc', 'Cos')",
    "Operation('*')",
    "Fundamental_Quantity('B')",
    "Operation('ScalarY')",
    "Scalar_Function(FuncValue='PHI')",
    "Operation('UMathFunc', 'Sin')",
    "Operation('*')",
    "Operation('+')",
]

Radial stress tensor (reusing named expressions)#

Field expression builder

b_radial = fx.named_expression("b_radial")
b_tangential = fx.named_expression("b_tangential")
stress = (b_radial * b_radial + -(b_tangential * b_tangential)) / 1.25664e-06 / 2

Previous operation stack

operations = [
    "NameOfExpression('b_radial')",
    "NameOfExpression('b_radial')",
    "Operation('*')",
    "NameOfExpression('b_tangential')",
    "NameOfExpression('b_tangential')",
    "Operation('*')",
    "Operation('Neg')",
    "Operation('+')",
    "Scalar_Constant(1.25664e-06)",
    "Operation('/')",
    "Scalar_Constant(2)",
    "Operation('/')",
]

Python numbers are accepted as operands and are turned into the matching Scalar_Constant / Complex_Constant tokens, so / 1.25664e-06 / 2 reads naturally.

Registering, evaluating, and exporting#

A built expression is materialized through the underlying calculator:

power = dot(poynting.real(), fx.normal()).integrate(Surface("MySheet"))

name = power.add("power_flow")  # register as a named expression
result = power.evaluate(setup="Setup1 : LastAdaptive")  # register and evaluate
power.export("power.fld", solution="Setup1 : LastAdaptive")  # register and export

Use verify() to check a chain locally before sending it to AEDT (a malformed or unbalanced stack raises a clear error), and checkpoint() to keep very long or heavily reused expressions short by registering an intermediate named expression and continuing from a single-token reference to it.

Coverage#

The builder reproduces all of the built-in catalog expressions exactly, including the remaining ones not shown above: voltage_line_time, voltage_line_maxwell, voltage_drop, voltage_drop_2025, current_line, current_line_time, electric_charge, e_line, wave_impedance_y / wave_impedance_z, h_field_minimum_y_position / h_field_minimum_z_position, b_tangential, and tangential_stress_tensor.

For the full list of types and operations, and the operations that are not yet wrapped, see the API reference for the field_calculator_expressions module.