def interpolate_ebands(self, vertices_names=None, line_density=20, ngkpt=None, shiftk=(0, 0, 0), kpoints=None): """ Build new |ElectronBands| object by interpolating the KS Hamiltonian with Wannier functions. Supports k-path via (vertices_names, line_density), IBZ mesh defined by ngkpt and shiftk or input list of kpoints. Args: vertices_names: Used to specify the k-path for the interpolated QP band structure List of tuple, each tuple is of the form (kfrac_coords, kname) where kfrac_coords are the reduced coordinates of the k-point and kname is a string with the name of the k-point. Each point represents a vertex of the k-path. ``line_density`` defines the density of the sampling. If None, the k-path is automatically generated according to the point group of the system. line_density: Number of points in the smallest segment of the k-path. Used with ``vertices_names``. ngkpt: Mesh divisions. Used if bands should be interpolated in the IBZ. shiftk: Shifts for k-meshs. Used with ngkpt. kpoints: |KpointList| object taken e.g from a previous ElectronBands. Has precedence over vertices_names and line_density. Returns: |ElectronBands| object with Wannier-interpolated energies. """ # Need KpointList object. if kpoints is None: if ngkpt is not None: # IBZ sampling kpoints = IrredZone.from_ngkpt(self.structure, ngkpt, shiftk, kptopt=1, verbose=0) else: # K-Path if vertices_names is None: vertices_names = [(k.frac_coords, k.name) for k in self.structure.hsym_kpoints] kpoints = Kpath.from_vertices_and_names(self.structure, vertices_names, line_density=line_density) nk = len(kpoints) eigens = np.zeros((self.nsppol, nk, self.mwan)) # Interpolate Hamiltonian for each kpoint and spin. start = time.time() write_warning = True for spin in range(self.nsppol): num_wan = self.nwan_spin[spin] for ik, kpt in enumerate(kpoints): oeigs = self.hwan.eval_sk(spin, kpt.frac_coords) eigens[spin, ik, :num_wan] = oeigs if num_wan < self.mwan: # May have different number of wannier functions if nsppol == 2. # Here I use the last value to fill eigens matrix (not very clean but oh well). eigens[spin, ik, num_wan:self.mwan] = oeigs[-1] if write_warning: cprint("Different number of wannier functions for spin. Filling last bands with oeigs[-1]", "yellow") write_warning = False print("Interpolation completed in %.3f [s]" % (time.time() - start)) occfacts = np.zeros_like(eigens) return ElectronBands(self.structure, kpoints, eigens, self.ebands.fermie, occfacts, self.ebands.nelect, self.nspinor, self.nspden, smearing=self.ebands.smearing)
def get_interpolated_ebands_plotter(self, vertices_names=None, knames=None, line_density=20, ngkpt=None, shiftk=(0, 0, 0), kpoints=None, **kwargs): """ Args: vertices_names: Used to specify the k-path for the interpolated QP band structure It's a list of tuple, each tuple is of the form (kfrac_coords, kname) where kfrac_coords are the reduced coordinates of the k-point and kname is a string with the name of the k-point. Each point represents a vertex of the k-path. ``line_density`` defines the density of the sampling. If None, the k-path is automatically generated according to the point group of the system. knames: List of strings with the k-point labels defining the k-path. It has precedence over `vertices_names`. line_density: Number of points in the smallest segment of the k-path. Used with ``vertices_names``. ngkpt: Mesh divisions. Used if bands should be interpolated in the IBZ. shiftk: Shifts for k-meshs. Used with ngkpt. kpoints: |KpointList| object taken e.g from a previous ElectronBands. Has precedence over vertices_names and line_density. Return: |ElectronBandsPlotter| object. """ diff_str = self.has_different_structures() if diff_str: cprint(diff_str, "yellow") # Need KpointList object (assume same structures in Robot) nc0 = self.abifiles[0] if kpoints is None: if ngkpt is not None: # IBZ sampling kpoints = IrredZone.from_ngkpt(nc0.structure, ngkpt, shiftk, kptopt=1, verbose=0) else: # K-Path if knames is not None: kpoints = Kpath.from_names(nc0.structure, knames, line_density=line_density) else: if vertices_names is None: vertices_names = [(k.frac_coords, k.name) for k in nc0.structure.hsym_kpoints] kpoints = Kpath.from_vertices_and_names(nc0.structure, vertices_names, line_density=line_density) plotter = ElectronBandsPlotter() for label, abiwan in self.items(): plotter.add_ebands(label, abiwan.interpolate_ebands(kpoints=kpoints)) return plotter
def test_kpath_api(self): """Testing Kpath API.""" structure = abilab.Structure.as_structure(abidata.cif_file("si.cif")) knames = ["G", "X", "L", "G"] kpath = Kpath.from_names(structure, knames, line_density=5) repr(kpath); str(kpath) assert kpath.to_string(verbose=2, title="Kpath") assert not kpath.is_ibz and kpath.is_path assert kpath[0].is_gamma and kpath[-1].is_gamma #assert len(kpath.ds) == len(self) - 1 #assert kpath.ksampling.kptopt == 1 #self.assert_equal(kpath.ksampling.mpdivs, [4, 4, 4]) assert len(kpath.ds) == len(kpath) - 1 assert len(kpath.versors) == len(kpath) - 1 assert len(kpath.lines) == len(knames) - 1 self.assert_almost_equal(kpath.frac_bounds, structure.get_kcoords_from_names(knames)) self.assert_almost_equal(kpath.cart_bounds, structure.get_kcoords_from_names(knames, cart_coords=True)) r = kpath.find_points_along_path(kpath.get_cart_coords()) assert len(r.ikfound) == len(kpath) self.assert_equal(r.ikfound, [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0])
def interpolate_ebands(self, vertices_names=None, line_density=20, ngkpt=None, shiftk=(0, 0, 0), kpoints=None): """ Build new |ElectronBands| object by interpolating the KS Hamiltonian with Wannier functions. Supports k-path via (vertices_names, line_density), IBZ mesh defined by ngkpt and shiftk or input list of kpoints. Args: vertices_names: Used to specify the k-path for the interpolated QP band structure List of tuple, each tuple is of the form (kfrac_coords, kname) where kfrac_coords are the reduced coordinates of the k-point and kname is a string with the name of the k-point. Each point represents a vertex of the k-path. ``line_density`` defines the density of the sampling. If None, the k-path is automatically generated according to the point group of the system. line_density: Number of points in the smallest segment of the k-path. Used with ``vertices_names``. ngkpt: Mesh divisions. Used if bands should be interpolated in the IBZ. shiftk: Shifts for k-meshs. Used with ngkpt. kpoints: |KpointList| object taken e.g from a previous ElectronBands. Has precedence over vertices_names and line_density. Returns: |ElectronBands| object with Wannier-interpolated energies. """ # Need KpointList object. if kpoints is None: if ngkpt is not None: # IBZ sampling kpoints = IrredZone.from_ngkpt(self.structure, ngkpt, shiftk, kptopt=1, verbose=0) else: # K-Path if vertices_names is None: vertices_names = [(k.frac_coords, k.name) for k in self.structure.hsym_kpoints] kpoints = Kpath.from_vertices_and_names( self.structure, vertices_names, line_density=line_density) nk = len(kpoints) eigens = np.zeros((self.nsppol, nk, self.mwan)) # Interpolate Hamiltonian for each kpoint and spin. start = time.time() write_warning = True for spin in range(self.nsppol): num_wan = self.nwan_spin[spin] for ik, kpt in enumerate(kpoints): oeigs = self.hwan.eval_sk(spin, kpt.frac_coords) eigens[spin, ik, :num_wan] = oeigs if num_wan < self.mwan: # May have different number of wannier functions if nsppol == 2. # Here I use the last value to fill eigens matrix (not very clean but oh well). eigens[spin, ik, num_wan:self.mwan] = oeigs[-1] if write_warning: cprint( "Different number of wannier functions for spin. Filling last bands with oeigs[-1]", "yellow") write_warning = False print("Interpolation completed in %.3f [s]" % (time.time() - start)) occfacts = np.zeros_like(eigens) return ElectronBands(self.structure, kpoints, eigens, self.ebands.fermie, occfacts, self.ebands.nelect, self.nspinor, self.nspden, smearing=self.ebands.smearing)
def qpoints(self): """List of Q-points.""" frac_coords = self.reader.read_value('qpoints') return Kpath(self.structure.reciprocal_lattice, frac_coords, ksampling=None)
def test_kpath_api(self): """Testing Kpath API.""" structure = abilab.Structure.as_structure(abidata.cif_file("si.cif")) knames = ["G", "X", "L", "G"] kpath = Kpath.from_names(structure, knames, line_density=5) repr(kpath) str(kpath) assert kpath.to_string(verbose=2, title="Kpath") assert not kpath.is_ibz and kpath.is_path assert kpath[0].is_gamma and kpath[-1].is_gamma #assert len(kpath.ds) == len(self) - 1 #assert kpath.ksampling.kptopt == 1 #self.assert_equal(kpath.ksampling.mpdivs, [4, 4, 4]) assert len(kpath.ds) == len(kpath) - 1 assert len(kpath.versors) == len(kpath) - 1 assert len(kpath.lines) == len(knames) - 1 self.assert_almost_equal(kpath.frac_bounds, structure.get_kcoords_from_names(knames)) self.assert_almost_equal( kpath.cart_bounds, structure.get_kcoords_from_names(knames, cart_coords=True)) r = kpath.find_points_along_path(kpath.get_cart_coords()) assert len(r.ikfound) == len(kpath) self.assert_equal( r.ikfound, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0]) #kpath = IrredZone.from_kppa(structure, kppa=1000, shiftk=[0.5, 0.5, 0.5], kptopt=1, verbose=1) #assert not kpath.is_ibz and kpath.is_path #assert len(kpath) == 60 #self.assert_equal(kpath.ksampling.mpdivs, [8, 8, 8]) segments = build_segments( k0_list=(0, 0, 0), npts=1, step=0.01, red_dirs=(1, 0, 0), reciprocal_lattice=structure.reciprocal_lattice) assert len(segments) == 1 assert np.all(segments[0] == (0, 0, 0)) step, npts = 0.1, 5 red_dir = np.array((1, 1, 0)) segments = build_segments( k0_list=(0, 0, 0, 0.5, 0, 0), npts=npts, step=step, red_dirs=red_dir, reciprocal_lattice=structure.reciprocal_lattice) #print("segments:\n", segments) # (nk0_list, len(red_dirs) * npts, 3) assert segments.shape == (2, npts, 3) self.assert_almost_equal(segments[0, 2], (0, 0, 0)) self.assert_almost_equal(segments[1, 2], (0.5, 0.0, 0)) def r2c(vec): return structure.reciprocal_lattice.get_cartesian_coords(vec) cart_vers = r2c(red_dir) cart_vers /= np.linalg.norm(cart_vers) self.assert_almost_equal(r2c(segments[1, 1] - segments[1, 0]), step * cart_vers) self.assert_almost_equal(r2c(segments[1, 3] - segments[1, 2]), step * cart_vers)