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 __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 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()
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 __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))
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")
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))
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())
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())
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())
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()
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 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())
def qpoints(self): return KpointList(self.structure.reciprocal_lattice, frac_coords=self.reader.read_value("qpts"))
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
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)
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()
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")
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)
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]
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")
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]
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"))
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