def main2(): fname1 = "geometry/test_poscars/hackit.pos" A = pcread.poscar(fname1) fname2 = "geometry/test_poscars/hackit.pos" B = pcread.poscar(fname2) Astats = cell_stats(A.cell) Bstats = cell_stats(B.cell) m = np.array([[1,0,0],[0,1,1],[1,0,2]]) A = supercell(A,np.dot(A.cell, m)) Astats = cell_stats(A.cell) m = len(A)/len(B) ## for now aSSUME m integer print "vol factor", m nmatch = 0 print "target", Astats print A.cell allms = pickle.load(file("Ms_upto_2.pickle")) # allms = pickle.load(file("someMs.pickle")) # B = supercell(B, np.dot(B.cell, np.array([[m,0,0],[0,1,0],[0,0,1]]))) Bcells = enum.supercells(B, [m]) print "B.cell" print B.cell print "all size m Bcells", Bcells for Bc in Bcells[m]: Bs = supercell(B, np.dot(B.cell, Bc)) Bstats = cell_stats(Bs.cell) print "source", Bstats print Bs.cell # M = np.dot(npl.inv(B.cell), A.cell) # print "correct M (same as original m):" # print M print "testing like crazy:" for i in range(len(allms)): M = allms[i] newb = np.dot(Bs.cell, M) stats = cell_stats(newb) if (equal_stats(stats, Astats)): print "match", i, stats print "M=" print M print "newb=" print newb print "----" Btest = supercell(Bs, newb) fout = file("ucellX%d.tcl"% nmatch , "w") write_xyz_noopt(Btest, "B.X%d" %nmatch ,1, no_atoms=True) write_struct(fout, Btest, "B.X%d.xyz" %nmatch, 0, False) fout.close() nmatch += 1 if nmatch > 4: sys.exit()
def test_random(): from numpy import dot, all, abs from numpy.random import randint from random import choice from pylada.ce import Cluster from pylada.crystal import binary, supercell lattice = binary.zinc_blende() lattice[0].type = ['Si', 'Ge'] lattice[1].type = ['Si', 'Ge', 'C'] # now try random clusters with cell and their supercells for i in xrange(10): # random cluster a = Cluster(lattice) site = choice([0, 1]) a.add_spin(lattice[site].pos) for j in xrange(4): site = choice([0, 1]) pos = lattice[site].pos + dot(lattice.cell, randint(4, size=(3,))-2) try: a.add_spin(pos) except ValueError: pass # random structure structure = supercell(lattice, dot(lattice.cell, get_cell(3))) for atom in structure: atom.type = choice(lattice[atom.site].type) # random supercell for j in xrange(5): sp = supercell(structure, dot(structure.cell, get_cell(3))) for atom in sp: atom.site = structure[atom.site].site assert all(abs(a(sp) - len(sp) / len(structure) * a(structure)) < 1e-8)
def test_onsite(): """ Tests J0 PI calculation. This uses the same algorithmic pathway as more complex figures, but can be easily computed as the sum of particular specie-dependent terms on each site. """ from numpy import dot, abs, all from random import choice from pylada.crystal import binary, supercell from pylada.ce import Cluster lattice = binary.zinc_blende() for atom in lattice: atom.type = ['Si', 'Ge', 'C'] structure = binary.zinc_blende() for atom in structure: atom.type = 'Si' a = Cluster(lattice) # Empty cluster first assert abs(a(structure) - len(structure)) < 1e-8 for i in xrange(10): superstructure = supercell(lattice, dot(lattice.cell, get_cell())) for atom in superstructure: atom.type = choice(atom.type) assert abs(a(superstructure) - len(superstructure)) < 1e-8 # Try on-site cluster. # loop over random supercells. # PI should be number of proportional to number of each atomic type on each # site, or thereabouts mapping = a.occupation_mapping() for i in xrange(10): # create random superstructure superstructure = supercell(lattice, dot(lattice.cell, get_cell())) for atom in superstructure: atom.type = choice(atom.type) # now first and second site clusters for i, site in enumerate(lattice): # loop over flavors. types = [u.type for u in superstructure] a.spins = None a.add_spin(site.pos) s = mapping[i].itervalues().next().copy() s[:] = 0e0 for t in site.type: s += float(types.count(t)) * mapping[i][t] assert all(abs(a(superstructure) - s) < 1e-8)
def test_primitive(cell): """ Tests whether primitivization works. """ from numpy import abs, dot from numpy.linalg import inv from pylada.crystal import supercell, Structure, are_periodic_images as api, primitive, \ is_primitive lattice = Structure(0.0, 0.5, 0.5, 0.5, 0.0, 0.5, 0.5, 0.5, 0.0, scale=2.0, m=True) \ .add_atom(0, 0, 0, "As") \ .add_atom(0.25, 0.25, 0.25, ['In', 'Ga'], m=True) structure = supercell(lattice, dot(lattice.cell, cell)) assert not is_primitive(structure) structure = primitive(structure, 1e-8) assert is_primitive(structure) assert abs(structure.volume - lattice.volume) < 1e-8 assert len(structure) == len(lattice) assert is_integer(dot(structure.cell, inv(lattice.cell))) assert is_integer(dot(lattice.cell, inv(structure.cell))) invcell = inv(lattice.cell) for atom in structure: assert api(lattice[atom.site].pos, atom.pos, invcell) assert atom.type == lattice[atom.site].type assert getattr(lattice[atom.site], 'm', False) == getattr(atom, 'm', False) assert (getattr(atom, 'm', False) or atom.site == 0)
def reindex_sites(structure, lattice, tolerance=0.5): """ Reindexes atoms of structure according to lattice sites. Expects that the structure is an exact supercell of the lattice, as far cell vectors are concerned. The atoms, however, may have moved around a bit. To get an index, an atom must be clearly closer to one ideal lattice site than to any other, within a given tolerance (in units of `structure.scale`?). """ from pylada.crystal import neighbors, supercell from copy import deepcopy # haowei: should not change lattice lat = deepcopy(lattice) # first give a natural index for the sites in lattice for i, a in enumerate(lat): a.site = i # in the supercell, each atom carry the site from the lat above, and will # goes into the neighs lat = supercell(lattice=lat, supercell=structure.cell * structure.scale / lat.scale) for atom in structure: neighs_in_str = [n for n in neighbors(structure, 1, atom.pos)] d = neighs_in_str[0][2] # if two atoms from structure and lattice have exactly the same coordination # and hence dist = 0, it will be neglected by neighbors # add 1E-6 to atom.pos to avoid this, but aparrently this is not a perfect # solution, Haowei neighs = [n for n in neighbors(lat, 2, atom.pos + 1E-6)] assert abs(neighs[1][2]) > 1e-12,\ RuntimeError('Found two sites occupying the same position.') if neighs[0][2] * lat.scale > tolerance * d: atom.site = -1 else: atom.site = neighs[0][0].site
def test_ediff(): from pickle import loads, dumps from pylada.crystal import Structure, supercell from pylada.vasp.incar._params import Ediff, Ediffg structure = Structure([[0, 0.5, 0.5], [0.5, 0, 0.5], [0.5, 0.5, 0]])\ .add_atom(0, 0, 0, 'Si')\ .add_atom(0.25, 0.25, 0.25, 'Si') assert Ediff(None).incar_string(structure=structure) is None a = loads(dumps(Ediff(1e-4))).incar_string(structure=structure).split() assert a[0] == 'EDIFF' and a[1] == '=' and abs(float(a[2]) - 1e-4 * 2.) < 1e-8 a = loads(dumps(Ediff(-1e-4))).incar_string(structure=structure).split() assert a[0] == 'EDIFF' and a[1] == '=' and abs(float(a[2]) - 1e-4) < 1e-8 and float(a[2]) > 0e0 assert Ediffg(None).incar_string(structure=structure) is None a = loads(dumps(Ediffg(1e-4))).incar_string(structure=structure).split() assert a[0] == 'EDIFFG' and a[1] == '=' and abs(float(a[2]) - 1e-4 * 2.) < 1e-8 a = loads(dumps(Ediffg(-1e-4))).incar_string(structure=structure).split() assert a[0] == 'EDIFFG' and a[1] == '=' and abs(float(a[2]) + 1e-4) < 1e-8 structure = supercell(structure, [[1, 0, 0], [0, 1, 0], [0, 0, 1]]) a = loads(dumps(Ediff(1e-4))).incar_string(structure=structure).split() assert a[0] == 'EDIFF' and a[1] == '=' and abs(float(a[2]) - 1e-4 * 8.) < 1e-8 a = loads(dumps(Ediff(-1e-4))).incar_string(structure=structure).split() assert a[0] == 'EDIFF' and a[1] == '=' and abs(float(a[2]) - 1e-4) < 1e-8 and float(a[2]) > 0e0 a = loads(dumps(Ediffg(1e-4))).incar_string(structure=structure).split() assert a[0] == 'EDIFFG' and a[1] == '=' and abs(float(a[2]) - 1e-4 * 8.) < 1e-8 a = loads(dumps(Ediffg(-1e-4))).incar_string(structure=structure).split() assert a[0] == 'EDIFFG' and a[1] == '=' and abs(float(a[2]) + 1e-4) < 1e-8
def test_disorder(lim=8): from numpy import all, array, dot from numpy.random import random, randint from numpy.linalg import det from pylada.crystal import binary, supercell from pylada.vff import build_tree lattice = binary.zinc_blende() for i in xrange(10): cell = randint(-lim, lim, (3,3)) while det(cell) == 0: cell = randint(-lim, lim, (3,3)) a = supercell(lattice, dot(lattice.cell, cell)) b = build_tree(a, overlap=0.8) ids = [id(node.center) for node in b] connections = array([ sorted([ids.index(id(n.center)) for n, v in node]) for node in b ]) epsilon = random((3,3)) * 0.1 epsilon = epsilon + epsilon.T a.cell += dot(epsilon, a.cell) for atom in a: atom.pos += dot(epsilon, atom.pos) b = build_tree(a, overlap=0.8) c = array([ sorted([ids.index(id(n.center)) for n, v in node]) for node in b ]) assert all(connections == c) b = build_tree(a, overlap=0.8) for atom in a: atom.pos += random(3) * 0.05 - 0.025 c = array([ sorted([ids.index(id(n.center)) for n, v in node]) for node in b ]) assert all(connections == c) return a
def test_toarray(): """ Tests label exchange """ from random import choice from numpy import all, zeros from pylada.crystal import binary, supercell, HFTransform from pylada.decorations import Transforms lattice = binary.zinc_blende() lattice[0].type = ['Si', 'Ge'] lattice[1].type = ['Si', 'Ge', 'C'] transforms = Transforms(lattice) lattice = transforms.lattice for u in range(11): structure = supercell(lattice, get_cell()) for atom in structure: atom.type = choice(atom.type) hft = HFTransform(lattice, structure) a = transforms.toarray(hft, structure) b = zeros(len(structure), dtype='int') for atom in structure: site = lattice[atom.site] b[hft.index(atom.pos - site.pos, atom.site)] = site.type.index(atom.type) + 1 assert all(a == b)
def test_translations(cell): from numpy import abs, all from pylada.crystal import binary, supercell, HFTransform from pylada.decorations import Transforms lattice = binary.zinc_blende() lattice[0].type = ['Si', 'Ge'] lattice[1].type = ['Si', 'Ge', 'C'] # create random structure structure = supercell(lattice, cell) hft = HFTransform(lattice, structure) # these are all the translations translations = Transforms(lattice).translations(hft) assert translations.shape == (len(structure) // len(lattice) - 1, len(structure)) # compute each translation and gets decorations for atom in structure: if atom.site != 0: continue # create translation trans = atom.pos - lattice[0].pos if all(abs(trans) < 1e-8): continue # figure out its index index = hft.index(trans) - 1 for site in structure: pos = site.pos - lattice[site.site].pos i = hft.index(pos, site.site) j = hft.index(pos + trans, site.site) assert translations[index, i] == j
def test_labelexchange(): """ Tests label exchange """ from pylada.crystal import binary, supercell, HFTransform from pylada.decorations import Transforms lattice = binary.zinc_blende() lattice[0].type = ['Si', 'Ge'] lattice[1].type = ['Si', 'Ge', 'C'] transforms = Transforms(lattice) lattice = transforms.lattice structure = supercell(lattice, [[8, 0, 0], [0, 0.5, 0.5], [0, -0.5, 0.5]]) species = ['Ge', 'C', 'Si', 'C', 'Si', 'C', 'Si', 'Si', 'Ge', 'Si', 'Ge', 'Si', 'Ge', 'Si', 'Ge', 'Ge', 'Ge', 'C', 'Ge', 'Si', 'Si', 'Si', 'Si', 'Ge', 'Si', 'Ge', 'Si', 'Si', 'Si', 'C', 'Ge', 'Si'] for atom, s in zip(structure, species): atom.type = s hft = HFTransform(lattice, structure) x = transforms.toarray(hft, structure) results = [21112222221111123331111231122131, # <- this is x 21112222221111122221111321133121, 21112222221111123332222132211232, 21112222221111121112222312233212, 21112222221111122223333123311323, 21112222221111121113333213322313, 12221111112222213331111231122131, 12221111112222212221111321133121, 12221111112222213332222132211232, 12221111112222211112222312233212, 12221111112222212223333123311323, 12221111112222211113333213322313] permutations = transforms.label_exchange(hft) for a, b in zip(permutations(x), results[1:]): assert int(str(a)[1:-1].replace(' ', '')) == b
def test_primitive(cell): """ Tests whether primitivization works. """ from numpy import abs, dot from numpy.linalg import inv from pylada.crystal import supercell, Structure, are_periodic_images as api, primitive, \ is_primitive lattice = Structure(0.0, 0.5, 0.5, 0.5, 0.0, 0.5, 0.5, 0.5, 0.0, scale=2.0, m=True ) \ .add_atom(0, 0, 0, "As") \ .add_atom(0.25, 0.25, 0.25, ['In', 'Ga'], m=True) structure = supercell(lattice, dot(lattice.cell, cell)) assert not is_primitive(structure) structure = primitive(structure, 1e-8) assert is_primitive(structure) assert abs(structure.volume - lattice.volume) < 1e-8 assert len(structure) == len(lattice) assert is_integer(dot(structure.cell, inv(lattice.cell))) assert is_integer(dot(lattice.cell, inv(structure.cell))) invcell = inv(lattice.cell) for atom in structure: assert api(lattice[atom.site].pos, atom.pos, invcell) assert atom.type == lattice[atom.site].type assert getattr(lattice[atom.site], 'm', False) == getattr(atom, 'm', False) assert (getattr(atom, 'm', False) or atom.site == 0)
def test_coordination_shells(): from random import random from numpy import array from numpy.random import randint, random from pylada.crystal import supercell, Structure lattice = Structure([[0, 0.5, 0.5], [0.5, 0, 0.5], [0.5, 0.5, 0]]) \ .add_atom(0, 0, 0, "Si") \ .add_atom(0.25, 0.25, 0.25, "Ge") for atom in lattice: check(lattice, atom) structure = supercell(lattice, [[1, 1, 0], [-5, 2, 0], [0, 0, 1]]) for index in randint(len(structure), size=4): check(structure, structure[index]) for atom in lattice: atom.pos += random(3) * 1e-4 - 5e-5 for atom in lattice: check(lattice, atom, 1e-2) for atom in structure: atom.pos += random(3) * 1e-4 - 5e-5 for index in randint(len(structure), size=4): check(structure, structure[index], 1e-2) check_against_neighbors(structure, 1e-8) lattice = Structure([[0, 0.5, 0.5], [0.5, 0, 0.5], [0.5, 0.5, 0]]) \ .add_atom(0, 0, 0, "Si") check_against_neighbors(structure, 1e-8) lattice = Structure([[-0.5, 0.5, 0.5], [0.5, -0.5, 0.5], [0.5, 0.5, -0.5]]) \ .add_atom(0, 0, 0, "Si") check_against_neighbors(structure, 1e-8)
def explore_defect(defect, host, **kwargs): """ Diagnostic tool to determine defect from defect calculation and host. :Parameters: defect : `pylada.vasp.ExtractDFT` Extraction object for the vasp calculation of the defect structure. The defect structure should be a supercell of the host. Its unit cell must be an exact multiple of the host unit cell. Atoms may have moved around, however. host : `pylada.vasp.ExtractDFT` Extraction object for the vasp calculation of the host structure. kwargs Passed on to `reindex_sites`. :return: Dictionary containing three items: - 'vacancy': a list of atoms from the host *missing* in the defect structure. The position of these atoms correspond to the missing atom in the supercell (not the translational equivalent of the unit-cell). - 'substitution': list of indices referring to atoms in the defect structure with substituted types (w.r.t. the host). - 'intersititial': list of indices referring to atoms in the defect structure with no counterpart in the host structure. :note: The results may be incorrect if the defects incur too much relaxation. """ from copy import deepcopy from pylada.crystal.defects import reindex_sites from pylada.crystal import supercell dstr = deepcopy(defect.structure) hstr = host.structure reindex_sites(dstr, hstr, **kwargs) result = {'interstitial': [], 'substitution': [], 'vacancy': []} # looks for intersitials and substitutionals. for i, atom in enumerate(dstr): if atom.site == -1: result['interstitial'].append(i) elif atom.type != hstr[atom.site].type: result['substitution'].append(i) # looks for vacancies. # haowei: supercell, scale filled = supercell(lattice=hstr, supercell=dstr.cell * dstr.scale / hstr.scale) reindex_sites(filled, dstr, **kwargs) for atom in filled: if atom.site != -1: continue result['vacancy'].append(deepcopy(atom)) return result
def test_supercell(): """ Simple supercell test. """ from numpy import identity, abs, all, dot from numpy.linalg import inv from pylada.crystal import supercell, Structure, are_periodic_images as api from quantities import angstrom lattice = Structure(0.0, 0.5, 0.5, 0.5, 0.0, 0.5, 0.5, 0.5, 0.0, scale=2.0, m=True ) \ .add_atom(0, 0, 0, "As") \ .add_atom(0.25, 0.25, 0.25, ['In', 'Ga'], m=True) result = supercell(lattice, dot(lattice.cell, [[-1, 1, 1], [1, -1, 1], [1, 1, -1]])) assert all(abs(result.cell - identity(3)) < 1e-8) assert abs(result.scale - 2 * angstrom) < 1e-8 assert getattr(result, 'm', False) assert all(abs(result[0].pos - [0.00, 0.00, 0.00]) < 1e-8) assert result[0].type == "As" assert getattr(result[0], 'site', -1) == 0 assert api(result[0].pos, lattice[0].pos, inv(lattice.cell)) assert all(abs(result[1].pos - [0.25, 0.25, 0.25]) < 1e-8) assert result[1].type == ["In", "Ga"] assert getattr(result[1], 'm', False) assert getattr(result[1], 'site', -1) == 1 assert api(result[1].pos, lattice[1].pos, inv(lattice.cell)) assert all(abs(result[2].pos - [0.50, 0.00, 0.50]) < 1e-8) assert result[2].type == "As" assert getattr(result[2], 'site', -1) == 0 assert api(result[2].pos, lattice[0].pos, inv(lattice.cell)) assert all(abs(result[3].pos - [0.75, 0.25, 0.75]) < 1e-8) assert result[3].type == ["In", "Ga"] assert getattr(result[3], 'm', False) assert getattr(result[3], 'site', -1) == 1 assert api(result[3].pos, lattice[1].pos, inv(lattice.cell)) assert all(abs(result[4].pos - [0.50, 0.50, 0.00]) < 1e-8) assert result[4].type == "As" assert getattr(result[4], 'site', -1) == 0 assert api(result[4].pos, lattice[0].pos, inv(lattice.cell)) assert all(abs(result[5].pos - [0.75, 0.75, 0.25]) < 1e-8) assert result[5].type == ["In", "Ga"] assert getattr(result[5], 'm', False) assert getattr(result[5], 'site', -1) == 1 assert api(result[5].pos, lattice[1].pos, inv(lattice.cell)) assert all(abs(result[6].pos - [0.00, 0.50, 0.50]) < 1e-8) assert result[6].type == "As" assert getattr(result[6], 'site', -1) == 0 assert api(result[6].pos, lattice[0].pos, inv(lattice.cell)) assert all(abs(result[7].pos - [0.25, 0.75, 0.75]) < 1e-8) assert result[7].type == ["In", "Ga"] assert getattr(result[7], 'm', False) assert getattr(result[7], 'site', -1) == 1 assert api(result[7].pos, lattice[1].pos, inv(lattice.cell))
def main3(): from pylada.math import gruber fname1 = "geometry/test_poscars/hackit.pos" A0 = pcread.poscar(fname1) m = np.array([[1,0,0],[0,1,1],[0,0,2]]) A = supercell(A0,np.dot(A0.cell, m)) Ag = gruber(A.cell) m = np.array([[2,0,0],[0,1,0],[0,0,1]]) B = supercell(A0,np.dot(A0.cell, m)) Bg = gruber(B.cell) sa = cell_stats(Ag) print sa A2 = ang2vec(sa[3][0],sa[3][1],sa[3][2],sa[4][0],sa[4][1],sa[4][2]) print Ag print A2 sb = cell_stats(Bg) B2 = ang2vec(sb[3][0],sb[3][1],sb[3][2],sb[4][0],sb[4][1],sb[4][2]) print Bg print B2
def test_single_counting(): from pylada.crystal import binary, supercell from pylada.vff import build_tree a = binary.zinc_blende() a = supercell(binary.zinc_blende(), [[4, 0, 0], [0, 2, 0], [0, 0, 1]]) b = build_tree(a, overlap=0.5) n = 0 for center in b: for endpoint, vector in center.sc_bond_iter(): n += 1 for other, v in endpoint.sc_bond_iter(): assert other is not center assert id(center) in [id(c) for c, v in endpoint] assert n == 2 * len(a)
def get_a_supercell(u): from random import randint from numpy import array from numpy.linalg import det from pylada.crystal import supercell lattice = get_some_lattice(u) while True: cell = [[randint(-2, 3) for j in range(3)] for k in range(3)] if det(cell) != 0: break structure = supercell(lattice, cell) copy = structure.copy() for atom in copy: del atom.site return structure, copy, lattice
def test_angle(): from pylada.crystal import binary, supercell from pylada.vff import build_tree a = binary.zinc_blende() a = supercell(binary.zinc_blende(), [[4, 0, 0], [0, 2, 0], [0, 0, 1]]) b = build_tree(a, overlap=0.5) for center in b: ids = [id(u.center) for u, d in center] angles = set([(id(u.center), id(v.center)) for (u, d), (v, d) in center.angle_iter()]) for i, ida in enumerate(ids[:-1]): for idb in ids[i+1:]: if (ida, idb) in angles: assert (idb, ida) not in angles else: assert (idb, ida) in angles assert len(angles) == 6
def test_tree(): from numpy import all, array, dot, sum, any from pylada.crystal import binary, supercell from pylada.vff import build_tree a = binary.zinc_blende() a = supercell(binary.zinc_blende(), [[2, 0, 0], [0, 2, 0], [0, 0, 1]]) b = build_tree(a, overlap=0.5) for center in b: positions = [] for i, (bond, vector) in enumerate(center): position = bond.pos + dot(a.cell, vector) assert abs(sum((position - center.pos)**2) - 0.25*0.25*3) < 1e-8 assert all( [any(abs(array(p) - position[None, :]) > 1e-8) for p in positions] ) positions.append(position) assert i == 3
def test_firstisid(cell): """ Assumption is made in Transforms.transformations """ from numpy import abs, all, identity from pylada.crystal import binary, supercell, space_group lattice = binary.zinc_blende() lattice[0].type = ['Si', 'Ge'] lattice[1].type = ['Si', 'Ge', 'C'] # create random structure structure = supercell(lattice, cell) while len(structure) > 1: structure.pop(-1) assert len(structure) == 1 sg = space_group(structure)[0] assert all(abs(sg[:3] - identity(3, dtype='float64')) < 1e-8) assert all(abs(sg[3]) < 1e-8)
def test_rotations(): from numpy import all, dot, zeros from numpy.linalg import inv from pylada.crystal import binary, supercell, HFTransform, space_group, \ which_site from pylada.enum import Transforms lattice = binary.zinc_blende() lattice[0].type = ['Si', 'Ge'] lattice[1].type = ['Si', 'Ge', 'C'] sg = space_group(lattice) invcell = inv(lattice.cell) def get_cells(n): for i in xrange(1, n): yield [[i, 0, 0], [0, 0.5, 0.5], [0, -0.5, 0.5]] for i in xrange(1, n): yield [[i, 0, 0], [0, i, 0], [0, 0, 1]] for i in xrange(1, n): yield [[i, 0, 0], [0, i, 0], [0, 0, i]] yield dot(lattice.cell, [[1, 0, 0], [0, 1, 0], [0, 0, 2]]) for cell in get_cells(8): # create random structure structure = supercell(lattice, cell) hft = HFTransform(lattice, structure) # these are all the translations transforms = Transforms(lattice) permutations = transforms.transformations(hft) assert permutations.shape == (len(sg) - 1, len(structure)) operations = transforms.invariant_ops(structure) assert any(operations) # compute each translation and gets decorations for index, (op, isgood) in enumerate(zip(sg[1:], operations)): if not isgood: continue # Create rotation and figure out its index permutation = zeros(len(structure), dtype='int') - 1 for atom in structure: pos = dot(op[:3], atom.pos) + op[3] newsite = which_site(pos, lattice, invcell) i = hft.index(atom.pos - lattice[atom.site].pos, atom.site) j = hft.index(pos - lattice[newsite].pos, newsite) permutation[i] = j assert all(permutation == permutations[index])
def test_deformed_b5(u): from pytest import raises from random import randint from numpy import all, abs, dot, array, concatenate from pylada.crystal import HFTransform, supercell lattice = b5(u) supercell = supercell(lattice, dot(lattice.cell, [[2, 2, 0], [0, 2, 2], [4, 0, 4]])) a = HFTransform(lattice.cell, supercell) assert all(abs(a.transform - [[-1, 1, 1], [1, -1, 1], [5, -3, -1]]) < 1e-8) assert all(abs(a.quotient - [2, 2, 8]) < 1e-8) all_indices = set() others = set() for atom in supercell: indices = a.indices(atom.pos - lattice[atom.site].pos) index = a.index(atom.pos - lattice[atom.site].pos, atom.site) assert index not in all_indices, (index, all_indices) assert all(indices >= 0) assert all(indices <= a.quotient) all_indices.add(index) assert str(concatenate((indices, [atom.site]))) not in others others.add(str(concatenate((indices, [atom.site])))) for i in range(20): vec = dot( supercell.cell, array([randint(-20, 20), randint(-20, 20), randint(-20, 20)], dtype="float64")) vec += atom.pos - lattice[atom.site].pos assert all(abs(a.indices(vec) - indices) < 1e-8) with raises(ValueError): a.indices(vec + [0.1, 0.1, 0]) assert index == a.index(vec, atom.site) with raises(ValueError): a.index(vec + [0.1, 0.1, 0]) assert len(all_indices) == len(supercell)
def test_supercell_indices(): from pytest import raises from random import randint from numpy import all, abs, dot, array from pylada.crystal import HFTransform, Structure, supercell unitcell = array([[0, 0.5, 0.5], [0.5, 0, 0.5], [0.5, 0.5, 0]]) lattice = Structure(unitcell).add_atom(0, 0, 0, "Si") supercell = supercell( lattice, dot(lattice.cell, [[3, 0, 5], [0, 0, -1], [-2, 1, 2]])) a = HFTransform(unitcell, supercell) assert all(abs(a.transform - [[0, 2, 0], [1, 5, -1], [-2, -4, 0]]) < 1e-8) assert all(abs(a.quotient - [1, 1, 3]) < 1e-8) all_indices = set() for atom in supercell: indices = a.indices(atom.pos) index = a.index(atom.pos) assert index not in all_indices, (index, all_indices) assert all(indices >= 0) assert all(indices <= a.quotient) assert index == a.flatten_indices(*indices) all_indices.add(index) for i in range(20): vec = dot( supercell.cell, array([randint(-20, 20), randint(-20, 20), randint(-20, 20)], dtype="float64")) vec += atom.pos assert all(abs(a.indices(vec) - indices) < 1e-8) with raises(ValueError): a.indices(vec + [0.1, 0.1, 0]) assert index == a.index(vec) with raises(ValueError): a.index(vec + [0.1, 0.1, 0]) assert len(all_indices) == len(supercell)
def test_manysupercell(): from numpy import dot from numpy.linalg import inv, det from pylada.crystal import supercell, binary, are_periodic_images as api lattice = binary.zinc_blende() invlat = inv(lattice.cell) for i in range(10): cell = get_cell() struc = supercell(lattice, dot(lattice.cell, cell)) assert len(struc) == len(lattice) * int(abs(det(cell)) + 0.01) invcell = inv(struc.cell) for i, atom in enumerate(struc): # compare to lattice tolat = [api(atom.pos, site.pos, invlat) for site in lattice] assert tolat.count(True) == 1 assert tolat.index(True) == atom.site assert lattice[tolat.index(True)].type == atom.type # compare to self tolat = [api(atom.pos, site.pos, invcell) for site in struc] assert tolat.count(True) == 1 assert i == tolat.index(True)
def create_supercell(struct, N1, N2, N3): """ Create a supercell with lattice vector N1 x N2 x N3 of input cell Parameters struct = input structure (whoes supercell to be made) as pylada structure obj N1, N2, N3 = multiple for X, Y, Z cell vectors respectively Returns supercell = (N1 x N2 x N3) of input structure """ N1 = float(N1) N2 = float(N2) N3 = float(N3) input_str = deepcopy(struct) transp_cell = np.transpose(input_str.cell) new_cell = np.transpose( np.array( [N1 * transp_cell[0], N2 * transp_cell[1], N3 * transp_cell[2]])) sc = supercell(input_str, new_cell) return sc
def test_labelexchange(): """ Tests label exchange """ from pylada.crystal import binary, supercell, HFTransform from pylada.decorations import Transforms lattice = binary.zinc_blende() lattice[0].type = ['Si', 'Ge'] lattice[1].type = ['Si', 'Ge', 'C'] transforms = Transforms(lattice) lattice = transforms.lattice structure = supercell(lattice, [[8, 0, 0], [0, 0.5, 0.5], [0, -0.5, 0.5]]) species = [ 'Ge', 'C', 'Si', 'C', 'Si', 'C', 'Si', 'Si', 'Ge', 'Si', 'Ge', 'Si', 'Ge', 'Si', 'Ge', 'Ge', 'Ge', 'C', 'Ge', 'Si', 'Si', 'Si', 'Si', 'Ge', 'Si', 'Ge', 'Si', 'Si', 'Si', 'C', 'Ge', 'Si' ] for atom, s in zip(structure, species): atom.type = s hft = HFTransform(lattice, structure) x = transforms.toarray(hft, structure) results = [ 21112222221111123331111231122131, # <- this is x 21112222221111122221111321133121, 21112222221111123332222132211232, 21112222221111121112222312233212, 21112222221111122223333123311323, 21112222221111121113333213322313, 12221111112222213331111231122131, 12221111112222212221111321133121, 12221111112222213332222132211232, 12221111112222211112222312233212, 12221111112222212223333123311323, 12221111112222211113333213322313 ] permutations = transforms.label_exchange(hft) for a, b in zip(permutations(x), results[1:]): assert int(str(a)[1:-1].replace(' ', '')) == b
def mess_supercells(options, A): # generate arbitrary supercells and mess_up() both. # tools should find they are the all the same. from pylada import enum from pylada.crystal import primitive A = primitive(A) # Acells = enum.supercells(A,[2]) # Acells = Acells[2] # print Acells # if len(Acells) == 1: # return # custom to do a better job making hard cells! Acells = [ np.array([[2, 0, 0], [3, 2, 0], [4, 1, 1]]), np.array([[1, 0, 0], [3, 4, 0], [2, 0, 1]]) ] print Acells for idx in range(len(Acells) - 2, len(Acells)): AA = supercell(A, np.dot(A.cell, Acells[idx])) mess_cell(options, AA, "%d" % idx)
def test_rotations(cell): from numpy import all, dot, zeros from numpy.linalg import inv from pylada.crystal import binary, supercell, HFTransform, space_group, \ which_site from pylada.decorations import Transforms lattice = binary.zinc_blende() lattice[0].type = ['Si', 'Ge'] lattice[1].type = ['Si', 'Ge', 'C'] sg = space_group(lattice) invcell = inv(lattice.cell) # create random structure structure = supercell(lattice, cell) hft = HFTransform(lattice, structure) # these are all the translations transforms = Transforms(lattice) permutations = transforms.transformations(hft) assert permutations.shape == (len(sg) - 1, len(structure)) operations = transforms.invariant_ops(structure) assert any(operations) # compute each translation and gets decorations for index, (op, isgood) in enumerate(zip(sg[1:], operations)): if not isgood: continue # Create rotation and figure out its index permutation = zeros(len(structure), dtype='int') - 1 for atom in structure: pos = dot(op[:3], atom.pos) + op[3] newsite = which_site(pos, lattice, invcell) i = hft.index(atom.pos - lattice[atom.site].pos, atom.site) j = hft.index(pos - lattice[newsite].pos, newsite) permutation[i] = j assert all(permutation == permutations[index])
def test_supercell_indices(): from pytest import raises from random import randint from numpy import all, abs, dot, array from pylada.crystal import HFTransform, Structure, supercell unitcell = array([[0, 0.5, 0.5], [0.5, 0, 0.5], [0.5, 0.5, 0]]) lattice = Structure(unitcell).add_atom(0, 0, 0, "Si") supercell = supercell(lattice, dot(lattice.cell, [[3, 0, 5], [0, 0, -1], [-2, 1, 2]])) a = HFTransform(unitcell, supercell) assert all(abs(a.transform - [[0, 2, 0], [1, 5, -1], [-2, -4, 0]]) < 1e-8) assert all(abs(a.quotient - [1, 1, 3]) < 1e-8) all_indices = set() for atom in supercell: indices = a.indices(atom.pos) index = a.index(atom.pos) assert index not in all_indices, (index, all_indices) assert all(indices >= 0) assert all(indices <= a.quotient) assert index == a.flatten_indices(*indices) all_indices.add(index) for i in range(20): vec = dot(supercell.cell, array( [randint(-20, 20), randint(-20, 20), randint(-20, 20)], dtype="float64")) vec += atom.pos assert all(abs(a.indices(vec) - indices) < 1e-8) with raises(ValueError): a.indices(vec + [0.1, 0.1, 0]) assert index == a.index(vec) with raises(ValueError): a.index(vec + [0.1, 0.1, 0]) assert len(all_indices) == len(supercell)
def test_deformed_b5(u): from pytest import raises from random import randint from numpy import all, abs, dot, array, concatenate from pylada.crystal import HFTransform, supercell lattice = b5(u) supercell = supercell(lattice, dot(lattice.cell, [[2, 2, 0], [0, 2, 2], [4, 0, 4]])) a = HFTransform(lattice.cell, supercell) assert all(abs(a.transform - [[-1, 1, 1], [1, -1, 1], [5, -3, -1]]) < 1e-8) assert all(abs(a.quotient - [2, 2, 8]) < 1e-8) all_indices = set() others = set() for atom in supercell: indices = a.indices(atom.pos - lattice[atom.site].pos) index = a.index(atom.pos - lattice[atom.site].pos, atom.site) assert index not in all_indices, (index, all_indices) assert all(indices >= 0) assert all(indices <= a.quotient) all_indices.add(index) assert str(concatenate((indices, [atom.site]))) not in others others.add(str(concatenate((indices, [atom.site])))) for i in range(20): vec = dot(supercell.cell, array( [randint(-20, 20), randint(-20, 20), randint(-20, 20)], dtype="float64")) vec += atom.pos - lattice[atom.site].pos assert all(abs(a.indices(vec) - indices) < 1e-8) with raises(ValueError): a.indices(vec + [0.1, 0.1, 0]) assert index == a.index(vec, atom.site) with raises(ValueError): a.index(vec + [0.1, 0.1, 0]) assert len(all_indices) == len(supercell)
def raw_anim(A, B, options): # just animate between A and B, straight up! ### this option is under development savedir = os.getcwd() os.chdir(options.trajdir) structure = pcread.poscar(options.A) structure = pcread.poscar(options.B) print "saving starting anim" Bpath = deepcopy(B) tag = "Bpath0" write_xyz(options, Bpath, tag, options.output_tiles) fout = file("%s.tcl" % tag, "w") write_struct(fout, Bpath, "%s.xyz" % tag, 0, center=False, bonds=True, bond_len=options.bond_len) fout.close() # now write frames dt = 1.0 / (options.frames - 1) t = 0 iter = 0 eps = 1e-6 curpos = [] while t <= 1 + eps: Bpath = deepcopy(B) Bpath.cell = t * A.cell + (1.0 - t) * B.cell for i in range(len(apos)): pos = t * A[i].pos[i] + (1.0 - t) * B[i].pos[i] if (iter == 0): Bpath[i].pos = into_cell( pos, Bpath.cell) # then make sure it's _in_ the unit cell curpos.append(Bpath[i].pos) else: Bpath[i].pos = closest_to(pos, Bpath.cell, curpos[i]) curpos[i] = Bpath[i].pos if (iter == 0): ## testing/bug fixing from pylada.crystal import space_group, primitive from pylada.math import gruber Btest = primitive(Bpath) g = gruber(Btest.cell) print "src has cell:" print Btest.cell # print g Btest = supercell(Btest, g) spacegroup = space_group(Btest) sg = spglib.get_spacegroup(Btest, symprec=1e-4, angle_tolerance=2.0) print "src has %d syms and sg %s" % (len(spacegroup), str(sg)) Bstart = deepcopy(Bpath) sg = spglib.get_spacegroup(Bpath, symprec=1e-4, angle_tolerance=2.0) # sg = spglib.get_spacegroup(Bpath, symprec=1e-1, angle_tolerance=10.0) ### debugging print t, sg, tag if (iter == options.frames - 1): ## testing/bug fixing from pylada.crystal import space_group, primitive from pylada.math import gruber Btest = primitive(Bpath) g = gruber(Btest.cell) print "target has cell:" print Btest.cell # print g Btest = supercell(Btest, g) spacegroup = space_group(Btest) sg = spglib.get_spacegroup(Btest, symprec=1e-4, angle_tolerance=2.0) print "target has %d syms and sg %s" % (len(spacegroup), str(sg)) Bend = deepcopy(Bpath) tag = "traj.%d" % iter write_xyz(options, Bpath, tag, options.output_tiles) fout = file("%s.tcl" % tag, "w") write_struct(fout, Bpath, "%s.xyz" % tag, 0, center=False, bonds=True, bond_len=options.bond_len) fout.close() # write poscar we can analyze later # bigB = supercell(Bpath, np.dot(eye2,Bpath.cell)) # for writing a big poscar with open("%s.POSCAR" % tag, "w") as f: pcwrite.poscar(Bpath, f, vasp5=True) t += dt iter += 1 os.chdir(savedir) if (options.verbose > 2): write_tcl(options, Bend, Bstart, pairs[1], "pairs") # some special work to verify we really arrived at B: # Borig = pcread.poscar(options.A) # M = np.dot(Borig.cell, npl.inv(Bpath.cell)) # Bfinal = transform_cell(M,Bpath) # bigB = supercell(Bfinal, np.dot(eye2,Bfinal.cell)) ## this is a special "doubling" test # with open("final.POSCAR", "w") as f: pcwrite.poscar(bigB, f, vasp5=True) # with open("final.POSCAR", "w") as f: pcwrite.poscar(Bfinal, f, vasp5=True) # sg = spglib.get_spacegroup(Bfinal, symprec=1e-4, angle_tolerance=2.0) ## this is "B in A coords" # print "spacegroup of final structure: ", sg sg = spglib.get_spacegroup(B, symprec=1e-4, angle_tolerance=2.0) print "spacegroup of initial structure (B, [Bflip in code]) ", sg sg = spglib.get_spacegroup(A, symprec=1e-4, angle_tolerance=2.0) print "spacegroup of target structure (A) ", sg
def make_anim(A, B, Tm, shift, pairs, options): # combined view of the unit call and atom transforms # A is target, B is src, after src has been rotated and its unit cell axes permuted so that they # "most align" with those of A. Then transform is just two parts: first is unit cell Tform "Tm" # next is mapping in pairs ### no longer true: which is expressed in 3N-dim space as bigA. from copy import deepcopy from util import write_struct, write_xyz, transform_cell, write_tcl if options.verbose > 1: print "Exploring minimal path we have discovered..." # the results come out a little convoluated b/c of all the steps, so here we gather the # actual start and finish positions. details = False print B.cell print "maps to" print A.cell print "with internal atom shift" print shift print "and atom idx pairing" ppidx = pairs[0] ppos = pairs[1] ainv = npl.inv(A.cell) apos = [] bpos = [] for i in range(len(ppidx)): p = ppidx[i] q = ppos[i] print p, q ##, into_cell(np.dot(B.cell, np.dot(ainv, q[4])), B.cell) apos.append(q[3]) # target atom position bpos.append(q[4]) # src atom position if (options.verbose > 2): print "and A is just" print A.cell for a in A: print a.pos, into_cell(a.pos, A.cell) print "and B is just" print B.cell for b in B: print b.pos, into_cell(b.pos, B.cell) if (not os.path.exists(options.trajdir)): os.mkdir(options.trajdir) savedir = os.getcwd() os.chdir(options.trajdir) if (options.verbose > 1): print "saving starting anim" Bpath = deepcopy(B) tag = "Bpath0" write_xyz(options, Bpath, tag, options.output_tiles) fout = file("%s.tcl" % tag, "w") write_struct(fout, Bpath, "%s.xyz" % tag, 0, center=False, bonds=True, bond_len=options.bond_len) fout.close() # now write frames eye2 = 2.0 * np.identity(3) # for writing a big cell if we want dt = 1.0 / (options.frames - 1) t = 0 iter = 0 eps = 1e-6 curpos = [] while t <= 1 + eps: Bpath = deepcopy(B) Bpath.cell = t * A.cell + (1.0 - t) * B.cell for i in range(len(apos)): p = t * apos[i] + (1.0 - t) * bpos[ i] # this is an abs position, but in A's frame of reference (both apos and bpos are created with # B.cell transformed to A.cell. Here we are mapping to cells in between original B.cell and A.cell) # Note apos and bpos are not taken directly from A, B input cells but are part of the "pairing" data c = np.dot(ainv, p) # so get the coords pos = np.dot(Bpath.cell, c) # and express it w.r.t. evolving Bpath frame if (iter == 0): Bpath[i].pos = into_cell( pos, Bpath.cell) # then make sure it's _in_ the unit cell curpos.append(Bpath[i].pos) else: Bpath[i].pos = closest_to(pos, Bpath.cell, curpos[i]) curpos[i] = Bpath[i].pos if (iter == 0): ## testing/bug fixing Bstart = deepcopy(Bpath) if (options.verbose > 2): from pylada.crystal import space_group, primitive from pylada.math import gruber Btest = primitive(Bpath) g = gruber(Btest.cell) print "src has primitive cell:" print Btest.cell # print g Btest = supercell(Btest, g) spacegroup = space_group(Btest) sg = spglib.get_spacegroup(Btest, symprec=1e-4, angle_tolerance=2.0) print "src has %d syms and sg %s" % (len(spacegroup), str(sg)) sg = spglib.get_spacegroup(Bpath, symprec=1e-4, angle_tolerance=2.0) # sg = spglib.get_spacegroup(Bpath, symprec=1e-1, angle_tolerance=10.0) ### debugging if (options.verbose > 1): print t, sg, tag if (iter == options.frames - 1): ## testing/bug fixing Bend = deepcopy(Bpath) if (options.verbose > 2): from pylada.crystal import space_group, primitive from pylada.math import gruber Btest = primitive(Bpath) g = gruber(Btest.cell) print "target has primitive cell:" print Btest.cell # print g Btest = supercell(Btest, g) spacegroup = space_group(Btest) sg = spglib.get_spacegroup(Btest, symprec=1e-4, angle_tolerance=2.0) print "target has %d syms and sg %s" % (len(spacegroup), str(sg)) tag = "traj.%d" % iter write_xyz(options, Bpath, tag, options.output_tiles) fout = file("%s.tcl" % tag, "w") write_struct(fout, Bpath, "%s.xyz" % tag, 0, center=False, bonds=True, bond_len=options.bond_len) fout.close() # write poscar we can analyze later # bigB = supercell(Bpath, np.dot(eye2,Bpath.cell)) # for writing a big poscar with open("%s.POSCAR" % tag, "w") as f: pcwrite.poscar(Bpath, f, vasp5=True) t += dt iter += 1 os.chdir(savedir) if (options.verbose > 2): write_tcl(options, Bend, Bstart, pairs[1], "pairs") # some special work to verify we really arrived at B: # Borig = pcread.poscar(options.A) # M = np.dot(Borig.cell, npl.inv(Bpath.cell)) # Bfinal = transform_cell(M,Bpath) # bigB = supercell(Bfinal, np.dot(eye2,Bfinal.cell)) ## this is a special "doubling" test # with open("final.POSCAR", "w") as f: pcwrite.poscar(bigB, f, vasp5=True) # with open("final.POSCAR", "w") as f: pcwrite.poscar(Bfinal, f, vasp5=True) # sg = spglib.get_spacegroup(Bfinal, symprec=1e-4, angle_tolerance=2.0) ## this is "B in A coords" # print "spacegroup of final structure: ", sg sg = spglib.get_spacegroup(B, symprec=1e-4, angle_tolerance=2.0) if (options.verbose > 0): print "spacegroup of initial structure (B, [Bflip in code]) ", sg sg = spglib.get_spacegroup(A, symprec=1e-4, angle_tolerance=2.0) if (options.verbose > 1): print "spacegroup of target structure (A) ", sg
from copy import deepcopy import os from pylada.crystal import supercell, Structure import pylada.periodic_table as pt import pickle import numpy as np nproc = 96 # Primittive structure perfectStruc = Structure([[0.5, 0.5, 0], [0.5, 0, 0.5], [0, 0.5, 0.5]]) perfectStruc.add_atom(0, 0, 0, 'Si') perfectStruc.add_atom(0.25, 0.25, 0.25, 'Si') # Building the (perfect) supercell perfectStrucsc = supercell(perfectStruc, 4 * perfectStruc.cell) # Primitive Cell Calculations ######################################################## # Relaxation pwrelax = pwcalc() pwrelax.name = "pcPara" pwrelax.calc_type = "vc-relax" pwrelax.restart_mode = "from_scratch" pwrelax.pseudo_dir = os.path.expanduser("~/scratch/pseudo_pz-bhs/") pwrelax.celldm = 10.7 pwrelax.ecutwfc = 45.0 pwrelax.ecutrho = 400.0 pwrelax.nbnd = len(perfectStruc) * 4 pwrelax.occupations = "fixed" pwrelax.masses = {'Si': pt.Si.atomic_weight}
# print("Done with the supercell") try: slab = minimize_broken_bonds(bulk=bulk,slab=slab,vacuum=vacuum,charge=charge,minimize_total=True) except AssertionError: print("Charges do not sum up to zero for %s, the charges are:"%(files[f]), charge) print("Going to the next structure.") break # print("Done with the supercell construction, now shaping it") cell=transpose(slab.cell) cell[2][0]=0. cell[2][1]=0. slab.cell=transpose(cell) r=diag([1,1,1]) slab=supercell(slab,dot(slab.cell,r)) write.poscar(structure=slab,file=outdir_cur + '/POSCAR_%s%s%s_%slay_%svac' %(miller[0],miller[1],miller[2],nlayers,vacuum),vasp5=True) file.write('% 2i % 2i % 2i broken_bonds %2.4f %2.4f polar=%s\n' %(miller[0],miller[1],miller[2],count_broken_bonds(bulk=bulk,slab=slab),count_broken_bonds_per_area(bulk=bulk,slab=slab),is_polar(slab=slab,charge=charge))) file.flush() else: file.write('DONE %d\n'%(miller_bounds)) file.flush() file.close() print("%s on core %d: DONE"%(files[f], rank)) continue file.write('FAILED\n') file.flush()
relax = Relax(copy=vasp) relax.nsw=75 relax.minrelsteps= 4 relax.maxiter = 10 relax.keep_steps = True relax.first_trial = { "kpoints": "\n0\nAuto\n10", "encut": 0.9 } ############### setting up the structures # input bulk primitive cell In2O3prim = read.poscar('POSCAR_In2O3') # create bulk supercell In2O3_sc = supercell(In2O3prim,np.diag([In2O3prim.cell[0][0]*2., In2O3prim.cell[1][1]*2., In2O3prim.cell[2][2]*2.])) # create list of job folders calcs = ['epsilon', 'SC', 'Ini', 'VIn', 'OIn'] structures = {} for calc in calcs: if calc=='epsilon': structure=deepcopy(In2O3prim) structures[calc]=structure else: structure=deepcopy(In2O3_sc) # supercell
from pylada.crystal import supercell, Structure from prepare import reciprocal from mpl_toolkits.mplot3d import Axes3D import matplotlib matplotlib.use('TkAgg') import matplotlib.pyplot as plt tol = 1e-12 # Primittive structure A = Structure([[0.5, 0.5, 0], [0.5, 0, 0.5], [0, 0.5, 0.5]]) A.add_atom(0, 0, 0, 'Si') A.add_atom(0.25, 0.25, 0.25, 'Si') # Building the (perfect) supercell Asc = supercell(A, [[3, 0, 0], [0, 3, 0], [0, 0, 3]]) rpc = reciprocal(A.cell) #reciprocal lattice of PC irpc = np.linalg.inv(rpc) #inverse of reciprocal lattice of PC rsc = reciprocal(Asc.cell) #reciprocal lattice of SC irsc = np.linalg.inv(rsc) #inverse of reciprocal lattice of SC # big square # Finds the furthest corner corner = np.array([[0, 0, 0]]) for i in range(2): for j in range(2): for k in range(2): corner = np.reshape( np.max(np.concatenate(
def make_surface(structure=None, miller=None, nlayers=5, vacuum=15, acc=5): """Returns a slab from the 3D structure Takes a structure and makes a slab defined by the miller indices with nlayers number of layers and vacuum defining the size of the vacuum thickness. Variable acc determines the number of loops used to get the direct lattice vectors perpendicular and parallel to miller. For high index surfaces use larger acc value .. warning: (1) cell is always set such that miller is alogn z-axes (2) nlayers and vacuum are always along z-axes. :param structure: LaDa structure :param miller: 3x1 float64 array Miller indices defining the slab :param nlayers: integer Number of layers in the slab :param vacuum: real Vacuum thicness in angstroms :param acc: integer number of loops for finding the cell vectors of the slab structure """ direct_cell = transpose(structure.cell) reciprocal_cell = 2 * pi * transpose(inv(direct_cell)) orthogonal = [] # lattice vectors orthogonal to miller for n1 in arange(-acc, acc + 1): for n2 in arange(-acc, acc + 1): for n3 in arange(-acc, acc + 1): pom = array([n1, n2, n3]) if dot(pom, miller) == 0 and dot(pom, pom) != 0: orthogonal.append(array([n1, n2, n3])) # chose the shortest parallel and set it to be a3 lattice vector norm_orthogonal = [sqrt(dot(dot(x, direct_cell), dot(x, direct_cell))) for x in orthogonal] a1 = orthogonal[norm_orthogonal.index(min(norm_orthogonal))] # chose the shortest orthogonal to miller and not colinear with a1 and set it as a2 in_plane = [] for x in orthogonal: if dot(x, x) > 1e-3: v = cross(dot(x, direct_cell), dot(a1, direct_cell)) v = sqrt(dot(v, v)) if v > 1e-3: in_plane.append(x) norm_in_plane = [sqrt(dot(dot(x, direct_cell), dot(x, direct_cell))) for x in in_plane] a2 = in_plane[norm_in_plane.index(min(norm_in_plane))] a1 = dot(a1, direct_cell) a2 = dot(a2, direct_cell) # new cartesian axes z-along miller, x-along a1, and y-to define the right-hand orientation e1 = a1 / sqrt(dot(a1, a1)) e2 = a2 - dot(e1, a2) * e1 e2 = e2 / sqrt(dot(e2, e2)) e3 = cross(e1, e2) # find vectors parallel to miller and set the shortest to be a3 parallel = [] for n1 in arange(-acc, acc + 1): for n2 in arange(-acc, acc + 1): for n3 in arange(-acc, acc + 1): pom = dot(array([n1, n2, n3]), direct_cell) if sqrt(dot(pom, pom)) - dot(e3, pom) < 1e-8 and sqrt(dot(pom, pom)) > 1e-3: parallel.append(pom) # if there are no lattice vectors parallel to miller if len(parallel) == 0: for n1 in arange(-acc, acc + 1): for n2 in arange(-acc, acc + 1): for n3 in arange(-acc, acc + 1): pom = dot(array([n1, n2, n3]), direct_cell) if dot(e3, pom) > 1e-3: parallel.append(pom) parallel = [x for x in parallel if sqrt( dot(x - dot(e1, x) * e1 - dot(e2, x) * e2, x - dot(e1, x) * e1 - dot(e2, x) * e2)) > 1e-3] norm_parallel = [sqrt(dot(x, x)) for x in parallel] assert len(norm_parallel) != 0, "Increase acc, found no lattice vectors parallel to (hkl)" a3 = parallel[norm_parallel.index(min(norm_parallel))] # making a structure in the new unit cell - defined by the a1,a2,a3 new_direct_cell = array([a1, a2, a3]) assert abs(det(new_direct_cell)) > 1e-5, "Something is wrong your volume is equal to zero" # make sure determinant is positive if det(new_direct_cell) < 0.: new_direct_cell = array([-a1, a2, a3]) #structure = fill_structure(transpose(new_direct_cell),structure.to_lattice()) structure = supercell(lattice=structure, supercell=transpose(new_direct_cell)) # transformation matrix to new coordinates x' = dot(m,x) m = array([e1, e2, e3]) # seting output structure out_structure = Structure() out_structure.scale = structure.scale out_structure.cell = transpose(dot(new_direct_cell, transpose(m))) for atom in structure: p = dot(m, atom.pos) out_structure.add_atom(p[0], p[1], p[2], atom.type) # repaeting to get nlayers and vacuum repeat_cell = dot(out_structure.cell, array([[1., 0., 0.], [0., 1., 0.], [0., 0., nlayers]])) out_structure = supercell(lattice=out_structure, supercell=repeat_cell) # checking whether there are atoms close to the cell faces and putting them back to zero for i in range(len(out_structure)): scaled_pos = dot(out_structure[i].pos, inv(transpose(out_structure.cell))) for j in range(3): if abs(scaled_pos[j] - 1.) < 1e-5: scaled_pos[j] = 0. out_structure[i].pos = dot(scaled_pos, transpose(out_structure.cell)) # adding vaccum to the cell out_structure.cell = out_structure.cell + \ array([[0., 0., 0.], [0., 0., 0.], [0., 0., float(vacuum) / float(out_structure.scale)]]) # translating atoms so that center of the slab and the center of the cell along z-axes coincide max_z = max([x.pos[2] for x in out_structure]) min_z = min([x.pos[2] for x in out_structure]) center_atoms = 0.5 * (max_z + min_z) center_cell = 0.5 * out_structure.cell[2][2] for i in range(len(out_structure)): out_structure[i].pos = out_structure[i].pos + array([0., 0., center_cell - center_atoms]) # exporting the final structure return out_structure
def expand_cell_by(A, m): cellA = np.array(m) * A.cell bigA = supercell(A, cellA) return bigA