示例#1
0
def getHessFull(gammas=None, amounts=None, numExps=3):
    if gammas is None:
        gammas = getGammas(numExps)
    if amounts is None:
        amounts = getAmounts(numExps)

    numExps = scipy.size(gammas)

    hessgg = getHessGG(gammas)

    hessAA = getHessAA(amounts, gammas)

    numerAg1 = -scipy.outer(amounts, amounts * gammas)
    denomAg1 = scipy.outer(scipy.ones(numExps), gammas)
    denomAg2 = scipy.transpose(denomAg1) + denomAg1
    denomAg3 = denomAg2 * denomAg2
    hessAg = old_div(numerAg1, denomAg3)

    numergA1 = -scipy.outer(amounts * gammas, amounts)
    denomgA1 = scipy.outer(gammas, scipy.ones(numExps))
    denomgA2 = scipy.transpose(denomgA1) + denomgA1
    denomgA3 = denomgA2 * denomgA2
    hessgA = old_div(numergA1, denomgA3)

    hessFull = scipy.bmat([[hessAA, hessAg], [hessgA, hessgg]])

    return hessFull
示例#2
0
def getHessFullLogTime(gammas=None, amounts=None, numExps=3):
    """use this routine for new paper"""
    if gammas is None:
        gammas = getGammas(numExps)
    if amounts is None:
        amounts = getAmounts(numExps)

    numExps = scipy.size(gammas)

    amountsLess1 = amounts[0:-1]
    gammasLess1 = gammas[0:-1]

    hessgg = getHessGGLogTime(gammas=gammas, amounts=amounts)

    hessAA = getHessAALogTime(amounts=amounts, gammas=gammas)

    numerAg1 = scipy.array(-2. * scipy.outer(amountsLess1, amounts * gammas))
    denomAg1 = scipy.array(scipy.outer(gammasLess1, scipy.ones(numExps)))
    denomAg2 = scipy.array(scipy.outer(scipy.ones(numExps - 1), gammas))
    denomAg3 = scipy.array(denomAg1 + denomAg2)
    denomAg4 = denomAg2 + gammas[-1]
    hessAg = scipy.array(old_div(numerAg1, denomAg3)) - scipy.array(
        old_div(numerAg1, denomAg4))

    hessgA = scipy.transpose(hessAg)

    hessFull = scipy.array(scipy.bmat([[hessAA, hessAg], [hessgA, hessgg]]))

    return hessFull
示例#3
0
    def getDerivatives(self, N, op):
        """ Compute the successive derivative of an eigenvalue of an OP instance
        
        Parameters
        -----------
        N: int
            the number derivative to compute
        op: OP
            the operator OP instance that describe the eigenvalue problem
            
        RHS derivative must start at n=1 for 1st derivatives
        """

        # get nu0 value where the derivative are computed
        self.nu0 = op.nu0
        # construction de la matrice de l'opérateur L, ie L.L
        L = op.createL(self.lda)
        # normalization condition (push elsewhere : différente méthode, indépendace vs type )
        # must be done before L1x
        v = np.ones(shape=self.x.shape)
        # see also VecScale
        self.x *= (1 / v.dot(self.x))
        self.dx[0] = self.x

        # constrution du vecteur (\partial_\lambda L)x, ie L.L1x
        L1x = op.createDL_ldax(self)

        # bordered
        # ---------------------------------------------------------------------
        # Same matrix to factorize for all RHS
        Zer = np.zeros(shape=(1, 1), dtype=np.complex)
        Zerv = np.zeros(shape=(1, ), dtype=np.complex)
        Bord = sp.bmat([[L, L1x.reshape(-1, 1)],
                        [v.reshape(1, -1),
                         Zer]])  # reshape is to avoid (n,) in bmat

        # if N > 1 loop for higher order terms
        print('> Linear solve...')
        # n start now at 1 for uniformization
        for n in range(1, N + 1):
            # compute RHS
            tic = time.time()  # init timer
            Ftemp = op.getRHS(self, n)
            #F= sp.bmat([Ftemp, Zerv]).reshape(-1,1)
            F = np.concatenate((Ftemp, Zerv))
            # print("              # getRHS real time :", time.time()-tic)

            tic = time.time()  # init timer
            if n == 1:
                # compute the lu factor
                lu, piv = sp.linalg.lu_factor(Bord)
            # Forward and back substitution, u contains [dx, dlda])
            u = sp.linalg.lu_solve((lu, piv), F)
            # print("              # solve LU real time :", time.time()-tic)

            # get lda^(n)
            derivee = u[-1]
            # store the value
            self.dlda.append(derivee)
            self.dx.append(u.copy()[:-1])
示例#4
0
def getJacobianLog(times, gammas, amounts=None):
    """This is the routine to use for new paper (with times exponentially
    distributed."""
    numExps = scipy.size(gammas)
    if amounts is None:
        amounts = scipy.ones(numExps, 'd')
    jacG = getJacobianLogG(times, gammas, amounts)
    jacA = getJacobianLogA(times, gammas, amounts)
    return scipy.transpose(scipy.array(scipy.bmat([[jacA], [jacG]])))
示例#5
0
def ProcessQuarterMatrix(p):
    """
    this is used if parameters define just upper right and lower left
    quadrants of antisymmetric matrix.
    """
    n = scipy.sqrt(scipy.size(p))
    Mu = scipy.resize(p, (n, n))
    Mfull = scipy.bmat([[scipy.zeros((n, n)), Mu],
                        [-scipy.transpose(Mu),
                         scipy.zeros((n, n))]])
    return scipy.linalg.expm(Mfull)
示例#6
0
    def solve(self, wls):
        """Anisotropic solver.

        INPUT
        wls = wavelengths to scan (any asarray-able object).

        OUTPUT
        self.DEO1, self.DEE1, self.DEO3, self.DEE3 = power reflected
        and transmitted.
        """

        self.wls = S.atleast_1d(wls)

        LAMBDA = self.LAMBDA
        n = self.n
        multilayer = self.multilayer
        alpha = self.alpha
        delta = self.delta
        psi = self.psi
        phi = self.phi

        nlayers = len(multilayer)
        i = S.arange(-n, n + 1)
        nood = 2 * n + 1
        hmax = nood - 1

        DEO1 = S.zeros((nood, self.wls.size))
        DEO3 = S.zeros_like(DEO1)
        DEE1 = S.zeros_like(DEO1)
        DEE3 = S.zeros_like(DEO1)

        c1 = np.array([1., 0., 0.])
        c3 = np.array([1., 0., 0.])
        # grating on the xy plane
        K = 2 * pi / LAMBDA * np.array(
            [S.sin(phi), 0., S.cos(phi)], dtype=complex)
        dirk1 = np.array([
            S.sin(alpha) * S.cos(delta),
            S.sin(alpha) * S.sin(delta),
            S.cos(alpha)
        ])

        # D polarization vector
        u = np.array([
            S.cos(psi) * S.cos(alpha) * S.cos(delta) -
            S.sin(psi) * S.sin(delta),
            S.cos(psi) * S.cos(alpha) * S.sin(delta) +
            S.sin(psi) * S.cos(delta),
            -S.cos(psi) * S.sin(alpha),
        ])

        kO1i = S.zeros((3, i.size), dtype=complex)
        kE1i = S.zeros_like(kO1i)
        kO3i = S.zeros_like(kO1i)
        kE3i = S.zeros_like(kO1i)

        Mp = S.zeros((4 * nood, 4 * nood, nlayers), dtype=complex)
        M = S.zeros((4 * nood, 4 * nood, nlayers), dtype=complex)

        dlt = (i == 0).astype(int)

        for iwl, wl in enumerate(self.wls):

            nO1 = nE1 = multilayer[0].mat.n(wl).item()
            nO3 = nE3 = multilayer[-1].mat.n(wl).item()

            # wavevectors
            k = 2 * pi / wl

            eps1 = S.diag(S.asarray([nE1, nO1, nO1])**2)
            eps3 = S.diag(S.asarray([nE3, nO3, nO3])**2)

            # ordinary wave
            abskO1 = k * nO1
            # abskO3 = k * nO3
            # extraordinary wave
            # abskE1 = k * nO1 *nE1 / S.sqrt(nO1**2 + (nE1**2 - nO1**2) * S.dot(-c1, dirk1)**2)
            # abskE3 = k * nO3 *nE3 / S.sqrt(nO3**2 + (nE3**2 - nO3**2) * S.dot(-c3, dirk1)**2)

            k1 = abskO1 * dirk1

            kO1i[0, :] = k1[0] - i * K[0]
            kO1i[1, :] = k1[1] * S.ones_like(i)
            kO1i[2, :] = -dispersion_relation_ordinary(kO1i[0, :], kO1i[1, :],
                                                       k, nO1)

            kE1i[0, :] = kO1i[0, :]
            kE1i[1, :] = kO1i[1, :]
            kE1i[2, :] = -dispersion_relation_extraordinary(
                kE1i[0, :], kE1i[1, :], k, nO1, nE1, c1)

            kO3i[0, :] = kO1i[0, :]
            kO3i[1, :] = kO1i[1, :]
            kO3i[2, :] = dispersion_relation_ordinary(kO3i[0, :], kO3i[1, :],
                                                      k, nO3)

            kE3i[0, :] = kO1i[0, :]
            kE3i[1, :] = kO1i[1, :]
            kE3i[2, :] = dispersion_relation_extraordinary(
                kE3i[0, :], kE3i[1, :], k, nO3, nE3, c3)

            # k2i = S.r_[[k1[0] - i * K[0]], [k1[1] - i * K[1]], [k1[2] - i * K[2]]]
            k2i = S.r_[[k1[0] - i * K[0]], [k1[1] - i * K[1]], [-i * K[2]]]

            # aliases for constant wavevectors
            kx = kO1i[0, :]  # o kE1i(1,;), tanto e' lo stesso
            ky = k1[1]

            # matrices
            I = S.eye(nood, dtype=complex)
            ZERO = S.zeros((nood, nood), dtype=complex)
            Kx = S.diag(kx / k)
            Ky = ky / k * I
            Kz = S.diag(k2i[2, :] / k)
            KO1z = S.diag(kO1i[2, :] / k)
            KE1z = S.diag(kE1i[2, :] / k)
            KO3z = S.diag(kO3i[2, :] / k)
            KE3z = S.diag(kE3i[2, :] / k)

            ARO = Kx * eps1[0, 0] + Ky * eps1[1, 0] + KO1z * eps1[2, 0]
            BRO = Kx * eps1[0, 1] + Ky * eps1[1, 1] + KO1z * eps1[2, 1]
            CRO_1 = inv(Kx * eps1[0, 2] + Ky * eps1[1, 2] + KO1z * eps1[2, 2])

            ARE = Kx * eps1[0, 0] + Ky * eps1[1, 0] + KE1z * eps1[2, 0]
            BRE = Kx * eps1[0, 1] + Ky * eps1[1, 1] + KE1z * eps1[2, 1]
            CRE_1 = inv(Kx * eps1[0, 2] + Ky * eps1[1, 2] + KE1z * eps1[2, 2])

            ATO = Kx * eps3[0, 0] + Ky * eps3[1, 0] + KO3z * eps3[2, 0]
            BTO = Kx * eps3[0, 1] + Ky * eps3[1, 1] + KO3z * eps3[2, 1]
            CTO_1 = inv(Kx * eps3[0, 2] + Ky * eps3[1, 2] + KO3z * eps3[2, 2])

            ATE = Kx * eps3[0, 0] + Ky * eps3[1, 0] + KE3z * eps3[2, 0]
            BTE = Kx * eps3[0, 1] + Ky * eps3[1, 1] + KE3z * eps3[2, 1]
            CTE_1 = inv(Kx * eps3[0, 2] + Ky * eps3[1, 2] + KE3z * eps3[2, 2])

            DRE = c1[1] * KE1z - c1[2] * Ky
            ERE = c1[2] * Kx - c1[0] * KE1z
            FRE = c1[0] * Ky - c1[1] * Kx

            DTE = c3[1] * KE3z - c3[2] * Ky
            ETE = c3[2] * Kx - c3[0] * KE3z
            FTE = c3[0] * Ky - c3[1] * Kx

            b = S.r_[u[0] * dlt, u[1] * dlt,
                     (k1[1] / k * u[2] - k1[2] / k * u[1]) * dlt,
                     (k1[2] / k * u[0] - k1[0] / k * u[2]) * dlt, ]
            Ky_CRO_1 = ky / k * CRO_1
            Ky_CRE_1 = ky / k * CRE_1
            Kx_CRO_1 = kx[:, S.newaxis] / k * CRO_1
            Kx_CRE_1 = kx[:, S.newaxis] / k * CRE_1
            MR31 = -S.dot(Ky_CRO_1, ARO)
            MR32 = -S.dot(Ky_CRO_1, BRO) - KO1z
            MR33 = -S.dot(Ky_CRE_1, ARE)
            MR34 = -S.dot(Ky_CRE_1, BRE) - KE1z
            MR41 = S.dot(Kx_CRO_1, ARO) + KO1z
            MR42 = S.dot(Kx_CRO_1, BRO)
            MR43 = S.dot(Kx_CRE_1, ARE) + KE1z
            MR44 = S.dot(Kx_CRE_1, BRE)
            MR = S.asarray(
                S.bmat([
                    [I, ZERO, I, ZERO],
                    [ZERO, I, ZERO, I],
                    [MR31, MR32, MR33, MR34],
                    [MR41, MR42, MR43, MR44],
                ]))

            Ky_CTO_1 = ky / k * CTO_1
            Ky_CTE_1 = ky / k * CTE_1
            Kx_CTO_1 = kx[:, S.newaxis] / k * CTO_1
            Kx_CTE_1 = kx[:, S.newaxis] / k * CTE_1
            MT31 = -S.dot(Ky_CTO_1, ATO)
            MT32 = -S.dot(Ky_CTO_1, BTO) - KO3z
            MT33 = -S.dot(Ky_CTE_1, ATE)
            MT34 = -S.dot(Ky_CTE_1, BTE) - KE3z
            MT41 = S.dot(Kx_CTO_1, ATO) + KO3z
            MT42 = S.dot(Kx_CTO_1, BTO)
            MT43 = S.dot(Kx_CTE_1, ATE) + KE3z
            MT44 = S.dot(Kx_CTE_1, BTE)
            MT = S.asarray(
                S.bmat([
                    [I, ZERO, I, ZERO],
                    [ZERO, I, ZERO, I],
                    [MT31, MT32, MT33, MT34],
                    [MT41, MT42, MT43, MT44],
                ]))

            Mp.fill(0.0)
            M.fill(0.0)

            for nlayer in range(nlayers - 2, 0, -1):  # internal layers

                layer = multilayer[nlayer]
                thickness = layer.thickness

                EPS2, EPS21 = layer.getEPSFourierCoeffs(wl,
                                                        n,
                                                        anisotropic=True)

                # Exx = S.squeeze(EPS2[0, 0, :])
                # Exx = toeplitz(S.flipud(Exx[0:hmax + 1]), Exx[hmax:])
                Exy = S.squeeze(EPS2[0, 1, :])
                Exy = toeplitz(S.flipud(Exy[0:hmax + 1]), Exy[hmax:])
                Exz = S.squeeze(EPS2[0, 2, :])
                Exz = toeplitz(S.flipud(Exz[0:hmax + 1]), Exz[hmax:])

                Eyx = S.squeeze(EPS2[1, 0, :])
                Eyx = toeplitz(S.flipud(Eyx[0:hmax + 1]), Eyx[hmax:])
                Eyy = S.squeeze(EPS2[1, 1, :])
                Eyy = toeplitz(S.flipud(Eyy[0:hmax + 1]), Eyy[hmax:])
                Eyz = S.squeeze(EPS2[1, 2, :])
                Eyz = toeplitz(S.flipud(Eyz[0:hmax + 1]), Eyz[hmax:])

                Ezx = S.squeeze(EPS2[2, 0, :])
                Ezx = toeplitz(S.flipud(Ezx[0:hmax + 1]), Ezx[hmax:])
                Ezy = S.squeeze(EPS2[2, 1, :])
                Ezy = toeplitz(S.flipud(Ezy[0:hmax + 1]), Ezy[hmax:])
                Ezz = S.squeeze(EPS2[2, 2, :])
                Ezz = toeplitz(S.flipud(Ezz[0:hmax + 1]), Ezz[hmax:])

                Exx_1 = S.squeeze(EPS21[0, 0, :])
                Exx_1 = toeplitz(S.flipud(Exx_1[0:hmax + 1]), Exx_1[hmax:])
                Exx_1_1 = inv(Exx_1)

                # lalanne
                Ezz_1 = inv(Ezz)
                Ky_Ezz_1 = ky / k * Ezz_1
                Kx_Ezz_1 = kx[:, S.newaxis] / k * Ezz_1
                Exz_Ezz_1 = S.dot(Exz, Ezz_1)
                Eyz_Ezz_1 = S.dot(Eyz, Ezz_1)
                H11 = 1j * S.dot(Ky_Ezz_1, Ezy)
                H12 = 1j * S.dot(Ky_Ezz_1, Ezx)
                H13 = S.dot(Ky_Ezz_1, Kx)
                H14 = I - S.dot(Ky_Ezz_1, Ky)
                H21 = 1j * S.dot(Kx_Ezz_1, Ezy)
                H22 = 1j * S.dot(Kx_Ezz_1, Ezx)
                H23 = S.dot(Kx_Ezz_1, Kx) - I
                H24 = -S.dot(Kx_Ezz_1, Ky)
                H31 = S.dot(Kx, Ky) + Exy - S.dot(Exz_Ezz_1, Ezy)
                H32 = Exx_1_1 - S.dot(Ky, Ky) - S.dot(Exz_Ezz_1, Ezx)
                H33 = 1j * S.dot(Exz_Ezz_1, Kx)
                H34 = -1j * S.dot(Exz_Ezz_1, Ky)
                H41 = S.dot(Kx, Kx) - Eyy + S.dot(Eyz_Ezz_1, Ezy)
                H42 = -S.dot(Kx, Ky) - Eyx + S.dot(Eyz_Ezz_1, Ezx)
                H43 = -1j * S.dot(Eyz_Ezz_1, Kx)
                H44 = 1j * S.dot(Eyz_Ezz_1, Ky)
                H = 1j * S.diag(S.repeat(S.diag(Kz), 4)) + S.asarray(
                    S.bmat([
                        [H11, H12, H13, H14],
                        [H21, H22, H23, H24],
                        [H31, H32, H33, H34],
                        [H41, H42, H43, H44],
                    ]))

                q, W = eig(H)
                W1, W2, W3, W4 = S.split(W, 4)

                #
                # boundary conditions
                #
                # x = [R T]
                # R = [ROx ROy REx REy]
                # T = [TOx TOy TEx TEy]
                # b + MR.R = M1p.c
                # M1.c = M2p.c
                # ...
                # ML.c = MT.T
                # therefore: b + MR.R = (M1p.M1^-1.M2p.M2^-1. ...).MT.T
                # missing equations from (46)..(49) in glytsis_rigorous
                # [b] = [-MR Mtot.MT] [R]
                # [0]   [...........] [T]

                z = S.zeros_like(q)
                z[S.where(q.real > 0)] = -thickness
                D = S.exp(k * q * z)
                Sy0 = W1 * D[S.newaxis, :]
                Sx0 = W2 * D[S.newaxis, :]
                Uy0 = W3 * D[S.newaxis, :]
                Ux0 = W4 * D[S.newaxis, :]

                z = thickness * S.ones_like(q)
                z[S.where(q.real > 0)] = 0
                D = S.exp(k * q * z)
                D1 = S.exp(-1j * k2i[2, :] * thickness)
                Syd = D1[:, S.newaxis] * W1 * D[S.newaxis, :]
                Sxd = D1[:, S.newaxis] * W2 * D[S.newaxis, :]
                Uyd = D1[:, S.newaxis] * W3 * D[S.newaxis, :]
                Uxd = D1[:, S.newaxis] * W4 * D[S.newaxis, :]

                Mp[:, :, nlayer] = S.r_[Sx0, Sy0, -1j * Ux0, -1j * Uy0]
                M[:, :, nlayer] = S.r_[Sxd, Syd, -1j * Uxd, -1j * Uyd]

            Mtot = S.eye(4 * nood, dtype=complex)
            for nlayer in range(1, nlayers - 1):
                Mtot = S.dot(S.dot(Mtot, Mp[:, :, nlayer]), inv(M[:, :,
                                                                  nlayer]))

            BC_b = S.r_[b, S.zeros_like(b)]
            BC_A1 = S.c_[-MR, S.dot(Mtot, MT)]
            BC_A2 = S.asarray(
                S.bmat([
                    [
                        (c1[0] * I - c1[2] * S.dot(CRO_1, ARO)),
                        (c1[1] * I - c1[2] * S.dot(CRO_1, BRO)),
                        ZERO,
                        ZERO,
                        ZERO,
                        ZERO,
                        ZERO,
                        ZERO,
                    ],
                    [
                        ZERO,
                        ZERO,
                        (DRE - S.dot(S.dot(FRE, CRE_1), ARE)),
                        (ERE - S.dot(S.dot(FRE, CRE_1), BRE)),
                        ZERO,
                        ZERO,
                        ZERO,
                        ZERO,
                    ],
                    [
                        ZERO,
                        ZERO,
                        ZERO,
                        ZERO,
                        (c3[0] * I - c3[2] * S.dot(CTO_1, ATO)),
                        (c3[1] * I - c3[2] * S.dot(CTO_1, BTO)),
                        ZERO,
                        ZERO,
                    ],
                    [
                        ZERO,
                        ZERO,
                        ZERO,
                        ZERO,
                        ZERO,
                        ZERO,
                        (DTE - S.dot(S.dot(FTE, CTE_1), ATE)),
                        (ETE - S.dot(S.dot(FTE, CTE_1), BTE)),
                    ],
                ]))

            BC_A = S.r_[BC_A1, BC_A2]

            x = linsolve(BC_A, BC_b)

            ROx, ROy, REx, REy, TOx, TOy, TEx, TEy = S.split(x, 8)

            ROz = -S.dot(CRO_1, (S.dot(ARO, ROx) + S.dot(BRO, ROy)))
            REz = -S.dot(CRE_1, (S.dot(ARE, REx) + S.dot(BRE, REy)))
            TOz = -S.dot(CTO_1, (S.dot(ATO, TOx) + S.dot(BTO, TOy)))
            TEz = -S.dot(CTE_1, (S.dot(ATE, TEx) + S.dot(BTE, TEy)))

            denom = (k1[2] - S.dot(u, k1) * u[2]).real
            DEO1[:, iwl] = (-(
                (S.absolute(ROx)**2 + S.absolute(ROy)**2 + S.absolute(ROz)**2)
                * S.conj(kO1i[2, :]) -
                (ROx * kO1i[0, :] + ROy * kO1i[1, :] + ROz * kO1i[2, :]) *
                S.conj(ROz)).real / denom)
            DEE1[:, iwl] = (-(
                (S.absolute(REx)**2 + S.absolute(REy)**2 + S.absolute(REz)**2)
                * S.conj(kE1i[2, :]) -
                (REx * kE1i[0, :] + REy * kE1i[1, :] + REz * kE1i[2, :]) *
                S.conj(REz)).real / denom)
            DEO3[:, iwl] = (
                (S.absolute(TOx)**2 + S.absolute(TOy)**2 + S.absolute(TOz)**2)
                * S.conj(kO3i[2, :]) -
                (TOx * kO3i[0, :] + TOy * kO3i[1, :] + TOz * kO3i[2, :]) *
                S.conj(TOz)).real / denom
            DEE3[:, iwl] = (
                (S.absolute(TEx)**2 + S.absolute(TEy)**2 + S.absolute(TEz)**2)
                * S.conj(kE3i[2, :]) -
                (TEx * kE3i[0, :] + TEy * kE3i[1, :] + TEz * kE3i[2, :]) *
                S.conj(TEz)).real / denom

        # save the results
        self.DEO1 = DEO1
        self.DEE1 = DEE1
        self.DEO3 = DEO3
        self.DEE3 = DEE3

        return self
示例#7
0
    def solve(self, wls):
        """Isotropic solver.

        INPUT
        wls = wavelengths to scan (any asarray-able object).

        OUTPUT
        self.DE1, self.DE3 = power reflected and transmitted.

        NOTE
        see:
        Moharam, "Formulation for stable and efficient implementation
        of the rigorous coupled-wave analysis of binary gratings",
        JOSA A, 12(5), 1995
        Lalanne, "Highly improved convergence of the coupled-wave
        method for TM polarization", JOSA A, 13(4), 1996
        Moharam, "Stable implementation of the rigorous coupled-wave
        analysis for surface-relief gratings: enhanced trasmittance
        matrix approach", JOSA A, 12(5), 1995
        """

        self.wls = S.atleast_1d(wls)

        LAMBDA = self.LAMBDA
        n = self.n
        multilayer = self.multilayer
        alpha = self.alpha
        delta = self.delta
        psi = self.psi
        phi = self.phi

        nlayers = len(multilayer)
        i = S.arange(-n, n + 1)
        nood = 2 * n + 1
        hmax = nood - 1

        # grating vector (on the xz plane)
        # grating on the xy plane
        K = 2 * pi / LAMBDA * np.array(
            [S.sin(phi), 0., S.cos(phi)], dtype=complex)

        DE1 = S.zeros((nood, self.wls.size))
        DE3 = S.zeros_like(DE1)

        dirk1 = np.array([
            S.sin(alpha) * S.cos(delta),
            S.sin(alpha) * S.sin(delta),
            S.cos(alpha)
        ])

        # usefull matrices
        I = S.eye(i.size)
        I2 = S.eye(i.size * 2)
        ZERO = S.zeros_like(I)

        X = S.zeros((2 * nood, 2 * nood, nlayers), dtype=complex)
        MTp1 = S.zeros((2 * nood, 2 * nood, nlayers), dtype=complex)
        MTp2 = S.zeros_like(MTp1)

        EPS2 = S.zeros(2 * hmax + 1, dtype=complex)
        EPS21 = S.zeros_like(EPS2)

        dlt = (i == 0).astype(int)

        for iwl, wl in enumerate(self.wls):

            # free space wavevector
            k = 2 * pi / wl

            n1 = multilayer[0].mat.n(wl).item()
            n3 = multilayer[-1].mat.n(wl).item()

            # incident plane wave wavevector
            k1 = k * n1 * dirk1

            # all the other wavevectors
            tmp_x = k1[0] - i * K[0]
            tmp_y = k1[1] * S.ones_like(i)
            tmp_z = dispersion_relation_ordinary(tmp_x, tmp_y, k, n1)
            k1i = S.r_[[tmp_x], [tmp_y], [tmp_z]]

            # k2i = S.r_[[k1[0] - i*K[0]], [k1[1] - i * K[1]], [-i * K[2]]]

            tmp_z = dispersion_relation_ordinary(tmp_x, tmp_y, k, n3)
            k3i = S.r_[[k1i[0, :]], [k1i[1, :]], [tmp_z]]

            # aliases for constant wavevectors
            kx = k1i[0, :]
            ky = k1[1]

            # angles of reflection
            # phi_i = S.arctan2(ky,kx)
            phi_i = S.arctan2(ky, kx.real)  # OKKIO

            Kx = S.diag(kx / k)
            Ky = ky / k * I
            Z1 = S.diag(k1i[2, :] / (k * n1**2))
            Y1 = S.diag(k1i[2, :] / k)
            Z3 = S.diag(k3i[2, :] / (k * n3**2))
            Y3 = S.diag(k3i[2, :] / k)
            # Fc = S.diag(S.cos(phi_i))
            fc = S.cos(phi_i)
            # Fs = S.diag(S.sin(phi_i))
            fs = S.sin(phi_i)

            MR = S.asarray(
                S.bmat([[I, ZERO], [-1j * Y1, ZERO], [ZERO, I],
                        [ZERO, -1j * Z1]]))

            MT = S.asarray(
                S.bmat([[I, ZERO], [1j * Y3, ZERO], [ZERO, I], [ZERO,
                                                                1j * Z3]]))

            # internal layers (grating or layer)
            X.fill(0.0)
            MTp1.fill(0.0)
            MTp2.fill(0.0)
            for nlayer in range(nlayers - 2, 0, -1):  # internal layers

                layer = multilayer[nlayer]
                d = layer.thickness

                EPS2, EPS21 = layer.getEPSFourierCoeffs(wl,
                                                        n,
                                                        anisotropic=False)

                E = toeplitz(EPS2[hmax::-1], EPS2[hmax:])
                E1 = toeplitz(EPS21[hmax::-1], EPS21[hmax:])
                E11 = inv(E1)
                # B = S.dot(Kx, linsolve(E,Kx)) - I
                B = kx[:, S.newaxis] / k * linsolve(E, Kx) - I
                # A = S.dot(Kx, Kx) - E
                A = S.diag((kx / k)**2) - E

                # Note: solution bug alfredo
                # randomizzo Kx un po' a caso finche' cond(A) e' piccolo (<1e10)
                # soluzione sporca... :-(
                # per certi kx, l'operatore di helmholtz ha 2 autovalori nulli e A, B
                # non sono invertibili --> cambio leggermente i kx... ma dovrei invece
                # trattare separatamente (analiticamente) questi casi
                if cond(A) > 1e10:
                    warning("BAD CONDITIONING: randomization of kx")
                    while cond(A) > 1e10:
                        Kx = Kx * (1 + 1e-9 * S.rand())
                        B = kx[:, S.newaxis] / k * linsolve(E, Kx) - I
                        A = S.diag((kx / k)**2) - E

                if S.absolute(K[2] / k) > 1e-10:

                    raise ValueError(
                        "First Order Helmholtz Operator not implemented, yet!")

                elif ky == 0 or S.allclose(S.diag(Ky / ky * k), 1):

                    # lalanne
                    # H_U_reduced = S.dot(Ky, Ky) + A
                    H_U_reduced = (ky / k)**2 * I + A
                    # H_S_reduced = S.dot(Ky, Ky) + S.dot(Kx, linsolve(E, S.dot(Kx, E11))) - E11
                    H_S_reduced = ((ky / k)**2 * I + kx[:, S.newaxis] / k *
                                   linsolve(E, kx[:, S.newaxis] / k * E11) -
                                   E11)

                    q1, W1 = eig(H_U_reduced)
                    q1 = S.sqrt(q1)
                    q2, W2 = eig(H_S_reduced)
                    q2 = S.sqrt(q2)

                    # boundary conditions

                    # V11 = S.dot(linsolve(A, W1), S.diag(q1))
                    V11 = linsolve(A, W1) * q1[S.newaxis, :]
                    V12 = (ky / k) * S.dot(linsolve(A, Kx), W2)
                    V21 = (ky / k) * S.dot(linsolve(B, Kx), linsolve(E, W1))
                    # V22 = S.dot(linsolve(B, W2), S.diag(q2))
                    V22 = linsolve(B, W2) * q2[S.newaxis, :]

                    # Vss = S.dot(Fc, V11)
                    Vss = fc[:, S.newaxis] * V11
                    # Wss = S.dot(Fc, W1)  + S.dot(Fs, V21)
                    Wss = fc[:, S.newaxis] * W1 + fs[:, S.newaxis] * V21
                    # Vsp = S.dot(Fc, V12) - S.dot(Fs, W2)
                    Vsp = fc[:, S.newaxis] * V12 - fs[:, S.newaxis] * W2
                    # Wsp = S.dot(Fs, V22)
                    Wsp = fs[:, S.newaxis] * V22
                    # Wpp = S.dot(Fc, V22)
                    Wpp = fc[:, S.newaxis] * V22
                    # Vpp = S.dot(Fc, W2)  + S.dot(Fs, V12)
                    Vpp = fc[:, S.newaxis] * W2 + fs[:, S.newaxis] * V12
                    # Wps = S.dot(Fc, V21) - S.dot(Fs, W1)
                    Wps = fc[:, S.newaxis] * V21 - fs[:, S.newaxis] * W1
                    # Vps = S.dot(Fs, V11)
                    Vps = fs[:, S.newaxis] * V11

                    Mc2bar = S.asarray(
                        S.bmat([
                            [Vss, Vsp, Vss, Vsp],
                            [Wss, Wsp, -Wss, -Wsp],
                            [Wps, Wpp, -Wps, -Wpp],
                            [Vps, Vpp, Vps, Vpp],
                        ]))

                    x = S.r_[S.exp(-k * q1 * d), S.exp(-k * q2 * d)]

                    # Mc1 = S.dot(Mc2bar, S.diag(S.r_[S.ones_like(x), x]))
                    xx = S.r_[S.ones_like(x), x]
                    Mc1 = Mc2bar * xx[S.newaxis, :]

                    X[:, :, nlayer] = S.diag(x)

                    MTp = linsolve(Mc2bar, MT)
                    MTp1[:, :, nlayer] = MTp[0:2 * nood, :]
                    MTp2 = MTp[2 * nood:, :]

                    MT = S.dot(
                        Mc1,
                        S.r_[I2,
                             S.
                             dot(MTp2,
                                 linsolve(MTp1[:, :, nlayer], X[:, :,
                                                                nlayer])), ],
                    )

                else:

                    ValueError(
                        "Second Order Helmholtz Operator not implemented, yet!"
                    )

            # M = S.asarray(S.bmat([-MR, MT]))
            M = S.c_[-MR, MT]
            b = S.r_[S.sin(psi) * dlt,
                     1j * S.sin(psi) * n1 * S.cos(alpha) * dlt,
                     -1j * S.cos(psi) * n1 * dlt,
                     S.cos(psi) * S.cos(alpha) * dlt, ]

            x = linsolve(M, b)
            R, T = S.split(x, 2)
            Rs, Rp = S.split(R, 2)
            for ii in range(1, nlayers - 1):
                T = S.dot(linsolve(MTp1[:, :, ii], X[:, :, ii]), T)
            Ts, Tp = S.split(T, 2)

            DE1[:, iwl] = (k1i[2, :] / (k1[2])).real * S.absolute(Rs)**2 + (
                k1i[2, :] / (k1[2] * n1**2)).real * S.absolute(Rp)**2
            DE3[:, iwl] = (k3i[2, :] / (k1[2])).real * S.absolute(Ts)**2 + (
                k3i[2, :] / (k1[2] * n3**2)).real * S.absolute(Tp)**2

        # save the results
        self.DE1 = DE1
        self.DE3 = DE3

        return self
示例#8
0
文件: RCWA.py 项目: DanHickstein/EMpy
    def solve(self, wls):
        """Anisotropic solver.

        INPUT
        wls = wavelengths to scan (any asarray-able object).

        OUTPUT
        self.DEO1, self.DEE1, self.DEO3, self.DEE3 = power reflected
        and transmitted.
        """

        self.wls = S.atleast_1d(wls)

        LAMBDA = self.LAMBDA
        n = self.n
        multilayer = self.multilayer
        alpha = self.alpha
        delta = self.delta
        psi = self.psi
        phi = self.phi

        nlayers = len(multilayer)
        i = S.arange(-n, n + 1)
        nood = 2 * n + 1
        hmax = nood - 1

        DEO1 = S.zeros((nood, self.wls.size))
        DEO3 = S.zeros_like(DEO1)
        DEE1 = S.zeros_like(DEO1)
        DEE3 = S.zeros_like(DEO1)

        c1 = S.array([1., 0., 0.])
        c3 = S.array([1., 0., 0.])
        # grating on the xy plane
        K = 2 * pi / LAMBDA * \
            S.array([S.sin(phi), 0., S.cos(phi)], dtype=complex)
        dirk1 = S.array([S.sin(alpha) * S.cos(delta),
                         S.sin(alpha) * S.sin(delta),
                         S.cos(alpha)])

        # D polarization vector
        u = S.array([S.cos(psi) * S.cos(alpha) * S.cos(delta) - S.sin(psi) * S.sin(delta),
                     S.cos(psi) * S.cos(alpha) * S.sin(delta) +
                     S.sin(psi) * S.cos(delta),
                     -S.cos(psi) * S.sin(alpha)])

        kO1i = S.zeros((3, i.size), dtype=complex)
        kE1i = S.zeros_like(kO1i)
        kO3i = S.zeros_like(kO1i)
        kE3i = S.zeros_like(kO1i)

        Mp = S.zeros((4 * nood, 4 * nood, nlayers), dtype=complex)
        M = S.zeros((4 * nood, 4 * nood, nlayers), dtype=complex)

        dlt = (i == 0).astype(int)

        for iwl, wl in enumerate(self.wls):

            nO1 = nE1 = multilayer[0].mat.n(wl).item()
            nO3 = nE3 = multilayer[-1].mat.n(wl).item()

            # wavevectors
            k = 2 * pi / wl

            eps1 = S.diag(S.asarray([nE1, nO1, nO1]) ** 2)
            eps3 = S.diag(S.asarray([nE3, nO3, nO3]) ** 2)

            # ordinary wave
            abskO1 = k * nO1
            # abskO3 = k * nO3
            # extraordinary wave
            # abskE1 = k * nO1 *nE1 / S.sqrt(nO1**2 + (nE1**2 - nO1**2) * S.dot(-c1, dirk1)**2)
            # abskE3 = k * nO3 *nE3 / S.sqrt(nO3**2 + (nE3**2 - nO3**2) * S.dot(-c3, dirk1)**2)

            k1 = abskO1 * dirk1

            kO1i[0, :] = k1[0] - i * K[0]
            kO1i[1, :] = k1[1] * S.ones_like(i)
            kO1i[2, :] = - \
                dispersion_relation_ordinary(kO1i[0, :], kO1i[1, :], k, nO1)

            kE1i[0, :] = kO1i[0, :]
            kE1i[1, :] = kO1i[1, :]
            kE1i[2,
                 :] = -dispersion_relation_extraordinary(kE1i[0,
                                                              :],
                                                         kE1i[1,
                                                              :],
                                                         k,
                                                         nO1,
                                                         nE1,
                                                         c1)

            kO3i[0, :] = kO1i[0, :]
            kO3i[1, :] = kO1i[1, :]
            kO3i[
                2, :] = dispersion_relation_ordinary(
                kO3i[
                    0, :], kO3i[
                    1, :], k, nO3)

            kE3i[0, :] = kO1i[0, :]
            kE3i[1, :] = kO1i[1, :]
            kE3i[
                2, :] = dispersion_relation_extraordinary(
                kE3i[
                    0, :], kE3i[
                    1, :], k, nO3, nE3, c3)

            # k2i = S.r_[[k1[0] - i * K[0]], [k1[1] - i * K[1]], [k1[2] - i * K[2]]]
            k2i = S.r_[[k1[0] - i * K[0]], [k1[1] - i * K[1]], [- i * K[2]]]

            # aliases for constant wavevectors
            kx = kO1i[0, :]  # o kE1i(1,;), tanto e' lo stesso
            ky = k1[1]

            # matrices
            I = S.eye(nood, dtype=complex)
            ZERO = S.zeros((nood, nood), dtype=complex)
            Kx = S.diag(kx / k)
            Ky = ky / k * I
            Kz = S.diag(k2i[2, :] / k)
            KO1z = S.diag(kO1i[2, :] / k)
            KE1z = S.diag(kE1i[2, :] / k)
            KO3z = S.diag(kO3i[2, :] / k)
            KE3z = S.diag(kE3i[2, :] / k)

            ARO = Kx * eps1[0, 0] + Ky * eps1[1, 0] + KO1z * eps1[2, 0]
            BRO = Kx * eps1[0, 1] + Ky * eps1[1, 1] + KO1z * eps1[2, 1]
            CRO_1 = inv(Kx * eps1[0, 2] + Ky * eps1[1, 2] + KO1z * eps1[2, 2])

            ARE = Kx * eps1[0, 0] + Ky * eps1[1, 0] + KE1z * eps1[2, 0]
            BRE = Kx * eps1[0, 1] + Ky * eps1[1, 1] + KE1z * eps1[2, 1]
            CRE_1 = inv(Kx * eps1[0, 2] + Ky * eps1[1, 2] + KE1z * eps1[2, 2])

            ATO = Kx * eps3[0, 0] + Ky * eps3[1, 0] + KO3z * eps3[2, 0]
            BTO = Kx * eps3[0, 1] + Ky * eps3[1, 1] + KO3z * eps3[2, 1]
            CTO_1 = inv(Kx * eps3[0, 2] + Ky * eps3[1, 2] + KO3z * eps3[2, 2])

            ATE = Kx * eps3[0, 0] + Ky * eps3[1, 0] + KE3z * eps3[2, 0]
            BTE = Kx * eps3[0, 1] + Ky * eps3[1, 1] + KE3z * eps3[2, 1]
            CTE_1 = inv(Kx * eps3[0, 2] + Ky * eps3[1, 2] + KE3z * eps3[2, 2])

            DRE = c1[1] * KE1z - c1[2] * Ky
            ERE = c1[2] * Kx - c1[0] * KE1z
            FRE = c1[0] * Ky - c1[1] * Kx

            DTE = c3[1] * KE3z - c3[2] * Ky
            ETE = c3[2] * Kx - c3[0] * KE3z
            FTE = c3[0] * Ky - c3[1] * Kx

            b = S.r_[u[0] * dlt, u[1] * dlt, (k1[1] / k * u[2] - k1[2] / k * u[1]) * dlt, (
                k1[2] / k * u[0] - k1[0] / k * u[2]) * dlt]
            Ky_CRO_1 = ky / k * CRO_1
            Ky_CRE_1 = ky / k * CRE_1
            Kx_CRO_1 = kx[:, S.newaxis] / k * CRO_1
            Kx_CRE_1 = kx[:, S.newaxis] / k * CRE_1
            MR31 = -S.dot(Ky_CRO_1, ARO)
            MR32 = -S.dot(Ky_CRO_1, BRO) - KO1z
            MR33 = -S.dot(Ky_CRE_1, ARE)
            MR34 = -S.dot(Ky_CRE_1, BRE) - KE1z
            MR41 = S.dot(Kx_CRO_1, ARO) + KO1z
            MR42 = S.dot(Kx_CRO_1, BRO)
            MR43 = S.dot(Kx_CRE_1, ARE) + KE1z
            MR44 = S.dot(Kx_CRE_1, BRE)
            MR = S.asarray(S.bmat([[I, ZERO, I, ZERO],
                                   [ZERO, I, ZERO, I],
                                   [MR31, MR32, MR33, MR34],
                                   [MR41, MR42, MR43, MR44]]))

            Ky_CTO_1 = ky / k * CTO_1
            Ky_CTE_1 = ky / k * CTE_1
            Kx_CTO_1 = kx[:, S.newaxis] / k * CTO_1
            Kx_CTE_1 = kx[:, S.newaxis] / k * CTE_1
            MT31 = -S.dot(Ky_CTO_1, ATO)
            MT32 = -S.dot(Ky_CTO_1, BTO) - KO3z
            MT33 = -S.dot(Ky_CTE_1, ATE)
            MT34 = -S.dot(Ky_CTE_1, BTE) - KE3z
            MT41 = S.dot(Kx_CTO_1, ATO) + KO3z
            MT42 = S.dot(Kx_CTO_1, BTO)
            MT43 = S.dot(Kx_CTE_1, ATE) + KE3z
            MT44 = S.dot(Kx_CTE_1, BTE)
            MT = S.asarray(S.bmat([[I, ZERO, I, ZERO],
                                   [ZERO, I, ZERO, I],
                                   [MT31, MT32, MT33, MT34],
                                   [MT41, MT42, MT43, MT44]]))

            Mp.fill(0.0)
            M.fill(0.0)

            for nlayer in range(nlayers - 2, 0, -1):  # internal layers

                layer = multilayer[nlayer]
                thickness = layer.thickness

                EPS2, EPS21 = layer.getEPSFourierCoeffs(
                    wl, n, anisotropic=True)

                # Exx = S.squeeze(EPS2[0, 0, :])
                # Exx = toeplitz(S.flipud(Exx[0:hmax + 1]), Exx[hmax:])
                Exy = S.squeeze(EPS2[0, 1, :])
                Exy = toeplitz(S.flipud(Exy[0:hmax + 1]), Exy[hmax:])
                Exz = S.squeeze(EPS2[0, 2, :])
                Exz = toeplitz(S.flipud(Exz[0:hmax + 1]), Exz[hmax:])

                Eyx = S.squeeze(EPS2[1, 0, :])
                Eyx = toeplitz(S.flipud(Eyx[0:hmax + 1]), Eyx[hmax:])
                Eyy = S.squeeze(EPS2[1, 1, :])
                Eyy = toeplitz(S.flipud(Eyy[0:hmax + 1]), Eyy[hmax:])
                Eyz = S.squeeze(EPS2[1, 2, :])
                Eyz = toeplitz(S.flipud(Eyz[0:hmax + 1]), Eyz[hmax:])

                Ezx = S.squeeze(EPS2[2, 0, :])
                Ezx = toeplitz(S.flipud(Ezx[0:hmax + 1]), Ezx[hmax:])
                Ezy = S.squeeze(EPS2[2, 1, :])
                Ezy = toeplitz(S.flipud(Ezy[0:hmax + 1]), Ezy[hmax:])
                Ezz = S.squeeze(EPS2[2, 2, :])
                Ezz = toeplitz(S.flipud(Ezz[0:hmax + 1]), Ezz[hmax:])

                Exx_1 = S.squeeze(EPS21[0, 0, :])
                Exx_1 = toeplitz(S.flipud(Exx_1[0:hmax + 1]), Exx_1[hmax:])
                Exx_1_1 = inv(Exx_1)

                # lalanne
                Ezz_1 = inv(Ezz)
                Ky_Ezz_1 = ky / k * Ezz_1
                Kx_Ezz_1 = kx[:, S.newaxis] / k * Ezz_1
                Exz_Ezz_1 = S.dot(Exz, Ezz_1)
                Eyz_Ezz_1 = S.dot(Eyz, Ezz_1)
                H11 = 1j * S.dot(Ky_Ezz_1, Ezy)
                H12 = 1j * S.dot(Ky_Ezz_1, Ezx)
                H13 = S.dot(Ky_Ezz_1, Kx)
                H14 = I - S.dot(Ky_Ezz_1, Ky)
                H21 = 1j * S.dot(Kx_Ezz_1, Ezy)
                H22 = 1j * S.dot(Kx_Ezz_1, Ezx)
                H23 = S.dot(Kx_Ezz_1, Kx) - I
                H24 = -S.dot(Kx_Ezz_1, Ky)
                H31 = S.dot(Kx, Ky) + Exy - S.dot(Exz_Ezz_1, Ezy)
                H32 = Exx_1_1 - S.dot(Ky, Ky) - S.dot(Exz_Ezz_1, Ezx)
                H33 = 1j * S.dot(Exz_Ezz_1, Kx)
                H34 = -1j * S.dot(Exz_Ezz_1, Ky)
                H41 = S.dot(Kx, Kx) - Eyy + S.dot(Eyz_Ezz_1, Ezy)
                H42 = -S.dot(Kx, Ky) - Eyx + S.dot(Eyz_Ezz_1, Ezx)
                H43 = -1j * S.dot(Eyz_Ezz_1, Kx)
                H44 = 1j * S.dot(Eyz_Ezz_1, Ky)
                H = 1j * S.diag(S.repeat(S.diag(Kz), 4)) + \
                    S.asarray(S.bmat([[H11, H12, H13, H14],
                                      [H21, H22, H23, H24],
                                      [H31, H32, H33, H34],
                                      [H41, H42, H43, H44]]))

                q, W = eig(H)
                W1, W2, W3, W4 = S.split(W, 4)

                #
                # boundary conditions
                #
                # x = [R T]
                # R = [ROx ROy REx REy]
                # T = [TOx TOy TEx TEy]
                # b + MR.R = M1p.c
                # M1.c = M2p.c
                # ...
                # ML.c = MT.T
                # therefore: b + MR.R = (M1p.M1^-1.M2p.M2^-1. ...).MT.T
                # missing equations from (46)..(49) in glytsis_rigorous
                # [b] = [-MR Mtot.MT] [R]
                # [0]   [...........] [T]

                z = S.zeros_like(q)
                z[S.where(q.real > 0)] = -thickness
                D = S.exp(k * q * z)
                Sy0 = W1 * D[S.newaxis, :]
                Sx0 = W2 * D[S.newaxis, :]
                Uy0 = W3 * D[S.newaxis, :]
                Ux0 = W4 * D[S.newaxis, :]

                z = thickness * S.ones_like(q)
                z[S.where(q.real > 0)] = 0
                D = S.exp(k * q * z)
                D1 = S.exp(-1j * k2i[2, :] * thickness)
                Syd = D1[:, S.newaxis] * W1 * D[S.newaxis, :]
                Sxd = D1[:, S.newaxis] * W2 * D[S.newaxis, :]
                Uyd = D1[:, S.newaxis] * W3 * D[S.newaxis, :]
                Uxd = D1[:, S.newaxis] * W4 * D[S.newaxis, :]

                Mp[:, :, nlayer] = S.r_[Sx0, Sy0, -1j * Ux0, -1j * Uy0]
                M[:, :, nlayer] = S.r_[Sxd, Syd, -1j * Uxd, -1j * Uyd]

            Mtot = S.eye(4 * nood, dtype=complex)
            for nlayer in range(1, nlayers - 1):
                Mtot = S.dot(
                    S.dot(Mtot, Mp[:, :, nlayer]), inv(M[:, :, nlayer]))

            BC_b = S.r_[b, S.zeros_like(b)]
            BC_A1 = S.c_[-MR, S.dot(Mtot, MT)]
            BC_A2 = S.asarray(S.bmat(
                [[(c1[0] * I - c1[2] * S.dot(CRO_1, ARO)), (c1[1] * I - c1[2] * S.dot(CRO_1, BRO)), ZERO, ZERO, ZERO,
                  ZERO, ZERO, ZERO],
                 [ZERO, ZERO, (DRE - S.dot(S.dot(FRE, CRE_1), ARE)), (ERE - S.dot(S.dot(FRE, CRE_1), BRE)), ZERO, ZERO,
                  ZERO, ZERO],
                 [ZERO, ZERO, ZERO, ZERO, (c3[0] * I - c3[2] * S.dot(CTO_1, ATO)),
                  (c3[1] * I - c3[2] * S.dot(CTO_1, BTO)), ZERO, ZERO],
                 [ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, (DTE - S.dot(S.dot(FTE, CTE_1), ATE)),
                  (ETE - S.dot(S.dot(FTE, CTE_1), BTE))]]))

            BC_A = S.r_[BC_A1, BC_A2]

            x = linsolve(BC_A, BC_b)

            ROx, ROy, REx, REy, TOx, TOy, TEx, TEy = S.split(x, 8)

            ROz = -S.dot(CRO_1, (S.dot(ARO, ROx) + S.dot(BRO, ROy)))
            REz = -S.dot(CRE_1, (S.dot(ARE, REx) + S.dot(BRE, REy)))
            TOz = -S.dot(CTO_1, (S.dot(ATO, TOx) + S.dot(BTO, TOy)))
            TEz = -S.dot(CTE_1, (S.dot(ATE, TEx) + S.dot(BTE, TEy)))

            denom = (k1[2] - S.dot(u, k1) * u[2]).real
            DEO1[:, iwl] = -((S.absolute(ROx) ** 2 + S.absolute(ROy) ** 2 + S.absolute(ROz) ** 2) * S.conj(kO1i[2, :]) -
                             (ROx * kO1i[0, :] + ROy * kO1i[1, :] + ROz * kO1i[2, :]) * S.conj(ROz)).real / denom
            DEE1[:, iwl] = -((S.absolute(REx) ** 2 + S.absolute(REy) ** 2 + S.absolute(REz) ** 2) * S.conj(kE1i[2, :]) -
                             (REx * kE1i[0, :] + REy * kE1i[1, :] + REz * kE1i[2, :]) * S.conj(REz)).real / denom
            DEO3[:, iwl] = ((S.absolute(TOx) ** 2 + S.absolute(TOy) ** 2 + S.absolute(TOz) ** 2) * S.conj(kO3i[2, :]) -
                            (TOx * kO3i[0, :] + TOy * kO3i[1, :] + TOz * kO3i[2, :]) * S.conj(TOz)).real / denom
            DEE3[:, iwl] = ((S.absolute(TEx) ** 2 + S.absolute(TEy) ** 2 + S.absolute(TEz) ** 2) * S.conj(kE3i[2, :]) -
                            (TEx * kE3i[0, :] + TEy * kE3i[1, :] + TEz * kE3i[2, :]) * S.conj(TEz)).real / denom

        # save the results
        self.DEO1 = DEO1
        self.DEE1 = DEE1
        self.DEO3 = DEO3
        self.DEE3 = DEE3

        return self
示例#9
0
文件: RCWA.py 项目: DanHickstein/EMpy
    def solve(self, wls):
        """Isotropic solver.

        INPUT
        wls = wavelengths to scan (any asarray-able object).

        OUTPUT
        self.DE1, self.DE3 = power reflected and transmitted.

        NOTE
        see:
        Moharam, "Formulation for stable and efficient implementation
        of the rigorous coupled-wave analysis of binary gratings",
        JOSA A, 12(5), 1995
        Lalanne, "Highly improved convergence of the coupled-wave
        method for TM polarization", JOSA A, 13(4), 1996
        Moharam, "Stable implementation of the rigorous coupled-wave
        analysis for surface-relief gratings: enhanced trasmittance
        matrix approach", JOSA A, 12(5), 1995
        """

        self.wls = S.atleast_1d(wls)

        LAMBDA = self.LAMBDA
        n = self.n
        multilayer = self.multilayer
        alpha = self.alpha
        delta = self.delta
        psi = self.psi
        phi = self.phi

        nlayers = len(multilayer)
        i = S.arange(-n, n + 1)
        nood = 2 * n + 1
        hmax = nood - 1

        # grating vector (on the xz plane)
        # grating on the xy plane
        K = 2 * pi / LAMBDA * \
            S.array([S.sin(phi), 0., S.cos(phi)], dtype=complex)

        DE1 = S.zeros((nood, self.wls.size))
        DE3 = S.zeros_like(DE1)

        dirk1 = S.array([S.sin(alpha) * S.cos(delta),
                         S.sin(alpha) * S.sin(delta),
                         S.cos(alpha)])

        # usefull matrices
        I = S.eye(i.size)
        I2 = S.eye(i.size * 2)
        ZERO = S.zeros_like(I)

        X = S.zeros((2 * nood, 2 * nood, nlayers), dtype=complex)
        MTp1 = S.zeros((2 * nood, 2 * nood, nlayers), dtype=complex)
        MTp2 = S.zeros_like(MTp1)

        EPS2 = S.zeros(2 * hmax + 1, dtype=complex)
        EPS21 = S.zeros_like(EPS2)

        dlt = (i == 0).astype(int)

        for iwl, wl in enumerate(self.wls):

            # free space wavevector
            k = 2 * pi / wl

            n1 = multilayer[0].mat.n(wl).item()
            n3 = multilayer[-1].mat.n(wl).item()

            # incident plane wave wavevector
            k1 = k * n1 * dirk1

            # all the other wavevectors
            tmp_x = k1[0] - i * K[0]
            tmp_y = k1[1] * S.ones_like(i)
            tmp_z = dispersion_relation_ordinary(tmp_x, tmp_y, k, n1)
            k1i = S.r_[[tmp_x], [tmp_y], [tmp_z]]

            # k2i = S.r_[[k1[0] - i*K[0]], [k1[1] - i * K[1]], [-i * K[2]]]

            tmp_z = dispersion_relation_ordinary(tmp_x, tmp_y, k, n3)
            k3i = S.r_[[k1i[0, :]], [k1i[1, :]], [tmp_z]]

            # aliases for constant wavevectors
            kx = k1i[0, :]
            ky = k1[1]

            # angles of reflection
            # phi_i = S.arctan2(ky,kx)
            phi_i = S.arctan2(ky, kx.real)  # OKKIO

            Kx = S.diag(kx / k)
            Ky = ky / k * I
            Z1 = S.diag(k1i[2, :] / (k * n1 ** 2))
            Y1 = S.diag(k1i[2, :] / k)
            Z3 = S.diag(k3i[2, :] / (k * n3 ** 2))
            Y3 = S.diag(k3i[2, :] / k)
            # Fc = S.diag(S.cos(phi_i))
            fc = S.cos(phi_i)
            # Fs = S.diag(S.sin(phi_i))
            fs = S.sin(phi_i)

            MR = S.asarray(S.bmat([[I, ZERO],
                                   [-1j * Y1, ZERO],
                                   [ZERO, I],
                                   [ZERO, -1j * Z1]]))

            MT = S.asarray(S.bmat([[I, ZERO],
                                   [1j * Y3, ZERO],
                                   [ZERO, I],
                                   [ZERO, 1j * Z3]]))

            # internal layers (grating or layer)
            X.fill(0.0)
            MTp1.fill(0.0)
            MTp2.fill(0.0)
            for nlayer in range(nlayers - 2, 0, -1):  # internal layers

                layer = multilayer[nlayer]
                d = layer.thickness

                EPS2, EPS21 = layer.getEPSFourierCoeffs(
                    wl, n, anisotropic=False)

                E = toeplitz(EPS2[hmax::-1], EPS2[hmax:])
                E1 = toeplitz(EPS21[hmax::-1], EPS21[hmax:])
                E11 = inv(E1)
                # B = S.dot(Kx, linsolve(E,Kx)) - I
                B = kx[:, S.newaxis] / k * linsolve(E, Kx) - I
                # A = S.dot(Kx, Kx) - E
                A = S.diag((kx / k) ** 2) - E

                # Note: solution bug alfredo
                # randomizzo Kx un po' a caso finche' cond(A) e' piccolo (<1e10)
                # soluzione sporca... :-(
                # per certi kx, l'operatore di helmholtz ha 2 autovalori nulli e A, B
                # non sono invertibili --> cambio leggermente i kx... ma dovrei invece
                # trattare separatamente (analiticamente) questi casi
                if cond(A) > 1e10:
                    warning('BAD CONDITIONING: randomization of kx')
                    while cond(A) > 1e10:
                        Kx = Kx * (1 + 1e-9 * S.rand())
                        B = kx[:, S.newaxis] / k * linsolve(E, Kx) - I
                        A = S.diag((kx / k) ** 2) - E

                if S.absolute(K[2] / k) > 1e-10:

                    raise ValueError(
                        'First Order Helmholtz Operator not implemented, yet!')

                elif ky == 0 or S.allclose(S.diag(Ky / ky * k), 1):

                    # lalanne
                    # H_U_reduced = S.dot(Ky, Ky) + A
                    H_U_reduced = (ky / k) ** 2 * I + A
                    # H_S_reduced = S.dot(Ky, Ky) + S.dot(Kx, linsolve(E, S.dot(Kx, E11))) - E11
                    H_S_reduced = (ky / k) ** 2 * I + kx[:, S.newaxis] / k * linsolve(E,
                                                                                      kx[:, S.newaxis] / k * E11) - E11

                    q1, W1 = eig(H_U_reduced)
                    q1 = S.sqrt(q1)
                    q2, W2 = eig(H_S_reduced)
                    q2 = S.sqrt(q2)

                    # boundary conditions

                    # V11 = S.dot(linsolve(A, W1), S.diag(q1))
                    V11 = linsolve(A, W1) * q1[S.newaxis, :]
                    V12 = (ky / k) * S.dot(linsolve(A, Kx), W2)
                    V21 = (ky / k) * S.dot(linsolve(B, Kx), linsolve(E, W1))
                    # V22 = S.dot(linsolve(B, W2), S.diag(q2))
                    V22 = linsolve(B, W2) * q2[S.newaxis, :]

                    # Vss = S.dot(Fc, V11)
                    Vss = fc[:, S.newaxis] * V11
                    # Wss = S.dot(Fc, W1)  + S.dot(Fs, V21)
                    Wss = fc[:, S.newaxis] * W1 + fs[:, S.newaxis] * V21
                    # Vsp = S.dot(Fc, V12) - S.dot(Fs, W2)
                    Vsp = fc[:, S.newaxis] * V12 - fs[:, S.newaxis] * W2
                    # Wsp = S.dot(Fs, V22)
                    Wsp = fs[:, S.newaxis] * V22
                    # Wpp = S.dot(Fc, V22)
                    Wpp = fc[:, S.newaxis] * V22
                    # Vpp = S.dot(Fc, W2)  + S.dot(Fs, V12)
                    Vpp = fc[:, S.newaxis] * W2 + fs[:, S.newaxis] * V12
                    # Wps = S.dot(Fc, V21) - S.dot(Fs, W1)
                    Wps = fc[:, S.newaxis] * V21 - fs[:, S.newaxis] * W1
                    # Vps = S.dot(Fs, V11)
                    Vps = fs[:, S.newaxis] * V11

                    Mc2bar = S.asarray(S.bmat([[Vss, Vsp, Vss, Vsp],
                                               [Wss, Wsp, -Wss, -Wsp],
                                               [Wps, Wpp, -Wps, -Wpp],
                                               [Vps, Vpp, Vps, Vpp]]))

                    x = S.r_[S.exp(-k * q1 * d), S.exp(-k * q2 * d)]

                    # Mc1 = S.dot(Mc2bar, S.diag(S.r_[S.ones_like(x), x]))
                    xx = S.r_[S.ones_like(x), x]
                    Mc1 = Mc2bar * xx[S.newaxis, :]

                    X[:, :, nlayer] = S.diag(x)

                    MTp = linsolve(Mc2bar, MT)
                    MTp1[:, :, nlayer] = MTp[0:2 * nood, :]
                    MTp2 = MTp[2 * nood:, :]

                    MT = S.dot(
                        Mc1, S.r_[
                            I2, S.dot(
                                MTp2, linsolve(
                                    MTp1[
                                        :, :, nlayer], X[
                                        :, :, nlayer]))])

                else:

                    ValueError(
                        'Second Order Helmholtz Operator not implemented, yet!')

            # M = S.asarray(S.bmat([-MR, MT]))
            M = S.c_[-MR, MT]
            b = S.r_[S.sin(psi) * dlt,
                     1j * S.sin(psi) * n1 * S.cos(alpha) * dlt,
                     -1j * S.cos(psi) * n1 * dlt,
                     S.cos(psi) * S.cos(alpha) * dlt]

            x = linsolve(M, b)
            R, T = S.split(x, 2)
            Rs, Rp = S.split(R, 2)
            for ii in range(1, nlayers - 1):
                T = S.dot(linsolve(MTp1[:, :, ii], X[:, :, ii]), T)
            Ts, Tp = S.split(T, 2)

            DE1[:, iwl] = (k1i[2, :] / (k1[2])).real * S.absolute(Rs) ** 2 + \
                          (k1i[2, :] / (k1[2] * n1 ** 2)).real * \
                S.absolute(Rp) ** 2
            DE3[:, iwl] = (k3i[2, :] / (k1[2])).real * S.absolute(Ts) ** 2 + \
                          (k3i[2, :] / (k1[2] * n3 ** 2)).real * \
                S.absolute(Tp) ** 2

        # save the results
        self.DE1 = DE1
        self.DE3 = DE3

        return self
示例#10
0
    def _LMLgrad_covar(self,covar,**kw_args):
        """
        calculates LMLgrad for covariance parameters
        """
        start = TIME.time()

        # precompute some stuff
        if covar=='Cr':     n_params = self.Cr.getNumberParams()
        elif covar=='Cg':   n_params = self.Cg.getNumberParams()
        elif covar=='Cn':   n_params = self.Cn.getNumberParams()

        if covar=='Cr':
            trR = self.cache['trXrXr']
            RY = self.cache['XrXrY'] 
            RLY = self.cache['XrXrLY'] 
            WrRY1 = self.cache['XrXrXrY'] 
            WrRY2 = self.cache['XXrXrY'] 
            WrRLY1 = self.cache['XrXrXrLY'] 
            WrRLY2 = self.cache['XXrXrLY'] 
            XrRXr = self.cache['XrXrXrXr']
            XrRX = self.cache['XrXrXrX']
            XRX = self.cache['XXrXrX']
        elif covar=='Cg':
            trR = self.cache['trXX']
            RY = self.cache['XXY'] 
            RLY = self.cache['XXLY'] 
            WrRY1 = self.cache['XrXXY'] 
            WrRY2 = self.cache['XXXY'] 
            WrRLY1 = self.cache['XrXXLY'] 
            WrRLY2 = self.cache['XXXLY'] 
            XrRXr = self.cache['XrXXXr']
            XrRX = self.cache['XrXXX']
            XRX = self.cache['XXXX']
        else:
            trR = self.N
            RY = self.Y
            RLY = self.cache['LY'] 
            WrRY1 = self.cache['XrY']
            WrRY2 = self.cache['XY']
            WrRLY1 = self.cache['XrLY']
            WrRLY2 = self.cache['XLY']
            XrRXr = self.cache['XrXr']
            XrRX = self.cache['XXr'].T
            XRX = self.cache['XX']

        smartSum(self.time,'lmlgrad_trace2_rKDW_%s'%covar,TIME.time()-start)
        smartSum(self.count,'lmlgrad_trace2_rKDW_%s'%covar,1)

        # fill gradient vector
        RV = SP.zeros(n_params)
        for i in range(n_params):
            #0. calc LCL

            if covar=='Cr':     C = self.Cr.Kgrad_param(i)
            elif covar=='Cg':   C = self.Cg.Kgrad_param(i)
            elif covar=='Cn':   C = self.Cn.Kgrad_param(i)

            LCL = SP.dot(self.cache['Lc'],SP.dot(C,self.cache['Lc'].T))

            ELCL = SP.dot(self.cache['Estar'].T,LCL)
            ELCLE = SP.dot(ELCL,self.cache['Estar'])
            ELCLCsh = SP.dot(ELCL,self.cache['CstarH'])
            CshLCL = SP.dot(self.cache['CstarH'].T,LCL) 
            CshLCLCsh = SP.dot(CshLCL,self.cache['CstarH'])

            # WCoRW
            WCoRW11 = SP.kron(ELCLE,XrRXr)
            WCoRW12 = SP.kron(ELCLCsh,XrRX)
            WCoRW22 = SP.kron(CshLCLCsh,XRX)
            WCoRW = SP.array(SP.bmat([[WCoRW11,WCoRW12],[WCoRW12.T,WCoRW22]]))
            # WCoRLY
            WCoRLY1 = SP.dot(WrRLY1,ELCL.T) 
            WCoRLY2 = SP.dot(WrRLY2,CshLCL.T)
            WCoRLY = SP.concatenate([SP.reshape(WCoRLY1,(WCoRLY1.size,1),order='F'),
                                     SP.reshape(WCoRLY2,(WCoRLY2.size,1),order='F')]) 
            # CoRLY
            CoRLY = SP.dot(RLY,LCL.T)

            #1. der of log det
            start = TIME.time()
            trC = LCL.diagonal().sum()
            RV[i] = trC*trR
            RV[i]-= SP.sum(self.cache['Bi']*WCoRW)
            smartSum(self.time,'lmlgrad_trace2_WDKDW_%s'%covar,TIME.time()-start)
            smartSum(self.count,'lmlgrad_trace2_WDKDW_%s'%covar,1)

            #2. der of quad form
            start = TIME.time()
            RV[i] -= SP.sum(self.cache['LY']*CoRLY)
            RV[i] -= SP.sum(self.cache['BiWLY']*SP.dot(WCoRW,self.cache['BiWLY'])) 
            RV[i] += 2*SP.sum(self.cache['BiWLY']*WCoRLY) 
            
            smartSum(self.time,'lmlgrad_quadForm_%s'%covar,TIME.time()-start)
            smartSum(self.count,'lmlgrad_quadForm_%s'%covar,1)

            RV[i] *= 0.5

        return RV
示例#11
0
    def _update_cache(self):
        """
        Update cache
        """
        cov_params_have_changed = self.Cr.params_have_changed or self.Cg.params_have_changed or self.Cn.params_have_changed

        if self.X_has_changed:
            self.cache['trXX'] = SP.sum(self.X**2)
            self.cache['XX'] = SP.dot(self.X.T,self.X)
            self.cache['XY'] = SP.dot(self.X.T,self.Y)
            self.cache['XXY'] = SP.dot(self.X,self.cache['XY'])
            self.cache['XXXY'] = SP.dot(self.cache['XX'],self.cache['XY'])
            self.cache['XXXX'] = SP.dot(self.cache['XX'],self.cache['XX'])

        if self.Xr_has_changed:
            self.cache['trXrXr'] = SP.sum(self.Xr**2)
            self.cache['XrXr'] = SP.dot(self.Xr.T,self.Xr)
            self.cache['XrY'] = SP.dot(self.Xr.T,self.Y)
            self.cache['XrXrY'] = SP.dot(self.Xr,self.cache['XrY'])
            self.cache['XrXrXrY'] = SP.dot(self.cache['XrXr'],self.cache['XrY'])
            self.cache['XrXrXrXr'] = SP.dot(self.cache['XrXr'],self.cache['XrXr'])

        if self.X_has_changed or self.Xr_has_changed:
            self.cache['XXr'] = SP.dot(self.X.T,self.Xr)
            self.cache['XXrXrY'] = SP.dot(self.cache['XXr'],self.cache['XrY'])
            self.cache['XXrXrX'] = SP.dot(self.cache['XXr'],self.cache['XXr'].T)
            self.cache['XrXXY'] = SP.dot(self.cache['XXr'].T,self.cache['XY'])
            self.cache['XrXXXr'] = SP.dot(self.cache['XXr'].T,self.cache['XXr'])
            self.cache['XrXrXrX'] = SP.dot(self.cache['XrXr'],self.cache['XXr'].T)
            self.cache['XrXXX'] = SP.dot(self.cache['XXr'].T,self.cache['XX'])
        
        if cov_params_have_changed:
            start = TIME.time()
            """ Col SVD Bg + Noise """
            S2,U2 = LA.eigh(self.Cn.K()+self.offset*SP.eye(self.P))
            self.cache['Sc2'] = S2
            US2   = SP.dot(U2,SP.diag(SP.sqrt(S2)))
            USi2  = SP.dot(U2,SP.diag(SP.sqrt(1./S2)))
            self.cache['Lc'] = USi2.T
            self.cache['Cstar'] = SP.dot(USi2.T,SP.dot(self.Cg.K(),USi2))
            self.cache['Scstar'],Ucstar = LA.eigh(self.cache['Cstar'])
            self.cache['CstarH'] = Ucstar*((self.cache['Scstar']**(0.5))[SP.newaxis,:])
            E = SP.reshape(self.Cr.getParams(),(self.P,self.rank),order='F')
            self.cache['Estar'] = SP.dot(USi2.T,E)
            self.cache['CE'] = SP.dot(self.cache['CstarH'].T,self.cache['Estar'])
            self.cache['EE'] = SP.dot(self.cache['Estar'].T,self.cache['Estar'])

        if cov_params_have_changed or self.Y_has_changed:
            self.cache['LY'] = SP.dot(self.Y,self.cache['Lc'].T)
            
        if cov_params_have_changed or self.Xr_has_changed or self.Y_has_changed:
            self.cache['XrLY'] = SP.dot(self.cache['XrY'],self.cache['Lc'].T)
            self.cache['WLY1'] = SP.dot(self.cache['XrLY'],self.cache['Estar'])
            self.cache['XrXrLY'] = SP.dot(self.cache['XrXrY'],self.cache['Lc'].T)
            self.cache['XrXrXrLY'] = SP.dot(self.cache['XrXrXrY'],self.cache['Lc'].T)

        if cov_params_have_changed or self.X_has_changed or self.Y_has_changed:
            self.cache['XLY'] = SP.dot(self.cache['XY'],self.cache['Lc'].T)
            self.cache['WLY2'] = SP.dot(self.cache['XLY'],self.cache['CstarH'])
            self.cache['XXLY'] = SP.dot(self.cache['XXY'],self.cache['Lc'].T)
            self.cache['XXXLY'] = SP.dot(self.cache['XXXY'],self.cache['Lc'].T)

        if cov_params_have_changed or self.X_has_changed or self.Xr_has_changed:
            """ calculate B """
            B11 = SP.kron(self.cache['EE'],self.cache['XrXr'])
            B11+= SP.eye(B11.shape[0])
            B21 = SP.kron(self.cache['CE'],self.cache['XXr'])
            B22 = SP.kron(SP.diag(self.cache['Scstar']),self.cache['XX'])
            B22+= SP.eye(B22.shape[0])
            B = SP.bmat([[B11,B21.T],[B21,B22]])
            self.cache['cholB'] = LA.cholesky(B).T 
            self.cache['Bi']    = LA.cho_solve((self.cache['cholB'],True),SP.eye(B.shape[0]))

        if cov_params_have_changed or self.X_has_changed or self.Xr_has_changed or self.Y_has_changed:
            self.cache['WLY'] = SP.concatenate([SP.reshape(self.cache['WLY1'],(self.cache['WLY1'].size,1),order='F'),
                                                SP.reshape(self.cache['WLY2'],(self.cache['WLY2'].size,1),order='F')])
            self.cache['BiWLY'] = SP.dot(self.cache['Bi'],self.cache['WLY'])
            self.cache['XXrXrLY'] = SP.dot(self.cache['XXrXrY'],self.cache['Lc'].T)
            self.cache['XrXXLY'] = SP.dot(self.cache['XrXXY'],self.cache['Lc'].T)

        self.Xr_has_changed = False
        self.X_has_changed = False
        self.Y_has_changed  = False
        self.Cr.params_have_changed = False
        self.Cg.params_have_changed = False
        self.Cn.params_have_changed = False
示例#12
0
def interp_decomp(A, k=None, mode='column', index_set=False):
    """
    Interpolative decomposition (ID).
    
    Algorithm for computing the low-rank ID 
    decomposition of a rectangular `(m, n)` matrix `A`, with target rank `k << min{m, n}`. 
    Input matrix is factored as `A = C * V`, using the column pivoted QR decomposition.
    The factor matrix `C` is formed of a subset of columns of `A`, 
    also called the partial column skeleton. The factor matrix `V` contains 
    a `(k, k)` identity matrix as a submatrix, and is well-conditioned. 

    If `mode='row'`, then the input matrix is factored as `A = Z * R`, using the 
    row pivoted QR decomposition. The factor matrix `R` is now formed as
    a subset of rows of `A`, also called the partial row skeleton.      
    
    Parameters
    ----------
    A : array_like, shape `(m, n)`.
        Input matrix.
    
    k : integer, `k << min{m,n}`.
        Target rank.

    mode: str `{'column', 'row'}`, default: `mode='column'`.
        'column' : ID using column pivoted QR.
        'row' : ID using row pivoted QR.

    index_set: str `{'True', 'False'}`, default: `index_set='False'`.
        'True' : Return column/row index set instead of `C` or `R`.     
        
    Returns
    -------
    If `mode='column'`:
        C:  array_like, shape `(m, k)`.
            Partial column skeleton.
        
        V : array_like, shape `(k, n)`.
            Well-conditioned matrix. 

    If `mode='row'`:
        Z:  array_like, shape `(m, k)`.
            Well-conditioned matrix.
        
        R : array_like, shape `(k, n)`.
            Partial row skeleton.


    Notes
    -----   


    References
    ----------    
    S. Voronin and P.Martinsson. 
    "RSVDPACK: Subroutines for computing partial singular value 
    decompositions via randomized sampling on single core, multi core, 
    and GPU architectures" (2015).
    (available at `arXiv <http://arxiv.org/abs/1502.05366>`_).


    Examples
    --------


    
    """

    # Shape of input matrix
    m, n = A.shape
    dat_type = A.dtype

    if dat_type == sci.float32:
        isreal = True
        real_type = sci.float32
        fT = rT
    elif dat_type == sci.float64:
        isreal = True
        real_type = sci.float64
        fT = rT
    elif dat_type == sci.complex64:
        isreal = False
        real_type = sci.float32
        fT = cT
    elif dat_type == sci.complex128:
        isreal = False
        real_type = sci.float64
        fT = cT
    else:
        raise ValueError("A.dtype is not supported")

    if k is None:
        raise ValueError("Target rank k is required.")

    if k < 0:
        raise ValueError("Target rank k not valid.")

    if k > min(m, n):
        k = min(m, n)

    if mode == 'row':
        A = rT(A)
        m, n = A.shape

    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    #Pivoted QR decomposition
    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Q, R, P = sci.linalg.qr(A,
                            mode='economic',
                            overwrite_a=False,
                            pivoting=True)

    # Select column subset
    C = A[:, P[0:k]]

    # Compute V
    T = sci.linalg.pinv2(R[0:k, 0:k]).dot(R[0:k, k:n])
    V = sci.bmat([[np.eye(k), T]])
    V = V[:, sci.argsort(P)]

    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # Return ID
    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    if mode == 'column':
        if index_set == False:
            return (C, V)
        else:
            return (P[0:k], V)

    if mode == 'row':
        if index_set == False:
            return (rT(V), rT(C))
        else:
            return (rT(V), P[0:k])