def bandpath(self, path=None, npoints=None, special_points=None, density=None, transformation=None): """Return a :class:`~ase.dft.kpoints.BandPath` for this lattice. See :meth:`ase.cell.Cell.bandpath` for description of parameters. >>> BCT(3, 5).bandpath() BandPath(path='GXYSGZS1NPY1Z,XP', cell=[3x3], special_points={GNPSS1XYY1Z}, kpts=[51x3]) .. note:: This produces the standard band path following AFlow conventions. If your cell does not follow this convention, you will need :meth:`ase.cell.Cell.bandpath` instead or the kpoints may not correspond to your particular cell. """ if special_points is None: special_points = self.get_special_points() if path is None: path = self._variant.special_path elif not isinstance(path, str): from ase.dft.kpoints import resolve_custom_points special_points = dict(special_points) path = resolve_custom_points(path, special_points, self._eps) cell = self.tocell() if transformation is not None: cell = transformation.dot(cell) bandpath = BandPath(cell=cell, path=path, special_points=special_points) return bandpath.interpolate(npoints=npoints, density=density)
def bandpath(self, path=None, npoints=None, special_points=None, density=None, transformation=None): """Return a :class:`~ase.dft.kpoints.BandPath` for this lattice. See :meth:`ase.cell.Cell.bandpath` for description of parameters. >>> BCT(3, 5).bandpath() BandPath(path='GXYSGZS1NPY1Z,XP', cell=[3x3], special_points={GNPSS1XYY1Z}, kpts=[51x3]) """ if special_points is None: special_points = self.get_special_points() if path is None: path = self._variant.special_path elif not isinstance(path, str): from ase.dft.kpoints import resolve_custom_points special_points = dict(special_points) path = resolve_custom_points(path, special_points, self._eps) cell = self.tocell() if transformation is not None: cell = transformation.dot(cell) bandpath = BandPath(cell=cell, path=path, special_points=special_points) return bandpath.interpolate(npoints=npoints, density=density)
def get_band_structure(atoms=None, calc=None, path=None, reference=None): """Create band structure object from Atoms or calculator.""" # path and reference are used internally at the moment, but # the exact implementation will probably change. WIP. # # XXX We throw away info about the bandpath when we create the calculator. # If we have kept the bandpath, we can provide it as an argument here. # It would be wise to check that the bandpath kpoints are the same as # those stored in the calculator. atoms = atoms if atoms is not None else calc.atoms calc = calc if calc is not None else atoms.calc kpts = calc.get_ibz_k_points() energies = [] for s in range(calc.get_number_of_spins()): energies.append( [calc.get_eigenvalues(kpt=k, spin=s) for k in range(len(kpts))]) energies = np.array(energies) if path is None: from ase.dft.kpoints import resolve_custom_points, find_bandpath_kinks path = atoms.cell.bandpath(npoints=0) # Kpoints are already evaluated, we just need to put them into # the path (whether they fit our idea of what the path is, or not). # # Depending on how the path was established, the kpoints might # be valid high-symmetry points, but since there are multiple # high-symmetry points of each type, they may not coincide # with ours if the bandpath was generated by another code. # # Here we hack it so the BandPath has proper points even if they # come from some weird source. # # This operation (manually hacking the bandpath) is liable to break. # TODO: Make it available as a proper (documented) bandpath method. kinks = find_bandpath_kinks(atoms.cell, kpts, eps=1e-5) pathspec = resolve_custom_points(kpts[kinks], path.special_points, eps=1e-5) path.kpts = kpts path.path = pathspec # XXX If we *did* get the path, now would be a good time to check # that it matches the cell! Although the path can only be passed # because we internally want to not re-evaluate the Bravais # lattice type. (We actually need an eps parameter, too.) if reference is None: # Fermi level should come from the GS calculation, not the BS one! reference = calc.get_fermi_level() if reference is None: # Fermi level may not be available, e.g., with non-Fermi smearing. # XXX Actually get_fermi_level() should raise an error when Fermi # level wasn't available, so we should fix that. reference = 0.0 return BandStructure(path=path, energies=energies, reference=reference)
def bandpath( self, path: str = None, npoints: int = None, *, density: float = None, special_points: Mapping[str, Sequence[float]] = None, eps: float = 2e-4, pbc: Union[bool, Sequence[bool]] = True) -> "ase.dft.kpoints.BandPath": """Build a :class:`~ase.dft.kpoints.BandPath` for this cell. If special points are None, determine the Bravais lattice of this cell and return a suitable Brillouin zone path with standard special points. If special special points are given, interpolate the path directly from the available data. Parameters: path: string String of special point names defining the path, e.g. 'GXL'. npoints: int Number of points in total. Note that at least one point is added for each special point in the path. density: float density of kpoints along the path in Å⁻¹. special_points: dict Dictionary mapping special points to scaled kpoint coordinates. For example ``{'G': [0, 0, 0], 'X': [1, 0, 0]}``. eps: float Tolerance for determining Bravais lattice. pbc: three bools Whether cell is periodic in each direction. Normally not necessary. If cell has three nonzero cell vectors, use e.g. pbc=[1, 1, 0] to request a 2D bandpath nevertheless. Example ------- >>> cell = Cell.fromcellpar([4, 4, 4, 60, 60, 60]) >>> cell.bandpath('GXW', npoints=20) BandPath(path='GXW', cell=[3x3], special_points={GKLUWX}, kpts=[20x3]) """ # TODO: Combine with the rotation transformation from bandpath() cell = self.uncomplete(pbc) if special_points is None: from ase.lattice import identify_lattice lat, op = identify_lattice(cell, eps=eps) bandpath = lat.bandpath(path, npoints=npoints, density=density) return bandpath.transform(op) else: from ase.dft.kpoints import BandPath, resolve_custom_points path = resolve_custom_points(path, special_points, eps=eps) bandpath = BandPath(cell, path=path, special_points=special_points) return bandpath.interpolate(npoints=npoints, density=density)
def bandpath(self, path=None, npoints=None, density=None, special_points=None, eps=2e-4): """Build a :class:`~ase.dft.kpoints.BandPath` for this cell. If special points are None, determine the Bravais lattice of this cell and return a suitable Brillouin zone path with standard special points. If special special points are given, interpolate the path directly from the available data. Parameters: path: string String of special point names defining the path, e.g. 'GXL'. npoints: int Number of points in total. Note that at least one point is added for each special point in the path. density: float density of kpoints along the path in Å⁻¹. special_points: dict Dictionary mapping special points to scaled kpoint coordinates. For example ``{'G': [0, 0, 0], 'X': [1, 0, 0]}``. eps: float Tolerance for determining Bravais lattice. Example ------- >>> cell = Cell.fromcellpar([4, 4, 4, 60, 60, 60]) >>> cell.bandpath('GXW', npoints=20) BandPath(path='GXW', cell=[3x3], special_points={GKLUWX}, kpts=[20x3]) """ # TODO: Combine with the rotation transformation from bandpath() if special_points is None: from ase.lattice import identify_lattice lat, op = identify_lattice(self, eps=eps) path = lat.bandpath(path, npoints=npoints, density=density) return path.transform(op) else: from ase.dft.kpoints import BandPath, resolve_custom_points path = resolve_custom_points(path, special_points, eps=eps) path = BandPath(self, path=path, special_points=special_points) return path.interpolate(npoints=npoints, density=density)
def test_bad_shape(): with pytest.raises(ValueError): resolve_custom_points([[np.zeros(2)]], {}, 0)
def test_autolabel_points_from_coords(kptcoords, special_points): path, dct = resolve_custom_points(kptcoords, {}, 0) assert path == 'Kpt0Kpt1' assert set(dct) == {'Kpt0', 'Kpt1'} # automatically labelled
def test_recognize_points_from_coords(special_points): path, dct = resolve_custom_points( [[special_points['A'], special_points['B']]], special_points, 1e-5) assert path == 'AB' assert set(dct) == set('AB')
def test_str(special_points): path, dct = resolve_custom_points('AB', special_points, 0) assert path == 'AB' assert set(dct) == set('AB')
def add_to_plot(self, readoutfilesobj, label=None): """ |Here you add individual plots that need to be plot and then just plot them with the plot() method |Use this method which is a part of the BandPlotterASE class you will have to give the bands to plot using a readoutfilesobj type of object """ try: Ef = readoutfilesobj.atoms_objects[0].calc.get_fermi_level() except: print(f"add_to_plot: Could not read fermi level on scf file") try: kpts = readoutfilesobj.atoms_bands_objects[ 0].calc.get_ibz_k_points() except: print(f"add_to_plot: Could not read k points on bands file") if self.include_dos or self.plot_only_dos: if self.plot_from_QE_dos_file: E = [] dos = [] with open(readoutfilesobj.dos_file_name, "r") as dos_file: for line in dos_file: # print(line) if "#" not in line: data = line.strip().split() E.append(float(data[0]) - Ef) dos.append(float(data[1])) # self.y_to_plot.append(dos) # self.x_to_plot.append(E) self.dos.append(dos) self.E_dos.append(E) if self.plot_only_dos: # Other wise we wil lappend to labels twice sicnce we will do it again at theloading of bands self.labels.append(label) else: # we are here getting the required information for DOS # self.get_dos(readoutfilesobj) calc = readoutfilesobj.atoms_nscf_objects[0].calc Ef_nscf = readoutfilesobj.atoms_nscf_objects[ 0].calc.get_fermi_level() dos = DOS(calc, width=0.2) self.dos.append(dos.get_dos()) E_nscf = dos.get_energies() Ef_diff = Ef - Ef_nscf if abs(Ef_diff) >= 0.001: print( f"Warning!!! In {readoutfilesobj.identifier[0]}:\t|E_f_scf-E_f_nscf| = {abs(Ef_diff):.3} eV (>= 0.001 eV); E_f_scf = {Ef} eV, E_f_nscf = {Ef_nscf} eV" ) if self.pin_fermi != "scf": self.E_dos.append(E_nscf) else: self.E_dos.append([E - Ef_diff for E in E_nscf]) # Test space for k path and k high symmetry points # print(kpts) # print(self.plot_only_dos) if self.plot_only_dos == False: # This is for teh band structure path = readoutfilesobj.atoms_bands_objects[0].cell.bandpath( npoints=0) kinks = find_bandpath_kinks( readoutfilesobj.atoms_bands_objects[0].cell, kpts, eps=1e-5) # These are the high symmetry points in use pathspec = resolve_custom_points( kpts[kinks], path.special_points, eps=1e-5 ) # This gives the postions for the relevant high symmetry points # path.kpts = kpts # path.path = pathspec klengths = [] for x in range(0, len(kpts)): if x == 0: kdist = np.sqrt((0.0 - kpts[x][0])**2 + (0.0 - kpts[x][1])**2 + (0.0 - kpts[x][2])**2) klengths.append(kdist) else: kdist = np.sqrt((kpts[x - 1][0] - kpts[x][0])**2 + (kpts[x - 1][1] - kpts[x][1])**2 + (kpts[x - 1][2] - kpts[x][2])**2) klengths.append(kdist + klengths[x - 1]) self.k_locations = [] for x in range(len(kinks)): self.k_locations.append(klengths[kinks[x]]) self.k_symbols = [] for x in pathspec: if x == "G": self.k_symbols.append("$\Gamma$") else: self.k_symbols.append(x) energies = [] for s in range(readoutfilesobj.atoms_bands_objects[0].calc. get_number_of_spins()): energies.append([ readoutfilesobj.atoms_bands_objects[0].calc. get_eigenvalues(kpt=k, spin=s) for k in range(len(kpts)) ]) # print(f"lenght of kpoints: {range(len(kpts))}") Energy_to_plot = [] if self.Ef_shift == True: for band in energies[0]: if self.pin_fermi != "nscf": Energy_to_plot.append([E - Ef for E in band]) else: Energy_to_plot.append( [E - Ef_nscf for E in band] ) # here the assumption is that if this option is ever reached then the idea is that an nscf calculation has already being done and dos is being plotted. tempMain = [] temp = [] for x in range(len(Energy_to_plot[0])): for kpoint in Energy_to_plot: temp.append(kpoint[x]) tempMain.append(temp) temp = [] self.y_to_plot.append(tempMain) self.x_to_plot.append(klengths) self.labels.append(label)