Exemplo n.º 1
0
 def __init__(self,
              calc=None,
              atoms=None,
              gpw_fname=None,
              pickle_fname=None):
     if not _has_gpaw:
         raise ImportError("GPAW was not imported. Please install gpaw.")
     if pickle_fname is None:
         if gpw_fname is not None:
             calc = GPAW(gpw_fname,
                         fixdensity=True,
                         symmetry='off',
                         txt='TB2J_wrapper.log',
                         basis='dzp',
                         mode='lcao')
             atoms = calc.atoms
             atoms.calc = calc
             E = atoms.get_potential_energy()
         tb = TightBinding(atoms, calc)
         self.H_NMM, self.S_NMM = tb.h_and_s()
         self.Rlist = tb.R_cN.T
     else:
         with open(fname, 'rb') as myfile:
             self.H_NMM, self.S_NMM, self.Rlist = pickle.load(myfile)
     self.nR, self.nbasis, _ = self.H_NMM.shape
     self.positions = np.zeros((self.nbasis, 3))
Exemplo n.º 2
0
def test_Ham():
    calc=GPAW('/home/hexu/projects/gpaw/bccFe/atoms_nscf.gpw', fixdensity=True, symmetry='off',  txt='nscf.txt')
    atoms=calc.atoms
    atoms.calc=calc
    calc.set(kpts=(3,3,3))
    E = atoms.get_potential_energy()
    tb=TightBinding(atoms, calc)
    kpath=monkhorst_pack([3,3,3])
    evals, evecs=tb.band_structure(kpath, blochstates=True)
Exemplo n.º 3
0
    def calculate_supercell_matrix(self,
                                   dump=0,
                                   name=None,
                                   filter=None,
                                   include_pseudo=True,
                                   atoms=None):
        """Calculate matrix elements of the el-ph coupling in the LCAO basis.

        This function calculates the matrix elements between LCAOs and local
        atomic gradients of the effective potential. The matrix elements are
        calculated for the supercell used to obtain finite-difference
        approximations to the derivatives of the effective potential wrt to
        atomic displacements.

        Parameters
        ----------
        dump: int
            Dump supercell matrix to pickle file (default: 0).

            0: Supercell matrix not saved

            1: Supercell matrix saved in a single pickle file.

            2: Dump matrix for different gradients in separate files. Useful
               for large systems where the total array gets too large for a
               single pickle file.

        name: string
            User specified name of the generated pickle file(s). If not
            provided, the string in the ``name`` attribute is used.
        filter: str
            Fourier filter atomic gradients of the effective potential. The
            specified components (``normal`` or ``umklapp``) are removed
            (default: None).
        include_pseudo: bool
            Include the contribution from the psedupotential in the atomic
            gradients. If ``False``, only the gradient of the effective
            potential is included (default: True).
        atoms: Atoms object
            Calculate supercell for an ``Atoms`` object different from the one
            provided in the ``__init__`` method (WARNING, NOT working!).
            
        """

        assert self.calc_lcao is not None, "Set LCAO calculator"

        # Supercell atoms
        if atoms is None:
            atoms_N = self.atoms * self.N_c
        else:
            atoms_N = atoms

        # Initialize calculator if required and extract useful quantities
        calc = self.calc_lcao
        if not hasattr(calc.wfs, 'S_qMM'):
            calc.initialize(atoms_N)
            calc.initialize_positions(atoms_N)
        self.set_basis_info()
        basis = calc.input_parameters['basis']

        # Extract useful objects from the calculator
        wfs = calc.wfs
        gd = calc.wfs.gd
        kd = calc.wfs.kd
        kpt_u = wfs.kpt_u
        setups = wfs.setups
        nao = setups.nao
        bfs = wfs.basis_functions
        dtype = wfs.dtype
        spin = 0  # XXX

        # If gamma calculation, overlap with neighboring cell cannot be removed
        if kd.gamma:
            print("WARNING: Gamma-point calculation.")
        else:
            # Bloch to real-space converter
            tb = TightBinding(atoms_N, calc)

        self.timer.write_now("Calculating supercell matrix")

        self.timer.write_now("Calculating real-space gradients")
        # Calculate finite-difference gradients (in Hartree / Bohr)
        V1t_xG, dH1_xasp = self.calculate_gradient()
        self.timer.write_now("Finished real-space gradients")

        # Fourier filter the atomic gradients of the effective potential
        if filter is not None:
            self.timer.write_now("Fourier filtering gradients")
            V1_xG = V1t_xG.copy()
            self.fourier_filter(V1t_xG, components=filter)
            self.timer.write_now("Finished Fourier filtering")

        # For the contribution from the derivative of the projectors
        dP_aqvMi = self.calculate_dP_aqvMi(wfs)
        # Equilibrium atomic Hamiltonian matrix (projector coefficients)
        dH_asp = pickle.load(open(self.name + '.eq.pckl'))[1]

        # Check that the grid is the same as in the calculator
        assert np.all(V1t_xG.shape[-3:] == (gd.N_c + gd.pbc_c - 1)), \
               "Mismatch in grids."

        # Calculate < i k | grad H | j k >, i.e. matrix elements in Bloch basis
        # List for supercell matrices;
        g_xNNMM = []
        self.timer.write_now("Calculating gradient of PAW Hamiltonian")

        # Do each cartesian component separately
        for i, a in enumerate(self.indices):
            for v in range(3):

                # Corresponding array index
                x = 3 * i + v
                V1t_G = V1t_xG[x]
                self.timer.write_now("%s-gradient of atom %u" %
                                     (['x', 'y', 'z'][v], a))

                # Array for different k-point components
                g_qMM = np.zeros((len(kpt_u), nao, nao), dtype)

                # 1) Gradient of effective potential
                self.timer.write_now(
                    "Starting gradient of effective potential")
                for kpt in kpt_u:
                    # Matrix elements
                    geff_MM = np.zeros((nao, nao), dtype)
                    bfs.calculate_potential_matrix(V1t_G, geff_MM, q=kpt.q)
                    tri2full(geff_MM, 'L')
                    # Insert in array
                    g_qMM[kpt.q] += geff_MM

                self.timer.write_now(
                    "Finished gradient of effective potential")

                if include_pseudo:
                    self.timer.write_now("Starting gradient of pseudo part")

                    # 2) Gradient of non-local part (projectors)
                    self.timer.write_now("Starting gradient of dH^a")
                    P_aqMi = calc.wfs.P_aqMi
                    # 2a) dH^a part has contributions from all other atoms
                    for kpt in kpt_u:
                        # Matrix elements
                        gp_MM = np.zeros((nao, nao), dtype)
                        dH1_asp = dH1_xasp[x]
                        for a_, dH1_sp in dH1_asp.items():
                            dH1_ii = unpack2(dH1_sp[spin])
                            gp_MM += np.dot(
                                P_aqMi[a_][kpt.q],
                                np.dot(dH1_ii,
                                       P_aqMi[a_][kpt.q].T.conjugate()))
                        g_qMM[kpt.q] += gp_MM
                    self.timer.write_now("Finished gradient of dH^a")

                    self.timer.write_now("Starting gradient of projectors")
                    # 2b) dP^a part has only contributions from the same atoms
                    dP_qvMi = dP_aqvMi[a]
                    dH_ii = unpack2(dH_asp[a][spin])
                    for kpt in kpt_u:
                        #XXX Sort out the sign here; conclusion -> sign = +1 !
                        P1HP_MM = +1 * np.dot(
                            dP_qvMi[kpt.q][v],
                            np.dot(dH_ii, P_aqMi[a][kpt.q].T.conjugate()))
                        # Matrix elements
                        gp_MM = P1HP_MM + P1HP_MM.T.conjugate()
                        g_qMM[kpt.q] += gp_MM
                    self.timer.write_now("Finished gradient of projectors")
                    self.timer.write_now("Finished gradient of pseudo part")

                # Extract R_c=(0, 0, 0) block by Fourier transforming
                if kd.gamma or kd.N_c is None:
                    g_MM = g_qMM[0]
                else:
                    # Convert to array
                    g_MM = tb.bloch_to_real_space(g_qMM, R_c=(0, 0, 0))[0]

                # Reshape to global unit cell indices
                N = np.prod(self.N_c)
                # Number of basis function in the primitive cell
                assert (nao % N) == 0, "Alarm ...!"
                nao_cell = nao / N
                g_NMNM = g_MM.reshape((N, nao_cell, N, nao_cell))
                g_NNMM = g_NMNM.swapaxes(1, 2).copy()
                self.timer.write_now("Finished supercell matrix")

                if dump != 2:
                    g_xNNMM.append(g_NNMM)
                else:
                    if name is not None:
                        fname = '%s.supercell_matrix_x_%2.2u.%s.pckl' % (
                            name, x, basis)
                    else:
                        fname = self.name + \
                                '.supercell_matrix_x_%2.2u.%s.pckl' % (x, basis)
                    if kd.comm.rank == 0:
                        fd = open(fname, 'w')
                        M_a = self.basis_info['M_a']
                        nao_a = self.basis_info['nao_a']
                        pickle.dump((g_NNMM, M_a, nao_a), fd, 2)
                        fd.close()

        self.timer.write_now("Finished gradient of PAW Hamiltonian")

        if dump != 2:
            # Collect gradients in one array
            self.g_xNNMM = np.array(g_xNNMM)

            # Dump to pickle file using binary mode together with basis info
            if dump and kd.comm.rank == 0:
                if name is not None:
                    fname = '%s.supercell_matrix.%s.pckl' % (name, basis)
                else:
                    fname = self.name + '.supercell_matrix.%s.pckl' % basis
                fd = open(fname, 'w')
                M_a = self.basis_info['M_a']
                nao_a = self.basis_info['nao_a']
                pickle.dump((self.g_xNNMM, M_a, nao_a), fd, 2)
                fd.close()
Exemplo n.º 4
0
    def calculate_supercell_matrix(self, dump=0, name=None, filter=None,
                                   include_pseudo=True, atoms=None):
        """Calculate matrix elements of the el-ph coupling in the LCAO basis.

        This function calculates the matrix elements between LCAOs and local
        atomic gradients of the effective potential. The matrix elements are
        calculated for the supercell used to obtain finite-difference
        approximations to the derivatives of the effective potential wrt to
        atomic displacements.

        Parameters
        ----------
        dump: int
            Dump supercell matrix to pickle file (default: 0).

            0: Supercell matrix not saved

            1: Supercell matrix saved in a single pickle file.

            2: Dump matrix for different gradients in separate files. Useful
               for large systems where the total array gets too large for a
               single pickle file.

        name: string
            User specified name of the generated pickle file(s). If not
            provided, the string in the ``name`` attribute is used.
        filter: str
            Fourier filter atomic gradients of the effective potential. The
            specified components (``normal`` or ``umklapp``) are removed
            (default: None).
        include_pseudo: bool
            Include the contribution from the psedupotential in the atomic
            gradients. If ``False``, only the gradient of the effective
            potential is included (default: True).
        atoms: Atoms object
            Calculate supercell for an ``Atoms`` object different from the one
            provided in the ``__init__`` method (WARNING, NOT working!).
            
        """

        assert self.calc_lcao is not None, "Set LCAO calculator"
            
        # Supercell atoms
        if atoms is None:
            atoms_N = self.atoms * self.N_c
        else:
            atoms_N = atoms
        
        # Initialize calculator if required and extract useful quantities
        calc = self.calc_lcao
        if not hasattr(calc.wfs, 'S_qMM'):
            calc.initialize(atoms_N)
            calc.initialize_positions(atoms_N)
        self.set_basis_info()
        basis = calc.input_parameters['basis']
            
        # Extract useful objects from the calculator
        wfs = calc.wfs
        gd = calc.wfs.gd
        kd = calc.wfs.kd
        kpt_u = wfs.kpt_u
        setups = wfs.setups
        nao = setups.nao
        bfs = wfs.basis_functions
        dtype = wfs.dtype
        spin = 0 # XXX
        
        # If gamma calculation, overlap with neighboring cell cannot be removed
        if kd.gamma:
            print "WARNING: Gamma-point calculation."
        else:
            # Bloch to real-space converter
            tb = TightBinding(atoms_N, calc)

        self.timer.write_now("Calculating supercell matrix")

        self.timer.write_now("Calculating real-space gradients")        
        # Calculate finite-difference gradients (in Hartree / Bohr)
        V1t_xG, dH1_xasp = self.calculate_gradient()
        self.timer.write_now("Finished real-space gradients")

        # Fourier filter the atomic gradients of the effective potential
        if filter is not None:
            self.timer.write_now("Fourier filtering gradients")
            V1_xG = V1t_xG.copy()
            self.fourier_filter(V1t_xG, components=filter)
            self.timer.write_now("Finished Fourier filtering")

        # For the contribution from the derivative of the projectors
        dP_aqvMi = self.calculate_dP_aqvMi(wfs)
        # Equilibrium atomic Hamiltonian matrix (projector coefficients)
        dH_asp = pickle.load(open(self.name + '.eq.pckl'))[1]
        
        # Check that the grid is the same as in the calculator
        assert np.all(V1t_xG.shape[-3:] == (gd.N_c + gd.pbc_c - 1)), \
               "Mismatch in grids."

        # Calculate < i k | grad H | j k >, i.e. matrix elements in Bloch basis
        # List for supercell matrices;
        g_xNNMM = []
        self.timer.write_now("Calculating gradient of PAW Hamiltonian")

        # Do each cartesian component separately
        for i, a in enumerate(self.indices):
            for v in range(3):

                # Corresponding array index
                x = 3 * i + v
                V1t_G = V1t_xG[x]
                self.timer.write_now("%s-gradient of atom %u" % 
                                     (['x','y','z'][v], a))

                # Array for different k-point components
                g_qMM = np.zeros((len(kpt_u), nao, nao), dtype)
                
                # 1) Gradient of effective potential
                self.timer.write_now("Starting gradient of effective potential")
                for kpt in kpt_u:
                    # Matrix elements
                    geff_MM = np.zeros((nao, nao), dtype)
                    bfs.calculate_potential_matrix(V1t_G, geff_MM, q=kpt.q)
                    tri2full(geff_MM, 'L')
                    # Insert in array
                    g_qMM[kpt.q] += geff_MM
                
                self.timer.write_now("Finished gradient of effective potential")

                if include_pseudo:
                    self.timer.write_now("Starting gradient of pseudo part")
                
                    # 2) Gradient of non-local part (projectors)
                    self.timer.write_now("Starting gradient of dH^a")
                    P_aqMi = calc.wfs.P_aqMi
                    # 2a) dH^a part has contributions from all other atoms
                    for kpt in kpt_u:
                        # Matrix elements
                        gp_MM = np.zeros((nao, nao), dtype)
                        dH1_asp = dH1_xasp[x]
                        for a_, dH1_sp in dH1_asp.items():
                            dH1_ii = unpack2(dH1_sp[spin])
                            gp_MM += np.dot(P_aqMi[a_][kpt.q], np.dot(dH1_ii,
                                            P_aqMi[a_][kpt.q].T.conjugate()))
                        g_qMM[kpt.q] += gp_MM
                    self.timer.write_now("Finished gradient of dH^a")
                    
                    self.timer.write_now("Starting gradient of projectors")
                    # 2b) dP^a part has only contributions from the same atoms
                    dP_qvMi = dP_aqvMi[a]
                    dH_ii = unpack2(dH_asp[a][spin])
                    for kpt in kpt_u:
                        #XXX Sort out the sign here; conclusion -> sign = +1 !
                        P1HP_MM = +1 * np.dot(dP_qvMi[kpt.q][v], np.dot(dH_ii,
                                              P_aqMi[a][kpt.q].T.conjugate()))
                        # Matrix elements
                        gp_MM = P1HP_MM + P1HP_MM.T.conjugate()
                        g_qMM[kpt.q] += gp_MM
                    self.timer.write_now("Finished gradient of projectors")
                    self.timer.write_now("Finished gradient of pseudo part")
                
                # Extract R_c=(0, 0, 0) block by Fourier transforming
                if kd.gamma or kd.N_c is None:
                    g_MM = g_qMM[0]
                else:
                    # Convert to array
                    g_MM = tb.bloch_to_real_space(g_qMM, R_c=(0, 0, 0))[0]
                
                # Reshape to global unit cell indices
                N = np.prod(self.N_c)
                # Number of basis function in the primitive cell
                assert (nao % N) == 0, "Alarm ...!"
                nao_cell = nao / N
                g_NMNM = g_MM.reshape((N, nao_cell, N, nao_cell))
                g_NNMM = g_NMNM.swapaxes(1, 2).copy()
                self.timer.write_now("Finished supercell matrix")
                
                if dump != 2:
                    g_xNNMM.append(g_NNMM)
                else:
                    if name is not None:
                        fname = '%s.supercell_matrix_x_%2.2u.%s.pckl' % (name, x, basis)
                    else:
                        fname = self.name + \
                                '.supercell_matrix_x_%2.2u.%s.pckl' % (x, basis)
                    if kd.comm.rank == 0:
                        fd = open(fname, 'w')
                        M_a = self.basis_info['M_a']
                        nao_a = self.basis_info['niAO_a']
                        pickle.dump((g_NNMM, M_a, nao_a), fd, 2)
                        fd.close()
                    
        self.timer.write_now("Finished gradient of PAW Hamiltonian")
        
        if dump != 2:
            # Collect gradients in one array
            self.g_xNNMM = np.array(g_xNNMM)
            
            # Dump to pickle file using binary mode together with basis info
            if dump and kd.comm.rank == 0:
                if name is not None:
                    fname = '%s.supercell_matrix.%s.pckl' % (name, basis)
                else:
                    fname = self.name + '.supercell_matrix.%s.pckl' % basis
                fd = open(fname, 'w')
                M_a = self.basis_info['M_a']
                nao_a = self.basis_info['nao_a']                
                pickle.dump((self.g_xNNMM, M_a, nao_a), fd, 2)
                fd.close()