def guided_mode_given_g(g, eps_array, d_array, n_modes=1, omega_lb=None, omega_ub=None, step=1e-2, tol=1e-2, pol='TE'): """ Finds the first 'n_modes' guided modes of polarization 'pol' for a given 'g' """ # Set lower and upper bound on the possible solutions eps_val = get_value(eps_array) d_val = get_value(d_array) if omega_lb is None: omega_lb = g/np.sqrt(eps_val[1:-1].max()) if omega_ub is None: omega_ub = g/np.sqrt(max(eps_val[0],eps_val[-1])) omega_lb = omega_lb*(1+tol) omega_ub = omega_ub*(1-tol) # D22real is used in the fsolve; D22test is vectorized and used on a test # array of omega-s to find sign flips D22real = lambda x,*args: bd.real(D22(x, *args, pol=pol)) D22test = lambda x,*args: bd.real(D22s_vec(x, *args, pol=pol)) # Making sure the bounds go all the way to omega_ub omega_bounds = np.append(np.arange(omega_lb, omega_ub, step), omega_ub) # Variables storing the solutions omega_solutions = [] coeffs = [] # Find omegas between which D22 changes sign D22s = D22test(omega_bounds, g, eps_val, d_val).real sign_change = np.where(D22s[0:-1]*D22s[1:] < 0)[0] lb = omega_bounds[0] # Use fsolve to find the first 'n_modes' guided modes for i in sign_change: if len(omega_solutions) >= n_modes: break lb = omega_bounds[i] ub = omega_bounds[i+1] # Compute guided mode frequency omega = bd.fsolve_D22(D22real, lb, ub, g, eps_array, d_array) omega_solutions.append(omega) chi_array = chi(omega, g, eps_array) if pol.lower()=='te' or pol.lower()=='tm': # Compute A-B coefficients AB = AB_matrices(omega, g, eps_array, d_array, chi_array, pol) # Normalize norm = normalization_coeff(omega, g, eps_array, d_array, chi_array, AB, pol) coeffs.append(AB / bd.sqrt(norm)) else: raise ValueError("Polarization should be 'TE' or 'TM'") return (omega_solutions, coeffs)
def chi(omega, g, eps): """ Function to compute chi_j, the z-direction wave-vector in each layer j Either omega is an array and eps is a number, or vice versa Input omega : frequency * 2π , in units of light speed/unit length eps : slab permittivity array g : wave vector along propagation direction Output chi : array of chi_j for all layers j including claddings """ sqarg = bd.array(eps * omega**2 - g**2, dtype=bd.complex) return bd.where(bd.real(sqarg) >= 0, bd.sqrt(sqarg), 1j * bd.sqrt(-sqarg))
def __init__(self, eps=1.): """Create a shape """ self.eps = eps self.area = bd.real(self.compute_ft(bd.array([[0.], [0.]])))