Symbolic Expression Parser: fparser

In openEMS, user-defined symbolic mathematical expressions are used to customize the simulation. These symbolic expressions are accepted as strings, which is evaluated by the C++ engine using the fparser library. Thus, all strings for the purposes above must be legal fparser expressions.

These custom expressions are used for three purposes.

  1. Vary a material’s property in space, using a weighting function.

  2. Construct a custom excitation signal \(e[t]\) to simulate a custom input waveform.

  3. Vary an excitation field’s numerical value in space using a weighting function, to construct a custom field pattern or polarization. This is needed for hollow waveguide, which must be excited appropriately launch the desired propagation mode. Transmission lines such as coaxial cables also work best with a custom field pattern to minimize artifacts due an abrupt field input.

fparser expressions are written in an independent mini-programming language (a Domain-Specific Language), and its syntax differs from the outer C++, Matlab/Octave, or Python interface. It’s necessary to have a quick review of its syntax.

Variables

  • Universal constants

    • pi, e

    • These constants are CSXCAD / openEMS extensions.

  • Temporal variables (SetCustomExcite() only)

    • t: simulation time (seconds).

  • Spatial variables (SetMaterialWeight(), SetExcitationWeight() only)

    • x, y, z: Cartesian coordinates \((x, y, z)\).

    • rho, a, z: Cylindrical coordinates \((\rho, \alpha, z)\).

    • r, t, a: Spherical coordinates: \((r, \theta, \alpha)\)

Temporal variables can only be used in temporal expressions with SetCustomExcite(), spatial variables can only be used in spatial expressions with SetMaterialWeight(), SetExcitationWeight(). Spatial variables cannot used in temporal variables, temporal variables cannot be used in spatial variables.

Warning

The meaning of t is context-dependent, it’s time in temporal expressions, and a coordinate in spatial expressions.

Coordinate Conversions

All spatial variables are always defined in all coordinate systems by internal conversion in the software, regardless of the coordinate system of the mesh. It’s acceptable to use Cylindrical coordinates in Cartesian simulations, and vice versa.

For reference, the exact software conversion rules from the native mesh coordinates inputs to fparser output variables are given in the following table. All formulas are identical to the actual code. Note that Spherical coordinates are never used as inputs, as the simulator does not support spherical mesh coordinates. They’re defined for convenience in Cartesian and Cylindrical simulations only.

Output

Definition

Cartesian

Cylindrical

x

X-axis Distance to Origin

\(x\)

\(\rho \cos(\alpha)\)

y

Y-axis Distance to Origin

\(y\)

\(\rho \sin(\alpha)\)

rho

Distance to Z-axis

(Radius)

\(\sqrt{x ^ 2 + y ^ 2}\)

\(\rho\)

a

Azimuthal Angle

\(\mathrm{atan2}(y, x)\)

\(\alpha\)

z

Z-axis Distance to Origin

(Cylinder Cross-Section Height)

\(z\)

\(z\)

r

Distance to Origin

\(\sqrt{x^2 + y^2 + z^2}\)

\(\sqrt{\rho^2+z^2}\)

t

Polar Angle

\(\pi / 2 - \arctan(z / \sqrt{x ^ 2 + y ^ 2})\)

\(\pi / 2 - \arctan(z / \rho)\)

Hint

It’s useful to start from a 2D plane: (x, y) or (rho, a) describe a point’s location in 2D Cartesian or 2D polar coordinates. Adding the third coordinate z determines its height, thus forming the 3D Cartesian or 3D Cylindrical coordinate system.

Warning

  • Although all spatial variables are always defined in all coordinate systems, they’re not interchangeable because of vector component (field polarization) differences. In a Cartesian simulation, the weighting functions [E_1, E_2, E_3] apply to \(E_x\), \(E_y\), \(E_z\). But in a Cylindrical simulation, they’re applied to \(E_\rho\), \(E_\alpha\), \(E_z\). Changing the simulation mesh’s coordinate system requires changing all weighting functions.

  • The azimuthal angle is always safe to use, \(\mathrm{atan2}(y, x)\) is defined everywhere.

  • The polar angle t is singular (t = NaN) at the origin (0, 0, 0), but it’s otherwise safe to use if \(x = y = 0\) because \(\arctan(z / 0) = \arctan(\pm \infty) = \pm \pi\) in IEEE-754.

Syntax

fparser supports a complete set of built-in functions, including trigonometry functions, conditional functions, and Boolean expressions. This makes functions expressive, if tricky.

See also

See the fparser project documentation [1] for full syntax. The following list is only a quick and incomplete reference. fparser has advanced features such as defining variables.

Math Functions

  • Trigonometry

    • acos(x), acosh(x), asin(x), asinh(x), atan(x), atan2(y, x), atanh(x), cos(x), cosh(x), cot(x), csc(x), sec(x), sin(x), sinh(x), tan(x), tanh(x).

  • Floating Point

    • int(x), ceil(x), floor(x), trunc(x), hypot(x, y).

  • Complex Number

    • arg(z), conj(z), real(z), imag(z), abs(z), polar(mag, phase).

  • Arithmetic

    • abs(x), sqrt(x), cbrt(x), exp(x), exp2(x), pow(x, y), log(x), log2(x), log10(x), max(x, y), min(x, y).

  • Bessel functions of the first and second kinds

    • j0(x), j1(x), jn(n, x)

    • y0(x), y1(x), yn(n, x)

    • These functions are CSXCAD extensions for spatial expressions only. It’s currently unimplemented for temporal expressions.

Other Syntax

  • Boolean expressions, evaluates to 0 or 1

    • (x = y), (x < y), (x <= y), (x != y), (x > y), (x >= y)

  • Conditonal Function

    • if(cond, value_if_true, value_if_false)

Note

All non-zero values are treated as True.

Examples

  • Set a radial field pattern to excite a coaxial cable (in Cylindrical coordinates only):

    '1 / rho'
    
  • Create a weighting function that alternates between 1 and 2, depending on a sinusoid’s “signal level”, using the spatial coordinate z as the independent variable, using a Boolean expression:

    '(sin(4 * z / 1000 * 2 * pi) > 0) + 1'
    
  • The same task, using the if function for better readability:

    'if(sin(4 * z / 1000 * 2 * pi) > 0, 2, 1)'
    
  • Set a radial field pattern to excite a coaxial cable (in Cartesian coordinates only):

    'x / (x * x + y * y) * (sqrt(x * x + y * y) < r_o) * (sqrt(x * x + y * y) > r_i)'
    

    Tip

    • Replace r_o, r_i with the actual numerical coordinates. Depending on the propagation direction, x and y can be y and z

    • For readability, you can construct a string dynamically in Octave/Python using string substitution from a common template.

    • This is one of the most complex fparser expressions commonly used, showing the advantage of the cylindrical coordinate system for symmetrical problems.

Bibliography