def __init__(self, ann: ANN, wl: float, width: float, thickness: float) -> None: """MSNeuralNetwork constructor Parameters ---------- ann : ANN The ANN object that contains the network and regression models wl : number The wavelength (most accurate around 1.55 µm) width : number The width of the cross section (most accurate around 550 nm) thickness : number The thickness of the cross section (most accurate around 250 nm) """ self.wl = wl self.width = width self.thickness = thickness self.ann = ann self.Hx_model = ann.Hx_model self.Hy_model = ann.Hy_model self.neff_model = ann.neff_model self.num_modes = 1 self.x = ann.x self.y = ann.y self.after_x = self.x self.after_y = self.y self.mesh = len(self.x) - 1 self.PML = False self.n = get_epsfunc( self.width, self.thickness, 2.5e-6, 2.5e-6, Si(self.wl * 1e6), SiO2(self.wl * 1e6), compute=True )(self.x, self.y)
def __init__( self, wl, width, thickness, num_modes=1, cladding_width=2.5e-6, cladding_thickness=2.5e-6, core_index=None, cladding_index=None, x=None, y=None, mesh=300, accuracy=1e-8, boundary="0000", epsfunc=None, ): self.wl = wl self.width = width self.thickness = thickness self.num_modes = num_modes self.cladding_width = cladding_width self.cladding_thickness = cladding_thickness self.core_index = core_index self.cladding_index = cladding_index self.x = x self.y = y self.mesh = mesh self.accuracy = accuracy self.boundary = boundary self.epsfunc = epsfunc if core_index == None: self.core_index = tools.Si(wl * 1e6) if cladding_index == None: self.cladding_index = tools.SiO2(wl * 1e6) if x == None: self.x = np.linspace(0, cladding_width, mesh) if y == None: self.y = np.linspace(0, cladding_width, mesh) if epsfunc == None: self.epsfunc = tools.get_epsfunc( self.width, self.thickness, self.cladding_width, self.cladding_thickness, self.core_index, self.cladding_index, )
def get_mode(self, mode_num: int = 0) -> EigenMode: """Returns the solved eigenmode Parameters ---------- mode_num : int mode index to return mode of Returns ------- EigenMode the EigenMode corresponding to the provdided mode index """ Hx, Hy, neff = self.mode epsfunc_before = get_epsfunc( self.width, self.thickness, 2.5e-6, 2.5e-6, Si(self.wl * 1e6), SiO2(self.wl * 1e6), compute=True ) epsfunc_after = get_epsfunc(self.width, self.thickness, 2.5e-6, 2.5e-6, Si(self.wl * 1e6), SiO2(self.wl * 1e6)) m = Mode( self.x, self.y, self.wl, neff, Hx + 0j, Hy + 0j, None, None, None, None, np.sqrt(epsfunc_after(self.x, self.y)), ) m.compute_other_fields(epsfunc_before, epsfunc_after) m.normalize() return m
def __init__(self, wl: float, width: float = None, thickness: float = None, num_modes: int = 1, cladding_width: float = 2.5e-6, cladding_thickness: float = 2.5e-6, core_index: float = None, cladding_index: float = None, x: "np.ndarray" = None, y: "np.ndarray" = None, mesh: int = 128, accuracy: float = 1e-8, boundary: str = "0000", epsfunc: Callable[["np.ndarray", "np.ndarray"], "np.ndarray"] = None, n: "np.ndarray" = None, PML: bool = False, subpixel: bool = True, center: tuple = (0, 0), **kwargs) -> None: """MSEMpy class constructor Parameters ---------- wl : number wavelength of the eigenmodes width : number width of the core in the cross section thickness : number thickness of the core in the cross section num_modes : int number of modes to solve for (default:1) cladding_width : number width of the cladding in the cross section (default:5e-6) cladding_thickness : number thickness of the cladding in the cross section (default:5e-6) core_index : number refractive index of the core (default:Si) cladding_index : number refractive index of the cladding (default:SiO2) mesh : int number of mesh points in each direction (xy) x : numpy array the cross section grid in the x direction (z propagation) (default:None) y : numpy array the cross section grid in the y direction (z propagation) (default:None) mesh : int the number of mesh points in each xy direction accuracy : number the minimum accuracy of the finite difference solution (default:1e-8) boundary : string the boundaries according to the EMpy library (default:"0000") epsfunc : function the function which defines the permittivity based on a grid (see EMpy library) (default:"0000") n : numpy array 2D profile of the refractive index PML : bool if True, will use PML boundaries. Default : False, PEC subpixel : bool if true, will use subpixel smoothing, assuming asking for a waveguide cross section and not providing an index map (recommended) """ self.wl = wl self.width = width self.thickness = thickness self.num_modes = num_modes self.cladding_width = cladding_width self.cladding_thickness = cladding_thickness self.core_index = core_index self.cladding_index = cladding_index self.x = x self.y = y self.mesh = mesh self.accuracy = accuracy self.boundary = boundary self.epsfunc = epsfunc self.n = n self.PML = PML if core_index is None: self.core_index = Si(wl * 1e6) if cladding_index is None: self.cladding_index = SiO2(wl * 1e6) if x is None: self.x = np.linspace(-0.5 * cladding_width, 0.5 * cladding_width, mesh) if y is None: self.y = np.linspace(-0.5 * cladding_width, 0.5 * cladding_width, mesh) if self.PML: # Create a PML at least half a wavelength long dx = np.diff(self.x) dy = np.diff(self.y) layer_xp = int(np.abs(0.5 * self.wl / dx[-1])) layer_xn = int(np.abs(0.5 * self.wl / dx[0])) layer_yp = int(np.abs(0.5 * self.wl / dy[-1])) layer_yn = int(np.abs(0.5 * self.wl / dy[0])) self.nlayers = [layer_yp, layer_yn, layer_xp, layer_xn] factor = 1 + 2j self.x, self.y, _, _, _, _ = stretchmesh(self.x, self.y, self.nlayers, factor) if epsfunc is None and (not subpixel) or (self.width is None): self.epsfunc = get_epsfunc( self.width, self.thickness, self.cladding_width, self.cladding_thickness, self.core_index, self.cladding_index, profile=self.n, nx=self.x, ny=self.y, ) elif epsfunc is None and subpixel and (self.width is not None): n = rectangle_to_n(center, self.width, self.thickness, self.x, self.y, subpixel, self.core_index, self.cladding_index) self.x = ((self.x)[1:] + (self.x)[:-1]) / 2 self.y = ((self.y)[1:] + (self.y)[:-1]) / 2 self.epsfunc = get_epsfunc( None, None, self.cladding_width, self.cladding_thickness, self.core_index, self.cladding_index, profile=n, nx=self.x, ny=self.y, ) self.after_x = self.x self.after_y = self.y self.n = np.sqrt(self.epsfunc(self.x, self.y))
def __init__(self, wl: float, width: float = None, num_modes: int = 1, cladding_width: float = 2.5e-6, core_index: float = None, cladding_index: float = None, x: "np.ndarray" = None, mesh: int = 128, accuracy: float = 1e-8, boundary: str = "0000", epsfunc: Callable[["np.ndarray", "np.ndarray"], "np.ndarray"] = None, n: "np.ndarray" = None, PML: bool = False, **kwargs): """MSEMpy class constructor Parameters ---------- wl : number wavelength of the eigenmodes width : number width of the core in the cross section num_modes : int number of modes to solve for (default:1) cladding_width : number width of the cladding in the cross section (default:5e-6) core_index : number refractive index of the core (default:Si) cladding_index : number refractive index of the cladding (default:SiO2) mesh : int number of mesh points in each direction (xy) x : numpy array the cross section grid in the x direction (z propagation) (default:None) mesh : int the number of mesh points in each xy direction accuracy : number the minimum accuracy of the finite difference solution (default:1e-8) boundary : string the boundaries according to the EMpy library (default:"0000") epsfunc : function the function which defines the permittivity based on a grid (see EMpy library) (default:"0000") n : numpy array 2D profile of the refractive index PML : boolean if True, will use PML boundaries. Default : False, PEC """ self.wl = wl self.width = width self.num_modes = num_modes self.cladding_width = cladding_width self.core_index = core_index self.cladding_index = cladding_index self.x = x self.mesh = mesh self.accuracy = accuracy self.boundary = boundary self.epsfunc = epsfunc self.n = n self.PML = PML if core_index is None: self.core_index = Si(wl * 1e6) if cladding_index is None: self.cladding_index = SiO2(wl * 1e6) if x is None: self.x = np.linspace(-0.5 * cladding_width, 0.5 * cladding_width, mesh) if self.PML: # Create a PML at least half a wavelength long dx = np.diff(self.x) layer_xp = int(np.abs(0.5 * self.wl / dx[-1])) layer_xn = int(np.abs(0.5 * self.wl / dx[0])) self.nlayers = [layer_xp, layer_xn, 0, 0] factor = 1 + 2j self.x, _, _, _, _, _ = stretchmesh(self.x, np.zeros(1), self.nlayers, factor) if epsfunc is None: self.epsfunc = get_epsfunc( self.width, None, self.cladding_width, None, self.core_index, self.cladding_index, profile=self.n, nx=self.x, ) self.after_x = self.x self.n = self.epsfunc(self.x, np.zeros(1))
polygons = [] for inp in range(num_inputs): starting_center = -0.5 * (num_inputs - 1) * (input_gap + input_width) n_input = np.ones(mesh) * cladding_index center = starting_center + inp * (input_gap + input_width) left_edge = center - 0.5 * input_width right_edge = center + 0.5 * input_width n_input = np.where((left_edge <= x) * (x <= right_edge), core_index, n_input) masks.append((left_edge <= x) * (x <= right_edge)) eps = get_epsfunc( width=None, thickness=thickness, cladding_width=8e-6, cladding_thickness=8e-6, core_index=core_index, cladding_index=cladding_index, profile=n_input, nx=x, )(x, y) polygons.append(create_polygon(x, y, eps, detranslate=False)) input_channel = MSLumerical( wavelength, mode=eme.mode, thickness=thickness, core_index=core_index, cladding_index=cladding_index, cladding_width=8e-6, cladding_thickness=8e-6,
def compute_other_fields(self, width, thickness): """Adapted from the EMpy library LICENSED UNDER MIT LICENSE""" from scipy.sparse import coo_matrix core_index = tools.Si(self.wl * 1e6) cladding_index = tools.SiO2(self.wl * 1e6) self.epsfunc = tools.get_epsfunc(width, thickness, 2.5e-6, 2.5e-6, tools.Si(self.wl * 1e6), tools.SiO2(self.wl * 1e6)) wl = self.wl x = np.array(self.x) y = np.array(self.y) boundary = "0000" # "A0" neffs = [self.neff] Hxs = [np.array(self.Hx)] Hys = [np.array(self.Hy)] Hzs = [] Exs = [] Eys = [] Ezs = [] for neff, Hx, Hy in zip(neffs, Hxs, Hys): dx = np.diff(x) dy = np.diff(y) dx = np.r_[dx[0], dx, dx[-1]].reshape(-1, 1) dy = np.r_[dy[0], dy, dy[-1]].reshape(1, -1) xc = (x[:-1] + x[1:]) / 2 yc = (y[:-1] + y[1:]) / 2 epsxx, epsxy, epsyx, epsyy, epszz = self._get_eps(xc, yc) nx = len(x) ny = len(y) k = 2 * np.pi / wl ones_nx = np.ones((nx, 1)) ones_ny = np.ones((1, ny)) n = np.dot(ones_nx, dy[:, 1:]).flatten() s = np.dot(ones_nx, dy[:, :-1]).flatten() e = np.dot(dx[1:, :], ones_ny).flatten() w = np.dot(dx[:-1, :], ones_ny).flatten() exx1 = epsxx[:-1, 1:].flatten() exx2 = epsxx[:-1, :-1].flatten() exx3 = epsxx[1:, :-1].flatten() exx4 = epsxx[1:, 1:].flatten() eyy1 = epsyy[:-1, 1:].flatten() eyy2 = epsyy[:-1, :-1].flatten() eyy3 = epsyy[1:, :-1].flatten() eyy4 = epsyy[1:, 1:].flatten() exy1 = epsxy[:-1, 1:].flatten() exy2 = epsxy[:-1, :-1].flatten() exy3 = epsxy[1:, :-1].flatten() exy4 = epsxy[1:, 1:].flatten() eyx1 = epsyx[:-1, 1:].flatten() eyx2 = epsyx[:-1, :-1].flatten() eyx3 = epsyx[1:, :-1].flatten() eyx4 = epsyx[1:, 1:].flatten() ezz1 = epszz[:-1, 1:].flatten() ezz2 = epszz[:-1, :-1].flatten() ezz3 = epszz[1:, :-1].flatten() ezz4 = epszz[1:, 1:].flatten() b = neff * k bzxne = (0.5 * (n * ezz1 * ezz2 / eyy1 + s * ezz2 * ezz1 / eyy2) * eyx4 / ezz4 / (n * eyy3 + s * eyy4) / ezz2 / ezz1 / (n * eyy2 + s * eyy1) / (e + w) * eyy3 * eyy1 * w * eyy2 + 0.5 * (ezz3 / exx2 * ezz2 * w + ezz2 / exx3 * ezz3 * e) * (1 - exx4 / ezz4) / ezz3 / ezz2 / (w * exx3 + e * exx2) / (w * exx4 + e * exx1) / (n + s) * exx2 * exx3 * exx1 * s) / b bzxse = (-0.5 * (n * ezz1 * ezz2 / eyy1 + s * ezz2 * ezz1 / eyy2) * eyx3 / ezz3 / (n * eyy3 + s * eyy4) / ezz2 / ezz1 / (n * eyy2 + s * eyy1) / (e + w) * eyy4 * eyy1 * w * eyy2 + 0.5 * (ezz4 / exx1 * ezz1 * w + ezz1 / exx4 * ezz4 * e) * (1 - exx3 / ezz3) / (w * exx3 + e * exx2) / ezz4 / ezz1 / (w * exx4 + e * exx1) / (n + s) * exx2 * n * exx1 * exx4) / b bzxnw = (-0.5 * (-n * ezz4 * ezz3 / eyy4 - s * ezz3 * ezz4 / eyy3) * eyx1 / ezz4 / ezz3 / (n * eyy3 + s * eyy4) / ezz1 / (n * eyy2 + s * eyy1) / (e + w) * eyy4 * eyy3 * eyy2 * e - 0.5 * (ezz3 / exx2 * ezz2 * w + ezz2 / exx3 * ezz3 * e) * (1 - exx1 / ezz1) / ezz3 / ezz2 / (w * exx3 + e * exx2) / (w * exx4 + e * exx1) / (n + s) * exx2 * exx3 * exx4 * s) / b bzxsw = (0.5 * (-n * ezz4 * ezz3 / eyy4 - s * ezz3 * ezz4 / eyy3) * eyx2 / ezz4 / ezz3 / (n * eyy3 + s * eyy4) / ezz2 / (n * eyy2 + s * eyy1) / (e + w) * eyy4 * eyy3 * eyy1 * e - 0.5 * (ezz4 / exx1 * ezz1 * w + ezz1 / exx4 * ezz4 * e) * (1 - exx2 / ezz2) / (w * exx3 + e * exx2) / ezz4 / ezz1 / (w * exx4 + e * exx1) / (n + s) * exx3 * n * exx1 * exx4) / b bzxn = ((0.5 * (-n * ezz4 * ezz3 / eyy4 - s * ezz3 * ezz4 / eyy3) * n * ezz1 * ezz2 / eyy1 * (2 * eyy1 / ezz1 / n**2 + eyx1 / ezz1 / n / w) + 0.5 * (n * ezz1 * ezz2 / eyy1 + s * ezz2 * ezz1 / eyy2) * n * ezz4 * ezz3 / eyy4 * (2 * eyy4 / ezz4 / n**2 - eyx4 / ezz4 / n / e)) / ezz4 / ezz3 / (n * eyy3 + s * eyy4) / ezz2 / ezz1 / (n * eyy2 + s * eyy1) / (e + w) * eyy4 * eyy3 * eyy1 * w * eyy2 * e + ((ezz3 / exx2 * ezz2 * w + ezz2 / exx3 * ezz3 * e) * (0.5 * ezz4 * ((1 - exx1 / ezz1) / n / w - exy1 / ezz1 * (2.0 / n**2 - 2 / n**2 * s / (n + s))) / exx1 * ezz1 * w + (ezz4 - ezz1) * s / n / (n + s) + 0.5 * ezz1 * (-(1 - exx4 / ezz4) / n / e - exy4 / ezz4 * (2.0 / n**2 - 2 / n**2 * s / (n + s))) / exx4 * ezz4 * e) - (ezz4 / exx1 * ezz1 * w + ezz1 / exx4 * ezz4 * e) * (-ezz3 * exy2 / n / (n + s) / exx2 * w + (ezz3 - ezz2) * s / n / (n + s) - ezz2 * exy3 / n / (n + s) / exx3 * e)) / ezz3 / ezz2 / (w * exx3 + e * exx2) / ezz4 / ezz1 / (w * exx4 + e * exx1) / (n + s) * exx2 * exx3 * n * exx1 * exx4 * s) / b bzxs = ((0.5 * (-n * ezz4 * ezz3 / eyy4 - s * ezz3 * ezz4 / eyy3) * s * ezz2 * ezz1 / eyy2 * (2 * eyy2 / ezz2 / s**2 - eyx2 / ezz2 / s / w) + 0.5 * (n * ezz1 * ezz2 / eyy1 + s * ezz2 * ezz1 / eyy2) * s * ezz3 * ezz4 / eyy3 * (2 * eyy3 / ezz3 / s**2 + eyx3 / ezz3 / s / e)) / ezz4 / ezz3 / (n * eyy3 + s * eyy4) / ezz2 / ezz1 / (n * eyy2 + s * eyy1) / (e + w) * eyy4 * eyy3 * eyy1 * w * eyy2 * e + ((ezz3 / exx2 * ezz2 * w + ezz2 / exx3 * ezz3 * e) * (-ezz4 * exy1 / s / (n + s) / exx1 * w - (ezz4 - ezz1) * n / s / (n + s) - ezz1 * exy4 / s / (n + s) / exx4 * e) - (ezz4 / exx1 * ezz1 * w + ezz1 / exx4 * ezz4 * e) * (0.5 * ezz3 * (-(1 - exx2 / ezz2) / s / w - exy2 / ezz2 * (2.0 / s**2 - 2 / s**2 * n / (n + s))) / exx2 * ezz2 * w - (ezz3 - ezz2) * n / s / (n + s) + 0.5 * ezz2 * ((1 - exx3 / ezz3) / s / e - exy3 / ezz3 * (2.0 / s**2 - 2 / s**2 * n / (n + s))) / exx3 * ezz3 * e)) / ezz3 / ezz2 / (w * exx3 + e * exx2) / ezz4 / ezz1 / (w * exx4 + e * exx1) / (n + s) * exx2 * exx3 * n * exx1 * exx4 * s) / b bzxe = ((n * ezz1 * ezz2 / eyy1 + s * ezz2 * ezz1 / eyy2) * (0.5 * n * ezz4 * ezz3 / eyy4 * (2.0 / e**2 - eyx4 / ezz4 / n / e) + 0.5 * s * ezz3 * ezz4 / eyy3 * (2.0 / e**2 + eyx3 / ezz3 / s / e)) / ezz4 / ezz3 / (n * eyy3 + s * eyy4) / ezz2 / ezz1 / (n * eyy2 + s * eyy1) / (e + w) * eyy4 * eyy3 * eyy1 * w * eyy2 * e + (-0.5 * (ezz3 / exx2 * ezz2 * w + ezz2 / exx3 * ezz3 * e) * ezz1 * (1 - exx4 / ezz4) / n / exx4 * ezz4 - 0.5 * (ezz4 / exx1 * ezz1 * w + ezz1 / exx4 * ezz4 * e) * ezz2 * (1 - exx3 / ezz3) / s / exx3 * ezz3) / ezz3 / ezz2 / (w * exx3 + e * exx2) / ezz4 / ezz1 / (w * exx4 + e * exx1) / (n + s) * exx2 * exx3 * n * exx1 * exx4 * s) / b bzxw = ((-n * ezz4 * ezz3 / eyy4 - s * ezz3 * ezz4 / eyy3) * (0.5 * n * ezz1 * ezz2 / eyy1 * (2.0 / w**2 + eyx1 / ezz1 / n / w) + 0.5 * s * ezz2 * ezz1 / eyy2 * (2.0 / w**2 - eyx2 / ezz2 / s / w)) / ezz4 / ezz3 / (n * eyy3 + s * eyy4) / ezz2 / ezz1 / (n * eyy2 + s * eyy1) / (e + w) * eyy4 * eyy3 * eyy1 * w * eyy2 * e + (0.5 * (ezz3 / exx2 * ezz2 * w + ezz2 / exx3 * ezz3 * e) * ezz4 * (1 - exx1 / ezz1) / n / exx1 * ezz1 + 0.5 * (ezz4 / exx1 * ezz1 * w + ezz1 / exx4 * ezz4 * e) * ezz3 * (1 - exx2 / ezz2) / s / exx2 * ezz2) / ezz3 / ezz2 / (w * exx3 + e * exx2) / ezz4 / ezz1 / (w * exx4 + e * exx1) / (n + s) * exx2 * exx3 * n * exx1 * exx4 * s) / b bzxp = ( ((-n * ezz4 * ezz3 / eyy4 - s * ezz3 * ezz4 / eyy3) * (0.5 * n * ezz1 * ezz2 / eyy1 * (-2.0 / w**2 - 2 * eyy1 / ezz1 / n**2 + k**2 * eyy1 - eyx1 / ezz1 / n / w) + 0.5 * s * ezz2 * ezz1 / eyy2 * (-2.0 / w**2 - 2 * eyy2 / ezz2 / s**2 + k**2 * eyy2 + eyx2 / ezz2 / s / w)) + (n * ezz1 * ezz2 / eyy1 + s * ezz2 * ezz1 / eyy2) * (0.5 * n * ezz4 * ezz3 / eyy4 * (-2.0 / e**2 - 2 * eyy4 / ezz4 / n**2 + k**2 * eyy4 + eyx4 / ezz4 / n / e) + 0.5 * s * ezz3 * ezz4 / eyy3 * (-2.0 / e**2 - 2 * eyy3 / ezz3 / s**2 + k**2 * eyy3 - eyx3 / ezz3 / s / e))) / ezz4 / ezz3 / (n * eyy3 + s * eyy4) / ezz2 / ezz1 / (n * eyy2 + s * eyy1) / (e + w) * eyy4 * eyy3 * eyy1 * w * eyy2 * e + ((ezz3 / exx2 * ezz2 * w + ezz2 / exx3 * ezz3 * e) * (0.5 * ezz4 * (-k**2 * exy1 - (1 - exx1 / ezz1) / n / w - exy1 / ezz1 * (-2.0 / n**2 - 2 / n**2 * (n - s) / s)) / exx1 * ezz1 * w + (ezz4 - ezz1) * (n - s) / n / s + 0.5 * ezz1 * (-k**2 * exy4 + (1 - exx4 / ezz4) / n / e - exy4 / ezz4 * (-2.0 / n**2 - 2 / n**2 * (n - s) / s)) / exx4 * ezz4 * e) - (ezz4 / exx1 * ezz1 * w + ezz1 / exx4 * ezz4 * e) * (0.5 * ezz3 * (-k**2 * exy2 + (1 - exx2 / ezz2) / s / w - exy2 / ezz2 * (-2.0 / s**2 + 2 / s**2 * (n - s) / n)) / exx2 * ezz2 * w + (ezz3 - ezz2) * (n - s) / n / s + 0.5 * ezz2 * (-k**2 * exy3 - (1 - exx3 / ezz3) / s / e - exy3 / ezz3 * (-2.0 / s**2 + 2 / s**2 * (n - s) / n)) / exx3 * ezz3 * e)) / ezz3 / ezz2 / (w * exx3 + e * exx2) / ezz4 / ezz1 / (w * exx4 + e * exx1) / (n + s) * exx2 * exx3 * n * exx1 * exx4 * s) / b bzyne = (0.5 * (n * ezz1 * ezz2 / eyy1 + s * ezz2 * ezz1 / eyy2) * (1 - eyy4 / ezz4) / (n * eyy3 + s * eyy4) / ezz2 / ezz1 / (n * eyy2 + s * eyy1) / (e + w) * eyy3 * eyy1 * w * eyy2 + 0.5 * (ezz3 / exx2 * ezz2 * w + ezz2 / exx3 * ezz3 * e) * exy4 / ezz3 / ezz2 / (w * exx3 + e * exx2) / ezz4 / (w * exx4 + e * exx1) / (n + s) * exx2 * exx3 * exx1 * s) / b bzyse = (-0.5 * (n * ezz1 * ezz2 / eyy1 + s * ezz2 * ezz1 / eyy2) * (1 - eyy3 / ezz3) / (n * eyy3 + s * eyy4) / ezz2 / ezz1 / (n * eyy2 + s * eyy1) / (e + w) * eyy4 * eyy1 * w * eyy2 + 0.5 * (ezz4 / exx1 * ezz1 * w + ezz1 / exx4 * ezz4 * e) * exy3 / ezz3 / (w * exx3 + e * exx2) / ezz4 / ezz1 / (w * exx4 + e * exx1) / (n + s) * exx2 * n * exx1 * exx4) / b bzynw = (-0.5 * (-n * ezz4 * ezz3 / eyy4 - s * ezz3 * ezz4 / eyy3) * (1 - eyy1 / ezz1) / ezz4 / ezz3 / (n * eyy3 + s * eyy4) / (n * eyy2 + s * eyy1) / (e + w) * eyy4 * eyy3 * eyy2 * e - 0.5 * (ezz3 / exx2 * ezz2 * w + ezz2 / exx3 * ezz3 * e) * exy1 / ezz3 / ezz2 / (w * exx3 + e * exx2) / ezz1 / (w * exx4 + e * exx1) / (n + s) * exx2 * exx3 * exx4 * s) / b bzysw = (0.5 * (-n * ezz4 * ezz3 / eyy4 - s * ezz3 * ezz4 / eyy3) * (1 - eyy2 / ezz2) / ezz4 / ezz3 / (n * eyy3 + s * eyy4) / (n * eyy2 + s * eyy1) / (e + w) * eyy4 * eyy3 * eyy1 * e - 0.5 * (ezz4 / exx1 * ezz1 * w + ezz1 / exx4 * ezz4 * e) * exy2 / ezz2 / (w * exx3 + e * exx2) / ezz4 / ezz1 / (w * exx4 + e * exx1) / (n + s) * exx3 * n * exx1 * exx4) / b bzyn = ((0.5 * (-n * ezz4 * ezz3 / eyy4 - s * ezz3 * ezz4 / eyy3) * ezz1 * ezz2 / eyy1 * (1 - eyy1 / ezz1) / w - 0.5 * (n * ezz1 * ezz2 / eyy1 + s * ezz2 * ezz1 / eyy2) * ezz4 * ezz3 / eyy4 * (1 - eyy4 / ezz4) / e) / ezz4 / ezz3 / (n * eyy3 + s * eyy4) / ezz2 / ezz1 / (n * eyy2 + s * eyy1) / (e + w) * eyy4 * eyy3 * eyy1 * w * eyy2 * e + (ezz3 / exx2 * ezz2 * w + ezz2 / exx3 * ezz3 * e) * (0.5 * ezz4 * (2.0 / n**2 + exy1 / ezz1 / n / w) / exx1 * ezz1 * w + 0.5 * ezz1 * (2.0 / n**2 - exy4 / ezz4 / n / e) / exx4 * ezz4 * e) / ezz3 / ezz2 / (w * exx3 + e * exx2) / ezz4 / ezz1 / (w * exx4 + e * exx1) / (n + s) * exx2 * exx3 * n * exx1 * exx4 * s) / b bzys = ((-0.5 * (-n * ezz4 * ezz3 / eyy4 - s * ezz3 * ezz4 / eyy3) * ezz2 * ezz1 / eyy2 * (1 - eyy2 / ezz2) / w + 0.5 * (n * ezz1 * ezz2 / eyy1 + s * ezz2 * ezz1 / eyy2) * ezz3 * ezz4 / eyy3 * (1 - eyy3 / ezz3) / e) / ezz4 / ezz3 / (n * eyy3 + s * eyy4) / ezz2 / ezz1 / (n * eyy2 + s * eyy1) / (e + w) * eyy4 * eyy3 * eyy1 * w * eyy2 * e - (ezz4 / exx1 * ezz1 * w + ezz1 / exx4 * ezz4 * e) * (0.5 * ezz3 * (2.0 / s**2 - exy2 / ezz2 / s / w) / exx2 * ezz2 * w + 0.5 * ezz2 * (2.0 / s**2 + exy3 / ezz3 / s / e) / exx3 * ezz3 * e) / ezz3 / ezz2 / (w * exx3 + e * exx2) / ezz4 / ezz1 / (w * exx4 + e * exx1) / (n + s) * exx2 * exx3 * n * exx1 * exx4 * s) / b bzye = (((-n * ezz4 * ezz3 / eyy4 - s * ezz3 * ezz4 / eyy3) * (-n * ezz2 / eyy1 * eyx1 / e / (e + w) + (ezz1 - ezz2) * w / e / (e + w) - s * ezz1 / eyy2 * eyx2 / e / (e + w)) + (n * ezz1 * ezz2 / eyy1 + s * ezz2 * ezz1 / eyy2) * (0.5 * n * ezz4 * ezz3 / eyy4 * (-(1 - eyy4 / ezz4) / n / e - eyx4 / ezz4 * (2.0 / e**2 - 2 / e**2 * w / (e + w))) + 0.5 * s * ezz3 * ezz4 / eyy3 * ((1 - eyy3 / ezz3) / s / e - eyx3 / ezz3 * (2.0 / e**2 - 2 / e**2 * w / (e + w))) + (ezz4 - ezz3) * w / e / (e + w))) / ezz4 / ezz3 / (n * eyy3 + s * eyy4) / ezz2 / ezz1 / (n * eyy2 + s * eyy1) / (e + w) * eyy4 * eyy3 * eyy1 * w * eyy2 * e + (0.5 * (ezz3 / exx2 * ezz2 * w + ezz2 / exx3 * ezz3 * e) * ezz1 * (2 * exx4 / ezz4 / e**2 - exy4 / ezz4 / n / e) / exx4 * ezz4 * e - 0.5 * (ezz4 / exx1 * ezz1 * w + ezz1 / exx4 * ezz4 * e) * ezz2 * (2 * exx3 / ezz3 / e**2 + exy3 / ezz3 / s / e) / exx3 * ezz3 * e) / ezz3 / ezz2 / (w * exx3 + e * exx2) / ezz4 / ezz1 / (w * exx4 + e * exx1) / (n + s) * exx2 * exx3 * n * exx1 * exx4 * s) / b bzyw = (((-n * ezz4 * ezz3 / eyy4 - s * ezz3 * ezz4 / eyy3) * (0.5 * n * ezz1 * ezz2 / eyy1 * ((1 - eyy1 / ezz1) / n / w - eyx1 / ezz1 * (2.0 / w**2 - 2 / w**2 * e / (e + w))) - (ezz1 - ezz2) * e / w / (e + w) + 0.5 * s * ezz2 * ezz1 / eyy2 * (-(1 - eyy2 / ezz2) / s / w - eyx2 / ezz2 * (2.0 / w**2 - 2 / w**2 * e / (e + w)))) + (n * ezz1 * ezz2 / eyy1 + s * ezz2 * ezz1 / eyy2) * (-n * ezz3 / eyy4 * eyx4 / w / (e + w) - s * ezz4 / eyy3 * eyx3 / w / (e + w) - (ezz4 - ezz3) * e / w / (e + w))) / ezz4 / ezz3 / (n * eyy3 + s * eyy4) / ezz2 / ezz1 / (n * eyy2 + s * eyy1) / (e + w) * eyy4 * eyy3 * eyy1 * w * eyy2 * e + (0.5 * (ezz3 / exx2 * ezz2 * w + ezz2 / exx3 * ezz3 * e) * ezz4 * (2 * exx1 / ezz1 / w**2 + exy1 / ezz1 / n / w) / exx1 * ezz1 * w - 0.5 * (ezz4 / exx1 * ezz1 * w + ezz1 / exx4 * ezz4 * e) * ezz3 * (2 * exx2 / ezz2 / w**2 - exy2 / ezz2 / s / w) / exx2 * ezz2 * w) / ezz3 / ezz2 / (w * exx3 + e * exx2) / ezz4 / ezz1 / (w * exx4 + e * exx1) / (n + s) * exx2 * exx3 * n * exx1 * exx4 * s) / b bzyp = (((-n * ezz4 * ezz3 / eyy4 - s * ezz3 * ezz4 / eyy3) * (0.5 * n * ezz1 * ezz2 / eyy1 * (-k**2 * eyx1 - (1 - eyy1 / ezz1) / n / w - eyx1 / ezz1 * (-2.0 / w**2 + 2 / w**2 * (e - w) / e)) + (ezz1 - ezz2) * (e - w) / e / w + 0.5 * s * ezz2 * ezz1 / eyy2 * (-k**2 * eyx2 + (1 - eyy2 / ezz2) / s / w - eyx2 / ezz2 * (-2.0 / w**2 + 2 / w**2 * (e - w) / e))) + (n * ezz1 * ezz2 / eyy1 + s * ezz2 * ezz1 / eyy2) * (0.5 * n * ezz4 * ezz3 / eyy4 * (-k**2 * eyx4 + (1 - eyy4 / ezz4) / n / e - eyx4 / ezz4 * (-2.0 / e**2 - 2 / e**2 * (e - w) / w)) + 0.5 * s * ezz3 * ezz4 / eyy3 * (-k**2 * eyx3 - (1 - eyy3 / ezz3) / s / e - eyx3 / ezz3 * (-2.0 / e**2 - 2 / e**2 * (e - w) / w)) + (ezz4 - ezz3) * (e - w) / e / w)) / ezz4 / ezz3 / (n * eyy3 + s * eyy4) / ezz2 / ezz1 / (n * eyy2 + s * eyy1) / (e + w) * eyy4 * eyy3 * eyy1 * w * eyy2 * e + ((ezz3 / exx2 * ezz2 * w + ezz2 / exx3 * ezz3 * e) * (0.5 * ezz4 * (-2.0 / n**2 - 2 * exx1 / ezz1 / w**2 + k**2 * exx1 - exy1 / ezz1 / n / w) / exx1 * ezz1 * w + 0.5 * ezz1 * (-2.0 / n**2 - 2 * exx4 / ezz4 / e**2 + k**2 * exx4 + exy4 / ezz4 / n / e) / exx4 * ezz4 * e) - (ezz4 / exx1 * ezz1 * w + ezz1 / exx4 * ezz4 * e) * (0.5 * ezz3 * (-2.0 / s**2 - 2 * exx2 / ezz2 / w**2 + k**2 * exx2 + exy2 / ezz2 / s / w) / exx2 * ezz2 * w + 0.5 * ezz2 * (-2.0 / s**2 - 2 * exx3 / ezz3 / e**2 + k**2 * exx3 - exy3 / ezz3 / s / e) / exx3 * ezz3 * e)) / ezz3 / ezz2 / (w * exx3 + e * exx2) / ezz4 / ezz1 / (w * exx4 + e * exx1) / (n + s) * exx2 * exx3 * n * exx1 * exx4 * s) / b ii = np.arange(nx * ny).reshape(nx, ny) # NORTH boundary ib = ii[:, -1] if boundary[0] == "S": sign = 1 elif boundary[0] == "A": sign = -1 elif boundary[0] == "0": sign = 0 else: raise ValueError("unknown boundary conditions") bzxs[ib] += sign * bzxn[ib] bzxse[ib] += sign * bzxne[ib] bzxsw[ib] += sign * bzxnw[ib] bzys[ib] -= sign * bzyn[ib] bzyse[ib] -= sign * bzyne[ib] bzysw[ib] -= sign * bzynw[ib] # SOUTH boundary ib = ii[:, 0] if boundary[1] == "S": sign = 1 elif boundary[1] == "A": sign = -1 elif boundary[1] == "0": sign = 0 else: raise ValueError("unknown boundary conditions") bzxn[ib] += sign * bzxs[ib] bzxne[ib] += sign * bzxse[ib] bzxnw[ib] += sign * bzxsw[ib] bzyn[ib] -= sign * bzys[ib] bzyne[ib] -= sign * bzyse[ib] bzynw[ib] -= sign * bzysw[ib] # EAST boundary ib = ii[-1, :] if boundary[2] == "S": sign = 1 elif boundary[2] == "A": sign = -1 elif boundary[2] == "0": sign = 0 else: raise ValueError("unknown boundary conditions") bzxw[ib] += sign * bzxe[ib] bzxnw[ib] += sign * bzxne[ib] bzxsw[ib] += sign * bzxse[ib] bzyw[ib] -= sign * bzye[ib] bzynw[ib] -= sign * bzyne[ib] bzysw[ib] -= sign * bzyse[ib] # WEST boundary ib = ii[0, :] if boundary[3] == "S": sign = 1 elif boundary[3] == "A": sign = -1 elif boundary[3] == "0": sign = 0 else: raise ValueError("unknown boundary conditions") bzxe[ib] += sign * bzxw[ib] bzxne[ib] += sign * bzxnw[ib] bzxse[ib] += sign * bzxsw[ib] bzye[ib] -= sign * bzyw[ib] bzyne[ib] -= sign * bzynw[ib] bzyse[ib] -= sign * bzysw[ib] # Assemble sparse matrix iall = ii.flatten() i_s = ii[:, :-1].flatten() i_n = ii[:, 1:].flatten() i_e = ii[1:, :].flatten() i_w = ii[:-1, :].flatten() i_ne = ii[1:, 1:].flatten() i_se = ii[1:, :-1].flatten() i_sw = ii[:-1, :-1].flatten() i_nw = ii[:-1, 1:].flatten() Izx = np.r_[iall, i_w, i_e, i_s, i_n, i_ne, i_se, i_sw, i_nw] Jzx = np.r_[iall, i_e, i_w, i_n, i_s, i_sw, i_nw, i_ne, i_se] Vzx = np.r_[bzxp[iall], bzxe[i_w], bzxw[i_e], bzxn[i_s], bzxs[i_n], bzxsw[i_ne], bzxnw[i_se], bzxne[i_sw], bzxse[i_nw], ] Izy = np.r_[iall, i_w, i_e, i_s, i_n, i_ne, i_se, i_sw, i_nw] Jzy = np.r_[iall, i_e, i_w, i_n, i_s, i_sw, i_nw, i_ne, i_se] + nx * ny Vzy = np.r_[bzyp[iall], bzye[i_w], bzyw[i_e], bzyn[i_s], bzys[i_n], bzysw[i_ne], bzynw[i_se], bzyne[i_sw], bzyse[i_nw], ] I = np.r_[Izx, Izy] J = np.r_[Jzx, Jzy] V = np.r_[Vzx, Vzy] B = coo_matrix((V, (I, J))).tocsr() HxHy = np.r_[Hx, Hy] Hz = B * HxHy.ravel() / 1j Hz = Hz.reshape(Hx.shape) # in xc e yc exx = epsxx[1:-1, 1:-1] exy = epsxy[1:-1, 1:-1] eyx = epsyx[1:-1, 1:-1] eyy = epsyy[1:-1, 1:-1] ezz = epszz[1:-1, 1:-1] edet = exx * eyy - exy * eyx h = e.reshape(nx, ny)[:-1, :-1] v = n.reshape(nx, ny)[:-1, :-1] # in xc e yc Dx = neff * EMpy.utils.centered2d(Hy) + (Hz[:-1, 1:] + Hz[ 1:, 1:] - Hz[:-1, :-1] - Hz[1:, :-1]) / (2j * k * v) Dy = -neff * EMpy.utils.centered2d(Hx) - (Hz[1:, :-1] + Hz[ 1:, 1:] - Hz[:-1, 1:] - Hz[:-1, :-1]) / (2j * k * h) Dz = ((Hy[1:, :-1] + Hy[1:, 1:] - Hy[:-1, 1:] - Hy[:-1, :-1]) / (2 * h) - (Hx[:-1, 1:] + Hx[1:, 1:] - Hx[:-1, :-1] - Hx[1:, :-1]) / (2 * v)) / (1j * k) Ex = (eyy * Dx - exy * Dy) / edet Ey = (exx * Dy - eyx * Dx) / edet Ez = Dz / ezz Hzs.append(Hz) Exs.append(Ex) Eys.append(Ey) Ezs.append(Ez) self.Hz = Hzs[0] self.Ex = Exs[0] self.Ey = Eys[0] self.Ez = Ezs[0]