emopt.modes¶
Solve for the modes of electromagnetic waveguides in 2D and 3D.
Waveguide modes can be computed by setting up a generalized eigenvalue problem corresponding to the source-free Maxwell’s equations assuming a solution to \(\mathbf{E}\) and \(\mathbf{H}\) which is proportional to \(e^{i k_z z}\), i.e.
where we have used the non-dimensionalized Maxwell’s equations. These equations can be written in the form
where \(A\) contains the discretized curls and material values, \(B\) is singular matrix containing only 1s and 0s, and \(n_z\) is the effective index of the mode whose field components are contained in \(x\). Although formulating the problem like this results in a sparse matrix with ~2x the number of values compared to other formulations discussed in the literature[1], it has the great advantage that the equations remain very simple which simplifies the code. This formulation also makes it almost trivial to implement anisotropic materials (tensors) in the future, if desired.
In addition to solving for the fields of a waveguide’s modes, we can also
compute the current sources which excite only that mode. This can be used in
conjunction with emopt.fdfd.FDFD to simulated waveguide structures
which are particularly interesting for applications in silicon photonics, etc.
References
[1] A. B. Fallahkhair, K. S. Li and T. E. Murphy, “Vector Finite Difference Modesolver for Anisotropic Dielectric Waveguides”, J. Lightwave Technol. 26(11), 1423-1431, (2008).
-
class
emopt.modes.ModeFullVector(wavelength, eps, mu, domain, n0=1.0, neigs=1, backwards=False, verbose=True)¶ Bases:
emopt.modes.ModeSolverSolve for the modes for a 2D slice of a 3D structure.
Parameters: - wavelength (float) – The wavelength of the modes.
- ds (float) – The grid spacing in the mode field (y) direction.
- eps (numpy.ndarray) – The array containing the slice of permittivity for which the modes are calculated.
- mu (numpy.ndarray) – The array containing the slice of permeabilities for which the modes are calculated.
- n0 (float (optional)) – The ‘guess’ for the effective index around which the modes are computed. In general, this value should be larger than the index of the mode you are looking for. (default = 1.0)
- neigs (int (optional)) – The number of modes to compute. (default = 1)
- backwards (bool) – Defines whether or not the mode propagates in the forward +x direction (False) or the backwards -x direction (True). (default = False)
-
neff¶ The list of solved effective indices
Type: list of floats
-
build(self)¶ Build the system of equations and prepare the mode solver for the solution process.
-
solve(self)¶ Solve for the modes of the structure.
-
get_field(self, i, component)¶ Get the desired raw field component of the i’th mode.
-
get_field_interp(self, i, component)¶ Get the desired interpolated field component of the i’th mode
-
get_mode_number(self, i): Estimate the number X of the given TE_X mode.
-
find_mode_index(self, X): Find the index of a TE_X mode with the desired X.
-
get_source(self, i, ds1, ds2, ds3=0.0)¶ Get the source current distribution for the i’th mode.
-
bc¶
-
build() Build the system of equations and prepare the mode solver for the solution process.
In order to solve for the eigen modes, we must first assemble the relevant matrices \(A\) and \(B\) for the generalized eigenvalue problem given by \(A x = n_x B x\) where \(n_x\) is the eigenvalue and \(x\) is the vector containing the eigen modes.
Notes
This function is run on all nodes.
-
component_energy(i)¶ Get the fraction of energy stored in each field component.
Parameters: i (int) – The index of the mode to analyze Returns: The list of energy fractions corresponding to Ex, Ey, Ez, Hx, Hy, Hz Return type: [float, float, float, float, float, float]
-
find_mode_index(P, Q)¶ Find the index of the index of the mode with X horizontal phase transitions and Y vertical phase transitions.
Parameters: Returns: The index of the mode with the desired number.
Return type:
-
get_field(i, component, permute=True, squeeze=False) Get the desired raw field component of the i’th mode.
Notes
This function only returns a non-None result on the master node. On all other nodes, None is returned.
See also
ModeFullVector.get_field_interp(),ModeFullVector.find_mode_index()Parameters: - i (int) – The index of the desired mode
- component (str) – The desired field component (Ex, Ey, Ez, Hx, Hy, Hz)
- permute (bool) – Permute the field components according to the normal direction of the supplied domain. Because all computation is internally performed assuming the mode propagates in the z direction, the field components need to be permuted in order to produce the desired result. (default = True)
Returns: (Master node only) an array containing the desired component of the mode field.
Return type: numpy.ndarray or None
-
get_field_interp(i, component, squeeze=False) Get the desired interpolated field component of the i’th mode.
In general, this function should be preferred over
ModeFullVector.get_field().In general, you may wish to solve for more than one mode. In order to get the desired mode, you must specify its index. If you do not know the index but you do know the desired mode number, then
ModeFullVector.find_mode_index()may be used to determine the index of the desired mode.Notes
The fields are solved for on a grid made up of compressed 2D Yee cells. The fields are thus interpolated at the center of this Yee cell (which happens to coincide with the position of Hz)
This function only returns a non-None result on the master node. On all other nodes, None is returned.
See also
ModeFullVector.get_field(),ModeFullVector.find_mode_index()Parameters: Returns: (Master node only) an array containing the desired component of the interpolated mode field.
Return type: numpy.ndarray or None
-
get_mode_number(i)¶ Determine the mode number.
This is based on the number of phase crossings.
Todo
Implement this function…
Parameters: i (int) – The index of the mode to analyze. Returns: The numbers X and Y of the mode. Return type: int, int
-
get_source(i, dx, dy, dz) Get the source current distribution for the i’th mode.
Notes
- Source calculations are only supported for Material3D structures.
2) The sources are computed assuming the mode is propagating in the z direction. In order to support modes propagating in different directions, the spatial coordinates are permuted. Fortunately, the underlying dislocated grids are invariant under this transformation. This is only necessary for calculating the material cross-sections.
Todo
Implement in parallelized manner.
Parameters: Returns: (On master node) The tuple (Jx, Jy, Jz, Mx, My, Mz) containing arrays of the source distributions.
Return type: tuple of numpy.ndarray
-
solve() Solve for the modes of the structure.
Notes
This function is run on all nodes.
-
class
emopt.modes.ModeSolver(wavelength, n0=1.0, neigs=1)¶ Bases:
future.types.newobject.newobjectA generic interface for electromagnetic mode solvers.
At a minimum, a mode solver must provide functions for solving for the modes of a structure, retrieving the fields of a desired mode, retrieving the effective index of a desired mode, and calculating the current sources which excite that mode.
-
neff¶ The list of solved effective indices
Type: list of floats
-
build(self)¶ Build the system of equations and prepare the mode solver for the solution process.
-
solve(self)¶ Solve for the modes of the structure.
-
get_field(self, i, component)¶ Get the desired field component of the i’th mode.
-
get_field_interp(self, i, component)¶ Get the desired interpolated field component of the i’th mode
-
get_source(self, i, ds1, ds2, ds3=0.0)¶ Get the source current distribution for the i’th mode.
-
build() Build the system of equations and prepare the mode solver for the solution process.
-
get_field(i, component) Get the raw field of the i’th mode.
This function should only be called after
solve().Parameters: Returns: (Master node only) The desired field component.
Return type: numpy.ndarray
-
get_field_interp(i, component) Get the interpolated field of the i’th mode.
This function should only be called after
solve(). In general, this field should be prefered overget_field().Parameters: Returns: (Master node only) The desired interpolated field component.
Return type: numpy.ndarray
-
get_source(i, ds1, ds2, ds3=0.0) Calculate the current source distribution which will excite the desired mode.
The current source distribution can be computed by assuming the computed mode fields are proportional to \(e^{i k_z z}\) and eminate from a ‘virtual’ plane (hence the fields are zero on one side of plane, and have the desired z-dependence on the other side). This assumed field can be plugged into the source-containing Maxwell’s equations to solve for :math`J` and \(M\).
Parameters:
-
neff
-
solve() Solve for the fields of the desired modes.
-
-
class
emopt.modes.ModeTE(wavelength, eps, mu, domain, n0=1.0, neigs=1, backwards=False)¶ Bases:
emopt.modes.ModeSolverSolve for the TE polarized modes of a 1D slice of a 2D structure.
The TE polarization consists of a non-zeros \(E_z\), \(H_x\), \(H_y\). The mode is assumed to propagate in the x direction and the mode field is a function of the y-position, i.e. the fields are
\[ \begin{align}\begin{aligned}E_z(x,y) = E_{mz}(y) e^{i k_x x}\\H_x(x,y) = H_{mx}(y) e^{i k_x x}\\H_y(x,y) = H_{my}(y) e^{i k_x x}\end{aligned}\end{align} \]where \(E_{mz}\), \(H_{mx}\), and \(H_{my}\) are the mode fields.
Parameters: - wavelength (float) – The wavelength of the modes.
- ds (float) – The grid spacing in the mode field (y) direction.
- eps (numpy.ndarray) – The array containing the slice of permittivity for which the modes are calculated.
- mu (numpy.ndarray) – The array containing the slice of permeabilities for which the modes are calculated.
- n0 (float (optional)) – The ‘guess’ for the effective index around which the modes are computed. In general, this value should be larger than the index of the mode you are looking for. (default = 1.0)
- neigs (int (optional)) – The number of modes to compute. (default = 1)
- backwards (bool) – Defines whether or not the mode propagates in the forward +x direction (False) or the backwards -x direction (True). (default = False)
-
neff¶ The list of solved effective indices
Type: list of floats
-
bc¶ - The boundary conditions used. The possible boundary conditions are:
- 0 – Perfect electric conductor (top and bottom) M – Perfect magnetic conductor (top and bottom) E – Electric field symmetry (bottom) and PEC (top) H – Magnetic field symmetry (bottom) and PEC (top) P – Periodicity (top and bottom) EM – Electric field symmetry (bottom) PMC (top) HM – Magnetic field symmetry (bottom) PMC (top)
Type: str
-
build(self)¶ Build the system of equations and prepare the mode solver for the solution process.
-
solve(self)¶ Solve for the modes of the structure.
-
get_field(self, i, component)¶ Get the desired raw field component of the i’th mode.
-
get_field_interp(self, i, component)¶ Get the desired interpolated field component of the i’th mode
-
get_mode_number(self, i): Estimate the number X of the given TE_X mode.
-
find_mode_index(self, X): Find the index of a TE_X mode with the desired X.
-
get_source(self, i, ds1, ds2, ds3=0.0)¶ Get the source current distribution for the i’th mode.
-
bc
-
build() Build the system of equations and prepare the mode solver for the solution process.
In order to solve for the eigen modes, we must first assemble the relevant matrices \(A\) and \(B\) for the generalized eigenvalue problem given by \(A x = n_x B x\) where \(n_x\) is the eigenvalue and \(x\) is the vector containing the eigen modes.
Notes
This function is run on all nodes.
-
dir
-
find_mode_index(**kwargs)¶
-
get_field(**kwargs)
-
get_field_interp(**kwargs)
-
get_mode_number(**kwargs)¶
-
get_source(i, dx, dy, dz=0.0) Get the source current distribution for the i’th mode.
Notes
For this calculation to work out, we assume that all field components are zero to the left of the center of the Yee cell (i.e. the positions of the Ez values). To the right of the center of the Yee cell, we assume the field components have an exp(ikx) dependence.
dy should be equal to ds.
This class assumes all modes propagate in the x direction. In order to propagate a mode in the y direction, x and y (dx and dy) can be permuted.
Todo
Implement in parallelized manner.
Parameters: Returns: (On ALL nodes) The tuple (Jz, Mx, My) containing arrays of the source distributions. In 2D, these source distributions are N x 1 arrays.
Return type: tuple of numpy.ndarray
-
solve() Solve for the modes of the structure.
In addition to solving for the modes, this function saves the results to the master node so that they can be easily retrieved for visualization, etc.
Notes
This function is run on all nodes.
-
class
emopt.modes.ModeTM(wavelength, eps, mu, domain, n0=1.0, neigs=1, backwards=False)¶ Bases:
emopt.modes.ModeTESolve for the TM polarized modes of a 1D slice of a 2D structure.
The TM polarization consists of a non-zeros \(H_z\), \(E_x\), \(E_y\). The mode is assumed to propagate in the x direction and the mode field is a function of the y-position, i.e. the fields are
\[ \begin{align}\begin{aligned}H_z(x,y) = H_{mz}(y) e^{i k_x x}\\E_x(x,y) = E_{mx}(y) e^{i k_x x}\\E_y(x,y) = E_{my}(y) e^{i k_x x}\end{aligned}\end{align} \]where \(H_{mz}\), \(E_{mx}\), and \(E_{my}\) are the mode fields.
Parameters: - wavelength (float) – The wavelength of the modes.
- ds (float) – The grid spacing in the mode field (y) direction.
- eps (numpy.ndarray) – The array containing the slice of permittivity for which the modes are calculated.
- mu (numpy.ndarray) – The array containing the slice of permeabilities for which the modes are calculated.
- n0 (float (optional)) – The ‘guess’ for the effective index around which the modes are computed. In general, this value should be larger than the index of the mode you are looking for. (default = 1.0)
- neigs (int (optional)) – The number of modes to compute. (default = 1)
- backwards (bool) – Defines whether or not the mode propagates in the forward +x direction (False) or the backwards -x direction (True). (default = False)
-
neff¶ The list of solved effective indices
Type: list of floats
-
build(self)¶ Build the system of equations and prepare the mode solver for the solution process.
-
solve(self)¶ Solve for the modes of the structure.
-
get_field(self, i, component)¶ Get the desired raw field component of the i’th mode.
-
get_field_interp(self, i, component)¶ Get the desired interpolated field component of the i’th mode
-
get_mode_number(self, i): Estimate the number X of the given TE_X mode.
-
find_mode_index(self, X): Find the index of a TE_X mode with the desired X.
-
get_source(self, i, ds1, ds2, ds3=0.0)¶ Get the source current distribution for the i’th mode.
-
bc¶
-
get_field(**kwargs)
-
get_field_interp(**kwargs)
-
get_source(dx, dy, dz=0.0) Get the source current distribution for the i’th mode.
Notes
For this calculation to work out, we assume that all field components are zero to the left of the center of the Yee cell (i.e. the positions of the Hz values). To the right of the center of the Yee cell, we assume the field components have an exp(ikx) dependence.
dy should be equal to ds.
This class assumes all modes propagate in the x direction. In order to propagate a mode in the y direction, x and y (dx and dy) can be permuted.
Todo
Implement in parallelized manner.
Parameters: Returns: (On ALL nodes) The tuple (Mz, Jx, Jy) containing arrays of the source distributions. In 2D, these source distributions are N x 1 arrays.
Return type: tuple of numpy.ndarray