Example #1
0
def compute_overlap_e_angled(
    E: field_t,
    H: field_t,
    axis: int,
    omega: complex,
    dxes: dx_lists_t,
    slices: List[slice],
    mu: field_t = None,
) -> field_t:
    """
    Given an eigenmode obtained by solve_waveguide_mode, calculates overlap_e for the
    mode orthogonality relation Integrate(((E x H_mode) + (E_mode x H)) dot dn)
    [assumes reflection symmetry].

    overlap_e makes use of the e2h operator to collapse the above expression into
     (vec(E) @ vec(overlap_e)), allowing for simple calculation of the mode overlap.

    :param E: E-field of the mode
    :param H: H-field of the mode (advanced by half of a Yee cell from E)
    :axis: propagation axis
    :param omega: Angular frequency of the simulation
    :param dxes: Grid parameters [dx_e, dx_h] as described in fdfd_tools.operators header
    :param slices: epsilon[tuple(slices)] is used to select the portion of the grid to use
        as the waveguide cross-section. slices[axis] should select only one
    :param mu: Magnetic permeability (default 1 everywhere)
    :return: overlap_e for calculating the mode overlap
    """
    if (slices[axis].stop - slices[axis].start) != 1:
        raise ValueError('The slice in the axis direction is not 1 wide.')
    # Write out the operator product for the mode orthogonality integral
    domain = np.zeros_like(E)
    domain[[slice(0, 3)] + slices] = 1

    dn = np.zeros_like(E)
    dn[axis] = np.ones_like(E[axis])
    dn_vec = vec(dn)

    e2h = operators.e2h(omega, dxes, mu)
    ds = sparse.diags(vec(domain))
    h_cross_ = operators.poynting_h_cross(np.conj(vec(H)), dxes)
    e_cross_ = operators.poynting_e_cross(np.conj(vec(E)), dxes)

    overlap_e = dn_vec @ ds @ (-h_cross_ + e_cross_ @ e2h)

    # Normalize
    norm_factor = np.abs(overlap_e @ vec(E))
    overlap_e /= norm_factor

    return unvec(overlap_e, E[0].shape)
Example #2
0
def compute_overlap_annulus(
    E: field_t,
    omega: complex,
    dxes: dx_lists_t,
    axis: int,
    mu: field_t = None,
) -> field_t:
    """This is hopefully going to calculate the overlap """

    # need to extract the size of dxes to adjust the size of mask and the E field
    len_dxes = np.concatenate(dxes, axis=0)

    # want to extract the absolute value, x=0, y=1, z=2

    # Domain is all zero
    domain = np.zeros_like(E[0], dtype=int)

    # Then set the slices part equal to 1 - may need to use our mask
    t = np.abs(len_dxes[0].size)

    # TODO adjust these values, may call from problem
    mask = annulus(t, t, [0, 0], 0.3 * t, 0.2 * t)
    mask = mask[..., newaxis]  # adds the z to mask
    domain[mask] = 1

    npts = E[0].size
    dn = np.zeros(npts * 3, dtype=int)
    dn[0:npts] = 1
    dn = np.roll(dn, npts * axis)

    e2h = operators.e2h(omega, dxes, mu)
    # Hopefully this works with the mask
    ds = sparse.diags(vec([domain] * 3))

    e_cross_ = operators.poynting_e_cross(vec(E), dxes)

    # Difference is, we have no H field
    overlap_e = dn @ ds @ (e_cross_ @ e2h)

    # Normalize
    norm_factor = np.abs(overlap_e @ vec(E))
    overlap_e /= norm_factor

    return unvec(overlap_e, E[0].shape)
Example #3
0
def compute_overlap_e(
    E: field_t,
    H: field_t,
    wavenumber: complex,
    omega: complex,
    dxes: dx_lists_t,
    axis: int,
    polarity: int,
    slices: List[slice],
    mu: field_t = None,
) -> field_t:
    """
    Given an eigenmode obtained by solve_waveguide_mode, calculates overlap_e for the
    mode orthogonality relation Integrate(((E x H_mode) + (E_mode x H)) dot dn)
    [assumes reflection symmetry].

    overlap_e makes use of the e2h operator to collapse the above expression into
     (vec(E) @ vec(overlap_e)), allowing for simple calculation of the mode overlap.

    :param E: E-field of the mode
    :param H: H-field of the mode (advanced by half of a Yee cell from E)
    :param wavenumber: Wavenumber of the mode
    :param omega: Angular frequency of the simulation
    :param dxes: Grid parameters [dx_e, dx_h] as described in fdfd_tools.operators header
    :param axis: Propagation axis (0=x, 1=y, 2=z)
    :param polarity: Propagation direction (+1 for +ve, -1 for -ve)
    :param slices: epsilon[tuple(slices)] is used to select the portion of the grid to use
        as the waveguide cross-section. slices[axis] should select only one
    :param mu: Magnetic permeability (default 1 everywhere)
    :return: overlap_e for calculating the mode overlap
    """
    cross_plane = [slice(None)] * 3
    cross_plane[axis] = slices[axis]

    # Determine phase factors for parallel slices
    a_shape = np.roll([-1, 1, 1], axis)
    a_E = np.real(dxes[0][axis]).cumsum()
    a_H = np.real(dxes[1][axis]).cumsum()
    iphi = -polarity * 1j * wavenumber
    phase_E = np.exp(iphi * (a_E - a_E[slices[axis]])).reshape(a_shape)
    phase_H = np.exp(iphi * (a_H - a_H[slices[axis]])).reshape(a_shape)

    # Expand our slice to the entire grid using the calculated phase factors
    Ee = [None] * 3
    He = [None] * 3
    for k in range(3):
        Ee[k] = phase_E * E[k][tuple(cross_plane)]
        He[k] = phase_H * H[k][tuple(cross_plane)]

    # Write out the operator product for the mode orthogonality integral
    domain = np.zeros_like(E[0], dtype=int)
    domain[tuple(slices)] = 1

    npts = E[0].size
    dn = np.zeros(npts * 3, dtype=int)
    dn[0:npts] = 1
    dn = np.roll(dn, npts * axis)

    e2h = operators.e2h(omega, dxes, mu)
    ds = sparse.diags(vec([domain] * 3))
    h_cross_ = operators.poynting_h_cross(vec(He), dxes)
    e_cross_ = operators.poynting_e_cross(vec(Ee), dxes)

    overlap_e = dn @ ds @ (-h_cross_ + e_cross_ @ e2h)

    # Normalize
    norm_factor = np.abs(overlap_e @ vec(Ee))
    overlap_e /= norm_factor

    return unvec(overlap_e, E[0].shape)