Пример #1
0
    def run(self, kpoints=np.array([[0], [0]]), pol='te', numeig=10):
        """
        Run the simulation. The computed eigen-frequencies are stored in
        :attr:`PlaneWaveExp.freqs`, and the corresponding eigenvectors - 
        in :attr:`PlaneWaveExp.eigvecs`.
        
        Parameters
        ----------
        kpoints : np.ndarray, optional
            Numpy array of shape (2, Nk) with the [kx, ky] coordinates of the 
            k-vectors over which the simulation is run.
        pol : {'te', 'tm'}, optional
            Polarization of the modes.
        numeig : int, optional
            Number of eigen-frequencies to be stored (starting from lowest).
        """
         
        self._kpoints = kpoints
        self.pol = pol.lower()
        # Change this if switching to a solver that allows for variable numeig
        self.numeig = numeig

        self._compute_ft()
        self._compute_eps_inv()

        freqs = []
        self._eigvecs = []
        for ik, k in enumerate(kpoints.T):
            # Construct the matrix for diagonalization
            if self.pol == 'te':
                mat = bd.dot(bd.transpose(k[:, bd.newaxis] + self.gvec), 
                                (k[:, bd.newaxis] + self.gvec))
                mat = mat * self.eps_inv_mat 
                
            elif self.pol == 'tm':
                Gk = bd.sqrt(bd.square(k[0] + self.gvec[0, :]) + \
                        bd.square(k[1] + self.gvec[1, :]))
                mat = bd.outer(Gk, Gk)
                mat = mat * self.eps_inv_mat
            else:
                raise ValueError("Polarization should be 'TE' or 'TM'")

            # Diagonalize using numpy.linalg.eigh() for now; should maybe switch 
            # to scipy.sparse.linalg.eigsh() in the future
            # NB: we shift the matrix by np.eye to avoid problems at the zero-
            # frequency mode at Gamma
            (freq2, evecs) = bd.eigh(mat + bd.eye(mat.shape[0]))
            freq1 = bd.sqrt(bd.abs(freq2 - bd.ones(mat.shape[0])))/2/np.pi
            i_sort = bd.argsort(freq1)[0:self.numeig]
            freq = freq1[i_sort]
            evec = evecs[:, i_sort]
            freqs.append(freq)
            self._eigvecs.append(evec)

        # Store the eigenfrequencies taking the standard reduced frequency 
        # convention for the units (2pi a/c)    
        self._freqs = bd.array(freqs)
        self.mat = mat
Пример #2
0
    def compute_ft(self, gvec):
        """
        Compute the 2D Fourier transform of the layer permittivity.
        """
        FT = bd.zeros(gvec.shape[1])
        for shape in self.shapes:
            # Note: compute_ft() returns the FT of a function that is one
            # inside the shape and zero outside
            FT = FT + (shape.eps - self.eps_b) * shape.compute_ft(gvec)

        # Apply some final coefficients
        # Note the hacky way to set the zero element so as to work with
        # 'autograd' backend
        ind0 = bd.abs(gvec[0, :]) + bd.abs(gvec[1, :]) < 1e-10
        FT = FT / self.lattice.ec_area
        FT = FT * (1 - ind0) + self.eps_avg * ind0

        return FT
Пример #3
0
def normalization_coeff(omega, g, eps_array, d_array, chi_array, ABref, 
                            pol='TE'):
    """
    Normalization of the guided modes (i.e. the A and B coeffs)
    """
    assert len(d_array)==len(eps_array)-2, \
        'd_array should have length = num_layers'
    if chi_array is None:
        chi_array = chi(omega, g, eps_array)
    As = ABref[:, 0].ravel()
    Bs = ABref[:, 1].ravel()
    if pol == 'TM': 
        term1 = (bd.abs(Bs[0])**2) * J_alpha(chi_array[0]-bd.conj(chi_array[0]))
        term2 = (bd.abs(As[-1])**2) * \
                    J_alpha(chi_array[-1]-bd.conj(chi_array[-1]))
        term3 = (
                (bd.abs(As[1:-1])**2 + bd.abs(Bs[1:-1])**2) * \
                I_alpha(chi_array[1:-1]-bd.conj(chi_array[1:-1]),d_array) + 
                (bd.conj(As[1:-1]) * Bs[1:-1] + As[1:-1] * bd.conj(Bs[1:-1])) *
                I_alpha(-chi_array[1:-1]-bd.conj(chi_array[1:-1]),d_array)  )
        return term1 + term2 + bd.sum(term3)
    elif pol == 'TE':
        term1 = (bd.abs(chi_array[0])**2 + g**2) * \
            (bd.abs(Bs[0])**2) * J_alpha(chi_array[0]-bd.conj(chi_array[0]))
        term2 = (bd.abs(chi_array[-1])**2 + g**2) * \
            (bd.abs(As[-1])**2) * J_alpha(chi_array[-1]-bd.conj(chi_array[-1]))
        term3 = (bd.abs(chi_array[1:-1])**2 + g**2) * (
                (bd.abs(As[1:-1])**2 + bd.abs(Bs[1:-1])**2) * \
                I_alpha(chi_array[1:-1]-bd.conj(chi_array[1:-1]), d_array)) + \
                (g**2 - bd.abs(chi_array[1:-1])**2) * (
                (bd.conj(As[1:-1]) * Bs[1:-1] + As[1:-1] * bd.conj(Bs[1:-1])) *
                I_alpha(-chi_array[1:-1]-bd.conj(chi_array[1:-1]), d_array)  )
        return term1 + term2 + bd.sum(term3)
    else:
        raise Exception('Polarization should be TE or TM.')