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)
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)
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)