Exemple #1
0
    def __init__(self, filepath):
        super(Fold2BlochNcfile, self).__init__(filepath)
        self.reader = ElectronsReader(filepath)

        # Initialize the electron bands from file.
        # Spectral weights are dimensioned with `nss`
        # Fortran arrays.
        # nctkarr_t("reduced_coordinates_of_unfolded_kpoints", "dp", "number_of_reduced_dimensions, nk_unfolded")
        # nctkarr_t("unfolded_eigenvalues", "dp", "max_number_of_states, nk_unfolded, number_of_spins")
        # nctkarr_t("spectral_weights", "dp", "max_number_of_states, nk_unfolded, nsppol_times_nspinor")
        self._ebands = self.reader.read_ebands()
        self.nss = max(self.nsppol, self.nspinor)
        self.fold_matrix = self.reader.read_value("fold_matrix")

        # Compute direct lattice of the primitive cell from fold_matrix.
        if is_diagonal(self.fold_matrix):
            folds = np.diagonal(self.fold_matrix)
            self.pc_lattice = Lattice(
                (self.structure.lattice.matrix.T * (1.0 / folds)).T.copy())
        else:
            raise NotImplementedError("non diagonal fold_matrix: %s" %
                                      str(self.fold_matrix))

        # Read fold2bloch output data.
        self.uf_kfrac_coords = self.reader.read_value(
            "reduced_coordinates_of_unfolded_kpoints")
        self.uf_kpoints = KpointList(self.pc_lattice.reciprocal_lattice,
                                     self.uf_kfrac_coords)
        self.uf_nkpt = len(self.uf_kpoints)
Exemple #2
0
    def __init__(self, filepath):
        super(ScrReader, self).__init__(filepath)

        # Read and store important quantities.
        self.structure = self.read_structure()
        qred_coords = self.read_value("qpoints_dielectric_function")
        self.qpoints = KpointList(self.structure.reciprocal_lattice,
                                  qred_coords)
        self.wpts = self.read_value("frequencies_dielectric_function",
                                    cmode="c")
Exemple #3
0
    def test_kpointlist(self):
        """Test KpointList."""
        lattice = self.lattice

        frac_coords = [0, 0, 0, 1/2, 1/2, 1/2, 1/3, 1/3, 1/3]
        weights = [0.1, 0.2, 0.7]

        klist = KpointList(lattice, frac_coords, weights=weights)
        repr(klist); str(klist)

        self.serialize_with_pickle(klist, protocols=[-1])
        self.assertMSONable(klist, test_if_subclass=False)

        self.assert_equal(klist.frac_coords.flatten(), frac_coords)
        self.assert_equal(klist.get_cart_coords(), np.reshape([k.cart_coords for k in klist], (-1, 3)))
        assert klist.sum_weights() == 1
        assert len(klist) == 3

        for i, kpoint in enumerate(klist):
            assert kpoint in klist
            assert klist.count(kpoint) == 1
            assert klist.find(kpoint) == i

        # Changing the weight of the Kpoint object should change the weights of klist.
        for kpoint in klist: kpoint.set_weight(1.0)
        assert np.all(klist.weights == 1.0)

        # Test find_closest
        iclose, kclose, dist = klist.find_closest([0, 0, 0])
        assert iclose == 0 and dist == 0.

        iclose, kclose, dist = klist.find_closest(Kpoint([0.001, 0.002, 0.003], klist.reciprocal_lattice))
        assert iclose == 0
        self.assert_almost_equal(dist, 0.001984943324127921)

        # Compute mapping k_index --> (k + q)_index, g0
        k2kqg = klist.get_k2kqg_map((0, 0, 0))
        assert all(ikq == ik for ik, (ikq, g0) in k2kqg.items())
        k2kqg = klist.get_k2kqg_map((1/2, 1/2, 1/2))
        assert len(k2kqg) == 2
        assert k2kqg[0][0] == 1 and np.all(k2kqg[0][1] == 0)
        assert k2kqg[1][0] == 0 and np.all(k2kqg[1][1] == 1)

        frac_coords = [0, 0, 0, 1/2, 1/3, 1/3]
        other_klist = KpointList(lattice, frac_coords)

        # Test __add__
        add_klist = klist + other_klist

        for k in itertools.chain(klist, other_klist):
            assert k in add_klist

        assert add_klist.count([0,0,0]) == 2

        # Remove duplicated k-points.
        add_klist = add_klist.remove_duplicated()
        assert add_klist.count([0,0,0]) == 1
        assert len(add_klist) == 4
        assert add_klist == add_klist.remove_duplicated()
Exemple #4
0
    def __init__(self, filepath):
        super(Fold2BlochNcfile, self).__init__(filepath)
        self.reader = ElectronsReader(filepath)

        # Initialize the electron bands from file.
        # Spectral weights are dimensioned with `nss`
	# Fortran arrays.
	# nctkarr_t("reduced_coordinates_of_unfolded_kpoints", "dp", "number_of_reduced_dimensions, nk_unfolded")
	# nctkarr_t("unfolded_eigenvalues", "dp", "max_number_of_states, nk_unfolded, number_of_spins")
	# nctkarr_t("spectral_weights", "dp", "max_number_of_states, nk_unfolded, nsppol_times_nspinor")
        self._ebands = self.reader.read_ebands()
        self.nss = max(self.nsppol, self.nspinor)
        self.fold_matrix = self.reader.read_value("fold_matrix")

        # Compute direct lattice of the primitive cell from fold_matrix.
        if is_diagonal(self.fold_matrix):
            folds = np.diagonal(self.fold_matrix)
            self.pc_lattice = Lattice((self.structure.lattice.matrix.T * (1.0 / folds)).T.copy())
        else:
            raise NotImplementedError("non diagonal fold_matrix: %s" % str(self.fold_matrix))

        # Read fold2bloch output data.
        self.uf_kfrac_coords = self.reader.read_value("reduced_coordinates_of_unfolded_kpoints")
        self.uf_kpoints = KpointList(self.pc_lattice.reciprocal_lattice, self.uf_kfrac_coords)
        self.uf_nkpt = len(self.uf_kpoints)
Exemple #5
0
    def __init__(self, filepath):
        super(ScrReader, self).__init__(filepath)

        # Read and store important quantities.
        self.structure = self.read_structure()
        qfrac_coords = self.read_value("qpoints_dielectric_function")
        self.kpoints = KpointList(self.structure.reciprocal_lattice,
                                  qfrac_coords)
        self.wpoints = self.read_value("frequencies_dielectric_function",
                                       cmode="c")
        self.ng = self.read_dimvalue(
            "number_of_coefficients_dielectric_function")

        # Find number of real/imaginary frequencies.
        self.nw = len(self.wpoints)
        self.nrew = self.nw
        self.nimw = 0
        for i, w in enumerate(self.wpoints):
            if np.iscomplex(w):
                self.nrew = i
                break

        self.nimw = self.nw - self.nrew
        if self.nimw and not np.all(np.iscomplex(
                self.wpoints[self.nrew + 1:])):
            raise ValueError(
                "wpoints should contained real points packed in the first positions\n"
                "followed by imaginary points but got: %s" % str(self.wpoints))

        # Define self.netcdf_name from the data available on file.
        nfound = 0
        netcdf_names = [
            "polarizability", "dielectric_function",
            "inverse_dielectric_function"
        ]
        for tryname in netcdf_names:
            if tryname in self.rootgrp.variables:
                self.netcdf_name = tryname
                nfound += 1

        if nfound == 0:
            raise RuntimeError("Cannot find `%s` in netcdf file" %
                               str(netcdf_names))
        if nfound > 1:
            raise RuntimeError(
                "Find multiple netcdf arrays (%s) in netcdf file!" %
                str(netcdf_names))
Exemple #6
0
    def __init__(self, filepath):
        super(ScrReader, self).__init__(filepath)

        # Read and store important quantities.
        self.structure = self.read_structure()
        qred_coords = self.read_value("qpoints_dielectric_function")
        self.qpoints = KpointList(self.structure.reciprocal_lattice, qred_coords)
        self.wpts = self.read_value("frequencies_dielectric_function", cmode="c")
Exemple #7
0
class ScrReader(ETSF_Reader):
    """
    This object reads the results stored in the SCR (Screening) file produced by ABINIT.
    It provides helper functions to access the most important quantities.
    """
    def __init__(self, filepath):
        super(ScrReader, self).__init__(filepath)

        # Read and store important quantities.
        self.structure = self.read_structure()
        qred_coords = self.read_value("qpoints_dielectric_function")
        self.qpoints = KpointList(self.structure.reciprocal_lattice, qred_coords)
        self.wpts = self.read_value("frequencies_dielectric_function", cmode="c")

    #def read_params(self):
    #    """
    #    Read the most importan parameters used to generate the data, i.e.
    #    the parameters that may be subject to convergence studies.

    #    Returns:
    #        :class:`AttrDict` a dictionary whose keys can be accessed
    #        with the dot notation i.e. d.key.
    #    """
    #    keys = ["npwwfn_used", "nbands_used",]
    #    return AttrDict({k: self.read_value(k) for k in keys})

    def find_qpoint_fileindex(self, qpoint):
        """
        Returns the q-point and the index of in the netcdf file.
        Accepts `Kpoint` instance or integer

        Raise:
            `KpointsError` if qpoint cannot be found.
        """
        if isinstance(qpoint, int): 
            iq = qpoint
        else:
            iq = self.qpoints.index(qpoint)

        return self.qpoints[iq], iq

    def read_wggfunc(self, qpoint, cls):
        """
        Read data at the given q-point and return an instance
        of `cls` where `cls` is a subclass of `WGGFunction`
        """
        qpoint, iq = self.find_qpoint_fileindex(qpoint)
        # TODO: I don't remember how to slice in python-netcdf
        # ecuteps
        all_gvecs = self.read_value("reduced_coordinates_plane_waves_dielectric_function")
        ecuteps = 2
        # TODO: Gpshere.find is very slow if we don't take advantage of shells
        gsphere = GSphere(ecuteps, self.structure.reciprocal_lattice, qpoint, all_gvecs[iq])

        full_wggmat = self.read_value(cls.etsf_name, cmode="c")
        wggmat = full_wggmat[iq]

        return cls(qpoint, self.wpts, gsphere, wggmat, inord="F")
Exemple #8
0
    def test_kpointlist(self):
        """Test KpointList."""
        lattice = self.lattice

        frac_coords = [0, 0, 0, 1/2, 1/2, 1/2, 1/3, 1/3, 1/3]
        weights = [0.1, 0.2, 0.7]

        klist = KpointList(lattice, frac_coords, weights=weights)

        self.assertTrue(klist.sum_weights() == 1)
        self.assertTrue(len(klist) == 3)

        for i, kpoint in enumerate(klist):
            self.assertTrue(kpoint in klist)
            self.assertTrue(klist.count(kpoint) == 1)
            self.assertTrue(klist.find(kpoint) == i)

        # Changing the weight of the Kpoint object shoul change the weights of klist.
        for kpoint in klist: kpoint.set_weight(1.0)
        self.assertTrue(np.all(klist.weights == 1.0))
Exemple #9
0
    def test_kpointlist(self):
        """Test KpointList."""
        lattice = self.lattice

        frac_coords = [0, 0, 0, 1/2, 1/2, 1/2, 1/3, 1/3, 1/3]
        weights = [0.1, 0.2, 0.7]

        klist = KpointList(lattice, frac_coords, weights=weights)

        self.serialize_with_pickle(klist, protocols=[-1])
        self.assertMSONable(klist, test_if_subclass=False)

        self.assertTrue(klist.sum_weights() == 1)
        self.assertTrue(len(klist) == 3)

        for i, kpoint in enumerate(klist):
            self.assertTrue(kpoint in klist)
            self.assertTrue(klist.count(kpoint) == 1)
            self.assertTrue(klist.find(kpoint) == i)

        # Changing the weight of the Kpoint object should change the weights of klist.
        for kpoint in klist: kpoint.set_weight(1.0)
        self.assertTrue(np.all(klist.weights == 1.0))

        frac_coords = [0, 0, 0, 1/2, 1/3, 1/3]

        other_klist = KpointList(lattice, frac_coords)

        # Test __add__
        add_klist = klist + other_klist

        for k in itertools.chain(klist, other_klist):
            self.assertTrue(k in add_klist)

        self.assertTrue(add_klist.count([0,0,0]) == 2)

        # Remove duplicated k-points.
        add_klist = add_klist.remove_duplicated()
        self.assertTrue(add_klist.count([0,0,0]) == 1)
        self.assertTrue(len(add_klist) == 4)
        self.assertTrue(add_klist == add_klist.remove_duplicated())
Exemple #10
0
    def test_kpointlist(self):
        """Test KpointList."""
        lattice = self.lattice

        frac_coords = [0, 0, 0, 1 / 2, 1 / 2, 1 / 2, 1 / 3, 1 / 3, 1 / 3]
        weights = [0.1, 0.2, 0.7]

        klist = KpointList(lattice, frac_coords, weights=weights)

        self.serialize_with_pickle(klist, protocols=[-1])
        self.assertMSONable(klist, test_if_subclass=False)

        assert klist.sum_weights() == 1
        assert len(klist) == 3

        for i, kpoint in enumerate(klist):
            assert kpoint in klist
            assert klist.count(kpoint) == 1
            assert klist.find(kpoint) == i

        # Changing the weight of the Kpoint object should change the weights of klist.
        for kpoint in klist:
            kpoint.set_weight(1.0)
        assert np.all(klist.weights == 1.0)

        # Test find_closest
        iclose, kclose, dist = klist.find_closest([0, 0, 0])
        assert iclose == 0 and dist == 0.

        iclose, kclose, dist = klist.find_closest(
            Kpoint([0.001, 0.002, 0.003], klist.reciprocal_lattice))
        assert iclose == 0
        self.assert_almost_equal(dist, 0.001984943324127921)

        frac_coords = [0, 0, 0, 1 / 2, 1 / 3, 1 / 3]
        other_klist = KpointList(lattice, frac_coords)

        # Test __add__
        add_klist = klist + other_klist

        for k in itertools.chain(klist, other_klist):
            assert k in add_klist

        assert add_klist.count([0, 0, 0]) == 2

        # Remove duplicated k-points.
        add_klist = add_klist.remove_duplicated()
        self.assertTrue(add_klist.count([0, 0, 0]) == 1)
        self.assertTrue(len(add_klist) == 4)
        self.assertTrue(add_klist == add_klist.remove_duplicated())
Exemple #11
0
    def from_file(cls, filepath):
        """Create the object from a netCDF file."""
        with PHBST_Reader(filepath) as r:
            structure = r.read_structure()

            # Build the list of q-points
            qpoints = KpointList(structure.reciprocal_lattice,
                                 frac_coords=r.read_qredcoords(),
                                 weights=r.read_qweights(),
                                 names=None)

            return cls(structure=structure,
                       qpoints=qpoints,
                       phfreqs=r.read_phfreqs(),
                       phdispl_cart=r.read_phdispl_cart())
Exemple #12
0
    def __init__(self, filepath):
        super(DdbFile, self).__init__(filepath)

        self._header = self._parse_header()

        self._structure = Structure.from_abivars(**self.header)
        # Add Spacegroup (needed in guessed_ngkpt)
        # FIXME: has_timerev is always True
        spgid, has_timerev, h = 0, True, self.header
        self._structure.set_spacegroup(SpaceGroup(spgid, h.symrel, h.tnons, h.symafm, has_timerev))

        frac_coords = self._read_qpoints()
        self._qpoints = KpointList(self.structure.reciprocal_lattice, frac_coords, weights=None, names=None)

        # Guess q-mesh
        self._guessed_ngqpt = self._guess_ngqpt()
Exemple #13
0
    def __init__(self, filepath):
        super(ScrReader, self).__init__(filepath)

        # Read and store important quantities.
        self.structure = self.read_structure()
        qfrac_coords = self.read_value("qpoints_dielectric_function")
        self.kpoints = KpointList(self.structure.reciprocal_lattice, qfrac_coords)
        self.wpoints = self.read_value("frequencies_dielectric_function", cmode="c")
        self.ng = self.read_dimvalue("number_of_coefficients_dielectric_function")

        # Find number of real/imaginary frequencies.
        self.nw = len(self.wpoints)
        self.nrew = self.nw
        self.nimw = 0
        for i, w in enumerate(self.wpoints):
            if np.iscomplex(w):
                self.nrew = i
                break

        self.nimw = self.nw - self.nrew
        if self.nimw and not np.all(np.iscomplex(self.wpoints[self.nrew+1:])):
            raise ValueError("wpoints should contained real points packed in the first positions\n"
                             "followed by imaginary points but got: %s" % str(self.wpoints))

        # Define self.netcdf_name from the data available on file.
        nfound = 0
        netcdf_names = ["polarizability", "dielectric_function", "inverse_dielectric_function"]
        for tryname in netcdf_names:
            if tryname in self.rootgrp.variables:
                self.netcdf_name = tryname
                nfound += 1

        if nfound == 0:
            raise RuntimeError("Cannot find `%s` in netcdf file" % str(netcdf_names))
        if nfound > 1:
            raise RuntimeError("Find multiple netcdf arrays (%s) in netcdf file!" % str(netcdf_names))
Exemple #14
0
    def test_kpointlist(self):
        """Test KpointList."""
        lattice = self.lattice

        frac_coords = [0, 0, 0, 1/2, 1/2, 1/2, 1/3, 1/3, 1/3]
        weights = [0.1, 0.2, 0.7]

        klist = KpointList(lattice, frac_coords, weights=weights)

        self.assertTrue(klist.sum_weights() == 1)
        self.assertTrue(len(klist) == 3)

        for i, kpoint in enumerate(klist):
            self.assertTrue(kpoint in klist)
            self.assertTrue(klist.count(kpoint) == 1)
            self.assertTrue(klist.find(kpoint) == i)

        # Changing the weight of the Kpoint object should change the weights of klist.
        for kpoint in klist: kpoint.set_weight(1.0)
        self.assertTrue(np.all(klist.weights == 1.0))

        frac_coords = [0, 0, 0, 1/2, 1/3, 1/3]
                                                                  
        other_klist = KpointList(lattice, frac_coords)

        # Test __add__
        add_klist = klist + other_klist 

        for k in itertools.chain(klist, other_klist):
            self.assertTrue(k in add_klist)

        self.assertTrue(add_klist.count([0,0,0]) == 2)

        # Remove duplicated k-points.
        add_klist = add_klist.remove_duplicated()
        self.assertTrue(add_klist.count([0,0,0]) == 1)
        self.assertTrue(len(add_klist) == 4)
        self.assertTrue(add_klist == add_klist.remove_duplicated())
Exemple #15
0
 def qpoints(self):
     return KpointList(self.structure.reciprocal_lattice,
                       frac_coords=self.reader.read_value("qpts"))
Exemple #16
0
class SigresReader(ETSF_Reader):
    """This object provides method to read data from the SIGRES file produced ABINIT.
    # See 70gw/m_sigma_results.F90

    # Name of the diagonal matrix elements stored in the file.
    # b1gw:b2gw,nkibz,nsppol*nsig_ab))
    #_DIAGO_MELS = [
    #    "sigxme",
    #    "vxcme",
    #    "vUme",
    #    "dsigmee0",
    #    "sigcmee0",
    #    "sigxcme",
    #    "ze0",
    #]

    integer :: b1gw,b2gw      ! min and Max gw band indeces over spin and k-points (used to dimension)
    integer :: gwcalctyp      ! Flag defining the calculation type.
    integer :: nkptgw         ! No. of points calculated
    integer :: nkibz          ! No. of irreducible k-points.
    integer :: nbnds          ! Total number of bands
    integer :: nomega_r       ! No. of real frequencies for the spectral function.
    integer :: nomega_i       ! No. of frequencies along the imaginary axis.
    integer :: nomega4sd      ! No. of real frequencies to evaluate the derivative of $\Sigma(E)$.
    integer :: nsig_ab        ! 1 if nspinor=1,4 for noncollinear case.
    integer :: nsppol         ! No. of spin polarizations.
    integer :: usepawu        ! 1 if we are using LDA+U as starting point (only for PAW)

    real(dp) :: deltae       ! Frequency step for the calculation of d\Sigma/dE
    real(dp) :: maxomega4sd  ! Max frequency around E_ks for d\Sigma/dE.
    real(dp) :: maxomega_r   ! Max frequency for spectral function.
    real(dp) :: scissor_ene  ! Scissor energy value. zero for None.

    integer,pointer :: maxbnd(:,:)
    ! maxbnd(nkptgw,nsppol)
    ! Max band index considered in GW for this k-point.

    integer,pointer :: minbnd(:,:)
    ! minbnd(nkptgw,nsppol)
    ! Min band index considered in GW for this k-point.

    real(dp),pointer :: degwgap(:,:)
    ! degwgap(nkibz,nsppol)
    ! Difference btw the QPState and the KS optical gap.

    real(dp),pointer :: egwgap(:,:)
    ! egwgap(nkibz,nsppol))
    ! QPState optical gap at each k-point and spin.

    real(dp),pointer :: en_qp_diago(:,:,:)
    ! en_qp_diago(nbnds,nkibz,nsppol))
    ! QPState energies obtained from the diagonalization of the Hermitian approximation to Sigma (QPSCGW)

    real(dp),pointer :: e0(:,:,:)
    ! e0(nbnds,nkibz,nsppol)
    ! KS eigenvalues for each band, k-point and spin. In case of self-consistent?

    real(dp),pointer :: e0gap(:,:)
    ! e0gap(nkibz,nsppol),
    ! KS gap at each k-point, for each spin.

    real(dp),pointer :: omega_r(:)
    ! omega_r(nomega_r)
    ! real frequencies used for the self energy.

    real(dp),pointer :: kptgw(:,:)
    ! kptgw(3,nkptgw)
    ! ! TODO there is a similar array in sigma_parameters
    ! List of calculated k-points.

    real(dp),pointer :: sigxme(:,:,:)
    ! sigxme(b1gw:b2gw,nkibz,nsppol*nsig_ab))
    ! Diagonal matrix elements of $\Sigma_x$ i.e $\<nks|\Sigma_x|nks\>$

    real(dp),pointer :: vxcme(:,:,:)
    ! vxcme(b1gw:b2gw,nkibz,nsppol*nsig_ab))
    ! $\<nks|v_{xc}[n_val]|nks\>$ matrix elements of vxc (valence-only contribution).

    real(dp),pointer :: vUme(:,:,:)
    ! vUme(b1gw:b2gw,nkibz,nsppol*nsig_ab))
    ! $\<nks|v_{U}|nks\>$ for LDA+U.

    complex(dpc),pointer :: degw(:,:,:)
    ! degw(b1gw:b2gw,nkibz,nsppol))
    ! Difference between the QPState and the KS energies.

    complex(dpc),pointer :: dsigmee0(:,:,:)
    ! dsigmee0(b1gw:b2gw,nkibz,nsppol*nsig_ab))
    ! Derivative of $\Sigma_c(E)$ calculated at the KS eigenvalue.

    complex(dpc),pointer :: egw(:,:,:)
    ! egw(nbnds,nkibz,nsppol))
    ! QPState energies, $\epsilon_{nks}^{QPState}$.

    complex(dpc),pointer :: eigvec_qp(:,:,:,:)
    ! eigvec_qp(nbnds,nbnds,nkibz,nsppol))
    ! Expansion of the QPState amplitude in the KS basis set.

    complex(dpc),pointer :: hhartree(:,:,:,:)
    ! hhartree(b1gw:b2gw,b1gw:b2gw,nkibz,nsppol*nsig_ab)
    ! $\<nks|T+v_H+v_{loc}+v_{nl}|mks\>$

    complex(dpc),pointer :: sigcme(:,:,:,:)
    ! sigcme(b1gw:b2gw,nkibz,nomega_r,nsppol*nsig_ab))
    ! $\<nks|\Sigma_{c}(E)|nks\>$ at each nomega_r frequency

    complex(dpc),pointer :: sigmee(:,:,:)
    ! sigmee(b1gw:b2gw,nkibz,nsppol*nsig_ab))
    ! $\Sigma_{xc}E_{KS} + (E_{QPState}- E_{KS})*dSigma/dE_KS

    complex(dpc),pointer :: sigcmee0(:,:,:)
    ! sigcmee0(b1gw:b2gw,nkibz,nsppol*nsig_ab))
    ! Diagonal mat. elements of $\Sigma_c(E)$ calculated at the KS energy $E_{KS}$

    complex(dpc),pointer :: sigcmesi(:,:,:,:)
    ! sigcmesi(b1gw:b2gw,nkibz,nomega_i,nsppol*nsig_ab))
    ! Matrix elements of $\Sigma_c$ along the imaginary axis.
    ! Only used in case of analytical continuation.

    complex(dpc),pointer :: sigcme4sd(:,:,:,:)
    ! sigcme4sd(b1gw:b2gw,nkibz,nomega4sd,nsppol*nsig_ab))
    ! Diagonal matrix elements of \Sigma_c around the zeroth order eigenvalue (usually KS).

    complex(dpc),pointer :: sigxcme(:,:,:,:)
    ! sigxme(b1gw:b2gw,nkibz,nomega_r,nsppol*nsig_ab))
    ! $\<nks|\Sigma_{xc}(E)|nks\>$ at each real frequency frequency.

    complex(dpc),pointer :: sigxcmesi(:,:,:,:)
    ! sigxcmesi(b1gw:b2gw,nkibz,nomega_i,nsppol*nsig_ab))
    ! Matrix elements of $\Sigma_{xc}$ along the imaginary axis.
    ! Only used in case of analytical continuation.

    complex(dpc),pointer :: sigxcme4sd(:,:,:,:)
    ! sigxcme4sd(b1gw:b2gw,nkibz,nomega4sd,nsppol*nsig_ab))
    ! Diagonal matrix elements of \Sigma_xc for frequencies around the zeroth order eigenvalues.

    complex(dpc),pointer :: ze0(:,:,:)
    ! ze0(b1gw:b2gw,nkibz,nsppol))
    ! renormalization factor. $(1-\dfrac{\partial\Sigma_c} {\partial E_{KS}})^{-1}$

    complex(dpc),pointer :: omega_i(:)
    ! omegasi(nomega_i)
    ! Frequencies along the imaginary axis used for the analytical continuation.

    complex(dpc),pointer :: omega4sd(:,:,:,:)
    ! omega4sd(b1gw:b2gw,nkibz,nomega4sd,nsppol).
    ! Frequencies used to evaluate the Derivative of Sigma.
    """
    def __init__(self, path):
        self.ks_bands = ElectronBands.from_file(path)
        self.nsppol = self.ks_bands.nsppol

        super(SigresReader, self).__init__(path)

        try:
            self.nomega_r = self.read_dimvalue("nomega_r")
        except self.Error:
            self.nomega_r = 0

        #self.nomega_i = self.read_dim("nomega_i")

        # Save important quantities needed to simplify the API.
        self.structure = self.read_structure()

        self.gwcalctyp = self.read_value("gwcalctyp")
        self.usepawu = self.read_value("usepawu")

        # 1) The K-points of the homogeneous mesh.
        self.ibz = self.ks_bands.kpoints

        # 2) The K-points where QPState corrections have been calculated.
        gwred_coords = self.read_redc_gwkpoints()
        self.gwkpoints = KpointList(self.structure.reciprocal_lattice, gwred_coords)

        # minbnd[nkptgw,nsppol] gives the minimum band index computed
        # Note conversion between Fortran and python convention.
        self.gwbstart_sk = self.read_value("minbnd") - 1
        self.gwbstop_sk = self.read_value("maxbnd")

        # min and Max band index for GW corrections.
        self.min_gwbstart = np.min(self.gwbstart_sk)
        self.max_gwbstart = np.max(self.gwbstart_sk)

        self.min_gwbstop = np.min(self.gwbstop_sk)
        self.max_gwbstop = np.max(self.gwbstop_sk)

        self._egw = self.read_value("egw", cmode="c")

        # Read and save important matrix elements.
        # All these arrays are dimensioned
        # vxcme(b1gw:b2gw,nkibz,nsppol*nsig_ab))
        self._vxcme = self.read_value("vxcme")
        self._sigxme = self.read_value("sigxme")

        self._hhartree = self.read_value("hhartree", cmode="c")

        self._vUme = self.read_value("vUme")
        #if self.usepawu == 0: self._vUme.fill(0.0)

        # Complex arrays
        self._sigcmee0 = self.read_value("sigcmee0", cmode="c")
        self._ze0 = self.read_value("ze0", cmode="c")

        # Frequencies for the spectral function.
        if self.has_spfunc:
            self._omega_r = self.read_value("omega_r")

            self._sigcme = self.read_value("sigcme", cmode="c")
            self._sigxcme = self.read_value("sigxcme", cmode="c")

        # Self-consistent case
        self._en_qp_diago = self.read_value("en_qp_diago")

        # <KS|QPState>
        self._eigvec_qp = self.read_value("eigvec_qp", cmode="c")

        #self._mlda_to_qp

    #def is_selfconsistent(self, mode):
    #    return self.gwcalctyp

    @property
    def has_spfunc(self):
        """True if self contains the spectral function."""
        return self.nomega_r

    def kpt2fileindex(self, kpoint):
        """
        Helper function that returns the index of kpoint in the netcdf file.
        Accepts `Kpoint` instance or integer

        Raise:
            `KpointsError` if kpoint cannot be found.

        .. note::

            This function is needed since arrays in the netcdf file are dimensioned
            with the total number of k-points in the IBZ.
        """
        if isinstance(kpoint, int):
            return kpoint
            #kpoint = self.gwkpoints[kpoint]

        try:
            return self.ibz.index(kpoint)
        except:
            raise

    def gwkpt2seqindex(self, gwkpoint):
        """
        This function returns the index of the GW k-point in (0:nkptgw)
        Used to access data in the arrays that are dimensioned [0:nkptgw] e.g. minbnd.
        """
        if isinstance(gwkpoint, int):
            return gwkpoint
        else:
            return self.gwkpoints.index(gwkpoint)

    def read_redc_gwkpoints(self):
        return self.read_value("kptgw")

    def read_allqps(self):
        qps_spin = self.nsppol * [None]

        for spin in range(self.nsppol):
            qps = []
            for gwkpoint in self.gwkpoints:
                ik = self.gwkpt2seqindex(gwkpoint)
                bands = range(self.gwbstart_sk[spin,ik], self.gwbstop_sk[spin,ik])
                for band in bands:
                    qps.append(self.read_qp(spin, gwkpoint, band))

            qps_spin[spin] = QPList(qps)

        return tuple(qps_spin)

    def read_qplist_sk(self, spin, kpoint):
        ik = self.gwkpt2seqindex(kpoint)
        bstart, bstop = self.gwbstart_sk[spin, ik], self.gwbstop_sk[spin, ik]

        return QPList([self.read_qp(spin, kpoint, band) for band in range(bstart, bstop)])

    #def read_qpene(self, spin, kpoint, band)

    def read_qpenes(self):
        return self._egw[:, :, :]

    def read_qp(self, spin, kpoint, band):
        ik_file = self.kpt2fileindex(kpoint)
        ib_file = band - self.gwbstart_sk[spin, self.gwkpt2seqindex(kpoint)]

        return QPState(
            spin=spin,
            kpoint=kpoint,
            band=band,
            e0=self.read_e0(spin, ik_file, band),
            qpe=self._egw[spin, ik_file, band],
            qpe_diago=self._en_qp_diago[spin, ik_file, band],
            vxcme=self._vxcme[spin, ik_file, ib_file],
            sigxme=self._sigxme[spin, ik_file, ib_file],
            sigcmee0=self._sigcmee0[spin, ik_file, ib_file],
            vUme=self._vUme[spin, ik_file, ib_file],
            ze0=self._ze0[spin, ik_file, ib_file],
        )

    def read_qpgaps(self):
        """Read the QP gaps. Returns ndarray with shape [nsppol, nkibz] in eV"""
        return self.read_value("egwgap")

    def read_e0(self, spin, kfile, band):
        return self.ks_bands.eigens[spin, kfile, band]

    def read_sigmaw(self, spin, kpoint, band):
        """Returns the real and the imaginary part of the self energy."""
        if not self.has_spfunc:
            raise ValueError("%s does not contain spectral function data" % self.path)

        ik = self.kpt2fileindex(kpoint)

        return self._omega_r, self._sigxcme[spin,:,ik,band]

    def read_spfunc(self, spin, kpoint, band):
        """
        Returns the spectral function.

         one/pi * ABS(AIMAG(Sr%sigcme(ib,ikibz,io,is))) /
         ( (REAL(Sr%omega_r(io)-Sr%hhartree(ib,ib,ikibz,is)-Sr%sigxcme(ib,ikibz,io,is)))**2 &
        +(AIMAG(Sr%sigcme(ib,ikibz,io,is)))**2) / Ha_eV,&
        """
        if not self.has_spfunc:
            raise ValueError("%s does not contain spectral function data" % self.path)

        ik = self.kpt2fileindex(kpoint)
        ib = band - self.gwbstart_sk[spin, self.gwkpt2seqindex(kpoint)]

        aim_sigc = np.abs(self._sigcme[spin,:,ik,ib].imag)

        den = np.zeros(self.nomega_r)
        for (io, omega) in enumerate(self._omega_r):
            den[io] = (omega - self._hhartree[spin,ik,ib,ib].real - self._sigxcme[spin,io,ik,ib].real) ** 2 + \
                self._sigcme[spin,io,ik,ib].imag ** 2

        return self._omega_r, 1./np.pi * (aim_sigc/den)

    def read_eigvec_qp(self, spin, kpoint, band=None):
        """
        Returns <KS|QPState> for the given spin, kpoint and band. If band is None, <KS_b|QP_{b'}> is returned.
        """
        ik = self.kpt2fileindex(kpoint)
        if band is not None:
            return self._eigvec_qp[spin,ik,:,band]
        else:
            return self._eigvec_qp[spin,ik,:,:]

    def read_params(self):
        """
        Read the parameters of the calculation.
        Returns :class:`AttrDict` instance with the value of the parameters.
        """
        param_names = [
            "ecutwfn",
            "ecuteps",
            "ecutsigx",
            "scr_nband",
            "sigma_nband",
            "gwcalctyp",
            "scissor_ene",
        ]

        params = AttrDict()
        for pname in param_names:
            params[pname] = self.read_value(pname, default=None)

        # Other quantities that might be subject to convergence studies.
        params["nkibz"] = len(self.ibz)

        return params

    def print_qps(self, spin=None, kpoints=None, bands=None, fmt=None, stream=sys.stdout):
        """
        Args:
            spin: Spin index, if None all spins are considered
            kpoints: List of k-points to select. Default: all kpoints
            bands: List of bands to select. Default is all bands
            fmt: Format string passe to `to_strdict`
            stream: file-like object.

        Returns
            List of tables.
        """
        spins = range(self.nsppol) if spin is None else [spin]
        kpoints = self.gwkpoints if kpoints is None else [kpoints]
        if bands is not None: bands = [bands]

        header = QPState.get_fields(exclude=["spin", "kpoint"])
        tables = []

        for spin in spins:
            for kpoint in kpoints:
                table_sk = PrettyTable(header)
                if bands is None:
                    ik = self.gwkpt2seqindex(kpoint)
                    bands = range(self.gwbstart_sk[spin,ik], self.gwbstop_sk[spin,ik])

                for band in bands:
                    qp = self.read_qp(spin, kpoint, band)
                    d = qp.to_strdict(fmt=fmt)
                    table_sk.add_row([d[k] for k in header])

                stream.write("\nkpoint: %s, spin: %s, energy units: eV (NB: bands start from zero)\n" % (kpoint, spin))
                print(table_sk, file=stream)
                stream.write("\n")

                # Add it to tables.
                tables.append(table_sk)

        return tables
Exemple #17
0
class Fold2BlochNcfile(AbinitNcFile, Has_Header, Has_Structure, Has_ElectronBands, NotebookWriter):
    """
    Netcdf file with output data produced by Fold2Bloch.

    Usage example:

    .. code-block:: python

        with Fold2BlochNcfile("foo_FOLD2BLOCH.nc") as fb:
            fb.plot_unfolded()

    .. rubric:: Inheritance Diagram
    .. inheritance-diagram:: Fold2BlochNcfile
    """
    @classmethod
    def from_wfkpath(cls, wfkpath, folds, workdir=None, manager=None, mpi_procs=1, verbose=0):
        """
        Run fold2bloch in workdir.

        Args:
            wfkpath:
            folds:
            workdir: Working directory of the fake task used to compute the ibz. Use None for temporary dir.
            manager: :class:`TaskManager` of the task. If None, the manager is initialized from the config file.
            mpi_procs: Number of MPI processors to use.
            verbose: Verbosity level.
        """
        # Build a simple manager to run the job in a shell subprocess
        from abipy import flowtk
        manager = flowtk.TaskManager.as_manager(manager).to_shell_manager(mpi_procs=mpi_procs)
        fold2bloch = flowtk.Fold2Bloch(manager=manager, verbose=verbose)

        # Create temporary directory and link to the WFK file
        import tempfile
        workdir = tempfile.mkdtemp() if workdir is None else workdir
        wfkpath = os.path.abspath(wfkpath)
        link = os.path.join(workdir, os.path.basename(wfkpath))
        os.symlink(wfkpath, link)

        # Run fold2bloch
        ncpath = fold2bloch.unfold(link, folds, workdir=workdir)

        return cls(ncpath)

    def __init__(self, filepath):
        super(Fold2BlochNcfile, self).__init__(filepath)
        self.reader = ElectronsReader(filepath)

        # Initialize the electron bands from file.
        # Spectral weights are dimensioned with `nss`
	# Fortran arrays.
	# nctkarr_t("reduced_coordinates_of_unfolded_kpoints", "dp", "number_of_reduced_dimensions, nk_unfolded")
	# nctkarr_t("unfolded_eigenvalues", "dp", "max_number_of_states, nk_unfolded, number_of_spins")
	# nctkarr_t("spectral_weights", "dp", "max_number_of_states, nk_unfolded, nsppol_times_nspinor")
        self._ebands = self.reader.read_ebands()
        self.nss = max(self.nsppol, self.nspinor)
        self.fold_matrix = self.reader.read_value("fold_matrix")

        # Compute direct lattice of the primitive cell from fold_matrix.
        if is_diagonal(self.fold_matrix):
            folds = np.diagonal(self.fold_matrix)
            self.pc_lattice = Lattice((self.structure.lattice.matrix.T * (1.0 / folds)).T.copy())
        else:
            raise NotImplementedError("non diagonal fold_matrix: %s" % str(self.fold_matrix))

        # Read fold2bloch output data.
        self.uf_kfrac_coords = self.reader.read_value("reduced_coordinates_of_unfolded_kpoints")
        self.uf_kpoints = KpointList(self.pc_lattice.reciprocal_lattice, self.uf_kfrac_coords)
        self.uf_nkpt = len(self.uf_kpoints)

    def __str__(self):
        return self.to_string()

    def to_string(self, verbose=0):
        """String representation."""
        lines = []; app = lines.append

        app(marquee("File Info", mark="="))
        app(self.filestat(as_string=True))
        app("")
        app(self.structure.to_string(verbose=verbose, title="Structure"))
        app("")
        app(self.ebands.to_string(with_structure=False, title="Electronic Bands"))

        app("Direct lattice of the primitive cell:")
        to_s = lambda x: "%0.6f" % x
        app("abc   : " + " ".join([to_s(i).rjust(10) for i in self.pc_lattice.abc]))
        app("angles: " + " ".join([to_s(i).rjust(10) for i in self.pc_lattice.angles]))
        if is_diagonal(self.fold_matrix):
            app("Diagonal folding: %s" % (str(np.diagonal(self.fold_matrix))))
        else:
            app("Folding matrix: %s" % str(self.fold_matrix))

        if verbose:
            app(self.uf_kpoints.to_string(verbose=verbose, title="Unfolded k-points"))

        if verbose > 2:
            app(self.hdr.to_string(verbose=verbose, title="Abinit Header"))

        return "\n".join(lines)

    @property
    def ebands(self):
        """|ElectronBands| object with folded band energies."""
        return self._ebands

    @property
    def structure(self):
        """|Structure| object defining the supercell."""
        return self.ebands.structure

    def close(self):
        """Close the file."""
        self.reader.close()

    @lazy_property
    def params(self):
        """:class:`OrderedDict` with parameters that might be subject to convergence studies."""
        od = self.get_ebands_params()
        return od

    @lazy_property
    def uf_eigens(self):
        """[nsppol, nk_unfolded, nband] |numpy-array| with unfolded eigenvalues in eV."""
        # nctkarr_t("unfolded_eigenvalues", "dp", "max_number_of_states, nk_unfolded, number_of_spins")
        return self.reader.read_value("unfolded_eigenvalues") * units.Ha_to_eV

    @lazy_property
    def uf_weights(self):
        """[nss, nk_unfolded, nband] array with spectral weights. nss = max(nspinor, nsppol)."""
        # nctkarr_t("spectral_weights", "dp", "max_number_of_states, nk_unfolded, nsppol_times_nspinor")
        return self.reader.read_value("spectral_weights")

    def get_spectral_functions(self, step=0.01, width=0.02):
        """
        Args:
            step: Energy step (eV) of the linear mesh.
            width: Standard deviation (eV) of the gaussian.

        Return:
            mesh, sfw, int_sfw
        """
        # Compute linear mesh.
        epad = 3.0 * width
        e_min = self.uf_eigens.min() - epad
        e_max = self.uf_eigens.max() + epad
        nw = int(1 + (e_max - e_min) / step)
        mesh, step = np.linspace(e_min, e_max, num=nw, endpoint=True, retstep=True)

        sfw = np.zeros((self.nss, self.uf_nkpt, nw))
        for spin in range(self.nss):
            for ik in range(self.uf_nkpt):
                for band in range(self.nband):
                    e = self.uf_eigens[spin, ik, band]
                    sfw[spin, ik] += self.uf_weights[spin, ik, band] * gaussian(mesh, width, center=e)

        from scipy.integrate import cumtrapz
        int_sfw = cumtrapz(sfw, x=mesh, initial=0.0)

        return dict2namedtuple(mesh=mesh, sfw=sfw, int_sfw=int_sfw)

    @add_fig_kwargs
    def plot_unfolded(self, kbounds, klabels, ylims=None, dist_tol=1e-12, verbose=0,
                      colormap="afmhot", facecolor="black", ax=None, fontsize=12, **kwargs):
        r"""
        Plot unfolded band structure with spectral weights.

        Args:
            klabels: dictionary whose keys are tuple with the reduced coordinates of the k-points.
                The values are the labels. e.g. ``klabels = {(0.0,0.0,0.0): "$\Gamma$", (0.5,0,0): "L"}``.
            ylims: Set the data limits for the y-axis. Accept tuple e.g. ``(left, right)``
                or scalar e.g. ``left``. If left (right) is None, default values are used
            dist_tol: A point is considered to be on the path if its distance from the line
                is less than dist_tol.
            verbose: Verbosity level.
            colormap: Have a look at the colormaps here and decide which one you like:
                http://matplotlib.sourceforge.net/examples/pylab_examples/show_colormaps.html
            facecolor:
            ax: |matplotlib-Axes| or None if a new figure should be created.
            fontsize: Legend and title fontsize.

        Returns: |matplotlib-Figure|
	"""
        cart_bounds = [self.pc_lattice.reciprocal_lattice.get_cartesian_coords(c)
                       for c in np.reshape(kbounds, (-1, 3))]
        uf_cart = self.uf_kpoints.get_cart_coords()

        p = find_points_along_path(cart_bounds, uf_cart, dist_tol)
        if len(p.ikfound) == 0:
            cprint("Warning: find_points_along_path returned zero points along the path. Try to increase dist_tol.", "yellow")
            return None
        if verbose:
            uf_frac_coords = np.reshape([k.frac_coords for k in self.uf_kpoints], (-1, 3))
            fcoords = uf_frac_coords[p.ikfound]
            print("Found %d points along input k-path" % len(fcoords))
            print("k-points of path in reduced coordinates:")
            print(fcoords)

        fact = 8.0
        e0 = self.ebands.fermie
        ax, fig, plt = get_ax_fig_plt(ax=ax)
        ax.set_facecolor(facecolor)

        xs = np.tile(p.dist_list, self.nband)
        marker_spin = {0: "^", 1: "v"} if self.nss == 2 else {0: "o"}
        for spin in range(self.nss):
            ys = self.uf_eigens[spin, p.ikfound, :] - e0
            ws = self.uf_weights[spin, p.ikfound, :]
            s = ax.scatter(xs, ys.T, s=fact * ws.T, c=ws.T,
                           marker=marker_spin[spin], label=None if self.nss == 1 else "spin %s" % spin,
                           linewidth=1, edgecolors='none', cmap=plt.get_cmap(colormap))
            plt.colorbar(s, ax=ax, orientation='vertical')

        ax.set_xticks(p.path_ticks, minor=False)
        ax.set_xticklabels(klabels, fontdict=None, minor=False, size=kwargs.pop("klabel_size", "large"))
        ax.grid(True)
        ax.set_ylabel('Energy (eV)')
        set_axlims(ax, ylims, "y")
        if self.nss == 2: ax.legend(loc="best", fontsize=fontsize, shadow=True)

        return fig

    def yield_figs(self, **kwargs):  # pragma: no cover
        """
        This function *generates* a predefined list of matplotlib figures with minimal input from the user.
        """
        print("TODO: Add call to plot_unfolded")
        yield self.ebands.plot(show=False)

    def write_notebook(self, nbpath=None):
        """
        Write a jupyter_ notebook to nbpath. If `nbpath` is None, a temporay file in the current
        working directory is created. Return path to the notebook.
        """
        nbformat, nbv, nb = self.get_nbformat_nbv_nb(title=None)

        nb.cells.extend([
            nbv.new_code_cell("f2b = abilab.abiopen('%s')" % self.filepath),
            nbv.new_code_cell("print(f2b)"),
            nbv.new_code_cell("f2b.ebands.plot();"),
            nbv.new_code_cell("#f2b.unfolded_kpoints.plot();"),
            nbv.new_code_cell(r"""\
# kbounds = [0, 1/2, 0, 0, 0, 0, 0, 0, 1/2]
# klabels = ["Y", "$\Gamma$", "X"]
# f2b.plot_unfolded(kbounds, klabels);"""),
        ])

        return self._write_nb_nbpath(nb, nbpath)
Exemple #18
0
    def test_kpointlist(self):
        """Test KpointList."""
        lattice = self.lattice

        frac_coords = [0, 0, 0, 1 / 2, 1 / 2, 1 / 2, 1 / 3, 1 / 3, 1 / 3]
        weights = [0.1, 0.2, 0.7]

        klist = KpointList(lattice, frac_coords, weights=weights)
        repr(klist)
        str(klist)

        self.serialize_with_pickle(klist, protocols=[-1])
        self.assertMSONable(klist, test_if_subclass=False)

        self.assert_equal(klist.frac_coords.flatten(), frac_coords)
        self.assert_equal(klist.get_cart_coords(),
                          np.reshape([k.cart_coords for k in klist], (-1, 3)))
        assert klist.sum_weights() == 1
        assert len(klist) == 3

        for i, kpoint in enumerate(klist):
            assert kpoint in klist
            assert klist.count(kpoint) == 1
            assert klist.find(kpoint) == i

        # Changing the weight of the Kpoint object should change the weights of klist.
        for kpoint in klist:
            kpoint.set_weight(1.0)
        assert np.all(klist.weights == 1.0)

        # Test find_closest
        iclose, kclose, dist = klist.find_closest([0, 0, 0])
        assert iclose == 0 and dist == 0.

        iclose, kclose, dist = klist.find_closest(
            Kpoint([0.001, 0.002, 0.003], klist.reciprocal_lattice))
        assert iclose == 0
        self.assert_almost_equal(dist, 0.001984943324127921)

        # Compute mapping k_index --> (k + q)_index, g0
        k2kqg = klist.get_k2kqg_map((0, 0, 0))
        assert all(ikq == ik for ik, (ikq, g0) in k2kqg.items())
        k2kqg = klist.get_k2kqg_map((1 / 2, 1 / 2, 1 / 2))
        assert len(k2kqg) == 2
        assert k2kqg[0][0] == 1 and np.all(k2kqg[0][1] == 0)
        assert k2kqg[1][0] == 0 and np.all(k2kqg[1][1] == 1)

        frac_coords = [0, 0, 0, 1 / 2, 1 / 3, 1 / 3]
        other_klist = KpointList(lattice, frac_coords)

        # Test __add__
        add_klist = klist + other_klist

        for k in itertools.chain(klist, other_klist):
            assert k in add_klist

        assert add_klist.count([0, 0, 0]) == 2

        # Remove duplicated k-points.
        add_klist = add_klist.remove_duplicated()
        assert add_klist.count([0, 0, 0]) == 1
        assert len(add_klist) == 4
        assert add_klist == add_klist.remove_duplicated()
Exemple #19
0
    def __init__(self, path):
        self.ks_bands = ElectronBands.from_file(path)
        self.nsppol = self.ks_bands.nsppol

        super(SigresReader, self).__init__(path)

        try:
            self.nomega_r = self.read_dimvalue("nomega_r")
        except self.Error:
            self.nomega_r = 0

        #self.nomega_i = self.read_dim("nomega_i")

        # Save important quantities needed to simplify the API.
        self.structure = self.read_structure()

        self.gwcalctyp = self.read_value("gwcalctyp")
        self.usepawu = self.read_value("usepawu")

        # 1) The K-points of the homogeneous mesh.
        self.ibz = self.ks_bands.kpoints

        # 2) The K-points where QPState corrections have been calculated.
        gwred_coords = self.read_redc_gwkpoints()
        self.gwkpoints = KpointList(self.structure.reciprocal_lattice, gwred_coords)

        # minbnd[nkptgw,nsppol] gives the minimum band index computed
        # Note conversion between Fortran and python convention.
        self.gwbstart_sk = self.read_value("minbnd") - 1
        self.gwbstop_sk = self.read_value("maxbnd")

        # min and Max band index for GW corrections.
        self.min_gwbstart = np.min(self.gwbstart_sk)
        self.max_gwbstart = np.max(self.gwbstart_sk)

        self.min_gwbstop = np.min(self.gwbstop_sk)
        self.max_gwbstop = np.max(self.gwbstop_sk)

        self._egw = self.read_value("egw", cmode="c")

        # Read and save important matrix elements.
        # All these arrays are dimensioned
        # vxcme(b1gw:b2gw,nkibz,nsppol*nsig_ab))
        self._vxcme = self.read_value("vxcme")
        self._sigxme = self.read_value("sigxme")

        self._hhartree = self.read_value("hhartree", cmode="c")

        self._vUme = self.read_value("vUme")
        #if self.usepawu == 0: self._vUme.fill(0.0)

        # Complex arrays
        self._sigcmee0 = self.read_value("sigcmee0", cmode="c")
        self._ze0 = self.read_value("ze0", cmode="c")

        # Frequencies for the spectral function.
        if self.has_spfunc:
            self._omega_r = self.read_value("omega_r")

            self._sigcme = self.read_value("sigcme", cmode="c")
            self._sigxcme = self.read_value("sigxcme", cmode="c")

        # Self-consistent case
        self._en_qp_diago = self.read_value("en_qp_diago")

        # <KS|QPState>
        self._eigvec_qp = self.read_value("eigvec_qp", cmode="c")
Exemple #20
0
class Fold2BlochNcfile(AbinitNcFile, Has_Header, Has_Structure,
                       Has_ElectronBands, NotebookWriter):
    """
    Netcdf file with output data produced by Fold2Bloch.

    Usage example:

    .. code-block:: python

        with Fold2BlochNcfile("foo_FOLD2BLOCH.nc") as fb:
            fb.plot_unfolded()

    .. rubric:: Inheritance Diagram
    .. inheritance-diagram:: Fold2BlochNcfile
    """
    @classmethod
    def from_wfkpath(cls,
                     wfkpath,
                     folds,
                     workdir=None,
                     manager=None,
                     mpi_procs=1,
                     verbose=0):
        """
        Run fold2bloch in workdir.

        Args:
            wfkpath:
            folds:
            workdir: Working directory of the fake task used to compute the ibz. Use None for temporary dir.
            manager: :class:`TaskManager` of the task. If None, the manager is initialized from the config file.
            mpi_procs: Number of MPI processors to use.
            verbose: Verbosity level.
        """
        # Build a simple manager to run the job in a shell subprocess
        from abipy import flowtk
        manager = flowtk.TaskManager.as_manager(manager).to_shell_manager(
            mpi_procs=mpi_procs)
        fold2bloch = flowtk.Fold2Bloch(manager=manager, verbose=verbose)

        # Create temporary directory and link to the WFK file
        import tempfile
        workdir = tempfile.mkdtemp() if workdir is None else workdir
        wfkpath = os.path.abspath(wfkpath)
        link = os.path.join(workdir, os.path.basename(wfkpath))
        os.symlink(wfkpath, link)

        # Run fold2bloch
        ncpath = fold2bloch.unfold(link, folds, workdir=workdir)

        return cls(ncpath)

    def __init__(self, filepath):
        super(Fold2BlochNcfile, self).__init__(filepath)
        self.reader = ElectronsReader(filepath)

        # Initialize the electron bands from file.
        # Spectral weights are dimensioned with `nss`
        # Fortran arrays.
        # nctkarr_t("reduced_coordinates_of_unfolded_kpoints", "dp", "number_of_reduced_dimensions, nk_unfolded")
        # nctkarr_t("unfolded_eigenvalues", "dp", "max_number_of_states, nk_unfolded, number_of_spins")
        # nctkarr_t("spectral_weights", "dp", "max_number_of_states, nk_unfolded, nsppol_times_nspinor")
        self._ebands = self.reader.read_ebands()
        self.nss = max(self.nsppol, self.nspinor)
        self.fold_matrix = self.reader.read_value("fold_matrix")

        # Compute direct lattice of the primitive cell from fold_matrix.
        if is_diagonal(self.fold_matrix):
            folds = np.diagonal(self.fold_matrix)
            self.pc_lattice = Lattice(
                (self.structure.lattice.matrix.T * (1.0 / folds)).T.copy())
        else:
            raise NotImplementedError("non diagonal fold_matrix: %s" %
                                      str(self.fold_matrix))

        # Read fold2bloch output data.
        self.uf_kfrac_coords = self.reader.read_value(
            "reduced_coordinates_of_unfolded_kpoints")
        self.uf_kpoints = KpointList(self.pc_lattice.reciprocal_lattice,
                                     self.uf_kfrac_coords)
        self.uf_nkpt = len(self.uf_kpoints)

    def __str__(self):
        return self.to_string()

    def to_string(self, verbose=0):
        """String representation."""
        lines = []
        app = lines.append

        app(marquee("File Info", mark="="))
        app(self.filestat(as_string=True))
        app("")
        app(self.structure.to_string(verbose=verbose, title="Structure"))
        app("")
        app(
            self.ebands.to_string(with_structure=False,
                                  title="Electronic Bands"))

        app("Direct lattice of the primitive cell:")
        to_s = lambda x: "%0.6f" % x
        app("abc   : " +
            " ".join([to_s(i).rjust(10) for i in self.pc_lattice.abc]))
        app("angles: " +
            " ".join([to_s(i).rjust(10) for i in self.pc_lattice.angles]))
        if is_diagonal(self.fold_matrix):
            app("Diagonal folding: %s" % (str(np.diagonal(self.fold_matrix))))
        else:
            app("Folding matrix: %s" % str(self.fold_matrix))

        if verbose:
            app(
                self.uf_kpoints.to_string(verbose=verbose,
                                          title="Unfolded k-points"))

        if verbose > 2:
            app(self.hdr.to_string(verbose=verbose, title="Abinit Header"))

        return "\n".join(lines)

    @property
    def ebands(self):
        """|ElectronBands| object with folded band energies."""
        return self._ebands

    @property
    def structure(self):
        """|Structure| object defining the supercell."""
        return self.ebands.structure

    def close(self):
        """Close the file."""
        self.reader.close()

    @lazy_property
    def params(self):
        """:class:`OrderedDict` with parameters that might be subject to convergence studies."""
        od = self.get_ebands_params()
        return od

    @lazy_property
    def uf_eigens(self):
        """[nsppol, nk_unfolded, nband] |numpy-array| with unfolded eigenvalues in eV."""
        # nctkarr_t("unfolded_eigenvalues", "dp", "max_number_of_states, nk_unfolded, number_of_spins")
        return self.reader.read_value("unfolded_eigenvalues") * units.Ha_to_eV

    @lazy_property
    def uf_weights(self):
        """[nss, nk_unfolded, nband] array with spectral weights. nss = max(nspinor, nsppol)."""
        # nctkarr_t("spectral_weights", "dp", "max_number_of_states, nk_unfolded, nsppol_times_nspinor")
        return self.reader.read_value("spectral_weights")

    def get_spectral_functions(self, step=0.01, width=0.02):
        """
        Args:
            step: Energy step (eV) of the linear mesh.
            width: Standard deviation (eV) of the gaussian.

        Return:
            mesh, sfw, int_sfw
        """
        # Compute linear mesh.
        epad = 3.0 * width
        e_min = self.uf_eigens.min() - epad
        e_max = self.uf_eigens.max() + epad
        nw = int(1 + (e_max - e_min) / step)
        mesh, step = np.linspace(e_min,
                                 e_max,
                                 num=nw,
                                 endpoint=True,
                                 retstep=True)

        sfw = np.zeros((self.nss, self.uf_nkpt, nw))
        for spin in range(self.nss):
            for ik in range(self.uf_nkpt):
                for band in range(self.nband):
                    e = self.uf_eigens[spin, ik, band]
                    sfw[spin,
                        ik] += self.uf_weights[spin, ik, band] * gaussian(
                            mesh, width, center=e)

        from scipy.integrate import cumtrapz
        int_sfw = cumtrapz(sfw, x=mesh, initial=0.0)

        return dict2namedtuple(mesh=mesh, sfw=sfw, int_sfw=int_sfw)

    @add_fig_kwargs
    def plot_unfolded(self,
                      kbounds,
                      klabels,
                      ylims=None,
                      dist_tol=1e-12,
                      verbose=0,
                      colormap="afmhot",
                      facecolor="black",
                      ax=None,
                      fontsize=12,
                      **kwargs):
        r"""
        Plot unfolded band structure with spectral weights.

        Args:
            klabels: dictionary whose keys are tuple with the reduced coordinates of the k-points.
                The values are the labels. e.g. ``klabels = {(0.0,0.0,0.0): "$\Gamma$", (0.5,0,0): "L"}``.
            ylims: Set the data limits for the y-axis. Accept tuple e.g. ``(left, right)``
                or scalar e.g. ``left``. If left (right) is None, default values are used
            dist_tol: A point is considered to be on the path if its distance from the line
                is less than dist_tol.
            verbose: Verbosity level.
            colormap: Have a look at the colormaps here and decide which one you like:
                http://matplotlib.sourceforge.net/examples/pylab_examples/show_colormaps.html
            facecolor:
            ax: |matplotlib-Axes| or None if a new figure should be created.
            fontsize: Legend and title fontsize.

        Returns: |matplotlib-Figure|
	"""
        cart_bounds = [
            self.pc_lattice.reciprocal_lattice.get_cartesian_coords(c)
            for c in np.reshape(kbounds, (-1, 3))
        ]
        uf_cart = self.uf_kpoints.get_cart_coords()

        p = find_points_along_path(cart_bounds, uf_cart, dist_tol)
        if len(p.ikfound) == 0:
            cprint(
                "Warning: find_points_along_path returned zero points along the path. Try to increase dist_tol.",
                "yellow")
            return None
        if verbose:
            uf_frac_coords = np.reshape(
                [k.frac_coords for k in self.uf_kpoints], (-1, 3))
            fcoords = uf_frac_coords[p.ikfound]
            print("Found %d points along input k-path" % len(fcoords))
            print("k-points of path in reduced coordinates:")
            print(fcoords)

        fact = 8.0
        e0 = self.ebands.fermie
        ax, fig, plt = get_ax_fig_plt(ax=ax)
        ax.set_facecolor(facecolor)

        xs = np.tile(p.dist_list, self.nband)
        marker_spin = {0: "^", 1: "v"} if self.nss == 2 else {0: "o"}
        for spin in range(self.nss):
            ys = self.uf_eigens[spin, p.ikfound, :] - e0
            ws = self.uf_weights[spin, p.ikfound, :]
            s = ax.scatter(xs,
                           ys.T,
                           s=fact * ws.T,
                           c=ws.T,
                           marker=marker_spin[spin],
                           label=None if self.nss == 1 else "spin %s" % spin,
                           linewidth=1,
                           edgecolors='none',
                           cmap=plt.get_cmap(colormap))
            plt.colorbar(s, ax=ax, orientation='vertical')

        ax.set_xticks(p.path_ticks, minor=False)
        ax.set_xticklabels(klabels,
                           fontdict=None,
                           minor=False,
                           size=kwargs.pop("klabel_size", "large"))
        ax.grid(True)
        ax.set_ylabel('Energy (eV)')
        set_axlims(ax, ylims, "y")
        if self.nss == 2: ax.legend(loc="best", fontsize=fontsize, shadow=True)

        return fig

    def yield_figs(self, **kwargs):  # pragma: no cover
        """
        This function *generates* a predefined list of matplotlib figures with minimal input from the user.
        """
        print("TODO: Add call to plot_unfolded")
        yield self.ebands.plot(show=False)

    def write_notebook(self, nbpath=None):
        """
        Write a jupyter_ notebook to nbpath. If `nbpath` is None, a temporay file in the current
        working directory is created. Return path to the notebook.
        """
        nbformat, nbv, nb = self.get_nbformat_nbv_nb(title=None)

        nb.cells.extend([
            nbv.new_code_cell("f2b = abilab.abiopen('%s')" % self.filepath),
            nbv.new_code_cell("print(f2b)"),
            nbv.new_code_cell("f2b.ebands.plot();"),
            nbv.new_code_cell("#f2b.unfolded_kpoints.plot();"),
            nbv.new_code_cell(r"""\
# kbounds = [0, 1/2, 0, 0, 0, 0, 0, 0, 1/2]
# klabels = ["Y", "$\Gamma$", "X"]
# f2b.plot_unfolded(kbounds, klabels);"""),
        ])

        return self._write_nb_nbpath(nb, nbpath)
Exemple #21
0
    def __init__(self, path):
        self.ks_bands = ElectronBands.from_file(path)
        self.nsppol = self.ks_bands.nsppol

        super(SigresReader, self).__init__(path)

        try:
            self.nomega_r = self.read_dimvalue("nomega_r")
        except self.Error:
            self.nomega_r = 0

        #self.nomega_i = self.read_dim("nomega_i")

        # Save important quantities needed to simplify the API.
        self.structure = self.read_structure()

        self.gwcalctyp = self.read_value("gwcalctyp")
        self.usepawu = self.read_value("usepawu")

        # 1) The K-points of the homogeneous mesh.
        self.ibz = self.ks_bands.kpoints

        # 2) The K-points where QPState corrections have been calculated.
        gwred_coords = self.read_redc_gwkpoints()
        self.gwkpoints = KpointList(self.structure.reciprocal_lattice, gwred_coords)

        # minbnd[nkptgw,nsppol] gives the minimum band index computed
        # Note conversion between Fortran and python convention.
        self.gwbstart_sk = self.read_value("minbnd") - 1
        self.gwbstop_sk = self.read_value("maxbnd")

        # min and Max band index for GW corrections.
        self.min_gwbstart = np.min(self.gwbstart_sk)
        self.max_gwbstart = np.max(self.gwbstart_sk)

        self.min_gwbstop = np.min(self.gwbstop_sk)
        self.max_gwbstop = np.max(self.gwbstop_sk)

        self._egw = self.read_value("egw", cmode="c")

        # Read and save important matrix elements.
        # All these arrays are dimensioned
        # vxcme(b1gw:b2gw,nkibz,nsppol*nsig_ab))
        self._vxcme = self.read_value("vxcme")
        self._sigxme = self.read_value("sigxme")

        self._hhartree = self.read_value("hhartree", cmode="c")

        self._vUme = self.read_value("vUme")
        #if self.usepawu == 0: self._vUme.fill(0.0)

        # Complex arrays
        self._sigcmee0 = self.read_value("sigcmee0", cmode="c")
        self._ze0 = self.read_value("ze0", cmode="c")

        # Frequencies for the spectral function.
        if self.has_spfunc:
            self._omega_r = self.read_value("omega_r")

            self._sigcme = self.read_value("sigcme", cmode="c")
            self._sigxcme = self.read_value("sigxcme", cmode="c")

        # Self-consistent case
        self._en_qp_diago = self.read_value("en_qp_diago")

        # <KS|QPState>
        self._eigvec_qp = self.read_value("eigvec_qp", cmode="c")
Exemple #22
0
class ScrReader(ETSF_Reader):
    """
    This object reads the results stored in the SCR (Screening) file produced by ABINIT.
    It provides helper functions to access the most important quantities.

    double inverse_dielectric_function(number_of_qpoints_dielectric_function,
    number_of_frequencies_dielectric_function, number_of_spins, number_of_spins,
    number_of_coefficients_dielectric_function, number_of_coefficients_dielectric_function, complex)

    .. rubric:: Inheritance Diagram
    .. inheritance-diagram:: ScrReader
    """
    def __init__(self, filepath):
        super(ScrReader, self).__init__(filepath)

        # Read and store important quantities.
        self.structure = self.read_structure()
        qfrac_coords = self.read_value("qpoints_dielectric_function")
        self.kpoints = KpointList(self.structure.reciprocal_lattice,
                                  qfrac_coords)
        self.wpoints = self.read_value("frequencies_dielectric_function",
                                       cmode="c")
        self.ng = self.read_dimvalue(
            "number_of_coefficients_dielectric_function")

        # Find number of real/imaginary frequencies.
        self.nw = len(self.wpoints)
        self.nrew = self.nw
        self.nimw = 0
        for i, w in enumerate(self.wpoints):
            if np.iscomplex(w):
                self.nrew = i
                break

        self.nimw = self.nw - self.nrew
        if self.nimw and not np.all(np.iscomplex(
                self.wpoints[self.nrew + 1:])):
            raise ValueError(
                "wpoints should contained real points packed in the first positions\n"
                "followed by imaginary points but got: %s" % str(self.wpoints))

        # Define self.netcdf_name from the data available on file.
        nfound = 0
        netcdf_names = [
            "polarizability", "dielectric_function",
            "inverse_dielectric_function"
        ]
        for tryname in netcdf_names:
            if tryname in self.rootgrp.variables:
                self.netcdf_name = tryname
                nfound += 1

        if nfound == 0:
            raise RuntimeError("Cannot find `%s` in netcdf file" %
                               str(netcdf_names))
        if nfound > 1:
            raise RuntimeError(
                "Find multiple netcdf arrays (%s) in netcdf file!" %
                str(netcdf_names))

    def read_params(self):
        """
        Read the most important parameters used to compute the screening i.e.
        the parameters that may be subject to convergence studies.

        Returns:
            |AttrDict| a dictionary whose keys can be accessed with the dot notation i.e. ``d.key``.
        """
        # TODO: ecuteps is missing!
        keys = [
            "ikxc", "inclvkb", "gwcalctyp", "nbands_used", "npwwfn_used",
            "spmeth", "test_type", "tordering", "awtr", "icutcoul", "gwcomp",
            "gwgamma", "mbpt_sciss", "spsmear", "zcut", "gwencomp"
        ]

        def convert(arr):
            """Convert to scalar if size == 1"""
            return np.asscalar(arr) if arr.size == 1 else arr

        return AttrDict({k: convert(self.read_value(k)) for k in keys})

    def read_emacro_lf(self, kpoint=(0, 0, 0)):
        """
        Read the macroscopic dielectric function *with* local field effects 1 / em1_{0,0)(kpoint, omega).

        Return: |Function1D| object.
        """
        if self.netcdf_name == "inverse_dielectric_function":
            em1 = self.read_wslice(kpoint, ig1=0, ig2=0)
            emacro = 1 / em1[:self.nrew]
        else:
            raise NotImplementedError(
                "emacro_lf with netcdf != InverseDielectricFunction")

        return Function1D(np.real(self.wpoints[:self.nrew]).copy(), emacro)

    def read_emacro_nlf(self, kpoint=(0, 0, 0)):
        """
        Read the macroscopic dielectric function *without* local field effects e_{0,0)(kpoint, omega).

        Return: |Function1D|

        .. warning::

            This function performs the inversion of e-1 to get e.
            that can be quite expensive and memory demanding for large matrices!
        """
        if self.netcdf_name == "inverse_dielectric_function":
            em1 = self.read_wggmat(kpoint)
            e = np.linalg.inv(em1.wggmat[:self.nrew, :, :])
        else:
            raise NotImplementedError(
                "emacro_nlf with netcdf != InverseDielectricFunction")

        return Function1D(np.real(self.wpoints[:self.nrew]).copy(), e[:, 0, 0])

    def read_eelf(self, kpoint=(0, 0, 0)):
        """
        Read electron energy loss function

            - Im(1/ emacro)

        Return: |Function1D| object.
        """
        # eelf = -Im(1 / eM)
        emacro_lf = self.read_emacro_lf(kpoint=kpoint)
        #emacro_lf = self.read_emacro_nlf(kpoint=kpoint)
        values = (-1 / emacro_lf.values).imag

        return Function1D(emacro_lf.mesh.copy(), values)

    def read_wggmat(self, kpoint, spin1=0, spin2=0, cls=None):
        """
        Read data at the given k-point and return an instance of ``cls`` where
        ``cls`` is a subclass of :class:`_AwggMatrix`
        """
        cls = _AwggMatrix.class_from_netcdf_name(
            self.netcdf_name) if cls is None else cls

        var = self.rootgrp.variables[
            "reduced_coordinates_plane_waves_dielectric_function"]
        # Use ik=0 because the basis set is not k-dependent.
        ik0 = 0
        gvecs = var[ik0, :]
        #print("gvecs", gvecs)

        kpoint, ik = self.find_kpoint_fileindex(kpoint)

        # FIXME ecuteps is missing
        # TODO: Gpshere.find is very slow if we don't take advantage of shells
        ecuteps = 2
        gsphere = GSphere(ecuteps, self.structure.reciprocal_lattice, kpoint,
                          gvecs)

        # Exchange spin due to F --> C
        values = self.rootgrp.variables[self.netcdf_name][ik, :, spin2,
                                                          spin1, :, :, :]
        wggmat = values[:, :, :, 0] + 1j * values[:, :, :, 1]

        return cls(self.wpoints, gsphere, wggmat, inord="F")

    def find_kpoint_fileindex(self, kpoint):
        """
        Returns the k-point and the index of the k-point in the netcdf file.
        Accepts |Kpoint| instance or integer.
        """
        if duck.is_intlike(kpoint):
            ik = int(kpoint)
        else:
            ik = self.kpoints.index(kpoint)

        return self.kpoints[ik], ik

    def read_wslice(self, kpoint, ig1=0, ig2=0, spin1=0, spin2=0):
        """Read slice along the frequency dimension."""
        kpoint, ik = self.find_kpoint_fileindex(kpoint)
        var = self.rootgrp.variables[self.netcdf_name]
        values = var[ik, :, spin2, spin1, ig2,
                     ig1, :]  # Exchange G indices F --> C

        return values[:, 0] + 1j * values[:, 1]
Exemple #23
0
class ScrReader(ETSF_Reader):
    """
    This object reads the results stored in the SCR (Screening) file produced by ABINIT.
    It provides helper functions to access the most important quantities.
    """
    def __init__(self, filepath):
        super(ScrReader, self).__init__(filepath)

        # Read and store important quantities.
        self.structure = self.read_structure()
        qred_coords = self.read_value("qpoints_dielectric_function")
        self.qpoints = KpointList(self.structure.reciprocal_lattice,
                                  qred_coords)
        self.wpts = self.read_value("frequencies_dielectric_function",
                                    cmode="c")

    #def read_params(self):
    #    """
    #    Read the most importan parameters used to generate the data, i.e.
    #    the parameters that may be subject to convergence studies.

    #    Returns:
    #        :class:`AttrDict` a dictionary whose keys can be accessed
    #        with the dot notation i.e. d.key.
    #    """
    #    keys = ["npwwfn_used", "nbands_used",]
    #    return AttrDict({k: self.read_value(k) for k in keys})

    def find_qpoint_fileindex(self, qpoint):
        """
        Returns the q-point and the index of in the netcdf file.
        Accepts `Kpoint` instance or integer

        Raise:
            `KpointsError` if qpoint cannot be found.
        """
        if isinstance(qpoint, int):
            iq = qpoint
        else:
            iq = self.qpoints.index(qpoint)

        return self.qpoints[iq], iq

    def read_wggfunc(self, qpoint, cls):
        """
        Read data at the given q-point and return an instance
        of `cls` where `cls` is a subclass of `WGGFunction`
        """
        qpoint, iq = self.find_qpoint_fileindex(qpoint)
        # TODO: I don't remember how to slice in python-netcdf
        # ecuteps
        all_gvecs = self.read_value(
            "reduced_coordinates_plane_waves_dielectric_function")
        ecuteps = 2
        # TODO: Gpshere.find is very slow if we don't take advantage of shells
        gsphere = GSphere(ecuteps, self.structure.reciprocal_lattice, qpoint,
                          all_gvecs[iq])

        full_wggmat = self.read_value(cls.etsf_name, cmode="c")
        wggmat = full_wggmat[iq]

        return cls(qpoint, self.wpts, gsphere, wggmat, inord="F")
Exemple #24
0
class ScrReader(ETSF_Reader):
    """
    This object reads the results stored in the SCR (Screening) file produced by ABINIT.
    It provides helper functions to access the most important quantities.

    double inverse_dielectric_function(number_of_qpoints_dielectric_function,
    number_of_frequencies_dielectric_function, number_of_spins, number_of_spins,
    number_of_coefficients_dielectric_function, number_of_coefficients_dielectric_function, complex)

    .. rubric:: Inheritance Diagram
    .. inheritance-diagram:: ScrReader
    """
    def __init__(self, filepath):
        super(ScrReader, self).__init__(filepath)

        # Read and store important quantities.
        self.structure = self.read_structure()
        qfrac_coords = self.read_value("qpoints_dielectric_function")
        self.kpoints = KpointList(self.structure.reciprocal_lattice, qfrac_coords)
        self.wpoints = self.read_value("frequencies_dielectric_function", cmode="c")
        self.ng = self.read_dimvalue("number_of_coefficients_dielectric_function")

        # Find number of real/imaginary frequencies.
        self.nw = len(self.wpoints)
        self.nrew = self.nw
        self.nimw = 0
        for i, w in enumerate(self.wpoints):
            if np.iscomplex(w):
                self.nrew = i
                break

        self.nimw = self.nw - self.nrew
        if self.nimw and not np.all(np.iscomplex(self.wpoints[self.nrew+1:])):
            raise ValueError("wpoints should contained real points packed in the first positions\n"
                             "followed by imaginary points but got: %s" % str(self.wpoints))

        # Define self.netcdf_name from the data available on file.
        nfound = 0
        netcdf_names = ["polarizability", "dielectric_function", "inverse_dielectric_function"]
        for tryname in netcdf_names:
            if tryname in self.rootgrp.variables:
                self.netcdf_name = tryname
                nfound += 1

        if nfound == 0:
            raise RuntimeError("Cannot find `%s` in netcdf file" % str(netcdf_names))
        if nfound > 1:
            raise RuntimeError("Find multiple netcdf arrays (%s) in netcdf file!" % str(netcdf_names))

    def read_params(self):
        """
        Read the most important parameters used to compute the screening i.e.
        the parameters that may be subject to convergence studies.

        Returns:
            |AttrDict| a dictionary whose keys can be accessed with the dot notation i.e. ``d.key``.
        """
        # TODO: ecuteps is missing!
        keys = ["ikxc", "inclvkb", "gwcalctyp", "nbands_used", "npwwfn_used",
                "spmeth", "test_type", "tordering", "awtr", "icutcoul", "gwcomp",
                "gwgamma", "mbpt_sciss", "spsmear", "zcut", "gwencomp"]

        def convert(arr):
            """Convert to scalar if size == 1"""
            return np.asscalar(arr) if arr.size == 1 else arr

        return AttrDict({k: convert(self.read_value(k)) for k in keys})

    def read_emacro_lf(self, kpoint=(0, 0, 0)):
        """
        Read the macroscopic dielectric function *with* local field effects 1 / em1_{0,0)(kpoint, omega).

        Return: |Function1D| object.
        """
        if self.netcdf_name == "inverse_dielectric_function":
            em1 = self.read_wslice(kpoint, ig1=0, ig2=0)
            emacro = 1 / em1[:self.nrew]
        else:
            raise NotImplementedError("emacro_lf with netcdf != InverseDielectricFunction")

        return Function1D(np.real(self.wpoints[:self.nrew]).copy(), emacro)

    def read_emacro_nlf(self, kpoint=(0, 0, 0)):
        """
        Read the macroscopic dielectric function *without* local field effects e_{0,0)(kpoint, omega).

        Return: |Function1D|

        .. warning::

            This function performs the inversion of e-1 to get e.
            that can be quite expensive and memory demanding for large matrices!
        """
        if self.netcdf_name == "inverse_dielectric_function":
            em1 = self.read_wggmat(kpoint)
            e = np.linalg.inv(em1.wggmat[:self.nrew, :, :])
        else:
            raise NotImplementedError("emacro_nlf with netcdf != InverseDielectricFunction")

        return Function1D(np.real(self.wpoints[:self.nrew]).copy(), e[:, 0, 0])

    def read_eelf(self, kpoint=(0, 0, 0)):
        """
        Read electron energy loss function

            - Im(1/ emacro)

        Return: |Function1D| object.
        """
        # eelf = -Im(1 / eM)
        emacro_lf = self.read_emacro_lf(kpoint=kpoint)
        #emacro_lf = self.read_emacro_nlf(kpoint=kpoint)
        values  = (-1 / emacro_lf.values).imag

        return Function1D(emacro_lf.mesh.copy(), values)

    def read_wggmat(self, kpoint, spin1=0, spin2=0, cls=None):
        """
        Read data at the given k-point and return an instance of ``cls`` where
        ``cls`` is a subclass of :class:`_AwggMatrix`
        """
        cls = _AwggMatrix.class_from_netcdf_name(self.netcdf_name) if cls is None else cls

        var = self.rootgrp.variables["reduced_coordinates_plane_waves_dielectric_function"]
        # Use ik=0 because the basis set is not k-dependent.
        ik0 = 0
        gvecs = var[ik0, :]
        #print("gvecs", gvecs)

        kpoint, ik = self.find_kpoint_fileindex(kpoint)

        # FIXME ecuteps is missing
        # TODO: Gpshere.find is very slow if we don't take advantage of shells
        ecuteps = 2
        gsphere = GSphere(ecuteps, self.structure.reciprocal_lattice, kpoint, gvecs)

        # Exchange spin due to F --> C
        values = self.rootgrp.variables[self.netcdf_name][ik, :, spin2, spin1, :, :, :]
        wggmat = values[:, :, :, 0] + 1j * values[:, :, :, 1]

        return cls(self.wpoints, gsphere, wggmat, inord="F")

    def find_kpoint_fileindex(self, kpoint):
        """
        Returns the k-point and the index of the k-point in the netcdf file.
        Accepts |Kpoint| instance or integer.
        """
        if duck.is_intlike(kpoint):
            ik = int(kpoint)
        else:
            ik = self.kpoints.index(kpoint)

        return self.kpoints[ik], ik

    def read_wslice(self, kpoint, ig1=0, ig2=0, spin1=0, spin2=0):
        """Read slice along the frequency dimension."""
        kpoint, ik = self.find_kpoint_fileindex(kpoint)
        var = self.rootgrp.variables[self.netcdf_name]
        values = var[ik, :, spin2, spin1, ig2, ig1, :]  # Exchange G indices F --> C

        return values[:, 0] + 1j * values[:, 1]
Exemple #25
0
 def qpoints(self):
     """List of q-points (ndarray)."""
     # Read the fractional coordinates and convert them to KpointList.
     return KpointList(self.structure.reciprocal_lattice,
                       frac_coords=self.read_value("qpoints"))
Exemple #26
0
class SigresReader(ETSF_Reader):
    """This object provides method to read data from the SIGRES file produced ABINIT.
    # See 70gw/m_sigma_results.F90

    # Name of the diagonal matrix elements stored in the file.
    # b1gw:b2gw,nkibz,nsppol*nsig_ab))
    #_DIAGO_MELS = [
    #    "sigxme",
    #    "vxcme",
    #    "vUme",
    #    "dsigmee0",
    #    "sigcmee0",
    #    "sigxcme",
    #    "ze0",
    #]

    integer :: b1gw,b2gw      ! min and Max gw band indeces over spin and k-points (used to dimension)
    integer :: gwcalctyp      ! Flag defining the calculation type.
    integer :: nkptgw         ! No. of points calculated
    integer :: nkibz          ! No. of irreducible k-points.
    integer :: nbnds          ! Total number of bands
    integer :: nomega_r       ! No. of real frequencies for the spectral function.
    integer :: nomega_i       ! No. of frequencies along the imaginary axis.
    integer :: nomega4sd      ! No. of real frequencies to evaluate the derivative of $\Sigma(E)$.
    integer :: nsig_ab        ! 1 if nspinor=1,4 for noncollinear case.
    integer :: nsppol         ! No. of spin polarizations.
    integer :: usepawu        ! 1 if we are using LDA+U as starting point (only for PAW)

    real(dp) :: deltae       ! Frequency step for the calculation of d\Sigma/dE
    real(dp) :: maxomega4sd  ! Max frequency around E_ks for d\Sigma/dE.
    real(dp) :: maxomega_r   ! Max frequency for spectral function.
    real(dp) :: scissor_ene  ! Scissor energy value. zero for None.

    integer,pointer :: maxbnd(:,:)
    ! maxbnd(nkptgw,nsppol)
    ! Max band index considered in GW for this k-point.

    integer,pointer :: minbnd(:,:)
    ! minbnd(nkptgw,nsppol)
    ! Min band index considered in GW for this k-point.

    real(dp),pointer :: degwgap(:,:)
    ! degwgap(nkibz,nsppol)
    ! Difference btw the QPState and the KS optical gap.

    real(dp),pointer :: egwgap(:,:)
    ! egwgap(nkibz,nsppol))
    ! QPState optical gap at each k-point and spin.

    real(dp),pointer :: en_qp_diago(:,:,:)
    ! en_qp_diago(nbnds,nkibz,nsppol))
    ! QPState energies obtained from the diagonalization of the Hermitian approximation to Sigma (QPSCGW)

    real(dp),pointer :: e0(:,:,:)
    ! e0(nbnds,nkibz,nsppol)
    ! KS eigenvalues for each band, k-point and spin. In case of self-consistent?

    real(dp),pointer :: e0gap(:,:)
    ! e0gap(nkibz,nsppol),
    ! KS gap at each k-point, for each spin.

    real(dp),pointer :: omega_r(:)
    ! omega_r(nomega_r)
    ! real frequencies used for the self energy.

    real(dp),pointer :: kptgw(:,:)
    ! kptgw(3,nkptgw)
    ! ! TODO there is a similar array in sigma_parameters
    ! List of calculated k-points.

    real(dp),pointer :: sigxme(:,:,:)
    ! sigxme(b1gw:b2gw,nkibz,nsppol*nsig_ab))
    ! Diagonal matrix elements of $\Sigma_x$ i.e $\<nks|\Sigma_x|nks\>$

    real(dp),pointer :: vxcme(:,:,:)
    ! vxcme(b1gw:b2gw,nkibz,nsppol*nsig_ab))
    ! $\<nks|v_{xc}[n_val]|nks\>$ matrix elements of vxc (valence-only contribution).

    real(dp),pointer :: vUme(:,:,:)
    ! vUme(b1gw:b2gw,nkibz,nsppol*nsig_ab))
    ! $\<nks|v_{U}|nks\>$ for LDA+U.

    complex(dpc),pointer :: degw(:,:,:)
    ! degw(b1gw:b2gw,nkibz,nsppol))
    ! Difference between the QPState and the KS energies.

    complex(dpc),pointer :: dsigmee0(:,:,:)
    ! dsigmee0(b1gw:b2gw,nkibz,nsppol*nsig_ab))
    ! Derivative of $\Sigma_c(E)$ calculated at the KS eigenvalue.

    complex(dpc),pointer :: egw(:,:,:)
    ! egw(nbnds,nkibz,nsppol))
    ! QPState energies, $\epsilon_{nks}^{QPState}$.

    complex(dpc),pointer :: eigvec_qp(:,:,:,:)
    ! eigvec_qp(nbnds,nbnds,nkibz,nsppol))
    ! Expansion of the QPState amplitude in the KS basis set.

    complex(dpc),pointer :: hhartree(:,:,:,:)
    ! hhartree(b1gw:b2gw,b1gw:b2gw,nkibz,nsppol*nsig_ab)
    ! $\<nks|T+v_H+v_{loc}+v_{nl}|mks\>$

    complex(dpc),pointer :: sigcme(:,:,:,:)
    ! sigcme(b1gw:b2gw,nkibz,nomega_r,nsppol*nsig_ab))
    ! $\<nks|\Sigma_{c}(E)|nks\>$ at each nomega_r frequency

    complex(dpc),pointer :: sigmee(:,:,:)
    ! sigmee(b1gw:b2gw,nkibz,nsppol*nsig_ab))
    ! $\Sigma_{xc}E_{KS} + (E_{QPState}- E_{KS})*dSigma/dE_KS

    complex(dpc),pointer :: sigcmee0(:,:,:)
    ! sigcmee0(b1gw:b2gw,nkibz,nsppol*nsig_ab))
    ! Diagonal mat. elements of $\Sigma_c(E)$ calculated at the KS energy $E_{KS}$

    complex(dpc),pointer :: sigcmesi(:,:,:,:)
    ! sigcmesi(b1gw:b2gw,nkibz,nomega_i,nsppol*nsig_ab))
    ! Matrix elements of $\Sigma_c$ along the imaginary axis.
    ! Only used in case of analytical continuation.

    complex(dpc),pointer :: sigcme4sd(:,:,:,:)
    ! sigcme4sd(b1gw:b2gw,nkibz,nomega4sd,nsppol*nsig_ab))
    ! Diagonal matrix elements of \Sigma_c around the zeroth order eigenvalue (usually KS).

    complex(dpc),pointer :: sigxcme(:,:,:,:)
    ! sigxme(b1gw:b2gw,nkibz,nomega_r,nsppol*nsig_ab))
    ! $\<nks|\Sigma_{xc}(E)|nks\>$ at each real frequency frequency.

    complex(dpc),pointer :: sigxcmesi(:,:,:,:)
    ! sigxcmesi(b1gw:b2gw,nkibz,nomega_i,nsppol*nsig_ab))
    ! Matrix elements of $\Sigma_{xc}$ along the imaginary axis.
    ! Only used in case of analytical continuation.

    complex(dpc),pointer :: sigxcme4sd(:,:,:,:)
    ! sigxcme4sd(b1gw:b2gw,nkibz,nomega4sd,nsppol*nsig_ab))
    ! Diagonal matrix elements of \Sigma_xc for frequencies around the zeroth order eigenvalues.

    complex(dpc),pointer :: ze0(:,:,:)
    ! ze0(b1gw:b2gw,nkibz,nsppol))
    ! renormalization factor. $(1-\dfrac{\partial\Sigma_c} {\partial E_{KS}})^{-1}$

    complex(dpc),pointer :: omega_i(:)
    ! omegasi(nomega_i)
    ! Frequencies along the imaginary axis used for the analytical continuation.

    complex(dpc),pointer :: omega4sd(:,:,:,:)
    ! omega4sd(b1gw:b2gw,nkibz,nomega4sd,nsppol).
    ! Frequencies used to evaluate the Derivative of Sigma.
    """
    def __init__(self, path):
        self.ks_bands = ElectronBands.from_file(path)
        self.nsppol = self.ks_bands.nsppol

        super(SigresReader, self).__init__(path)

        try:
            self.nomega_r = self.read_dimvalue("nomega_r")
        except self.Error:
            self.nomega_r = 0

        #self.nomega_i = self.read_dim("nomega_i")

        # Save important quantities needed to simplify the API.
        self.structure = self.read_structure()

        self.gwcalctyp = self.read_value("gwcalctyp")
        self.usepawu = self.read_value("usepawu")

        # 1) The K-points of the homogeneous mesh.
        self.ibz = self.ks_bands.kpoints

        # 2) The K-points where QPState corrections have been calculated.
        gwred_coords = self.read_redc_gwkpoints()
        self.gwkpoints = KpointList(self.structure.reciprocal_lattice, gwred_coords)

        # minbnd[nkptgw,nsppol] gives the minimum band index computed
        # Note conversion between Fortran and python convention.
        self.gwbstart_sk = self.read_value("minbnd") - 1
        self.gwbstop_sk = self.read_value("maxbnd")

        # min and Max band index for GW corrections.
        self.min_gwbstart = np.min(self.gwbstart_sk)
        self.max_gwbstart = np.max(self.gwbstart_sk)

        self.min_gwbstop = np.min(self.gwbstop_sk)
        self.max_gwbstop = np.max(self.gwbstop_sk)

        self._egw = self.read_value("egw", cmode="c")

        # Read and save important matrix elements.
        # All these arrays are dimensioned
        # vxcme(b1gw:b2gw,nkibz,nsppol*nsig_ab))
        self._vxcme = self.read_value("vxcme")
        self._sigxme = self.read_value("sigxme")

        self._hhartree = self.read_value("hhartree", cmode="c")

        self._vUme = self.read_value("vUme")
        #if self.usepawu == 0: self._vUme.fill(0.0)

        # Complex arrays
        self._sigcmee0 = self.read_value("sigcmee0", cmode="c")
        self._ze0 = self.read_value("ze0", cmode="c")

        # Frequencies for the spectral function.
        if self.has_spfunc:
            self._omega_r = self.read_value("omega_r")

            self._sigcme = self.read_value("sigcme", cmode="c")
            self._sigxcme = self.read_value("sigxcme", cmode="c")

        # Self-consistent case
        self._en_qp_diago = self.read_value("en_qp_diago")

        # <KS|QPState>
        self._eigvec_qp = self.read_value("eigvec_qp", cmode="c")

        #self._mlda_to_qp

    #def is_selfconsistent(self, mode):
    #    return self.gwcalctyp

    @property
    def has_spfunc(self):
        """True if self contains the spectral function."""
        return self.nomega_r

    def kpt2fileindex(self, kpoint):
        """
        Helper function that returns the index of kpoint in the netcdf file.
        Accepts `Kpoint` instance of integer

        Raise:
            `KpointsError` if kpoint cannot be found.

        .. note::

            This function is needed since arrays in the netcdf file are dimensioned
            with the total number of k-points in the IBZ.
        """
        if isinstance(kpoint, int):
            kpoint = self.gwkpoints[kpoint]

        try:
            return self.ibz.index(kpoint)
        except:
            raise

    def gwkpt2seqindex(self, gwkpoint):
        """
        This function returns the index of the GW k-point in (0:nkptgw)
        Used to access data in the arrays that are dimensioned [0:nkptgw] e.g. minbnd.
        """
        if isinstance(gwkpoint, int):
            return gwkpoint
        else:
            return self.gwkpoints.index(gwkpoint)

    def read_redc_gwkpoints(self):
        return self.read_value("kptgw")

    def read_allqps(self):
        qps_spin = self.nsppol * [None]

        for spin in range(self.nsppol):
            qps = []
            for gwkpoint in self.gwkpoints:
                ik = self.gwkpt2seqindex(gwkpoint)
                bands = range(self.gwbstart_sk[spin,ik], self.gwbstop_sk[spin,ik])
                for band in bands:
                    qps.append(self.read_qp(spin, gwkpoint, band))

            qps_spin[spin] = QPList(qps)

        return tuple(qps_spin)

    def read_qplist_sk(self, spin, kpoint):
        ik = self.gwkpt2seqindex(kpoint)
        bstart, bstop = self.gwbstart_sk[spin, ik], self.gwbstop_sk[spin, ik]

        return QPList([self.read_qp(spin, kpoint, band) for band in range(bstart, bstop)])

    #def read_qpene(self, spin, kpoint, band)

    def read_qpenes(self):
        return self._egw[:, :, :]

    def read_qp(self, spin, kpoint, band):
        ik_file = self.kpt2fileindex(kpoint)
        ib_file = band - self.gwbstart_sk[spin, self.gwkpt2seqindex(kpoint)]

        return QPState(
            spin=spin,
            kpoint=kpoint,
            band=band,
            e0=self.read_e0(spin, ik_file, band),
            qpe=self._egw[spin, ik_file, band],
            qpe_diago=self._en_qp_diago[spin, ik_file, band],
            vxcme=self._vxcme[spin, ik_file, ib_file],
            sigxme=self._sigxme[spin, ik_file, ib_file],
            sigcmee0=self._sigcmee0[spin, ik_file, ib_file],
            vUme=self._vUme[spin, ik_file, ib_file],
            ze0=self._ze0[spin, ik_file, ib_file],
        )

    def read_qpgaps(self):
        """Read the QP gaps. Returns ndarray with shape [nsppol, nkibz] in eV"""
        return self.read_value("egwgap")

    def read_e0(self, spin, kfile, band):
        return self.ks_bands.eigens[spin, kfile, band]

    def read_sigmaw(self, spin, kpoint, band):
        """Returns the real and the imaginary part of the self energy."""
        if not self.has_spfunc:
            raise ValueError("%s does not contain spectral function data" % self.path)

        ik = self.kpt2fileindex(kpoint)

        return self._omega_r, self._sigxcme[spin,:,ik,band]

    def read_spfunc(self, spin, kpoint, band):
        """
        Returns the spectral function.

         one/pi * ABS(AIMAG(Sr%sigcme(ib,ikibz,io,is))) /
         ( (REAL(Sr%omega_r(io)-Sr%hhartree(ib,ib,ikibz,is)-Sr%sigxcme(ib,ikibz,io,is)))**2 &
        +(AIMAG(Sr%sigcme(ib,ikibz,io,is)))**2) / Ha_eV,&
        """
        if not self.has_spfunc:
            raise ValueError("%s does not contain spectral function data" % self.path)

        ik = self.kpt2fileindex(kpoint)
        ib = band - self.gwbstart_sk[spin, self.gwkpt2seqindex(kpoint)]

        aim_sigc = np.abs(self._sigcme[spin,:,ik,ib].imag)

        den = np.zeros(self.nomega_r)
        for (io, omega) in enumerate(self._omega_r):
            den[io] = (omega - self._hhartree[spin,ik,ib,ib].real - self._sigxcme[spin,io,ik,ib].real) ** 2 + \
                self._sigcme[spin,io,ik,ib].imag ** 2

        return self._omega_r, 1./np.pi * (aim_sigc/den)

    def read_eigvec_qp(self, spin, kpoint, band=None):
        """
        Returns <KS|QPState> for the given spin, kpoint and band. If band is None, <KS_b|QP_{b'}> is returned.
        """
        ik = self.kpt2fileindex(kpoint)
        if band is not None:
            return self._eigvec_qp[spin,ik,:,band]
        else:
            return self._eigvec_qp[spin,ik,:,:]

    def read_params(self):
        """
        Read the parameters of the calculation. 
        Returns :class:`AttrDict` instance with the value of the parameters.
        """
        param_names = [
            "ecutwfn",
            "ecuteps",
            "ecutsigx",
            "scr_nband",
            "sigma_nband",
            "gwcalctyp",
            "scissor_ene",
        ]

        params = AttrDict()
        for pname in param_names:
            params[pname] = self.read_value(pname, default=None)
        
        # Other quantities that might be subject to convergence studies.
        params["nkibz"] = len(self.ibz)

        return params

    def print_qps(self, spin=None, kpoints=None, bands=None, fmt=None, stream=sys.stdout):
        """
        Args:
            spin: Spin index, if None all spins are considered
            kpoints: List of k-points to select. Default: all kpoints
            bands: List of bands to select. Default is all bands
            fmt: Format string passe to `to_strdict`
            stream: file-like object.

        Returns
            List of tables.
        """
        spins = range(self.nsppol) if spin is None else [spin]
        kpoints = self.gwkpoints if kpoints is None else [kpoints]
        if bands is not None: bands = [bands]

        header = QPState.get_fields(exclude=["spin", "kpoint"])
        tables = []

        for spin in spins:
            for kpoint in kpoints:
                table_sk = PrettyTable(header)
                if bands is None:
                    ik = self.gwkpt2seqindex(kpoint)
                    bands = range(self.gwbstart_sk[spin,ik], self.gwbstop_sk[spin,ik])

                for band in bands:
                    qp = self.read_qp(spin, kpoint, band)
                    d = qp.to_strdict(fmt=fmt)
                    table_sk.add_row([d[k] for k in header])

                stream.write("\nkpoint: %s, spin: %s, energy units: eV (NB: bands start from zero)\n" % (kpoint, spin))
                print(table_sk, file=stream)
                stream.write("\n")

                # Add it to tables.
                tables.append(table_sk)

        return tables