def cubic_kpath(): special_path = special_paths['cubic'] points = special_points['cubic'] paths = parse_path_string(special_path) special_kpts = [points[k] for k in paths[0]] kpts, xs, xspecial = bandpath(special_kpts, cell=np.eye(3), npoints=500) return kpts, xs, xspecial
def cubic_kpath(npoints=500, name=True): """ return the kpoint path for cubic Parameters: ---------------- npoints: int number of points. Returns: ----------------- kpts: kpoints xs: x cordinates for plot xspecial: x cordinates for special k points """ special_path = special_paths['cubic'] points = special_points['cubic'] paths = parse_path_string(special_path) special_kpts = [points[k] for k in paths[0]] kpts, xs, xspecial = bandpath(special_kpts, cell=np.eye(3), npoints=npoints) if not name: return kpts, xs, xspecial else: return kpts, xs, xspecial, special_path
def set_spectrum(self, bandpath=None, reference=None): bands = self.bands if bandpath != None: self.set_bandpath(bandpath) bp = parse_path_string(self.bandpath.path) jumps = [] kps = [] occs = [] kpoint_axis = [] kpoint_labels = [] label_coords = [] spectrum = [] icell_cv = 2 * np.pi * np.linalg.pinv(self.structure.cell).T for segment in bp: kpoint_labels.append(segment[0]) label_coords.append( label_coords[-1] if len(label_coords) > 0 else 0.0) for s1, s2 in zip(segment[:-1], segment[1:]): energies = bands[(s1, s2)].eigenvalues kpoints = np.dot(bands[(s1, s2)].kpoints, icell_cv) occ = bands[(s1, s2)].occupations kstep = np.linalg.norm(kpoints[-1, :] - kpoints[0, :]) kaxis = np.linspace(0, kstep, kpoints.shape[0]) + label_coords[-1] kstep += label_coords[-1] spectrum.append(energies) kps.append(kpoints) occs.append(occ) kpoint_axis.append(kaxis) label_coords.append(kstep) kpoint_labels.append(s2) jumps.append(label_coords[-1]) jumps = jumps[:-1] spectrum = np.concatenate(spectrum, axis=0) kps = np.concatenate(kps, axis=0) kpoint_axis = np.concatenate(kpoint_axis, axis=0) occs = np.concatenate(occs, axis=0) fermi_level = self.fermi_level.soc if self.soc else self.fermi_level.scalar self.set_energy_reference(reference, self.soc) reference, shift = self.energy_reference sp = BandSpectrum( atoms=self.structure.atoms, kpoints=kps, kpoint_axis=kpoint_axis, eigenvalues=spectrum, occupations=occs, label_coords=label_coords, kpoint_labels=kpoint_labels, jumps=jumps, fermi_level=fermi_level, reference=reference, shift=shift, bandpath=bandpath, ) self._spectrum = sp
def special_point_names(self): """Return all special point names as a list of strings. >>> BCT(3, 5).special_point_names ['G', 'N', 'P', 'S', 'S1', 'X', 'Y', 'Y1', 'Z'] """ labels = parse_path_string(self._variant.special_point_names) assert len(labels) == 1 # list of lists return labels[0]
def atoms2bandpath(atoms, path='default', k_points=False, ibz_k_points=False, dimension=3, verbose=False): cell = atoms.get_cell() icell = atoms.get_reciprocal_cell() try: cs = crystal_structure_from_cell(cell) except ValueError: cs = None if verbose: if cs: print('Crystal:', cs) print('Special points:', special_paths[cs]) print('Lattice vectors:') for i, v in enumerate(cell): print('{}: ({:16.9f},{:16.9f},{:16.9f})'.format(i + 1, *v)) print('Reciprocal vectors:') for i, v in enumerate(icell): print('{}: ({:16.9f},{:16.9f},{:16.9f})'.format(i + 1, *v)) # band path special_points = None if path: if path == 'default': path = special_paths[cs] paths = [] special_points = get_special_points(cell) for names in parse_path_string(path): points = [] for name in names: points.append(np.dot(icell.T, special_points[name])) paths.append((names, points)) else: paths = None # k points points = None if atoms.calc is not None and hasattr(atoms.calc, 'get_bz_k_points'): bzk = atoms.calc.get_bz_k_points() if path is None: try: size, offset = get_monkhorst_pack_size_and_offset(bzk) except ValueError: # This was not a MP-grid. Must be a path in the BZ: path = ''.join(labels_from_kpts(bzk, cell)[2]) if k_points: points = bzk elif ibz_k_points: points = atoms.calc.get_ibz_k_points() return BandPath(cell, kpts=points, special_points=special_points)
def mybandpath(path, cell, npoints=50, eps=1e-3): """Make a list of kpoints defining the path between the given points. path: list or str Can be: * a string that parse_path_string() understands: 'GXL' * a list of BZ points: [(0, 0, 0), (0.5, 0, 0)] * or several lists of BZ points if the the path is not continuous. cell: 3x3 Unit cell of the atoms. npoints: int Length of the output kpts list. Return list of k-points, list of x-coordinates and list of x-coordinates of special points.""" if isinstance(path, str): special = get_special_points(cell,eps=eps) paths = [] for names in parse_path_string(path): paths.append([special[name] for name in names]) elif np.array(path[0]).ndim == 1: paths = [path] else: paths = path points = np.concatenate(paths) dists = points[1:] - points[:-1] lengths = [np.linalg.norm(d) for d in kpoint_convert(cell, skpts_kc=dists)] i = 0 for path in paths[:-1]: i += len(path) lengths[i - 1] = 0 length = sum(lengths) kpts = [] x0 = 0 x = [] X = [0] for P, d, L in zip(points[:-1], dists, lengths): n = max(2, int(round(L * (npoints - len(x)) / (length - x0)))) for t in np.linspace(0, 1, n)[:-1]: kpts.append(P + t * d) x.append(x0 + t * L) x0 += L X.append(x0) kpts.append(points[-1]) x.append(x0) return np.array(kpts), np.array(x), np.array(X)
def read_bands(self): outputyaml = self.outputdir.joinpath("band.yaml") assert outputyaml.exists(), "File band.yaml not found." with open(outputyaml, "r") as stream: try: data = yaml.safe_load(stream) except yaml.YAMLError as exc: raise Exception(exc) labels = data["labels"] bpstring = [] for i, pair in enumerate(labels): if i == 0: bpstring.append(pair[0]) elif i == len(labels) - 1: bpstring.append(pair[0]) bpstring.append(pair[1]) else: bpstring.append(pair[0]) bpstring = "".join(bpstring) bpstring = bpstring.replace("|", ",") bplist = parse_path_string(bpstring) special_points = (self.structure.cell.get_bravais_lattice().bandpath(). special_points) self._bandpath = BandPath(path=bpstring, cell=self.structure.cell, special_points=special_points) phon = data["phonon"] nqpoints = data["segment_nqpoint"] qpoints = np.array([k["q-position"] for k in phon], dtype=np.float32) pbands = np.array([[l["frequency"] for l in k["band"]] for k in phon], dtype=np.float32) b = namedtuple("band", ["qpoints", "frequencies"]) count = 0 bands = {} i = 0 for segment in bplist: for pair in zip(segment[:-1], segment[1:]): j1, j2 = count, nqpoints[i] + count count = j2 qp = qpoints[j1:j2, :] pb = pbands[j1:j2, :] bands[pair] = b(qp, pb) rev = (pair[1], pair[0]) bands[rev] = b(qp[::-1], pb[::-1]) i += 1 return bands
def set_spectrum(self, bandpath=None, unit=r"cm$^{-1}$"): assert unit in [r"cm$^{-1}$", "Thz"], "Unit not recognized." bands = self.bands if bandpath != None: self.set_bandpath(bandpath) bp = parse_path_string(self.bandpath.path) jumps = [] qps = [] qpoint_axis = [] qpoint_labels = [] label_coords = [] spectrum = [] icell_cv = 2 * np.pi * np.linalg.pinv(self.structure.cell).T for segment in bp: qpoint_labels.append(segment[0]) label_coords.append( label_coords[-1] if len(label_coords) > 0 else 0.0) for s1, s2 in zip(segment[:-1], segment[1:]): freqs = bands[(s1, s2)].frequencies qpoints = np.dot(bands[(s1, s2)].qpoints, icell_cv) qstep = np.linalg.norm(qpoints[-1, :] - qpoints[0, :]) qaxis = np.linspace(0, qstep, qpoints.shape[0]) + label_coords[-1] qstep += label_coords[-1] spectrum.append(freqs) qps.append(qpoints) qpoint_axis.append(qaxis) label_coords.append(qstep) qpoint_labels.append(s2) jumps.append(label_coords[-1]) jumps = jumps[:-1] spectrum = np.concatenate(spectrum, axis=0) # unit in Thz # 1 Thz = 33.356 cm^-1 if unit == r"cm$^{-1}$": spectrum *= 33.356 qps = np.concatenate(qps, axis=0) qpoint_axis = np.concatenate(qpoint_axis, axis=0) atoms = self.structure.copy() sp = PhononSpectrum( qpoints=qps, qpoint_axis=qpoint_axis, frequencies=spectrum, atoms=atoms, label_coords=label_coords, qpoint_labels=qpoint_labels, jumps=jumps, unit=unit, bandpath=bp, ) self._spectrum = sp
def generate_kpath_ase(cell, symprec): eig_val_max = np.real(np.linalg.eigvals(cell)).max() eps = eig_val_max * symprec lattice = crystal_structure_from_cell(cell, eps) paths = special_paths.get(lattice, None) if paths is None: paths = special_paths['orthorhombic'] paths = parse_path_string(special_paths[lattice]) points = special_points.get(lattice) if points is None: try: points = get_special_points(cell) except Exception: return [] return generate_kpath_parameters(points, paths, 100)
def get_bandpath_as_aims_strings(self, pbc=[True, True, True]): """This function sets up the band path according to Setyawan-Curtarolo conventions. Returns: list: List of strings containing the k-path sections. """ from ase.dft.kpoints import parse_path_string, kpoint_convert atoms = self.structure.atoms atoms.pbc = pbc path = parse_path_string( atoms.cell.get_bravais_lattice(pbc=atoms.pbc).bandpath().path) # list Of lists of path segments points = atoms.cell.get_bravais_lattice( pbc=atoms.pbc).bandpath().special_points segments = [] for seg in path: section = [(i, j) for i, j in zip(seg[:-1], seg[1:])] segments.append(section) output_bands = [] index = 1 for seg in segments: output_bands.append( "## Brillouin Zone section Nr. {:d}\n".format(index)) for sec in seg: dist = np.array(points[sec[1]]) - np.array(points[sec[0]]) length = np.linalg.norm( kpoint_convert(atoms.cell, skpts_kc=dist)) npoints = np.int_(np.round(np.asarray(length) * 20)) vec1 = "{:.6f} {:.6f} {:.6f}".format(*points[sec[0]]) vec2 = "{:.6f} {:.6f} {:.6f}".format(*points[sec[1]]) output_bands.append( "{vec1} \t {vec2} \t {npoints} \t {label1} {label2}". format( label1=sec[0], label2=sec[1], npoints=npoints, vec1=vec1, vec2=vec2, )) index += 1 return output_bands
def set_bandpath(self, bandpathstring): new_bandpath = parse_path_string(bandpathstring) old_path = self.bandpath special_points = old_path.special_points pairs = [(s[0], s[1]) for s in self.bands.keys()] for segment in new_bandpath: assert len(segment) > 1, "A vertex needs at least two points." p = zip(segment[:-1], segment[1:]) for s1, s2 in p: assert any(x in pairs for x in ((s1, s2), ( s2, s1))), "The k-path {}-{} has not been calculated.".format( s1, s2) else: new_path = BandPath( path=bandpathstring, cell=self.structure.cell, special_points=special_points, ) self._bandpath = new_path
ax.view_init(azim=azim / pi * 180, elev=elev / pi * 180) for X, cell in [('cubic', np.eye(3)), ('fcc', [[0, 1, 1], [1, 0, 1], [1, 1, 0]]), ('bcc', [[-1, 1, 1], [1, -1, 1], [1, 1, -1]]), ('tetragonal', [[1, 0, 0], [0, 1, 0], [0, 0, 1.3]]), ('orthorhombic', [[1, 0, 0], [0, 1.2, 0], [0, 0, 1.4]]), ('hexagonal', [[1, 0, 0], [-0.5, 3**0.5 / 2, 0], [0, 0, 1]]), ('monoclinic', [[1, 0, 0], [0, 1, 0], [0, 0.2, 1]])]: icell = np.linalg.inv(cell) print(cell, X) special_points = get_special_points(cell, X) paths = [] for names in parse_path_string(special_paths[X]): points = [] for name in names: points.append(np.dot(icell, special_points[name])) paths.append((names, points)) if X == 'bcc': scale = 0.6 elev = pi / 13 else: scale = 1 elev = None plot(cell, paths, elev, scale) plt.savefig(X + '.svg')
def bz3d_plot(cell, vectors=False, paths=None, points=None, ax=None, elev=None, scale=1, repeat=None, transformations=None, hide_ax=True, **kwargs): """ For now this is lifted from ase.dft.bz.bz3d_plot with some modifications. All copyright and licensing terms for this and bz2d_plot are those of the current release of ASE (Atomic Simulation Environment). :param cell: :param vectors: :param paths: :param points: :param elev: :param scale: :return: """ try: from ase.dft.bz import bz_vertices # dynamic because we do not require ase except ImportError: warnings.warn('You will need to install ASE (Atomic Simulation Environment) to use this feature.') raise ImportError('You will need to install ASE before using Brillouin Zone plotting') class Arrow3D(FancyArrowPatch): def __init__(self, xs, ys, zs, *args, **kwargs): FancyArrowPatch.__init__(self, (0, 0), (0, 0), *args, **kwargs) self._verts3d = xs, ys, zs def draw(self, renderer): xs3d, ys3d, zs3d = self._verts3d xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, renderer.M) self.set_positions((xs[0], ys[0]), (xs[1], ys[1])) FancyArrowPatch.draw(self, renderer) icell = np.linalg.inv(cell).T kpoints = points if isinstance(paths, str): from ase.dft.kpoints import (get_special_points, special_paths, parse_path_string, crystal_structure_from_cell) special_points = get_special_points(cell) structure = crystal_structure_from_cell(cell) path_string = special_paths[structure] if paths == 'all' else paths paths = [] for names in parse_path_string(path_string): points = [] for name in names: points.append(np.dot(icell.T, special_points[name])) paths.append((names, points)) if ax is None: fig = plt.figure(figsize=(5, 5)) ax = fig.gca(projection='3d') azim = np.pi / 5 elev = elev or np.pi / 6 x = np.sin(azim) y = np.cos(azim) view = [x * np.cos(elev), y * np.cos(elev), np.sin(elev)] bz1 = bz_vertices(icell) maxp = 0.0 if repeat is None: repeat = (1, 1, 1,) dx, dy, dz = icell[0], icell[1], icell[2] rep_x, rep_y, rep_z = repeat if isinstance(rep_x, int): rep_x = (0, rep_x) if isinstance(rep_y, int): rep_y = (0, rep_y) if isinstance(rep_z, int): rep_z = (0, rep_z) c = kwargs.pop('c', 'k') c = kwargs.pop('color', c) for ix, iy, iz in itertools.product(range(*rep_x), range(*rep_y), range(*rep_z)): delta = dx * ix + dy * iy + dz * iz for points, normal in bz1: color = c if np.dot(normal, view) < 0: ls = ':' else: ls = '-' cosines = np.dot(icell, normal)/ np.linalg.norm(normal) / np.linalg.norm(icell, axis=1) for idx, cosine in enumerate(cosines): if np.abs(np.abs(cosine) - 1) < 1e-6 and False: # debugging this tup = [rep_x, rep_y, rep_z][idx] current = [ix, iy, iz][idx] if cosine < 0: current = current - 1 if tup[0] < current + 1 < tup[1]: color = (1, 1, 1, 0) if current + 1 != tup[1] and current != tup[0]: ls = ':' color='blue' x, y, z = np.concatenate([points, points[:1]]).T x, y, z = x + delta[0], y + delta[1], z + delta[2] ax.plot(x, y, z, c=color, ls=ls, **kwargs) maxp = max(maxp, points.max()) if vectors: ax.add_artist(Arrow3D([0, icell[0, 0]], [0, icell[0, 1]], [0, icell[0, 2]], mutation_scale=20, lw=1, arrowstyle='-|>', color='k')) ax.add_artist(Arrow3D([0, icell[1, 0]], [0, icell[1, 1]], [0, icell[1, 2]], mutation_scale=20, lw=1, arrowstyle='-|>', color='k')) ax.add_artist(Arrow3D([0, icell[2, 0]], [0, icell[2, 1]], [0, icell[2, 2]], mutation_scale=20, lw=1, arrowstyle='-|>', color='k')) maxp = max(maxp, 0.6 * icell.max()) if paths is not None: for names, points in paths: x, y, z = np.array(points).T ax.plot(x, y, z, c='r', ls='-') for name, point in zip(names, points): x, y, z = point if name == 'G': name = '\\Gamma' elif len(name) > 1: name = name[0] + '_' + name[1] ax.text(x, y, z, '$' + name + '$', ha='center', va='bottom', color='r') if kpoints is not None: for p in kpoints: ax.scatter(p[0], p[1], p[2], c='b') if hide_ax: ax.set_axis_off() ax.autoscale_view(tight=True) s = maxp / 0.5 * 0.45 * scale ax.set_xlim(-s, s) ax.set_ylim(-s, s) ax.set_zlim(-s, s) ax.set_aspect('equal') ax.view_init(azim=azim / np.pi * 180, elev=elev / np.pi * 180)
def special_point_names(self): labels = parse_path_string(self._variant.special_point_names) assert len(labels) == 1 # list of lists return labels[0]
ax.view_init(azim=azim / pi * 180, elev=elev / pi * 180) for X, cell in [ ('cubic', np.eye(3)), ('fcc', [[0, 1, 1], [1, 0, 1], [1, 1, 0]]), ('bcc', [[-1, 1, 1], [1, -1, 1], [1, 1, -1]]), ('tetragonal', [[1, 0, 0], [0, 1, 0], [0, 0, 1.3]]), ('orthorhombic', [[1, 0, 0], [0, 1.2, 0], [0, 0, 1.4]]), ('hexagonal', [[1, 0, 0], [-0.5, 3**0.5 / 2, 0], [0, 0, 1]]), ('monoclinic', [[1, 0, 0], [0, 1, 0], [0, 0.2, 1]])]: icell = np.linalg.inv(cell) special_points = get_special_points(X, cell) paths = [] for names in parse_path_string(special_paths[X]): points = [] for name in names: points.append(np.dot(icell, special_points[name])) paths.append((names, points)) if X == 'bcc': scale = 0.6 elev = pi / 13 else: scale = 1 elev = None plot(cell, paths, elev, scale) plt.savefig(X + '.svg')
def bz2d_plot(cell, vectors=False, paths=None, points=None, repeat=None, ax=None, transformations=None, offset=None, hide_ax=True, set_equal_aspect=True, **kwargs): """ This piece of code modified from ase.ase.dft.bz.py:bz2d_plot and follows copyright and license for ASE. Plots a Brillouin zone corresponding to a given unit cell :param cell: :param vectors: :param paths: :param points: :return: """ kpoints = points bz1, icell, cell = twocell_to_bz1(cell) if ax is None: ax = plt.axes() if isinstance(paths, str): from ase.dft.kpoints import (get_special_points, special_paths, parse_path_string, crystal_structure_from_cell) special_points = get_special_points(cell) structure = crystal_structure_from_cell(cell) path_string = special_paths[structure] if paths == 'all' else paths paths = [] for names in parse_path_string(path_string): points = [] for name in names: points.append(np.dot(icell.T, special_points[name])) paths.append((names, points)) maxp = 0.0 c = kwargs.pop('c', 'k') c = kwargs.pop('color', c) ls = kwargs.pop('ls', kwargs.pop('linestyle', '-')) for points, normal in bz1: points = apply_transformations(points, transformations) x, y, z = np.concatenate([points, points[:1]]).T ax.plot(x, y, c=c, ls=ls, **kwargs) maxp = max(maxp, points.max()) if repeat is not None: dx, dy = icell[0], icell[1] rep_x, rep_y = repeat if isinstance(rep_x, int): rep_x = (0, rep_x) if isinstance(rep_y, int): rep_y = (0, rep_y) for ix, iy in itertools.product(range(*rep_x), range(*rep_y)): delta = dx * ix + dy * iy for points, normal in bz1: x, y, z = np.concatenate([points, points[:1]]).T x, y = x + delta[0], y + delta[1] x, y, z = apply_transformations(np.asarray([x, y, z]).T, transformations).T c = kwargs.pop('c', 'k') c = kwargs.pop('color', c) ax.plot(x, y, c=c, ls=ls, **kwargs) maxp = max(maxp, points.max()) if vectors: ax.arrow(0, 0, icell[0, 0], icell[0, 1], lw=1, color='k', length_includes_head=True, head_width=0.03, head_length=0.05) ax.arrow(0, 0, icell[1, 0], icell[1, 1], lw=1, color='k', length_includes_head=True, head_width=0.03, head_length=0.05) if paths is not None: annotate_special_paths(ax, paths, offset=offset, transformations=transformations) if kpoints is not None: for p in kpoints: ax.scatter(p[0], p[1], c='b') if hide_ax: ax.set_axis_off() ax.autoscale_view(tight=True) if set_equal_aspect: ax.set_aspect('equal')
def __init__(self,astruct,mesh,evals,fermi_energy): import spglib,numpy cell=astruct_to_cell(astruct) self.lattice=cell[0] #celltmp=[ a if a!=float('inf') else 1.0 for a in astruct['cell']] #self.lattice=numpy.diag(celltmp) #print 'lattice',self.lattice #pos=[ [ a/b if b!=float('inf') else 0.0 for a,b in zip(at.values()[0], celltmp)]for at in astruct['positions']] #atoms=[ at.keys()[0] for at in astruct['positions']] #ianames,iatype=numpy.unique(atoms,return_inverse=True) #[1,]*4+[2,]*4 #we should write a function for the iatype #print 'iatype', iatype #cell=(self.lattice,pos,iatype) safe_print('spacegroup',spglib.get_spacegroup(cell, symprec=1e-5)) #then define the pathes and special points import ase.dft.kpoints as ase #we should adapt the 'cubic' cell_tmp=astruct['cell'] #print 'cell',cell_tmp,numpy.allclose(cell_tmp,[cell_tmp[0],]*len(cell_tmp)) if numpy.allclose(cell_tmp,[cell_tmp[0],]*len(cell_tmp)): lattice_string='cubic' else: lattice_string='orthorhombic' safe_print('Lattice found:',lattice_string) self.special_points=ase.get_special_points(lattice_string, self.lattice, eps=0.0001) self.special_paths=ase.parse_path_string(ase.special_paths[lattice_string]) self.fermi_energy=fermi_energy #dataset = spglib.get_symmetry_dataset(cell, symprec=1e-3) #print dataset #the shift has also to be put if present mapping, grid = spglib.get_ir_reciprocal_mesh(mesh, cell, is_shift=[0, 0, 0]) lookup=[] for ikpt in numpy.unique(mapping): ltmp=[] for ind, (m, g) in enumerate(zip(mapping, grid)): if m==ikpt: ltmp.append((g,ind)) lookup.append(ltmp) safe_print('irreductible k-points',len(lookup)) #print 'mapping',mapping #print 'grid',len(grid),numpy.max(grid) coords=numpy.array(grid, dtype = numpy.float)/mesh #print 'coords',coords #print 'shape',coords.shape #print grid #[ x+mesh[0]*y+mesh[0]*mesh[1]*z for x,y,z in grid] #brillouin zone kp=numpy.array([ k.kpt for k in evals]) ourkpt=numpy.rint(kp*(numpy.array(mesh))).astype(int) #print ourkpt bz=numpy.ndarray((coords.shape[0],evals[0].size),dtype=float) #print bz shift=(numpy.array(mesh)-1)/2 #print 'shift',shift for ik in lookup: irrk=None for orbs,bzk in zip(evals,ourkpt): for (kt,ind) in ik: if (bzk==kt).all(): irrk=orbs #print 'hello',orbs.kpt,kt break if irrk is not None: break if irrk is None: safe_print( 'error in ik',ik) safe_print( 'our',ourkpt) safe_print( 'spglib',grid) safe_print( 'mapping',mapping) for (kt,ind) in ik: #r=kt+shift #ind=numpy.argwhere([(g==kt).all() for g in grid]) #print 'ik',kt,r,ind #print irrk.shape, bz.shape #bz[r[0],r[1],r[2],:]=irrk.reshape(irrk.size) bz[ind,:]=irrk.reshape(irrk.size) #duplicate coordinates for the interpolation bztmp=bz#.reshape((mesh[0]*mesh[1]*mesh[2], -1)) #print bztmp ndup=7 duplicates=[[-1,0,0],[1,0,0],[0,-1,0],[0,1,0],[0,0,-1],[0,0,1]] bztot=numpy.ndarray((ndup,bztmp.shape[0],bztmp.shape[1])) bztot[0,:,:]=bztmp ctot=numpy.ndarray((ndup,coords.shape[0],coords.shape[1])) ctot[0,:,:]=coords for i,sh in enumerate(duplicates): bztot[i+1,:,:]=bztmp ctot[i+1,:,:]=coords+sh #print 'coors',coords,coords+[1.0,0,0] bztot=bztot.reshape((ndup*bztmp.shape[0], -1)) ctot=ctot.reshape((ndup*coords.shape[0], -1)) import scipy.interpolate.interpnd as interpnd self.interpolator=interpnd.LinearNDInterpolator(ctot,bztot) #sanity check of the interpolation sanity=0.0 for kpt in evals: diff=numpy.ravel(numpy.ravel(kpt)-numpy.ravel(self.interpolator([ kpt.kpt]))) sanity=max(sanity,numpy.dot(diff,diff)) print('Interpolation bias',sanity)
def plot_reciprocal_cell(atoms, path='default', k_points=False, ibz_k_points=False, plot_vectors=True, dimension=3, output=None, verbose=False): import matplotlib.pyplot as plt cell = atoms.get_cell() icell = atoms.get_reciprocal_cell() try: cs = crystal_structure_from_cell(cell) except ValueError: cs = None if verbose: if cs: print('Crystal:', cs) print('Special points:', special_paths[cs]) print('Lattice vectors:') for i, v in enumerate(cell): print('{}: ({:16.9f},{:16.9f},{:16.9f})'.format(i + 1, *v)) print('Reciprocal vectors:') for i, v in enumerate(icell): print('{}: ({:16.9f},{:16.9f},{:16.9f})'.format(i + 1, *v)) # band path if path: if path == 'default': path = special_paths[cs] paths = [] special_points = get_special_points(cell) for names in parse_path_string(path): points = [] for name in names: points.append(np.dot(icell.T, special_points[name])) paths.append((names, points)) else: paths = None # k points points = None if atoms.calc is not None and hasattr(atoms.calc, 'get_bz_k_points'): bzk = atoms.calc.get_bz_k_points() if path is None: try: size, offset = get_monkhorst_pack_size_and_offset(bzk) except ValueError: # This was not a MP-grid. Must be a path in the BZ: path = ''.join(labels_from_kpts(bzk, cell)[2]) if k_points: points = bzk elif ibz_k_points: points = atoms.calc.get_ibz_k_points() if points is not None: for i in range(len(points)): points[i] = np.dot(icell.T, points[i]) kwargs = { 'cell': cell, 'vectors': plot_vectors, 'paths': paths, 'points': points } if dimension == 1: bz1d_plot(**kwargs) elif dimension == 2: bz2d_plot(**kwargs) else: bz3d_plot(interactive=True, **kwargs) if output: plt.savefig(output) else: plt.show()
def set_spectrum(self, bandpath=None, reference=None): """ Sets :class:`~aimstools.bandstructures.mulliken_bandstructure.MullikenSpectrum` for a given bandpath. Bandpath should be ASE-formatted string, e.g., "GMKG,A", where the "," denotes jumps. """ bands = self.bands atoms = self.structure.copy() start = time.time() if bandpath != None: self.set_bandpath(bandpath) bp = parse_path_string(self.bandpath.path) jumps = [] kps = [] occs = [] kpoint_axis = [] kpoint_labels = [] label_coords = [] spectrum = [] icell_cv = 2 * np.pi * np.linalg.pinv(self.structure.cell).T contributions = [] for segment in bp: kpoint_labels.append(segment[0]) label_coords.append( label_coords[-1] if len(label_coords) > 0 else 0.0) for s1, s2 in zip(segment[:-1], segment[1:]): if (s1, s2) in bands.keys(): data = bands[(s1, s2)].data kpoints = np.dot(bands[(s1, s2)].kpoints, icell_cv) energies = data[0, :, :, :, 0] # (nkpoints, nspins, nstates) occ = data[0, :, :, :, 1] # (nkpoints, nspins, nstates) con = data[:, :, :, :, 2:] # (natoms, nkpoints, nspins, nstates, [tot, s, p, d, f]) elif (s1, s2) in [(k, j) for j, k in bands.keys()]: data = bands[(s2, s1)].data kpoints = np.dot(bands[(s2, s1)].kpoints, icell_cv)[::-1] energies = data[0, :, :, :, 0] # (nkpoints, nspins, nstates) energies = energies[::-1, :, :] occ = data[0, :, :, :, 1] # (nkpoints, nspins, nstates) occ = occ[::-1, :, :] con = data[:, :, :, :, 2:] # (natoms, nkpoints, nspins, nstates, [tot, s, p, d, f]) con = con[:, ::-1, ...] else: raise Exception( "Neither {}-{} nor {}-{} were found.".format( s1, s2, s2, s1)) kstep = np.linalg.norm(kpoints[-1, :] - kpoints[0, :]) kaxis = np.linspace(0, kstep, kpoints.shape[0]) + label_coords[-1] kstep += label_coords[-1] spectrum.append(energies) kps.append(kpoints) occs.append(occ) contributions.append(con) kpoint_axis.append(kaxis) label_coords.append(kstep) kpoint_labels.append(s2) jumps.append(label_coords[-1]) jumps = jumps[:-1] spectrum = np.concatenate(spectrum, axis=0) kps = np.concatenate(kps, axis=0) kpoint_axis = np.concatenate(kpoint_axis, axis=0) occs = np.concatenate(occs, axis=0) cons = np.concatenate(contributions, axis=1) fermi_level = self.fermi_level.soc if self.soc else self.fermi_level.scalar self.set_energy_reference(reference, self.soc) reference, shift = self.energy_reference spec = MullikenSpectrum( atoms=atoms, kpoints=kps, kpoint_axis=kpoint_axis, eigenvalues=spectrum, occupations=occs, contributions=cons, label_coords=label_coords, kpoint_labels=kpoint_labels, jumps=jumps, fermi_level=fermi_level, reference=reference, shift=shift, bandpath=bp, ) end = time.time() logger.info( "Creating spectrum from bands took {:.2f} seconds.".format(end - start)) self._spectrum = spec
def plot_magnon_band(ham, kvectors=np.array([[0, 0, 0], [0.5, 0, 0], [0.5, 0.5, 0], [0, 0, 0], [.5, .5, .5]]), knames=['$\Gamma$', 'X', 'M', '$\Gamma$', 'R'], supercell_matrix=None, npoints=100, color='red', ax=None, eps=1e-3, kpath_fname=None): if ax is None: fig, ax = plt.subplots() if knames is None or kvectors is None: from ase.build.tools import niggli_reduce_cell rcell, M = niggli_reduce_cell(ham.cell) fcell = fix_cell(ham.cell, eps=eps) lattice_type = crystal_structure_from_cell(rcell, eps=eps, niggli_reduce=False) labels = parse_path_string(special_paths[lattice_type]) knames = [item for sublist in labels for item in sublist] kpts, x, X = bandpath(special_paths[lattice_type], rcell, npoints=npoints, eps=1e-8) spk = get_special_points(ham.cell, eps=1e-8) else: kpts, x, X = bandpath(kvectors, fix_cell(ham.cell), npoints) spk = dict(zip(knames, kvectors)) if supercell_matrix is not None: kvectors = [np.dot(k, supercell_matrix) for k in kvectors] qsolver = QSolver(hamiltonian=ham) evals, evecs = qsolver.solve_all(kpts, eigen_vectors=True) nbands = evals.shape[1] #evecs imin = np.argmin(evals[:, 0]) emin = np.min(evals[:, 0]) nspin = evals.shape[1] // 3 evec_min = evecs[imin, :, 0].reshape(nspin, 3) # write information to file if kpath_fname is not None: with open(kpath_fname, 'w') as myfile: myfile.write("K-points:\n") for name, k in spk.items(): myfile.write("%s: %s\n" % (name, k)) myfile.write("\nThe energy minimum is at:") myfile.write("%s\n" % kpts[np.argmin(evals[:, 0])]) for i, ev in enumerate(evec_min): myfile.write("spin %s: %s \n" % (i, ev / np.linalg.norm(ev))) print("\nThe energy minimum is at:") print("%s\n" % kpts[np.argmin(evals[:, 0])]) print("\n The ground state is:") for i, ev in enumerate(evec_min): print("spin %s: %s" % (i, ev / np.linalg.norm(ev))) for i in range(nbands): ax.plot(x, (evals[:, i] - emin) / 1.6e-22) ax.set_xlabel('Q-point') ax.set_ylabel('Energy (meV)') ax.set_xlim(x[0], x[-1]) ax.set_ylim(0) ax.set_xticks(X) ax.set_xticklabels(knames) for x in X: ax.axvline(x, linewidth=0.6, color='gray') return ax