Beispiel #1
0
def get_transport_kpts(bzk_kc, dir='x'):

    from ase.dft.kpoints import get_monkhorst_pack_size_and_offset, \
        monkhorst_pack

    dir = 'xyz'.index(direction)
    transverse_dirs = np.delete([0, 1, 2], [dir])
    dtype = float
    if len(bzk_kc) > 1 or np.any(bzk_kc[0] != [0, 0, 0]):
        dtype = complex

    kpts_grid, kpts_shift = get_monkhorst_pack_size_and_offset(bzk_kc)

    # kpts in the transport direction
    nkpts_p = kpts_grid[dir]
    bzk_p_kc = monkhorst_pack((nkpts_p, 1, 1))[:, 0] + kpts_shift[dir]
    weight_p_k = 1. / nkpts_p

    # kpts in the transverse directions
    offset = np.zeros((3, ))
    offset[:len(transverse_dirs)] = kpts_shift[transverse_dirs]
    bzk_t_kc = monkhorst_pack(tuple(kpts_grid[transverse_dirs]) +
                              (1, )) + offset

    return (bzk_p_kc, weight_p_k), (bzk_t_kc, )
Beispiel #2
0
def atoms2bandstructure(atoms, parser, args):
    cell = atoms.get_cell()
    calc = atoms.calc
    bzkpts = calc.get_bz_k_points()
    ibzkpts = calc.get_ibz_k_points()
    efermi = calc.get_fermi_level()
    nibz = len(ibzkpts)
    nspins = 1 + int(calc.get_spin_polarized())

    eps = np.array([[calc.get_eigenvalues(kpt=k, spin=s)
                     for k in range(nibz)]
                    for s in range(nspins)])
    if not args.quiet:
        print('Spins, k-points, bands: {}, {}, {}'.format(*eps.shape))

    if bzkpts is None:
        if ibzkpts is None:
            raise ValueError('Cannot find any k-point data')
        else:
            path_kpts = ibzkpts
    else:
        try:
            size, offset = get_monkhorst_pack_size_and_offset(bzkpts)
        except ValueError:
            path_kpts = ibzkpts
        else:
            if not args.quiet:
                print('Interpolating from Monkhorst-Pack grid (size, offset):')
                print(size, offset)
            if args.path is None:
                err = 'Please specify a path!'
                try:
                    cs = crystal_structure_from_cell(cell)
                except ValueError:
                    err += ('\nASE cannot automatically '
                            'recognize this crystal structure')
                else:
                    from ase.dft.kpoints import special_paths
                    kptpath = special_paths[cs]
                    err += ('\nIt looks like you have a {} crystal structure.'
                            '\nMaybe you want its special path:'
                            ' {}'.format(cs, kptpath))
                parser.error(err)
            bz2ibz = calc.get_bz_to_ibz_map()

            path_kpts = bandpath(args.path, atoms.cell, args.points).kpts

            icell = atoms.get_reciprocal_cell()
            eps = monkhorst_pack_interpolate(path_kpts, eps.transpose(1, 0, 2),
                                             icell, bz2ibz, size, offset)
            eps = eps.transpose(1, 0, 2)

    special_points = get_special_points(cell)
    path = BandPath(atoms.cell, kpts=path_kpts,
                    special_points=special_points)

    return BandStructure(path, eps, reference=efermi)
Beispiel #3
0
def atoms2bandpath(atoms,
                   path='default',
                   k_points=False,
                   ibz_k_points=False,
                   dimension=3,
                   verbose=False):
    cell = atoms.get_cell()
    icell = atoms.get_reciprocal_cell()

    try:
        cs = crystal_structure_from_cell(cell)
    except ValueError:
        cs = None

    if verbose:
        if cs:
            print('Crystal:', cs)
            print('Special points:', special_paths[cs])
        print('Lattice vectors:')
        for i, v in enumerate(cell):
            print('{}: ({:16.9f},{:16.9f},{:16.9f})'.format(i + 1, *v))
        print('Reciprocal vectors:')
        for i, v in enumerate(icell):
            print('{}: ({:16.9f},{:16.9f},{:16.9f})'.format(i + 1, *v))

    # band path
    special_points = None
    if path:
        if path == 'default':
            path = special_paths[cs]
        paths = []
        special_points = get_special_points(cell)
        for names in parse_path_string(path):
            points = []
            for name in names:
                points.append(np.dot(icell.T, special_points[name]))
            paths.append((names, points))
    else:
        paths = None

    # k points
    points = None
    if atoms.calc is not None and hasattr(atoms.calc, 'get_bz_k_points'):
        bzk = atoms.calc.get_bz_k_points()
        if path is None:
            try:
                size, offset = get_monkhorst_pack_size_and_offset(bzk)
            except ValueError:
                # This was not a MP-grid.  Must be a path in the BZ:
                path = ''.join(labels_from_kpts(bzk, cell)[2])

        if k_points:
            points = bzk
        elif ibz_k_points:
            points = atoms.calc.get_ibz_k_points()

    return BandPath(cell, kpts=points, special_points=special_points)
Beispiel #4
0
    def __init__(self, calc, width=0.1, window=None, npts=401, comm=world):
        """Electronic Density Of States object.

        calc: calculator object
            Any ASE compliant calculator object.
        width: float
            Width of guassian smearing.  Use width=0.0 for linear tetrahedron
            interpolation.
        window: tuple of two float
            Use ``window=(emin, emax)``.  If not specified, a window
            big enough to hold all the eigenvalues will be used.
        npts: int
            Number of points.
        comm: communicator object
            MPI communicator for lti_dos

        """

        self.comm = comm
        self.npts = npts
        self.width = width
        self.w_k = calc.get_k_point_weights()
        self.nspins = calc.get_number_of_spins()
        self.e_skn = np.array([[
            calc.get_eigenvalues(kpt=k, spin=s) for k in range(len(self.w_k))
        ] for s in range(self.nspins)])
        try:  # two Fermi levels
            for i, eF in enumerate(calc.get_fermi_level()):
                self.e_skn[i] -= eF
        except TypeError:  # a single Fermi level
            self.e_skn -= calc.get_fermi_level()

        if window is None:
            emin = None
            emax = None
        else:
            emin, emax = window

        if emin is None:
            emin = self.e_skn.min() - 5 * self.width
        if emax is None:
            emax = self.e_skn.max() + 5 * self.width

        self.energies = np.linspace(emin, emax, npts)

        if width == 0.0:
            bzkpts = calc.get_bz_k_points()
            size, offset = get_monkhorst_pack_size_and_offset(bzkpts)
            bz2ibz = calc.get_bz_to_ibz_map()
            shape = (self.nspins, ) + tuple(size) + (-1, )
            self.e_skn = self.e_skn[:, bz2ibz].reshape(shape)
            self.cell = calc.atoms.cell
Beispiel #5
0
def get_realspace_hs(h_skmm, s_kmm, bzk_kc, weight_k):
    kpts_grid, kpts_shift = get_monkhorst_pack_size_and_offset(bzk_kc)
    R_rc = get_realspace_R(kpts_grid // 2)
    ibzk_kc = reduce_vecs(bzk_kc.tolist())

    h_srii = np.zeros_like(h_skmm)
    s_rii = np.zeros_like(s_kmm)
    for r, R_c in enumerate(R_rc):
        for k, ibzk_c in enumerate(ibzk_kc):
            c_k = np.exp(2.j * np.pi * np.dot(ibzk_c, R_c)) * weight_k[k]
            h_srii[:, r] += c_k * h_skmm[:, k]
            s_rii[r] += c_k * s_kmm[k]

    return h_srii, s_rii, R_rc
Beispiel #6
0
def main(args, parser):
    atoms = read(args.calculation)
    cell = atoms.get_cell()
    calc = atoms.calc
    bzkpts = calc.get_bz_k_points()
    ibzkpts = calc.get_ibz_k_points()
    efermi = calc.get_fermi_level()
    nibz = len(ibzkpts)
    nspins = 1 + int(calc.get_spin_polarized())
    eps = np.array([[calc.get_eigenvalues(kpt=k, spin=s)
                     for k in range(nibz)]
                    for s in range(nspins)])
    if not args.quiet:
        print('Spins, k-points, bands: {}, {}, {}'.format(*eps.shape))
    try:
        size, offset = get_monkhorst_pack_size_and_offset(bzkpts)
    except ValueError:
        path = ibzkpts
    else:
        if not args.quiet:
            print('Interpolating from Monkhorst-Pack grid (size, offset):')
            print(size, offset)
        if args.path is None:
            err = 'Please specify a path!'
            try:
                cs = crystal_structure_from_cell(cell)
            except ValueError:
                err += ('\nGPAW cannot autimatically '
                        'recognize this crystal structure')
            else:
                from ase.dft.kpoints import special_paths
                kptpath = special_paths[cs]
                err += ('\nIt looks like you have a {} crystal structure.'
                        '\nMaybe you want its special path:'
                        ' {}'.format(cs, kptpath))
            parser.error(err)
        bz2ibz = calc.get_bz_to_ibz_map()
        path = bandpath(args.path, atoms.cell, args.points)[0]
        icell = atoms.get_reciprocal_cell()
        eps = monkhorst_pack_interpolate(path, eps.transpose(1, 0, 2),
                                         icell, bz2ibz, size, offset)
        eps = eps.transpose(1, 0, 2)

    emin, emax = (float(e) for e in args.range)
    bs = BandStructure(atoms.cell, path, eps, reference=efermi)
    bs.plot(emin=emin, emax=emax)
Beispiel #7
0
def get_realspace_hs(h_skmm, s_kmm, bzk_kc, weight_k,
                     R_c=(0, 0, 0), direction='x', 
                     usesymm=None):

    from gpaw.symmetry import Symmetry
    from ase.dft.kpoints import get_monkhorst_pack_size_and_offset, \
        monkhorst_pack
    
    if usesymm is True:
        raise NotImplementedError, 'Only None and False have been implemented'

    nspins, nk, nbf = h_skmm.shape[:3]
    dir = 'xyz'.index(direction)
    transverse_dirs = np.delete([0, 1, 2], [dir])
    dtype = float
    if len(bzk_kc) > 1 or np.any(bzk_kc[0] != [0, 0, 0]):
        dtype = complex

    kpts_grid = get_monkhorst_pack_size_and_offset(bzk_kc)[0]

    # kpts in the transport direction
    nkpts_p = kpts_grid[dir]
    bzk_p_kc = monkhorst_pack((nkpts_p,1,1))[:, 0]
    weight_p_k = 1. / nkpts_p

   # kpts in the transverse directions
    bzk_t_kc = monkhorst_pack(tuple(kpts_grid[transverse_dirs]) + (1, ))
    if usesymm == False:
        #XXX a somewhat ugly hack:
        # By default GPAW reduces inversion sym in the z direction. The steps 
        # below assure reduction in the transverse dirs.
        # For now this part seems to do the job, but it may be written
        # in a smarter way in the future.
        symmetry = Symmetry([1], np.eye(3))
        symmetry.prune_symmetries(np.zeros((1, 3)))
        ibzk_kc, ibzweight_k = symmetry.reduce(bzk_kc)[:2]
        ibzk_t_kc, weights_t_k = symmetry.reduce(bzk_t_kc)[:2]
        ibzk_t_kc = ibzk_t_kc[:, :2]
        nkpts_t = len(ibzk_t_kc)
    else: # usesymm = None
        ibzk_kc = bzk_kc.copy()
        ibzk_t_kc = bzk_t_kc
        nkpts_t = len(bzk_t_kc)
        weights_t_k = [1. / nkpts_t for k in range(nkpts_t)]

    h_skii = np.zeros((nspins, nkpts_t, nbf, nbf), dtype)
    if s_kmm is not None:
        s_kii = np.zeros((nkpts_t, nbf, nbf), dtype)

    tol = 7
    for j, k_t in enumerate(ibzk_t_kc):
        for k_p in bzk_p_kc:
            k = np.zeros((3,))
            k[dir] = k_p
            k[transverse_dirs] = k_t
            kpoint_list = [list(np.round(k_kc, tol)) for k_kc in ibzk_kc]
            if list(np.round(k, tol)) not in kpoint_list:
                k = -k # inversion
                index = kpoint_list.index(list(np.round(k,tol)))
                h = h_skmm[:, index].conjugate()
                if s_kmm is not None:
                    s = s_kmm[index].conjugate()
                k=-k
            else: # kpoint in the ibz
                index = kpoint_list.index(list(np.round(k, tol)))
                h = h_skmm[:, index]
                if s_kmm is not None:
                    s = s_kmm[index]

            c_k = np.exp(2.j * np.pi * np.dot(k, R_c)) * weight_p_k
            h_skii[:, j] += c_k * h
            if s_kmm is not None:
                s_kii[j] += c_k * s 
    
    if s_kmm is None:
        return ibzk_t_kc, weights_t_k, h_skii
    else:
        return ibzk_t_kc, weights_t_k, h_skii, s_kii
Beispiel #8
0
    def __init__(
        self,
        nwannier,
        calc,
        file=None,
        nbands=None,
        fixedenergy=None,
        fixedstates=None,
        spin=0,
        initialwannier="random",
        seed=None,
        verbose=False,
    ):
        """
        Required arguments:

          ``nwannier``: The number of Wannier functions you wish to construct.
            This must be at least half the number of electrons in the system
            and at most equal to the number of bands in the calculation.

          ``calc``: A converged DFT calculator class.
            If ``file`` arg. is not provided, the calculator *must* provide the
            method ``get_wannier_localization_matrix``, and contain the
            wavefunctions (save files with only the density is not enough).
            If the localization matrix is read from file, this is not needed,
            unless ``get_function`` or ``write_cube`` is called.
          
        Optional arguments:

          ``nbands``: Bands to include in localization.
            The number of bands considered by Wannier can be smaller than the
            number of bands in the calculator. This is useful if the highest
            bands of the DFT calculation are not well converged.

          ``spin``: The spin channel to be considered.
            The Wannier code treats each spin channel independently.

          ``fixedenergy`` / ``fixedstates``: Fixed part of Heilbert space.
            Determine the fixed part of Hilbert space by either a maximal
            energy *or* a number of bands (possibly a list for multiple
            k-points).
            Default is None meaning that the number of fixed states is equated
            to ``nwannier``.

          ``file``: Read localization and rotation matrices from this file.

          ``initialwannier``: Initial guess for Wannier rotation matrix.
            Can be 'bloch' to start from the Bloch states, 'random' to be
            randomized, or a list passed to calc.get_initial_wannier.

          ``seed``: Seed for random ``initialwannier``.

          ``verbose``: True / False level of verbosity.
          """
        # Bloch phase sign convention
        sign = -1
        classname = calc.__class__.__name__
        if classname in ["Dacapo", "Jacapo"]:
            print "Using " + classname
            sign = +1

        self.nwannier = nwannier
        self.calc = calc
        self.spin = spin
        self.verbose = verbose
        self.kpt_kc = calc.get_bz_k_points()
        assert len(calc.get_ibz_k_points()) == len(self.kpt_kc)
        self.kptgrid = get_monkhorst_pack_size_and_offset(self.kpt_kc)[0]
        self.kpt_kc *= sign

        self.Nk = len(self.kpt_kc)
        self.unitcell_cc = calc.get_atoms().get_cell()
        self.largeunitcell_cc = (self.unitcell_cc.T * self.kptgrid).T
        self.weight_d, self.Gdir_dc = calculate_weights(self.largeunitcell_cc)
        self.Ndir = len(self.weight_d)  # Number of directions

        if nbands is not None:
            self.nbands = nbands
        else:
            self.nbands = calc.get_number_of_bands()
        if fixedenergy is None:
            if fixedstates is None:
                self.fixedstates_k = np.array([nwannier] * self.Nk, int)
            else:
                if type(fixedstates) is int:
                    fixedstates = [fixedstates] * self.Nk
                self.fixedstates_k = np.array(fixedstates, int)
        else:
            # Setting number of fixed states and EDF from specified energy.
            # All states below this energy (relative to Fermi level) are fixed.
            fixedenergy += calc.get_fermi_level()
            print fixedenergy
            self.fixedstates_k = np.array(
                [calc.get_eigenvalues(k, spin).searchsorted(fixedenergy) for k in range(self.Nk)], int
            )
        self.edf_k = self.nwannier - self.fixedstates_k
        if verbose:
            print "Wannier: Fixed states            : %s" % self.fixedstates_k
            print "Wannier: Extra degrees of freedom: %s" % self.edf_k

        # Set the list of neighboring k-points k1, and the "wrapping" k0,
        # such that k1 - k - G + k0 = 0
        #
        # Example: kpoints = (-0.375,-0.125,0.125,0.375), dir=0
        # G = [0.25,0,0]
        # k=0.375, k1= -0.375 : -0.375-0.375-0.25 => k0=[1,0,0]
        #
        # For a gamma point calculation k1 = k = 0,  k0 = [1,0,0] for dir=0
        if self.Nk == 1:
            self.kklst_dk = np.zeros((self.Ndir, 1), int)
            k0_dkc = self.Gdir_dc.reshape(-1, 1, 3)
        else:
            self.kklst_dk = np.empty((self.Ndir, self.Nk), int)
            k0_dkc = np.empty((self.Ndir, self.Nk, 3), int)

            # Distance between kpoints
            kdist_c = np.empty(3)
            for c in range(3):
                # make a sorted list of the kpoint values in this direction
                slist = np.argsort(self.kpt_kc[:, c], kind="mergesort")
                skpoints_kc = np.take(self.kpt_kc, slist, axis=0)
                kdist_c[c] = max([skpoints_kc[n + 1, c] - skpoints_kc[n, c] for n in range(self.Nk - 1)])

            for d, Gdir_c in enumerate(self.Gdir_dc):
                for k, k_c in enumerate(self.kpt_kc):
                    # setup dist vector to next kpoint
                    G_c = np.where(Gdir_c > 0, kdist_c, 0)
                    if max(G_c) < 1e-4:
                        self.kklst_dk[d, k] = k
                        k0_dkc[d, k] = Gdir_c
                    else:
                        self.kklst_dk[d, k], k0_dkc[d, k] = neighbor_k_search(k_c, G_c, self.kpt_kc)

        # Set the inverse list of neighboring k-points
        self.invkklst_dk = np.empty((self.Ndir, self.Nk), int)
        for d in range(self.Ndir):
            for k1 in range(self.Nk):
                self.invkklst_dk[d, k1] = self.kklst_dk[d].tolist().index(k1)

        Nw = self.nwannier
        Nb = self.nbands
        self.Z_dkww = np.empty((self.Ndir, self.Nk, Nw, Nw), complex)
        self.V_knw = np.zeros((self.Nk, Nb, Nw), complex)
        if file is None:
            self.Z_dknn = np.empty((self.Ndir, self.Nk, Nb, Nb), complex)
            for d, dirG in enumerate(self.Gdir_dc):
                for k in range(self.Nk):
                    k1 = self.kklst_dk[d, k]
                    k0_c = k0_dkc[d, k]
                    self.Z_dknn[d, k] = calc.get_wannier_localization_matrix(
                        nbands=Nb, dirG=dirG, kpoint=k, nextkpoint=k1, G_I=k0_c, spin=self.spin
                    )
        self.initialize(file=file, initialwannier=initialwannier, seed=seed)
    def __init__(self, kpts, nspins=1, collinear=True):
        """Construct descriptor object for kpoint/spin combinations (ks-pair).

        Parameters
        ----------
        kpts: None, sequence of 3 ints, or (n,3)-shaped array
            Specification of the k-point grid. None=Gamma, list of
            ints=Monkhorst-Pack, ndarray=user specified.
        nspins: int
            Number of spins.

        Attributes
        ===================  =================================================
        ``N_c``               Number of k-points in the different directions.
        ``nspins``            Number of spins in total.
        ``mynspins``          Number of spins on this CPU.
        ``nibzkpts``          Number of irreducible kpoints in 1st BZ.
        ``nks``               Number of k-point/spin combinations in total.
        ``mynks``             Number of k-point/spin combinations on this CPU.
        ``gamma``             Boolean indicator for gamma point calculation.
        ``comm``              MPI-communicator for kpoint distribution.
        ``weight_k``          Weights of each k-point
        ``ibzk_kc``           Unknown
        ``ibzk_qc``           Unknown
        ``sym_k``             Unknown
        ``time_reversal_k``   Unknown
        ``bz2ibz_k``          Unknown
        ``ibz2bz_k``          Unknown
        ``bz2bz_ks``          Unknown
        ``symmetry``          Object representing symmetries
        ===================  =================================================
        """

        if kpts is None:
            self.bzk_kc = np.zeros((1, 3))
            self.N_c = np.array((1, 1, 1), dtype=int)
            self.offset_c = np.zeros(3)
        elif isinstance(kpts[0], int):
            self.bzk_kc = monkhorst_pack(kpts)
            self.N_c = np.array(kpts, dtype=int)
            self.offset_c = np.zeros(3)
        else:
            self.bzk_kc = np.array(kpts, float)
            try:
                self.N_c, self.offset_c = \
                    get_monkhorst_pack_size_and_offset(self.bzk_kc)
            except ValueError:
                self.N_c = None
                self.offset_c = None

        self.collinear = collinear
        self.nspins = nspins
        self.nbzkpts = len(self.bzk_kc)

        # Gamma-point calculation?
        self.gamma = self.nbzkpts == 1 and np.allclose(self.bzk_kc, 0)

        # Point group and time-reversal symmetry neglected:
        self.weight_k = np.ones(self.nbzkpts) / self.nbzkpts
        self.ibzk_kc = self.bzk_kc.copy()
        self.sym_k = np.zeros(self.nbzkpts, int)
        self.time_reversal_k = np.zeros(self.nbzkpts, bool)
        self.bz2ibz_k = np.arange(self.nbzkpts)
        self.ibz2bz_k = np.arange(self.nbzkpts)
        self.bz2bz_ks = np.arange(self.nbzkpts)[:, np.newaxis]
        self.nibzkpts = self.nbzkpts
        self.nks = self.nibzkpts * self.nspins

        self.set_communicator(mpi.serial_comm)

        if self.gamma:
            self.description = '1 k-point (Gamma)'
        else:
            self.description = '%d k-points' % self.nbzkpts
            if self.N_c is not None:
                self.description += (': %d x %d x %d Monkhorst-Pack grid' %
                                     tuple(self.N_c))
                if self.offset_c.any():
                    self.description += ' + ['
                    for x in self.offset_c:
                        if x != 0 and abs(round(1 / x) - 1 / x) < 1e-12:
                            self.description += '1/%d,' % round(1 / x)
                        else:
                            self.description += '%f,' % x
                    self.description = self.description[:-1] + ']'
Beispiel #10
0
def get_realspace_hs(h_skmm, s_kmm, bzk_kc, weight_k,
                     R_c=(0, 0, 0), direction='x', 
                     symmetry={'enabled': False}):

    from gpaw.symmetry import Symmetry
    from ase.dft.kpoints import get_monkhorst_pack_size_and_offset, \
        monkhorst_pack
    
    if symmetry['point_group'] is True:
        raise NotImplementedError, 'Point group symmetry not implemented'

    nspins, nk, nbf = h_skmm.shape[:3]
    dir = 'xyz'.index(direction)
    transverse_dirs = np.delete([0, 1, 2], [dir])
    dtype = float
    if len(bzk_kc) > 1 or np.any(bzk_kc[0] != [0, 0, 0]):
        dtype = complex

    kpts_grid = get_monkhorst_pack_size_and_offset(bzk_kc)[0]

    # kpts in the transport direction
    nkpts_p = kpts_grid[dir]
    bzk_p_kc = monkhorst_pack((nkpts_p,1,1))[:, 0]
    weight_p_k = 1. / nkpts_p

   # kpts in the transverse directions
    bzk_t_kc = monkhorst_pack(tuple(kpts_grid[transverse_dirs]) + (1, ))
    if not 'time_reversal' in symmetry:
        symmetry['time_reversal'] = True
    if symmetry['time_reversal'] is True:
        #XXX a somewhat ugly hack:
        # By default GPAW reduces inversion sym in the z direction. The steps 
        # below assure reduction in the transverse dirs.
        # For now this part seems to do the job, but it may be written
        # in a smarter way in the future.
        symmetry = Symmetry([1], np.eye(3))
        symmetry.prune_symmetries_atoms(np.zeros((1, 3)))
        ibzk_kc, ibzweight_k = symmetry.reduce(bzk_kc)[:2]
        ibzk_t_kc, weights_t_k = symmetry.reduce(bzk_t_kc)[:2]
        ibzk_t_kc = ibzk_t_kc[:, :2]
        nkpts_t = len(ibzk_t_kc)
    else:
        ibzk_kc = bzk_kc.copy()
        ibzk_t_kc = bzk_t_kc
        nkpts_t = len(bzk_t_kc)
        weights_t_k = [1. / nkpts_t for k in range(nkpts_t)]

    h_skii = np.zeros((nspins, nkpts_t, nbf, nbf), dtype)
    if s_kmm is not None:
        s_kii = np.zeros((nkpts_t, nbf, nbf), dtype)

    tol = 7
    for j, k_t in enumerate(ibzk_t_kc):
        for k_p in bzk_p_kc:
            k = np.zeros((3,))
            k[dir] = k_p
            k[transverse_dirs] = k_t
            kpoint_list = [list(np.round(k_kc, tol)) for k_kc in ibzk_kc]
            if list(np.round(k, tol)) not in kpoint_list:
                k = -k # inversion
                index = kpoint_list.index(list(np.round(k,tol)))
                h = h_skmm[:, index].conjugate()
                if s_kmm is not None:
                    s = s_kmm[index].conjugate()
                k=-k
            else: # kpoint in the ibz
                index = kpoint_list.index(list(np.round(k, tol)))
                h = h_skmm[:, index]
                if s_kmm is not None:
                    s = s_kmm[index]

            c_k = np.exp(2.j * np.pi * np.dot(k, R_c)) * weight_p_k
            h_skii[:, j] += c_k * h
            if s_kmm is not None:
                s_kii[j] += c_k * s 
    
    if s_kmm is None:
        return ibzk_t_kc, weights_t_k, h_skii
    else:
        return ibzk_t_kc, weights_t_k, h_skii, s_kii
Beispiel #11
0
def get_berry_phases(calc, spin=0, dir=0, check2d=False):
    if isinstance(calc, str):
        calc = GPAW(calc, communicator=serial_comm, txt=None)

    M = np.round(calc.get_magnetic_moment())
    assert np.allclose(M, calc.get_magnetic_moment(), atol=0.05), \
        print(M, calc.get_magnetic_moment())
    nvalence = calc.wfs.setups.nvalence
    nocc_s = [int((nvalence + M) / 2), int((nvalence - M) / 2)]
    assert np.allclose(np.sum(nocc_s), nvalence)
    nocc = nocc_s[spin]

    bands = list(range(nocc))
    kpts_kc = calc.get_bz_k_points()
    size = get_monkhorst_pack_size_and_offset(kpts_kc)[0]
    Nk = len(kpts_kc)
    wfs = calc.wfs
    icell_cv = (2 * np.pi) * np.linalg.inv(calc.wfs.gd.cell_cv).T

    dO_aii = []
    for ia, id in enumerate(wfs.setups.id_a):
        dO_ii = calc.wfs.setups[ia].dO_ii
        dO_aii.append(dO_ii)

    kd = calc.wfs.kd
    nik = kd.nibzkpts

    u_knR = []
    P_kani = []
    for k in range(Nk):
        ik = kd.bz2ibz_k[k]
        k_c = kd.bzk_kc[k]
        ik_c = kd.ibzk_kc[ik]
        kpt = wfs.kpt_u[ik + spin * nik]
        psit_nG = kpt.psit_nG
        ut_nR = wfs.gd.empty(nocc, wfs.dtype)

        # Check that all states are occupied
        assert np.all(kpt.f_n[:nocc] > 1e-6)
        sym = kd.sym_k[k]
        U_cc = kd.symmetry.op_scc[sym]
        time_reversal = kd.time_reversal_k[k]
        sign = 1 - 2 * time_reversal
        phase_c = k_c - sign * np.dot(U_cc, ik_c)
        phase_c = phase_c.round().astype(int)

        N_c = wfs.gd.N_c

        if (U_cc == np.eye(3)).all() or np.allclose(ik_c - k_c, 0.0):
            for n in range(nocc):
                ut_nR[n, :] = wfs.pd.ifft(psit_nG[n], ik)
        else:
            i_cr = np.dot(U_cc.T, np.indices(N_c).reshape((3, -1)))
            i = np.ravel_multi_index(i_cr, N_c, 'wrap')

            for n in range(nocc):
                ut_nR[n, :] = wfs.pd.ifft(psit_nG[n],
                                          ik).ravel()[i].reshape(N_c)

        if time_reversal:
            ut_nR = ut_nR.conj()

        if np.any(phase_c):
            emikr_R = np.exp(-2j * np.pi *
                             np.dot(np.indices(N_c).T, phase_c / N_c).T)
            u_knR.append(ut_nR * emikr_R[np.newaxis])
        else:
            u_knR.append(ut_nR)

        a_a = []
        U_aii = []
        for a, id in enumerate(wfs.setups.id_a):
            b = kd.symmetry.a_sa[sym, a]
            S_c = np.dot(calc.spos_ac[a], U_cc) - calc.spos_ac[b]
            x = np.exp(2j * np.pi * np.dot(k_c, S_c))
            U_ii = wfs.setups[a].R_sii[sym].T * x
            a_a.append(b)
            U_aii.append(U_ii)

        P_ani = []
        for b, U_ii in zip(a_a, U_aii):
            P_ni = np.dot(kpt.P_ani[b][:nocc], U_ii)
            if time_reversal:
                P_ni = P_ni.conj()
            P_ani.append(P_ni)

        P_kani.append(P_ani)

    indices_kkk = np.arange(Nk).reshape(size)
    tmp = np.concatenate([[i for i in range(3) if i != dir], [dir]])
    indices_kk = indices_kkk.transpose(tmp).reshape(-1, size[dir])

    nkperp = len(indices_kk)
    phases = []
    if check2d:
        phases2d = []
    for indices_k in indices_kk:
        M_knn = []
        for j in range(size[dir]):
            k1 = indices_k[j]
            G_c = np.array([0, 0, 0])
            if j + 1 < size[dir]:
                k2 = indices_k[j + 1]
            else:
                k2 = indices_k[0]
                G_c[dir] = 1
            u1_nR = u_knR[k1]
            u2_nR = u_knR[k2]
            k1_c = kpts_kc[k1]
            k2_c = kpts_kc[k2] + G_c

            if np.any(G_c):
                emiGr_R = np.exp(-2j * np.pi *
                                 np.dot(np.indices(N_c).T, G_c / N_c).T)
                u2_nR = u2_nR * emiGr_R

            bG_c = k2_c - k1_c
            bG_v = np.dot(bG_c, icell_cv)
            M_nn = get_overlap(calc, bands, np.reshape(u1_nR, (nocc, -1)),
                               np.reshape(u2_nR, (nocc, -1)), P_kani[k1],
                               P_kani[k2], dO_aii, bG_v)
            M_knn.append(M_nn)
        det = np.linalg.det(M_knn)
        phases.append(np.imag(np.log(np.prod(det))))
        if check2d:
            # In the case of 2D systems we can check the
            # result
            k1 = indices_k[0]
            k1_c = kpts_kc[k1]
            G_c = [0, 0, 1]
            G_v = np.dot(G_c, icell_cv)
            u1_nR = u_knR[k1]
            emiGr_R = np.exp(-2j * np.pi *
                             np.dot(np.indices(N_c).T, G_c / N_c).T)
            u2_nR = u1_nR * emiGr_R

            M_nn = get_overlap(calc, bands, np.reshape(u1_nR, (nocc, -1)),
                               np.reshape(u2_nR, (nocc, -1)), P_kani[k1],
                               P_kani[k1], dO_aii, G_v)
            phase2d = np.imag(np.log(np.linalg.det(M_nn)))
            phases2d.append(phase2d)

    # Make sure the phases are continuous
    for p in range(nkperp - 1):
        delta = phases[p] - phases[p + 1]
        phases[p + 1] += np.round(delta / (2 * np.pi)) * 2 * np.pi

    phase = np.sum(phases) / nkperp
    if check2d:
        for p in range(nkperp - 1):
            delta = phases2d[p] - phases2d[p + 1]
            phases2d[p + 1] += np.round(delta / (2 * np.pi)) * 2 * np.pi

        phase2d = np.sum(phases2d) / nkperp

        diff = abs(phase - phase2d)
        if diff > 0.01:
            msg = 'Warning wrong phase: phase={}, 2dphase={}'
            print(msg.format(phase, phase2d))

    return indices_kk, phases
Beispiel #12
0
def create_kpoint_descriptor_with_refinement(refine, bzkpts_kc, nspins, atoms,
                                             symmetry, comm, timer):
    """Main routine to build refined k-point grids."""
    if 'center' not in refine:
        raise RuntimeError('Center for refinement not given!')
    if 'size' not in refine:
        raise RuntimeError('Grid size for refinement not given!')

    center_ic = np.array(refine.get('center'), dtype=float, ndmin=2)
    size = np.array(refine.get('size'), ndmin=2)
    reduce_symmetry = refine.get('reduce_symmetry', True)

    # Check that all sizes are odd. That's not so much an issue really.
    # But even Monkhorst-Pack grids have points on the boundary,
    # which just would require more special casing, which I want to avoid.
    if (np.array(size) % 2 == 0).any():
        raise RuntimeError(
            'Grid size for refinement must be odd!  Is: {}'.format(size))

    # Arguments needed for k-point descriptor construction
    kwargs = {
        'nspins': nspins,
        'atoms': atoms,
        'symmetry': symmetry,
        'comm': comm
    }

    # Define coarse grid points
    bzk_coarse_kc = bzkpts_kc

    # Define fine grid points
    centers_i, bzk_fine_kc, weight_fine_k = get_fine_bzkpts(
        center_ic, size, bzk_coarse_kc, kwargs)

    if reduce_symmetry:
        # Define new symmetry object ignoring symmetries violated by the
        # refined kpoints
        kd_fine = create_kpoint_descriptor(bzk_fine_kc, **kwargs)
        symm = prune_symmetries_kpoints(kd_fine, symmetry)
        del kd_fine
    else:
        symm = copy.copy(symmetry)
    kwargs['symmetry'] = symm

    # Create new descriptor with both sets of points

    with timer('Create mixed descriptor'):
        kd = create_mixed_kpoint_descriptor(bzk_coarse_kc, bzk_fine_kc,
                                            centers_i, weight_fine_k, kwargs)

    # Add missing k-points to fulfill group properties with
    # zero-weighted points
    with timer('Add_missing_points'):
        kd = add_missing_points(kd, kwargs)

    # Add additional +q k-points, if necessary
    if 'q' in refine:
        timer.start("+q")
        N_coarse_c = get_monkhorst_pack_size_and_offset(bzk_coarse_kc)[0]
        bla = N_coarse_c * refine['q']
        if not max(abs(bla - np.rint(bla))) < 1e-8:
            kd.refine_info.almostoptical = True
        kd = add_plusq_points(kd, refine['q'], kwargs)
        symm = kd.symmetry
        kwargs['symmetry'] = symm
        kd = add_missing_points(kd, kwargs)
        timer.stop("+q")

    return kd
Beispiel #13
0
    def __init__(
        self,
        evals,
        wfn,
        positions,
        kpts,
        nwann,
        weight_func,
        Sk=None,
        has_phase=True,
        Rgrid=None,
        exclude_bands=None,
    ):
        #eigen
        self.evals = np.array(evals, dtype=float)
        self.kpts = np.array(kpts, dtype=float)
        # TODO: Remove me.modify evals
        if False:
            shift = 0.3
            shift2 = shift - 0.01
            ik = self.find_k((0.5, 0, 0.5))
            print(ik)
            self.evals[ik, 0] -= shift
            self.evals[ik, 1] -= shift2

            ik = self.find_k((0.5, 0, -0.5))
            print(ik)
            self.evals[ik, 0] -= shift
            self.evals[ik, 1] -= shift2

            ik = self.find_k((-0.5, 0, -0.5))
            print(ik)
            self.evals[ik, 0] -= shift
            self.evals[ik, 1] -= shift2

            ik = self.find_k((-0.5, 0, 0.5))
            print(ik)
            self.evals[ik, 0] -= shift
            self.evals[ik, 1] -= shift2

        self.ndim = self.kpts.shape[1]
        self.nkpt, self.nbasis, self.nband = np.shape(wfn)
        if Sk is None:
            self.is_orthogonal = True
        else:
            self.S = Sk
            self.is_orthogonal = False
        # exclude bands
        if exclude_bands is None:
            exclude_bands = []
        self.ibands = tuple(
            [i for i in range(self.nband) if i not in exclude_bands])
        self.nband = len(self.ibands)
        self.nwann = nwann
        self.positions = positions
        # kpts
        self.nkpt = self.kpts.shape[0]
        self.kmesh, self.k_offset = get_monkhorst_pack_size_and_offset(
            self.kpts)
        self.kweight = np.ones(self.nkpt, dtype=float) / self.nkpt
        self.weight_func = weight_func

        # Rgrid
        self.Rgrid = Rgrid
        self._prepare_Rlist()
        self.nR = self.Rlist.shape[0]

        # calculate occupation functions
        self.occ = self.weight_func(self.evals[:, self.ibands])

        # remove e^ikr from wfn
        self.has_phase = has_phase
        if not has_phase:
            self.psi = wfn
        else:
            self._remove_phase(wfn)

        self.Amn = np.zeros((self.nkpt, self.nband, self.nwann), dtype=complex)

        self.wannk = np.zeros((self.nkpt, self.nbasis, self.nwann),
                              dtype=complex)
        self.Hwann_k = np.zeros((self.nkpt, self.nwann, self.nwann),
                                dtype=complex)

        self.HwannR = np.zeros((self.nR, self.nwann, self.nwann),
                               dtype=complex)
        self.wannR = np.zeros((self.nR, self.nbasis, self.nwann),
                              dtype=complex)
Beispiel #14
0
    def __init__(self, kpts, nspins=1, collinear=True, usefractrans=False):
        """Construct descriptor object for kpoint/spin combinations (ks-pair).

        Parameters
        ----------
        kpts: None, sequence of 3 ints, or (n,3)-shaped array
            Specification of the k-point grid. None=Gamma, list of
            ints=Monkhorst-Pack, ndarray=user specified.
        nspins: int
            Number of spins.
        usefractrans: bool
            Switch for the use of non-symmorphic symmetries aka: symmetries
            with fractional translations. False by default (experimental!!!)

        Attributes
        ===================  =================================================
        ``N_c``               Number of k-points in the different directions.
        ``nspins``            Number of spins in total.
        ``mynspins``          Number of spins on this CPU.
        ``nibzkpts``          Number of irreducible kpoints in 1st BZ.
        ``nks``               Number of k-point/spin combinations in total.
        ``mynks``             Number of k-point/spin combinations on this CPU.
        ``gamma``             Boolean indicator for gamma point calculation.
        ``comm``              MPI-communicator for kpoint distribution.
        ``weight_k``          Weights of each k-point
        ``ibzk_kc``           Unknown
        ``sym_k``             Unknown
        ``time_reversal_k``   Unknown
        ``bz2ibz_k``          Unknown
        ``ibz2bz_k``          Unknown
        ``bz2bz_ks``          Unknown
        ``symmetry``          Object representing symmetries
        ===================  =================================================
        """

        if kpts is None:
            self.bzk_kc = np.zeros((1, 3))
            self.N_c = np.array((1, 1, 1), dtype=int)
            self.offset_c = np.zeros(3)
        elif isinstance(kpts[0], int):
            self.bzk_kc = monkhorst_pack(kpts)
            self.N_c = np.array(kpts, dtype=int)
            self.offset_c = np.zeros(3)
        else:
            self.bzk_kc = np.array(kpts, float)
            try:
                self.N_c, self.offset_c = \
                          get_monkhorst_pack_size_and_offset(self.bzk_kc)
            except ValueError:
                self.N_c = None
                self.offset_c = None

        self.collinear = collinear
        self.nspins = nspins
        self.nbzkpts = len(self.bzk_kc)
        
        # Gamma-point calculation?
        self.usefractrans = usefractrans
        self.gamma = (self.nbzkpts == 1 and np.allclose(self.bzk_kc[0], 0.0))
        self.set_symmetry(None, None, usesymm=None)
        self.set_communicator(mpi.serial_comm)

        if self.gamma:
            self.description = '1 k-point (Gamma)'
        else:
            self.description = '%d k-points' % self.nbzkpts
            if self.N_c is not None:
                self.description += (': %d x %d x %d Monkhorst-Pack grid' %
                                     tuple(self.N_c))
                if self.offset_c.any():
                    self.description += ' + ['
                    for x in self.offset_c:
                        if x != 0 and abs(round(1 / x) - 1 / x) < 1e-12:
                            self.description += '1/%d,' % round(1 / x)
                        else:
                            self.description += '%f,' % x
                    self.description = self.description[:-1] + ']'
Beispiel #15
0
    def __init__(self, kpts, nspins=1):
        """Construct descriptor object for kpoint/spin combinations (ks-pair).

        Parameters
        ----------
        kpts: None, sequence of 3 ints, or (n,3)-shaped array
            Specification of the k-point grid. None=Gamma, list of
            ints=Monkhorst-Pack, ndarray=user specified.
        nspins: int
            Number of spins.

        Attributes
        ===================  =================================================
        ``N_c``               Number of k-points in the different directions.
        ``nspins``            Number of spins in total.
        ``mynspins``          Number of spins on this CPU.
        ``nibzkpts``          Number of irreducible kpoints in 1st BZ.
        ``nks``               Number of k-point/spin combinations in total.
        ``mynks``             Number of k-point/spin combinations on this CPU.
        ``gamma``             Boolean indicator for gamma point calculation.
        ``comm``              MPI-communicator for kpoint distribution.
        ``weight_k``          Weights of each k-point
        ``ibzk_kc``           Unknown
        ``ibzk_qc``           Unknown
        ``sym_k``             Unknown
        ``time_reversal_k``   Unknown
        ``bz2ibz_k``          Unknown
        ``ibz2bz_k``          Unknown
        ``bz2bz_ks``          Unknown
        ``symmetry``          Object representing symmetries
        ===================  =================================================
        """

        if kpts is None:
            self.bzk_kc = np.zeros((1, 3))
            self.N_c = np.array((1, 1, 1), dtype=int)
            self.offset_c = np.zeros(3)
        else:
            kpts = np.asarray(kpts)
            if kpts.ndim == 1:
                self.N_c = np.array(kpts, dtype=int)
                self.bzk_kc = monkhorst_pack(self.N_c)
                self.offset_c = np.zeros(3)
            else:
                self.bzk_kc = np.array(kpts, dtype=float)
                try:
                    self.N_c, self.offset_c = \
                        get_monkhorst_pack_size_and_offset(self.bzk_kc)
                except ValueError:
                    self.N_c = None
                    self.offset_c = None

        self.nspins = nspins
        self.nbzkpts = len(self.bzk_kc)

        # Gamma-point calculation?
        self.gamma = self.nbzkpts == 1 and np.allclose(self.bzk_kc, 0)

        # Point group and time-reversal symmetry neglected:
        self.weight_k = np.ones(self.nbzkpts) / self.nbzkpts
        self.ibzk_kc = self.bzk_kc.copy()
        self.sym_k = np.zeros(self.nbzkpts, int)
        self.time_reversal_k = np.zeros(self.nbzkpts, bool)
        self.bz2ibz_k = np.arange(self.nbzkpts)
        self.ibz2bz_k = np.arange(self.nbzkpts)
        self.bz2bz_ks = np.arange(self.nbzkpts)[:, np.newaxis]
        self.nibzkpts = self.nbzkpts
        self.nks = self.nibzkpts * self.nspins

        self.set_communicator(mpi.serial_comm)
Beispiel #16
0
def plot_reciprocal_cell(atoms,
                         path='default',
                         k_points=False,
                         ibz_k_points=False,
                         plot_vectors=True,
                         dimension=3,
                         output=None,
                         verbose=False):
    import matplotlib.pyplot as plt

    cell = atoms.get_cell()
    icell = atoms.get_reciprocal_cell()

    try:
        cs = crystal_structure_from_cell(cell)
    except ValueError:
        cs = None

    if verbose:
        if cs:
            print('Crystal:', cs)
            print('Special points:', special_paths[cs])
        print('Lattice vectors:')
        for i, v in enumerate(cell):
            print('{}: ({:16.9f},{:16.9f},{:16.9f})'.format(i + 1, *v))
        print('Reciprocal vectors:')
        for i, v in enumerate(icell):
            print('{}: ({:16.9f},{:16.9f},{:16.9f})'.format(i + 1, *v))

    # band path
    if path:
        if path == 'default':
            path = special_paths[cs]
        paths = []
        special_points = get_special_points(cell)
        for names in parse_path_string(path):
            points = []
            for name in names:
                points.append(np.dot(icell.T, special_points[name]))
            paths.append((names, points))
    else:
        paths = None

    # k points
    points = None
    if atoms.calc is not None and hasattr(atoms.calc, 'get_bz_k_points'):
        bzk = atoms.calc.get_bz_k_points()
        if path is None:
            try:
                size, offset = get_monkhorst_pack_size_and_offset(bzk)
            except ValueError:
                # This was not a MP-grid.  Must be a path in the BZ:
                path = ''.join(labels_from_kpts(bzk, cell)[2])

        if k_points:
            points = bzk
        elif ibz_k_points:
            points = atoms.calc.get_ibz_k_points()
        if points is not None:
            for i in range(len(points)):
                points[i] = np.dot(icell.T, points[i])

    kwargs = {
        'cell': cell,
        'vectors': plot_vectors,
        'paths': paths,
        'points': points
    }

    if dimension == 1:
        bz1d_plot(**kwargs)
    elif dimension == 2:
        bz2d_plot(**kwargs)
    else:
        bz3d_plot(interactive=True, **kwargs)

    if output:
        plt.savefig(output)
    else:
        plt.show()
Beispiel #17
0
    def __init__(self, nwannier, calc,
                 file=None,
                 nbands=None,
                 fixedenergy=None,
                 fixedstates=None,
                 spin=0,
                 initialwannier='random',
                 rng=np.random,
                 verbose=False):
        """
        Required arguments:

          ``nwannier``: The number of Wannier functions you wish to construct.
            This must be at least half the number of electrons in the system
            and at most equal to the number of bands in the calculation.

          ``calc``: A converged DFT calculator class.
            If ``file`` arg. is not provided, the calculator *must* provide the
            method ``get_wannier_localization_matrix``, and contain the
            wavefunctions (save files with only the density is not enough).
            If the localization matrix is read from file, this is not needed,
            unless ``get_function`` or ``write_cube`` is called.

        Optional arguments:

          ``nbands``: Bands to include in localization.
            The number of bands considered by Wannier can be smaller than the
            number of bands in the calculator. This is useful if the highest
            bands of the DFT calculation are not well converged.

          ``spin``: The spin channel to be considered.
            The Wannier code treats each spin channel independently.

          ``fixedenergy`` / ``fixedstates``: Fixed part of Heilbert space.
            Determine the fixed part of Hilbert space by either a maximal
            energy *or* a number of bands (possibly a list for multiple
            k-points).
            Default is None meaning that the number of fixed states is equated
            to ``nwannier``.

          ``file``: Read localization and rotation matrices from this file.

          ``initialwannier``: Initial guess for Wannier rotation matrix.
            Can be 'bloch' to start from the Bloch states, 'random' to be
            randomized, or a list passed to calc.get_initial_wannier.

          ``rng``: Random number generator for ``initialwannier``.

          ``verbose``: True / False level of verbosity.
          """
        # Bloch phase sign convention.
        # May require special cases depending on which code is used.
        sign = -1

        self.nwannier = nwannier
        self.calc = calc
        self.spin = spin
        self.verbose = verbose
        self.kpt_kc = calc.get_bz_k_points()
        assert len(calc.get_ibz_k_points()) == len(self.kpt_kc)
        self.kptgrid = get_monkhorst_pack_size_and_offset(self.kpt_kc)[0]
        self.kpt_kc *= sign

        self.Nk = len(self.kpt_kc)
        self.unitcell_cc = calc.get_atoms().get_cell()
        self.largeunitcell_cc = (self.unitcell_cc.T * self.kptgrid).T
        self.weight_d, self.Gdir_dc = calculate_weights(self.largeunitcell_cc)
        self.Ndir = len(self.weight_d)  # Number of directions

        if nbands is not None:
            self.nbands = nbands
        else:
            self.nbands = calc.get_number_of_bands()
        if fixedenergy is None:
            if fixedstates is None:
                self.fixedstates_k = np.array([nwannier] * self.Nk, int)
            else:
                if isinstance(fixedstates, int):
                    fixedstates = [fixedstates] * self.Nk
                self.fixedstates_k = np.array(fixedstates, int)
        else:
            # Setting number of fixed states and EDF from specified energy.
            # All states below this energy (relative to Fermi level) are fixed.
            fixedenergy += calc.get_fermi_level()
            print(fixedenergy)
            self.fixedstates_k = np.array(
                [calc.get_eigenvalues(k, spin).searchsorted(fixedenergy)
                 for k in range(self.Nk)], int)
        self.edf_k = self.nwannier - self.fixedstates_k
        if verbose:
            print('Wannier: Fixed states            : %s' % self.fixedstates_k)
            print('Wannier: Extra degrees of freedom: %s' % self.edf_k)

        # Set the list of neighboring k-points k1, and the "wrapping" k0,
        # such that k1 - k - G + k0 = 0
        #
        # Example: kpoints = (-0.375,-0.125,0.125,0.375), dir=0
        # G = [0.25,0,0]
        # k=0.375, k1= -0.375 : -0.375-0.375-0.25 => k0=[1,0,0]
        #
        # For a gamma point calculation k1 = k = 0,  k0 = [1,0,0] for dir=0
        if self.Nk == 1:
            self.kklst_dk = np.zeros((self.Ndir, 1), int)
            k0_dkc = self.Gdir_dc.reshape(-1, 1, 3)
        else:
            self.kklst_dk = np.empty((self.Ndir, self.Nk), int)
            k0_dkc = np.empty((self.Ndir, self.Nk, 3), int)

            # Distance between kpoints
            kdist_c = np.empty(3)
            for c in range(3):
                # make a sorted list of the kpoint values in this direction
                slist = np.argsort(self.kpt_kc[:, c], kind='mergesort')
                skpoints_kc = np.take(self.kpt_kc, slist, axis=0)
                kdist_c[c] = max([skpoints_kc[n + 1, c] - skpoints_kc[n, c]
                                  for n in range(self.Nk - 1)])

            for d, Gdir_c in enumerate(self.Gdir_dc):
                for k, k_c in enumerate(self.kpt_kc):
                    # setup dist vector to next kpoint
                    G_c = np.where(Gdir_c > 0, kdist_c, 0)
                    if max(G_c) < 1e-4:
                        self.kklst_dk[d, k] = k
                        k0_dkc[d, k] = Gdir_c
                    else:
                        self.kklst_dk[d, k], k0_dkc[d, k] = \
                            neighbor_k_search(k_c, G_c, self.kpt_kc)

        # Set the inverse list of neighboring k-points
        self.invkklst_dk = np.empty((self.Ndir, self.Nk), int)
        for d in range(self.Ndir):
            for k1 in range(self.Nk):
                self.invkklst_dk[d, k1] = self.kklst_dk[d].tolist().index(k1)

        Nw = self.nwannier
        Nb = self.nbands
        self.Z_dkww = np.empty((self.Ndir, self.Nk, Nw, Nw), complex)
        self.V_knw = np.zeros((self.Nk, Nb, Nw), complex)
        if file is None:
            self.Z_dknn = np.empty((self.Ndir, self.Nk, Nb, Nb), complex)
            for d, dirG in enumerate(self.Gdir_dc):
                for k in range(self.Nk):
                    k1 = self.kklst_dk[d, k]
                    k0_c = k0_dkc[d, k]
                    self.Z_dknn[d, k] = calc.get_wannier_localization_matrix(
                        nbands=Nb, dirG=dirG, kpoint=k, nextkpoint=k1,
                        G_I=k0_c, spin=self.spin)
        self.initialize(file=file, initialwannier=initialwannier, rng=rng)
Beispiel #18
0
    def __init__(self,
                 calc=None,
                 width=0.1,
                 window=None,
                 npts=401,
                 comm=world,
                 nspins=None,
                 w_k=None,
                 e_skn=None):
        """Electronic Density Of States object.

        calc: calculator object
            Any ASE compliant calculator object.
        width: float
            Width of guassian smearing.  Use width=0.0 for linear tetrahedron
            interpolation.
        window: tuple of two float
            Use ``window=(emin, emax)``.  If not specified, a window
            big enough to hold all the eigenvalues will be used.
        npts: int
            Number of points.
        comm: communicator object
            MPI communicator for lti_dos
        nspins: int
            number of spin channels
        w_k: list
            k-point weights
        e_skn: numpy array
            Kohn-Sham eigenvalues indexed by spin & k-point


        """
        self.comm = comm
        self.npts = npts
        self.width = width
        if calc is None:
            for kw in 'nspins', 'w_k', 'e_skn':
                val = locals()[kw]
                if val is not None:
                    setattr(self, kw, val)
                else:
                    raise ValueError(
                        f'When initialising a DOS object with calc=None, you must specify a value for {kw}'
                    )
        else:
            self.w_k = calc.get_k_point_weights()
            self.nspins = calc.get_number_of_spins()
            self.e_skn = np.array([[
                calc.get_eigenvalues(kpt=k, spin=s)
                for k in range(len(self.w_k))
            ] for s in range(self.nspins)])
            try:  # two Fermi levels
                for i, eF in enumerate(calc.get_fermi_level()):
                    self.e_skn[i] -= eF
            except TypeError:  # a single Fermi level
                self.e_skn -= calc.get_fermi_level()

        if window is None:
            emin = None
            emax = None
        else:
            emin, emax = window

        if emin is None:
            emin = self.e_skn.min() - 5 * self.width
        if emax is None:
            emax = self.e_skn.max() + 5 * self.width

        self.energies = np.linspace(emin, emax, npts)

        if width == 0.0:
            if calc is None:
                raise NotImplementedError(
                    f'When initialising a DOS object with width=0.0, you must specify a value for calc'
                )
            bzkpts = calc.get_bz_k_points()
            size, offset = get_monkhorst_pack_size_and_offset(bzkpts)
            bz2ibz = calc.get_bz_to_ibz_map()
            shape = (self.nspins, ) + tuple(size) + (-1, )
            self.e_skn = self.e_skn[:, bz2ibz].reshape(shape)
            self.cell = calc.atoms.cell