Skip to content

Electromagnetic Modes

Mode Types

fdtdx.core.modes.ModeTupleType = namedtuple('Mode', ['neff', 'Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz']) module-attribute

A named tuple representing an electromagnetic mode.

Attributes:

Name Type Description
neff

Complex effective refractive index of the mode

Ex

X component of the electric field

Ey

Y component of the electric field

Ez

Z component of the electric field

Hx

X component of the magnetic field

Hy

Y component of the magnetic field

Hz

Z component of the magnetic field

Mode Solvers

fdtdx.core.physics.modes.compute_modes(frequency, permittivity_cross_section, coords, direction, target_neff=None, angle_theta=0.0, angle_phi=0.0, num_modes=10, precision='double', filter_pol=None)

Compute optical modes of a waveguide cross-section.

This function uses the Tidy3D mode solver to compute the optical modes of a given waveguide cross-section defined by its permittivity distribution.

Parameters:

Name Type Description Default
frequency float

Operating frequency in Hz

required
permittivity_cross_section ndarray

2D array of relative permittivity values

required
coords List[ndarray]

List of coordinate arrays [x, y] defining the grid

required
direction Literal['+', '-']

Propagation direction, either "+" or "-"

required
target_neff float | None

Target effective index to search around. Defaults to None.

None
angle_theta float

Polar angle in radians. Defaults to 0.0.

0.0
angle_phi float

Azimuthal angle in radians. Defaults to 0.0.

0.0
num_modes int

Number of modes to compute. Defaults to 10.

10
precision Literal['single', 'double']

Numerical precision. Defaults to "double".

'double'
filter_pol Literal['te', 'tm'] | None

Mode polarization filter. Defaults to None.

None

Returns:

Type Description
List[ModeTupleType]

List[ModeTupleType]: List of computed modes sorted by decreasing real part of effective index. Each mode contains the field components and effective index.

Source code in src/fdtdx/core/physics/modes.py
def compute_modes(
    frequency: float,
    permittivity_cross_section: np.ndarray,
    coords: List[np.ndarray],
    direction: Literal["+", "-"],
    target_neff: float | None = None,
    angle_theta: float = 0.0,
    angle_phi: float = 0.0,
    num_modes: int = 10,
    precision: Literal["single", "double"] = "double",
    filter_pol: Literal["te", "tm"] | None = None,
) -> List[ModeTupleType]:
    """Compute optical modes of a waveguide cross-section.

    This function uses the Tidy3D mode solver to compute the optical modes of a given
    waveguide cross-section defined by its permittivity distribution.

    Args:
        frequency (float): Operating frequency in Hz
        permittivity_cross_section (np.ndarray): 2D array of relative permittivity values
        coords (List[np.ndarray]): List of coordinate arrays [x, y] defining the grid
        direction (Literal["+", "-"]): Propagation direction, either "+" or "-"
        target_neff (float | None, optional): Target effective index to search around. Defaults to None.
        angle_theta (float, optional): Polar angle in radians. Defaults to 0.0.
        angle_phi (float, optional): Azimuthal angle in radians. Defaults to 0.0.
        num_modes (int, optional): Number of modes to compute. Defaults to 10.
        precision (Literal["single", "double"], optional): Numerical precision. Defaults to "double".
        filter_pol (Literal["te", "tm"] | None, optional): Mode polarization filter. Defaults to None.

    Returns:
        List[ModeTupleType]: List of computed modes sorted by decreasing real part of
            effective index. Each mode contains the field components and effective index.
    """
    # see https://docs.flexcompute.com/projects/tidy3d/en/latest/_autosummary/tidy3d.ModeSpec.html#tidy3d.ModeSpec
    mode_spec = SimpleNamespace(
        num_modes=num_modes,
        target_neff=target_neff,
        num_pml=(0, 0),
        filter_pol=filter_pol,
        angle_theta=angle_theta,
        angle_phi=angle_phi,
        bend_radius=None,
        bend_axis=None,
        precision=precision,
        track_freq="central",
        group_index_step=False,
    )
    od = np.zeros_like(permittivity_cross_section)
    eps_cross = [
        permittivity_cross_section,
        od,
        od,
        od,
        permittivity_cross_section,
        od,
        od,
        od,
        permittivity_cross_section,
    ]

    EH, neffs, _ = _compute_modes(
        eps_cross=eps_cross,
        coords=coords,
        freq=frequency,
        # freq=tidy3d.C_0 / (wavelength / 1e-6),
        mode_spec=mode_spec,
        direction=direction,
    )
    ((Ex, Ey, Ez), (Hx, Hy, Hz)) = EH.squeeze()

    if num_modes == 1:
        modes = [
            ModeTupleType(
                Ex=Ex,
                Ey=Ey,
                Ez=Ez,
                Hx=Hx,
                Hy=Hy,
                Hz=Hz,
                neff=float(neffs.real) + 1j * float(neffs.imag),
            )
            for _ in range(num_modes)
        ]
    else:
        modes = [
            ModeTupleType(
                Ex=Ex[..., i],
                Ey=Ey[..., i],
                Ez=Ez[..., i],
                Hx=Hx[..., i],
                Hy=Hy[..., i],
                Hz=Hz[..., i],
                neff=neffs[i],
            )
            for i in range(num_modes)
        ]
    modes = sorted(modes, key=lambda m: float(np.real(m.neff)), reverse=True)
    return modes