def calc_commensurate_moire_cell(underlayer_a, overlayer_a, relative_angle=0, swap_angle=False): """ Calculates nearly commensurate moire unit cells for two hexagonal lattices :return: """ from ase.dft.kpoints import get_special_points from ase.dft.bz import bz_vertices underlayer_direct = hex_cell_2d(a=underlayer_a) overlayer_direct = hex_cell_2d(a=overlayer_a) underlayer_direct = [list(c) + [0] for c in underlayer_direct] + [[0, 0, 1]] overlayer_direct = [list(c) + [0] for c in overlayer_direct] + [[0, 0, 1]] underlayer_icell = np.linalg.inv(underlayer_direct).T overlayer_icell = np.linalg.inv(overlayer_direct).T underlayer_k = np.dot(underlayer_icell.T, get_special_points(underlayer_direct)['K']) overlayer_k = Rotation.from_rotvec([0, 0, relative_angle]).apply( np.dot(overlayer_icell.T, get_special_points(overlayer_direct)['K'])) moire_k = (underlayer_k - overlayer_k) moire_a = underlayer_a * (np.linalg.norm(underlayer_k) / np.linalg.norm(moire_k)) moire_angle = angle_between_vectors(underlayer_k, moire_k) if swap_angle: moire_angle = -moire_angle moire_cell = hex_cell_2d(moire_a) moire_cell = [list(c) + [0] for c in moire_cell] + [[0, 0, 1]] moire_cell = Rotation.from_rotvec([0, 0, moire_angle]).apply(moire_cell) moire_icell = np.linalg.inv(moire_cell).T moire_bz_points = bz_vertices(moire_icell) moire_bz_points = moire_bz_points[[len(p[0]) for p in moire_bz_points].index(6)][0] return { 'k_points': (underlayer_k, overlayer_k, moire_k), 'moire_a': moire_a, 'moire_k': moire_k, 'moire_cell': moire_cell, 'moire_icell': moire_icell, 'moire_bz_points': moire_bz_points, 'moire_bz_angle': moire_angle, }
def test_hex(): """Test band structure from different variations of hexagonal cells.""" firsttime = True for cell in [[[1, 0, 0], [0.5, 3**0.5 / 2, 0], [0, 0, 1]], [[1, 0, 0], [-0.5, 3**0.5 / 2, 0], [0, 0, 1]], [[0.5, -3**0.5 / 2, 0], [0.5, 3**0.5 / 2, 0], [0, 0, 1]]]: a = Atoms(cell=cell, pbc=True) a.cell *= 3 a.calc = FreeElectrons(nvalence=1, kpts={'path': 'GMKG'}) lat = a.cell.get_bravais_lattice() assert lat.name == 'HEX' print(repr(a.cell.get_bravais_lattice())) r = a.cell.reciprocal() k = get_special_points(a.cell)['K'] print(np.dot(k, r)) a.get_potential_energy() bs = a.calc.band_structure() coords, labelcoords, labels = bs.get_labels() assert ''.join(labels) == 'GMKG' e_skn = bs.energies if firsttime: coords1 = coords labelcoords1 = labelcoords e_skn1 = e_skn firsttime = False else: for d in [ coords - coords1, labelcoords - labelcoords1, e_skn - e_skn1 ]: assert abs(d).max() < 1e-13
def atoms2bandstructure(atoms, parser, args): cell = atoms.get_cell() calc = atoms.calc bzkpts = calc.get_bz_k_points() ibzkpts = calc.get_ibz_k_points() efermi = calc.get_fermi_level() nibz = len(ibzkpts) nspins = 1 + int(calc.get_spin_polarized()) eps = np.array([[calc.get_eigenvalues(kpt=k, spin=s) for k in range(nibz)] for s in range(nspins)]) if not args.quiet: print('Spins, k-points, bands: {}, {}, {}'.format(*eps.shape)) if bzkpts is None: if ibzkpts is None: raise ValueError('Cannot find any k-point data') else: path_kpts = ibzkpts else: try: size, offset = get_monkhorst_pack_size_and_offset(bzkpts) except ValueError: path_kpts = ibzkpts else: if not args.quiet: print('Interpolating from Monkhorst-Pack grid (size, offset):') print(size, offset) if args.path is None: err = 'Please specify a path!' try: cs = crystal_structure_from_cell(cell) except ValueError: err += ('\nASE cannot automatically ' 'recognize this crystal structure') else: from ase.dft.kpoints import special_paths kptpath = special_paths[cs] err += ('\nIt looks like you have a {} crystal structure.' '\nMaybe you want its special path:' ' {}'.format(cs, kptpath)) parser.error(err) bz2ibz = calc.get_bz_to_ibz_map() path_kpts = bandpath(args.path, atoms.cell, args.points).kpts icell = atoms.get_reciprocal_cell() eps = monkhorst_pack_interpolate(path_kpts, eps.transpose(1, 0, 2), icell, bz2ibz, size, offset) eps = eps.transpose(1, 0, 2) special_points = get_special_points(cell) path = BandPath(atoms.cell, kpts=path_kpts, special_points=special_points) return BandStructure(path, eps, reference=efermi)
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 kpath(): #DDB = abilab.abiopen('out_DDB') #struct = DDB.structure #atoms = DDB.structure.to_ase_atoms() atoms = bulk('Cu', 'fcc') points = get_special_points('fcc', atoms.cell, eps=0.01) GXW = [points[k] for k in 'GXWGL'] kpts, x, X = bandpath(GXW, atoms.cell, 700) names = ['$\Gamma$', 'X', 'W', '$\Gamma$', 'L'] return kpts, x, X, names, GXW
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 getBandKpoints(atoms, npoints=50, selectedPath = ['G','M','K','G','A','L','H'],shape='Hexagonal'): """ Generate the line mode k along the selected path not very kind ase interface lead to a puzzling input parameters """ from ase.dft.kpoints import get_bandpath, get_special_points points = get_special_points(shape,atoms.get_cell()) #print points GXW = [points[k] for k in selectedPath] kpts,rk,rspk = get_bandpath(GXW, atoms.get_cell(), npoints=npoints) reciprocal_vectors = 2*np.pi*atoms.get_reciprocal_cell() return np.dot(kpts,reciprocal_vectors)
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 test_monoclinic(): """Test band structure from different variations of hexagonal cells.""" import numpy as np from ase import Atoms from ase.calculators.test import FreeElectrons from ase.geometry import (crystal_structure_from_cell, cell_to_cellpar, cellpar_to_cell) from ase.dft.kpoints import get_special_points mc1 = [[1, 0, 0], [0, 1, 0], [0, 0.2, 1]] par = cell_to_cellpar(mc1) mc2 = cellpar_to_cell(par) mc3 = [[1, 0, 0], [0, 1, 0], [-0.2, 0, 1]] mc4 = [[1, 0, 0], [-0.2, 1, 0], [0, 0, 1]] path = 'GYHCEM1AXH1' firsttime = True for cell in [mc1, mc2, mc3, mc4]: a = Atoms(cell=cell, pbc=True) a.cell *= 3 a.calc = FreeElectrons(nvalence=1, kpts={'path': path}) cs = crystal_structure_from_cell(a.cell) assert cs == 'monoclinic' r = a.cell.reciprocal() k = get_special_points(a.cell)['H'] print(np.dot(k, r)) a.get_potential_energy() bs = a.calc.band_structure() coords, labelcoords, labels = bs.get_labels() assert ''.join(labels) == path e_skn = bs.energies # bs.plot() if firsttime: coords1 = coords labelcoords1 = labelcoords e_skn1 = e_skn firsttime = False else: for d in [ coords - coords1, labelcoords - labelcoords1, e_skn - e_skn1 ]: print(abs(d).max()) assert abs(d).max() < 1e-13, d
def process_kpath(paths, cell, special_points=None): promoted = False if len(cell) == 2: promoted = True cell = [c + [0] for c in cell] + [0, 0, 0] icell = np.linalg.inv(cell).T if special_points is None: from ase.dft.kpoints import get_special_points # pylint: disable=import-error special_points = get_special_points(cell) points = [[ special_point_to_vector(elem, icell, special_points) for elem in p ] for p in parse_path(paths)] if promoted: print(points) pass return points
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)
[1.95021879, 1.12595934, 0.79617349] ])) # Part 2: Find ground state density and diagonalize full hamiltonian calc = GPAW(mode=PW(500), kpts=(6, 6, 3), xc='RPBE', # Use smaller Fermi-Dirac smearing to avoid intraband transitions: occupations=FermiDirac(0.05), # nbands=0 will give zero empty bands, # nbands=-n will give n empty bands, # nao gives same number of bands as are atomic orbitals. nbands=100) atoms.set_calculator(calc) atoms.get_potential_energy() # Suggested by Ask Larsen special_points = kpoints.get_special_points(atoms.cell) print("\nSpecial Points: ", special_points) # decide some nice points bandpath = 'GWUXL' kpts, xcoords, labels = kpoints.bandpath(bandpath, atoms.cell, 100) calc.set(kpts=kpts, fixdensity=True) atoms.get_potential_energy() bs = atoms.calc.band_structure() # bs.plot(emin=-10, emax=50, filename=output_folder + '/caf2_bandstructure.png') bs.plot(filename=output_folder + '/caf2_bandstructure.png') bs.write(filename=output_folder + '/caf2_bandstructure.json')
import numpy as np from ase import Atoms Natoms = 4 A = 5.07202 # in angstrom LatVecs = np.zeros((3,3)) LatVecs[0,:] = [1.000000000000000, 0.000000000000000, 0.000000000000000] LatVecs[1,:] = [0.836301242074196, 0.548270218510140, 0.000000000000000] LatVecs[2,:] = [0.836301242074196, 0.249697083586569, 0.488110232379448] LatVecs = A*LatVecs print(LatVecs) coords = np.zeros((Natoms,3)) coords[0,:] = [0.000000000000000, 0.000000000000000, 0.000000000000000] coords[1,:] = [0.741937000000000, 0.741937000000000, 0.741937000000000] coords[2,:] = [0.258063000000000, 0.258063000000000, 0.258063000000000] coords[3,:] = [0.500000000000000, 0.500000000000000, 0.500000000000000] print(coords) coords = np.matmul(coords, LatVecs) atsymbs = ["Ni", "O", "O", "Li"] atoms = Atoms(symbols=atsymbs, positions=coords, cell=LatVecs, pbc=[True,True,True]) atoms.write("TEMP_atoms.xsf") from ase.dft.kpoints import get_special_points spec_kpts = get_special_points(atoms.cell, lattice="orthorhombic") print(spec_kpts)
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)
ax.set_aspect('equal') 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)
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Created on Mon Dec 24 08:59:33 2018 @author: clian """ from ase.dft.kpoints import get_special_points from ase.build import bulk from ase.io import read #si = bulk('Si', 'diamond', a=5.459) atoms = read('result', format='espresso-out') points = get_special_points(atoms.cell) line = 'K_POINTS crystal_b\n' line += '%i\n' % len(points) denK = 40 for point in points: line += '%4.3f %4.3f %4.3f %i ! %s \n' % ( points[point][0], points[point][1], points[point][2], denK, point) #print(points) open('bandkpt.part', 'w').write(line)
ax.set_zlim(-s, s) ax.set_aspect('equal') 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 path in special_paths[X]: points = [] for name in path: points.append(np.dot(icell, special_points[name])) paths.append((path, points)) if X == 'bcc': scale = 0.6 elev = pi / 13 else: scale = 1 elev = None plot(cell, paths, elev, scale)
ax.set_aspect('equal') 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)
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 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 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
from ase.calculators.test import FreeElectrons from ase.dft.kpoints import get_special_points firsttime = True for cell in [[[1, 0, 0], [0.5, 3**0.5 / 2, 0], [0, 0, 1]], [[1, 0, 0], [-0.5, 3**0.5 / 2, 0], [0, 0, 1]], [[0.5, -3**0.5 / 2, 0], [0.5, 3**0.5 / 2, 0], [0, 0, 1]]]: a = Atoms(cell=cell, pbc=True) a.cell *= 3 a.calc = FreeElectrons(nvalence=1, kpts={'path': 'GMKG'}) lat = a.cell.get_bravais_lattice() assert lat.name == 'HEX' print(repr(a.cell.get_bravais_lattice())) #print(crystal_structure_from_cell(a.cell)) r = a.get_reciprocal_cell() k = get_special_points(a.cell)['K'] print(np.dot(k, r)) a.get_potential_energy() bs = a.calc.band_structure() coords, labelcoords, labels = bs.get_labels() assert ''.join(labels) == 'GMKG' e_skn = bs.energies if firsttime: coords1 = coords labelcoords1 = labelcoords e_skn1 = e_skn firsttime = False else: for d in [ coords - coords1, labelcoords - labelcoords1, e_skn - e_skn1 ]: