Example #1
0
def make_current_exact_bandstructure(path, P, sys):

    Nk1 = P.Nk1
    n = P.n 

    kx_in_path = path[:, 0]
    ky_in_path = path[:, 1]

    mel_x = evaluate_njit_matrix(sys.melxjit, kx=kx_in_path, ky=ky_in_path, dtype=P.type_complex_np)
    mel_y = evaluate_njit_matrix(sys.melyjit, kx=kx_in_path, ky=ky_in_path, dtype=P.type_complex_np)

    mel_in_path = P.E_dir[0]*mel_x + P.E_dir[1]*mel_y
    mel_ortho = P.E_ort[0]*mel_x + P.E_ort[1]*mel_y

    @conditional_njit(P.type_complex_np)
    def current_exact_path(solution, _E_field=0, _A_field=0):
    
        J_exact_E_dir = 0
        J_exact_ortho = 0

        for i_k in range(Nk1):
            for i in range(n):
                J_exact_E_dir += - ( mel_in_path[i_k, i, i].real * solution[i_k, i, i].real )
                J_exact_ortho += - ( mel_ortho[i_k, i, i].real * solution[i_k, i, i].real )
                for j in range(n):
                    if i != j:
                        J_exact_E_dir += - np.real( mel_in_path[i_k, i, j] * solution[i_k, j, i] )
                        J_exact_ortho += - np.real( mel_ortho[i_k, i, j] * solution[i_k, j, i] )
                        
        return J_exact_E_dir, J_exact_ortho
    return current_exact_path
Example #2
0
    def diagonalize_path(self, path, P):

        kx_in_path = path[:, 0]
        ky_in_path = path[:, 1]
        pathlen = path[:, 0].size
        e_path = np.empty([pathlen, P.n], dtype=P.type_real_np)
        wf_path = np.empty([pathlen, P.n, P.n], dtype=P.type_complex_np)
        h_in_path = evaluate_njit_matrix(self.hfjit, kx_in_path, ky_in_path)

        for i in range(pathlen):
            e_path[i], wf_buff = lin.eigh(h_in_path[i, :, :])
            if self.degenerate_eigenvalues:
                for j in range(int(P.n / 2)):
                    wf1 = np.copy(wf_buff[:, 2 * j])
                    wf2 = np.copy(wf_buff[:, 2 * j + 1])
                    wf_buff[:, 2 * j] *= wf2[P.n - 2]
                    wf_buff[:, 2 * j] -= wf1[P.n - 2] * wf2
                    wf_buff[:, 2 * j + 1] *= wf1[P.n - 1]
                    wf_buff[:, 2 * j + 1] -= wf2[P.n - 1] * wf1
            wf_gauged_entry = np.copy(wf_buff[P.gidx, :])
            wf_buff[P.gidx, :] = np.abs(wf_gauged_entry)
            wf_buff[~(
                np.arange(np.size(wf_buff, axis=0)) == P.gidx)] *= np.exp(
                    1j * np.angle(wf_gauged_entry.conj()))
            wf_path[i] = wf_buff

        return e_path, wf_path
Example #3
0
    def evaluate_dipole(self, kx, ky, **fkwargs):
        """
        Transforms the symbolic expression for the
        berry connection/dipole moment matrix to an expression
        that is numerically evaluated.

        Parameters
        ----------
        kx, ky : np.ndarray
            array of all point combinations
        fkwargs :
            keyword arguments passed to the symbolic expression
        """
        # Evaluate all kpoints without BZ
        self.Ax_eval = evaluate_njit_matrix(self.Axfjit, kx, ky, **fkwargs)
        self.Ay_eval = evaluate_njit_matrix(self.Ayfjit, kx, ky, **fkwargs)
        return self.Ax_eval, self.Ay_eval
Example #4
0
    def eigensystem_dipole_path(self, path, P):

        # Set eigenfunction first time eigensystem_dipole_path is called
        if self.e is None:
            self.make_eigensystem_dipole(P)

        # Retrieve the set of k-points for the current path
        kx_in_path = path[:, 0]
        ky_in_path = path[:, 1]
        pathlen = path[:, 0].size
        self.e_in_path = np.zeros([pathlen, P.n], dtype=P.type_real_np)

        if P.do_semicl:
            self.dipole_path_x = np.zeros([pathlen, P.n, P.n],
                                          dtype=P.type_complex_np)
            self.dipole_path_y = np.zeros([pathlen, P.n, P.n],
                                          dtype=P.type_complex_np)
        else:
            # Calculate the dipole components along the path
            self.dipole_path_x = evaluate_njit_matrix(self.Axfjit,
                                                      kx=kx_in_path,
                                                      ky=ky_in_path,
                                                      dtype=P.type_complex_np)
            self.dipole_path_y = evaluate_njit_matrix(self.Ayfjit,
                                                      kx=kx_in_path,
                                                      ky=ky_in_path,
                                                      dtype=P.type_complex_np)

        for n, e in enumerate(self.efjit):
            self.e_in_path[:, n] = e(kx=kx_in_path, ky=ky_in_path)

        self.wf_in_path = evaluate_njit_matrix(self.Ujit,
                                               kx=kx_in_path,
                                               ky=ky_in_path,
                                               dtype=P.type_complex_np)

        self.dipole_in_path = P.E_dir[0] * self.dipole_path_x + P.E_dir[
            1] * self.dipole_path_y
        self.dipole_ortho = P.E_ort[0] * self.dipole_path_x + P.E_ort[
            1] * self.dipole_path_y
    def eigensystem_dipole_path(self, path, P):

        # Retrieve the set of k-points for the current path
        kx_in_path = path[:, 0]
        ky_in_path = path[:, 1]
        pathlen = path[:, 0].size
        self.e_in_path = np.zeros([pathlen, P.n], dtype=P.type_real_np)

        self.dipole_path_x = evaluate_njit_matrix(self.dipole_xfjit,
                                                  kx=kx_in_path,
                                                  ky=ky_in_path,
                                                  dtype=P.type_complex_np)
        self.dipole_path_y = evaluate_njit_matrix(self.dipole_yfjit,
                                                  kx=kx_in_path,
                                                  ky=ky_in_path,
                                                  dtype=P.type_complex_np)

        for n, e in enumerate(self.efjit):
            self.e_in_path[:, n] = e(kx=kx_in_path, ky=ky_in_path)

        self.dipole_in_path = P.E_dir[0] * self.dipole_path_x + P.E_dir[
            1] * self.dipole_path_y
        self.dipole_ortho = P.E_ort[0] * self.dipole_path_x + P.E_ort[
            1] * self.dipole_path_y
Example #6
0
def diagonalize_path(path, P, S):

    n = P.n
    gidx = P.gidx
    Nk1 = P.Nk1
    Nk2 = P.Nk2
    epsilon = P.epsilon
    hamiltonian = S.hnp

    e_path = np.empty([Nk1, n], dtype=P.type_real_np)
    wf_path = np.empty([Nk1, n, n], dtype=P.type_complex_np)
    kx_in_path = path[:, 0]
    ky_in_path = path[:, 1]
    h_in_path = evaluate_njit_matrix(hamiltonian, kx_in_path, ky_in_path)
    for i in range(Nk1):
        e_path[i], wf_buff = lin.eigh(h_in_path[i, :, :])
        wf_gauged_entry = np.copy(wf_buff[gidx, :])
        wf_buff[gidx, :] = np.abs(wf_gauged_entry)
        wf_buff[~(np.arange(np.size(wf_buff, axis=0)) == gidx)] *= np.exp(
            1j * np.angle(wf_gauged_entry.conj()))
        wf_path[i] = wf_buff

    return e_path, wf_path
Example #7
0
def make_current_exact_path_hderiv(path, P, sys):

    """
        Function that calculates the exact current via eq. (79)
    """

    E_dir = P.E_dir
    E_ort = P.E_ort

    Nk1 = P.Nk1
    n = P.n
    n_sheets = P.n_sheets
    type_complex_np = P.type_complex_np
    type_real_np = P.type_real_np
    sheet_current= P.sheet_current
    wf_in_path = sys.wf_in_path

    kx = path[:, 0]
    ky = path[:, 1]

    dhdkx = evaluate_njit_matrix(sys.hderivfjit[0], kx=kx, ky=ky, dtype=type_complex_np)
    dhdky = evaluate_njit_matrix(sys.hderivfjit[1], kx=kx, ky=ky, dtype=type_complex_np)

    matrix_element_x = np.empty([Nk1, n, n], dtype=type_complex_np)
    matrix_element_y = np.empty([Nk1, n, n], dtype=type_complex_np)

    for i_k in range(Nk1):
        buff = dhdkx[i_k, :, :] @ wf_in_path[i_k, :, :]
        matrix_element_x[i_k, :, :] = np.conjugate(wf_in_path[i_k, :, :].T) @ buff

        buff = dhdky[i_k, :, :] @ wf_in_path[i_k,:,:]
        matrix_element_y[i_k, :, :] = np.conjugate(wf_in_path[i_k, :, :].T) @ buff

    mel_in_path = matrix_element_x * E_dir[0] + matrix_element_y * E_dir[1]
    mel_ortho = matrix_element_x * E_ort[0] + matrix_element_y * E_ort[1]


    @conditional_njit(type_complex_np)
    def current_exact_path_hderiv(solution, _E_field=0, _A_field=0):

        if sheet_current:
            
            J_exact_E_dir = np.zeros((n_sheets, n_sheets), dtype=type_real_np)
            J_exact_ortho = np.zeros((n_sheets, n_sheets), dtype=type_real_np)

            n_s = int(n/n_sheets)
            for i_k in range(Nk1):
                sol = np.zeros((n,n), dtype=type_complex_np)
                for a in range(n):
                    for b in range(n):
                        for c in range(n):
                            for d in range(n):
                                sol[a, d] += np.conjugate(wf_in_path[i_k, b, a]) * wf_in_path[i_k, b, c] * solution[i_k, c, d]
                # sol =  np.dot( wf_in_path[i_k, :, :], np.dot(solution[i_k, :, :], np.conjugate(wf_in_path[i_k, :, :].T) ) )

                for s_i in range(n_sheets):
                    for s_j in range(n_sheets):
                        for i in range(n_s):
                            for j in range(n_s):
                                    J_exact_E_dir[s_i, s_j] += - np.real( mel_in_path[i_k, n_s*s_i + i, n_s*s_j + j] * sol[n_s*s_i + i, n_s*s_j + j] )
                                    J_exact_ortho[s_i, s_j] += - np.real( mel_ortho[i_k, n_s*s_i + i, n_s*s_j + j] * sol[n_s*s_i + i, n_s*s_j + j] )
        
        else:
            J_exact_E_dir = 0
            J_exact_ortho = 0

            for i_k in range(Nk1):
                for i in range(n):
                    J_exact_E_dir += - ( mel_in_path[i_k, i, i].real * solution[i_k, i, i].real )
                    J_exact_ortho += - ( mel_ortho[i_k, i, i].real * solution[i_k, i, i].real )
                    for j in range(n):
                        if i != j:
                            J_exact_E_dir += - np.real( mel_in_path[i_k, i, j] * solution[i_k, j, i] )
                            J_exact_ortho += - np.real( mel_ortho[i_k, i, j] * solution[i_k, j, i] )

        return J_exact_E_dir, J_exact_ortho
    return current_exact_path_hderiv
Example #8
0
def make_emission_exact_path_length(path, P, sys):
    """
    Construct a function that calculates the emission for the system solution per path.
    Works for length gauge.

    Parameters
    ----------
    sys : TwoBandSystem
        Hamiltonian and related functions
    path : np.ndarray [type_real_np]
        kx and ky components of path
    E_dir : np.ndarray [type_real_np]
        Direction of the electric field
    do_semicl : bool
        if semiclassical calculation should be done
    curvature : SymbolicCurvature
        Curvature is only needed for semiclassical calculation

    Returns:
    --------
    emission_kernel : function
        Calculates per timestep current of a path
    """
    E_dir = P.E_dir
    E_ort = P.E_ort

    kx_in_path = path[:, 0]
    ky_in_path = path[:, 1]
    pathlen = kx_in_path.size

    ##########################################################
    # Berry curvature container
    ##########################################################
    if P.do_semicl:
        Bcurv = np.empty((pathlen, 2), dtype=P.type_complex_np)

    h_deriv_x = evaluate_njit_matrix(sys.hderivfjit[0], kx=kx_in_path, ky=ky_in_path,
                                     dtype=P.type_complex_np)
    h_deriv_y = evaluate_njit_matrix(sys.hderivfjit[1], kx=kx_in_path, ky=ky_in_path,
                                     dtype=P.type_complex_np)

    h_deriv_E_dir= h_deriv_x*E_dir[0] + h_deriv_y*E_dir[1]
    h_deriv_ortho = h_deriv_x*E_ort[0] + h_deriv_y*E_ort[1]

    U = evaluate_njit_matrix(sys.Ujit, kx=kx_in_path, ky=ky_in_path, dtype=P.type_complex_np)
    U_h = evaluate_njit_matrix(sys.Ujit_h, kx=kx_in_path, ky=ky_in_path, dtype=P.type_complex_np)

    if P.do_semicl:
        Bcurv[:, 0] = sys.Bfjit[0][0](kx=kx_in_path, ky=ky_in_path)
        Bcurv[:, 1] = sys.Bfjit[1][1](kx=kx_in_path, ky=ky_in_path)

    symmetric_insulator = P.symmetric_insulator
    do_semicl = P.do_semicl
    @conditional_njit(P.type_complex_np)
    def emission_exact_path_length(solution, E_field, _A_field=1):
        '''
        Parameters:
        -----------
        solution : np.ndarray [type_complex_np]
            Per timestep solution, idx 0 is k; idx 1 is fv, pvc, pcv, fc
        E_field : type_real_np
            Per timestep E_field
        _A_field : dummy
            In the length gauge this is just a dummy variable

        Returns:
        --------
        I_E_dir : type_real_np
            Parallel to electric field component of current
        I_ortho : type_real_np
            Orthogonal to electric field component of current
        '''
        solution = solution.reshape(pathlen, 4)

        I_E_dir = 0
        I_ortho = 0

        rho_vv = solution[:, 0]
        rho_vc = solution[:, 1]
        rho_cv = solution[:, 2]
        rho_cc = solution[:, 3]

        if symmetric_insulator:
            rho_vv = -rho_cc

        for i_k in range(pathlen):

            dH_U_E_dir = h_deriv_E_dir[i_k] @ U[i_k]
            U_h_H_U_E_dir = U_h[i_k] @ dH_U_E_dir

            dH_U_ortho = h_deriv_ortho[i_k] @ U[i_k]
            U_h_H_U_ortho = U_h[i_k] @ dH_U_ortho

            I_E_dir += - U_h_H_U_E_dir[0, 0].real * rho_vv[i_k].real
            I_E_dir += - U_h_H_U_E_dir[1, 1].real * rho_cc[i_k].real
            I_E_dir += - 2*np.real(U_h_H_U_E_dir[0, 1] * rho_cv[i_k])

            I_ortho += - U_h_H_U_ortho[0, 0].real * rho_vv[i_k].real
            I_ortho += - U_h_H_U_ortho[1, 1].real * rho_cc[i_k].real
            I_ortho += - 2*np.real(U_h_H_U_ortho[0, 1] * rho_cv[i_k])

            if do_semicl:
                # '-' because there is q^2 compared to q only at the SBE current
                I_ortho += -E_field * Bcurv[i_k, 0].real * rho_vv[i_k].real
                I_ortho += -E_field * Bcurv[i_k, 1].real * rho_vc[i_k].real

        return I_E_dir, I_ortho

    return emission_exact_path_length
Example #9
0
    def evaluate(self, kx, ky, **fkwargs):
        # Evaluate all kpoints without BZ

        self.B_eval = evaluate_njit_matrix(self.Bfjit, kx, ky, **fkwargs)

        return self.B_eval