def get_spacegroup_and_volume(self, name, icsdno, natoms): # get experimental volume per formula unit output = commands.getoutput("grep 'space' /home/jyan/icsd/%s/icsd_%s.cif"%(name, icsdno)) if "No such file or directory" in output: return None, None volume = float(commands.getoutput("grep '_cell_volume' /home/jyan/icsd/%s/icsd_%s.cif"%(name, icsdno)).split()[1]) formulaunit = float(commands.getoutput("grep '_cell_formula_units_Z' /home/jyan/icsd/%s/icsd_%s.cif"%(name, icsdno)).split() [1]) chemformula = commands.getoutput("grep '_chemical_formula_sum' /home/jyan/icsd/%s/icsd_%s.cif"%(name, icsdno)).split() na = [] for s in chemformula: x = 0 for i in s: if i.isdigit(): x = int(i) + 10 * x na.append(x) if len(na) == 1: formulaunit *= na[0] else: ncell = gcd(na[0], na[1]) if len(na) > 2: for i in range(2, len(na)): ncell = gcd(ncell, na[i]) formulaunit *= ncell # try: # volume = read.icsd_cif_a("/home/jyan/icsd/%s/icsd_%s.cif"%(name, icsdno)).volume.magnitude # except: # return None, None return output.split("'")[1], volume / formulaunit
def filter_disorder(d): dnew = {} for key, item in d.items(): formula = item[0].replace("'",'').split() n = [] for el in formula: for i in el: if not i.isdigit(): el = el.replace(i, '') n.append(int(el)) ncell = n[0] if len(n) >= 2: ncell = gcd(n[0], n[1]) if len(n) > 2: for i in range(2, len(n)): ncell = gcd(ncell, n[i]) natoms = sum(n) / ncell if item[2] != 0 and (item[2] % natoms == 0 or natoms % item[2] == 0): dnew[key] = item else: print key, formula, item[2], natoms return dnew
def get_number_of_primitive_cell(self, Z): # input a list of atomic masses, and output number of primitive cells b = Counter(Z) nlist = [i[1] for i in b.items()] # number of atoms for each atom species if len(nlist) == 1: return nlist[0] else: ncell = gcd(nlist[0], nlist[1]) if len(nlist) > 2: for i in range(2, len(nlist)): ncell = gcd(ncell, nlist[i]) return ncell
def reduceindex(M): """Reduce Miller index to the lowest equivalent integers.""" oldM = M g = gcd(M[0], M[1]) h = gcd(g, M[2]) while h != 1: M = M // h g = gcd(M[0], M[1]) h = gcd(g, M[2]) if np.dot(oldM, M) > 0: return M else: return -M
def reduceindex(M): "Reduce Miller index to the lowest equivalent integers." oldM = M g = gcd(M[0], M[1]) h = gcd(g, M[2]) while h != 1: M = M/h g = gcd(M[0], M[1]) h = gcd(g, M[2]) if np.dot(oldM, M) > 0: return M else: return -M
def create_parsize_maxbands(nbands, world_size): """Safely parse command line parallel arguments for band parallel case.""" # D: number of domains # B: number of band groups if parsize_bands is None: if parsize_domain is None: B = gcd(nbands, world_size) # largest possible D = world_size // B else: D = parsize_domain B = gcd(nbands, world_size // np.prod(D)) else: B = parsize_bands D = parsize_domain or world_size // B return D, B
def reduceindex(M): """Reduce Miller index to the lowest equivalent integers.""" oldM = M g = gcd(M[0], M[1]) h = gcd(g, M[2]) while h != 1: if h == 0: raise ValueError("Division by zero: Are the miller indices linearly dependent?") M = M // h g = gcd(M[0], M[1]) h = gcd(g, M[2]) if np.dot(oldM, M) > 0: return M else: return -M
def reduceindex(M): """Reduce Miller index to the lowest equivalent integers.""" oldM = M g = gcd(M[0], M[1]) h = gcd(g, M[2]) while h != 1: if h == 0: raise ValueError( "Division by zero: Are the miller indices linearly dependent?") M = M // h g = gcd(M[0], M[1]) h = gcd(g, M[2]) if np.dot(oldM, M) > 0: return M else: return -M
def surface_from_ase(lattice, indices, layers, vacuum=None, tol=1e-10): """Create surface from a given lattice and Miller indices. lattice: Atoms object or str Bulk lattice structure of alloy or pure metal. Note that the unit-cell must be the conventional cell - not the primitive cell. One can also give the chemical symbol as a string, in which case the correct bulk lattice will be generated automatically. indices: sequence of three int Surface normal in Miller indices (h,k,l). layers: int Number of equivalent layers of the slab. vacuum: float Amount of vacuum added on both sides of the slab. Originally from ASE v. 3.11 """ indices = np.asarray(indices) if indices.shape != (3, ) or not indices.any() or indices.dtype != int: raise ValueError('%s is an invalid surface type' % indices) if isinstance(lattice, str): lattice = bulk(lattice, cubic=True) h, k, l = indices h0, k0, l0 = (indices == 0) if h0 and k0 or h0 and l0 or k0 and l0: # if two indices are zero if not h0: c1, c2, c3 = [(0, 1, 0), (0, 0, 1), (1, 0, 0)] if not k0: c1, c2, c3 = [(0, 0, 1), (1, 0, 0), (0, 1, 0)] if not l0: c1, c2, c3 = [(1, 0, 0), (0, 1, 0), (0, 0, 1)] else: p, q = ext_gcd(k, l) a1, a2, a3 = lattice.cell # constants describing the dot product of basis c1 and c2: # dot(c1,c2) = k1+i*k2, i in Z k1 = np.dot(p * (k * a1 - h * a2) + q * (l * a1 - h * a3), l * a2 - k * a3) k2 = np.dot(l * (k * a1 - h * a2) - k * (l * a1 - h * a3), l * a2 - k * a3) if abs(k2) > tol: i = -int(round(k1 / k2)) # i corresponding to the optimal basis p, q = p + i * l, q - i * k a, b = ext_gcd(p * k + q * l, h) c1 = (p * k + q * l, -p * h, -q * h) c2 = np.array((0, l, -k)) // abs(gcd(l, k)) c3 = (b, a * p, a * q) surf = build_from_ase(lattice, np.array([c1, c2, c3]), layers, tol) if vacuum is not None: surf.center(vacuum=vacuum, axis=2) return surf
def surface(lattice, indices, layers, vacuum=None, tol=1e-10): """Create surface from a given lattice and Miller indices. lattice: Atoms object or str Bulk lattice structure of alloy or pure metal. Note that the unit-cell must be the conventional cell - not the primitive cell. One can also give the chemical symbol as a string, in which case the correct bulk lattice will be generated automatically. indices: sequence of three int Surface normal in Miller indices (h,k,l). layers: int Number of equivalent layers of the slab. vacuum: float Amount of vacuum added on both sides of the slab. """ indices = np.asarray(indices) if indices.shape != (3,) or not indices.any() or indices.dtype != int: raise ValueError('%s is an invalid surface type' % indices) if isinstance(lattice, basestring): lattice = bulk(lattice, cubic=True) h, k, l = indices h0, k0, l0 = (indices == 0) if h0 and k0 or h0 and l0 or k0 and l0: # if two indices are zero if not h0: c1, c2, c3 = [(0, 1, 0), (0, 0, 1), (1, 0, 0)] if not k0: c1, c2, c3 = [(0, 0, 1), (1, 0, 0), (0, 1, 0)] if not l0: c1, c2, c3 = [(1, 0, 0), (0, 1, 0), (0, 0, 1)] else: p, q = ext_gcd(k, l) a1, a2, a3 = lattice.cell # constants describing the dot product of basis c1 and c2: # dot(c1,c2) = k1+i*k2, i in Z k1 = np.dot(p * (k * a1 - h * a2) + q * (l * a1 - h * a3), l * a2 - k * a3) k2 = np.dot(l * (k * a1 - h * a2) - k * (l * a1 - h * a3), l * a2 - k * a3) if abs(k2) > tol: i = -int(round(k1 / k2)) # i corresponding to the optimal basis p, q = p + i * l, q - i * k a, b = ext_gcd(p * k + q * l, h) c1 = (p * k + q * l, -p * h, -q * h) c2 = np.array((0, l, -k)) // abs(gcd(l, k)) c3 = (b, a * p, a * q) surf = build(lattice, np.array([c1, c2, c3]), layers, tol) if vacuum is not None: surf.center(vacuum=vacuum, axis=2) return surf
def _reduce(self): N = 0 for n in self._count.values(): if N == 0: N = n else: N = gcd(n, N) dct = {symb: n // N for symb, n in self._count.items()} return dct, N
def frac(f, n=2 * 3 * 4 * 5, tol=1e-6): if not isinstance(f, (int, float)): return np.array([frac(a, n, tol) for a in f]).T if f == 0: return 0, 1 x = n * f if abs(x - round(x)) > n * tol: raise ValueError x = int(round(x)) d = gcd(x, n) return x // d, n // d
def get_spacegroup_and_volume(self, name, icsdno, natoms): # get experimental volume per formula unit output = commands.getoutput( "grep 'space' /home/jyan/icsd/%s/icsd_%s.cif" % (name, icsdno)) if "No such file or directory" in output: return None, None volume = float( commands.getoutput( "grep '_cell_volume' /home/jyan/icsd/%s/icsd_%s.cif" % (name, icsdno)).split()[1]) formulaunit = float( commands.getoutput( "grep '_cell_formula_units_Z' /home/jyan/icsd/%s/icsd_%s.cif" % (name, icsdno)).split()[1]) chemformula = commands.getoutput( "grep '_chemical_formula_sum' /home/jyan/icsd/%s/icsd_%s.cif" % (name, icsdno)).split() na = [] for s in chemformula: x = 0 for i in s: if i.isdigit(): x = int(i) + 10 * x na.append(x) if len(na) == 1: formulaunit *= na[0] else: ncell = gcd(na[0], na[1]) if len(na) > 2: for i in range(2, len(na)): ncell = gcd(ncell, na[i]) formulaunit *= ncell # try: # volume = read.icsd_cif_a("/home/jyan/icsd/%s/icsd_%s.cif"%(name, icsdno)).volume.magnitude # except: # return None, None return output.split("'")[1], volume / formulaunit
def distribute_cpus(parsize_domain, parsize_bands, nspins, nibzkpts, comm=world, idiotproof=True, mode='fd'): nsk = nspins * nibzkpts if mode in ['fd', 'lcao']: if parsize_bands is None: parsize_bands = 1 else: # Plane wave mode: if parsize_bands is None: parsize_bands = comm.size // gcd(nsk, comm.size) p = Parallelization(comm, nsk) return p.build_communicators(domain=np.prod(parsize_domain), band=parsize_bands)
def surface(lattice, indices, layers, vacuum=None, tol=1e-10, termination=0): """Create surface from a given lattice and Miller indices. lattice: Atoms object or str Bulk lattice structure of alloy or pure metal. Note that the unit-cell must be the conventional cell - not the primitive cell. One can also give the chemical symbol as a string, in which case the correct bulk lattice will be generated automatically. indices: sequence of three int Surface normal in Miller indices (h,k,l). layers: int Number of equivalent layers of the slab. vacuum: float Amount of vacuum added on both sides of the slab. termination: int The termination "number" for your crystal. The same value will not produce the same termination for different symetrically identical bulk structures, but changing this value allows your to explore all the possible terminations for the bulk structure you provide it. note: this code is not well tested """ indices = np.asarray(indices) if indices.shape != (3,) or not indices.any() or indices.dtype != int: raise ValueError('%s is an invalid surface type' % indices) if isinstance(lattice, basestring): lattice = bulk(lattice, cubic=True) h, k, l = indices h0, k0, l0 = (indices == 0) if termination != 0: #changing termination import warnings warnings.warn('Work on changing terminations is currently in ' 'progress. Code may not behave as expected.') lattice1 = deepcopy(lattice) cell = lattice1.get_cell() pt = [0,0,0] millers = list(indices) for index,item in enumerate(millers): if item == 0: millers[index] = 10**9 #make zeros large numbers elif pt == [0,0,0]: #for numerical stability pt = list(cell[index]/float(item)/np.linalg.norm(cell[index])) h1,k1,l1 = millers N = np.array(cell[0]/h1+cell[1]/k1+cell[2]/l1) n = N/np.linalg.norm(N)# making a unit vector normal to cut plane d = [np.round(np.dot(n,(a-pt)),4) for a in lattice.get_scaled_positions()] d = set(d) d = sorted(list(d)) d = [0]+d #distances of atoms from cut plane displacement = (h*cell[0]+k*cell[1]+l*cell[2])*d[termination] lattice1.positions += displacement lattice = lattice1 if h0 and k0 or h0 and l0 or k0 and l0: # if two indices are zero if not h0: c1, c2, c3 = [(0, 1, 0), (0, 0, 1), (1, 0, 0)] if not k0: c1, c2, c3 = [(0, 0, 1), (1, 0, 0), (0, 1, 0)] if not l0: c1, c2, c3 = [(1, 0, 0), (0, 1, 0), (0, 0, 1)] else: p, q = ext_gcd(k, l) a1, a2, a3 = lattice.cell # constants describing the dot product of basis c1 and c2: # dot(c1,c2) = k1+i*k2, i in Z k1 = np.dot(p * (k * a1 - h * a2) + q * (l * a1 - h * a3), l * a2 - k * a3) k2 = np.dot(l * (k * a1 - h * a2) - k * (l * a1 - h * a3), l * a2 - k * a3) if abs(k2) > tol: i = -int(round(k1 / k2)) # i corresponding to the optimal basis p, q = p + i * l, q - i * k a, b = ext_gcd(p * k + q * l, h) c1 = (p * k + q * l, -p * h, -q * h) c2 = np.array((0, l, -k)) // abs(gcd(l, k)) c3 = (b, a * p, a * q) surf = build(lattice, np.array([c1, c2, c3]), layers, tol) if vacuum is not None: surf.center(vacuum=vacuum, axis=2) return surf
N = 2000 # number of bands repeats = 20 try: N = int(sys.argv[1]) K = int(sys.argv[2]) except (IndexError, ValueError): N = 6 K = 3 repeats = 3 # B: number of band groups # D: number of domains if parsize_bands is None: if parsize_domain is None: B = gcd(N, world.size) D = world.size // B else: B = world.size // np.prod(parsize_domain) D = parsize_domain else: B = parsize_bands D = world.size // B M = N // B # number of bands per group assert M * B == N, 'M=%d, B=%d, N=%d' % (M,B,N) h = 0.2 # grid spacing a = h * G # side length of box assert np.prod(D) * B == world.size, 'D=%s, B=%d, W=%d' % (D,B,world.size)
def nanotube(n, m, length=1, bond=1.42, symbol='C', verbose=False): if n < m: m, n = n, m sign = -1 else: sign = 1 nk = 6000 sq3 = sqrt(3.0) a = sq3 * bond l2 = n * n + m * m + n * m l = sqrt(l2) nd = gcd(n, m) if (n - m) % (3 * nd) == 0: ndr = 3 * nd else: ndr = nd nr = (2 * m + n) / ndr ns = -(2 * n + m) / ndr nn = 2 * l2 / ndr ichk = 0 if nr == 0: n60 = 1 else: n60 = nr * 4 absn = abs(n60) nnp = [] nnq = [] for i in range(-absn, absn + 1): for j in range(-absn, absn + 1): j2 = nr * j - ns * i if j2 == 1: j1 = m * i - n * j if j1 > 0 and j1 < nn: ichk += 1 nnp.append(i) nnq.append(j) if ichk == 0: raise RuntimeError('not found p, q strange!!') if ichk >= 2: raise RuntimeError('more than 1 pair p, q strange!!') nnnp = nnp[0] nnnq = nnq[0] if verbose: print 'the symmetry vector is', nnnp, nnnq lp = nnnp * nnnp + nnnq * nnnq + nnnp * nnnq r = a * sqrt(lp) c = a * l t = sq3 * c / ndr if 2 * nn > nk: raise RuntimeError('parameter nk is too small!') rs = c / (2.0 * np.pi) if verbose: print 'radius=', rs, t q1 = np.arctan((sq3 * m) / (2 * n + m)) q2 = np.arctan((sq3 * nnnq) / (2 * nnnp + nnnq)) q3 = q1 - q2 q4 = 2.0 * np.pi / nn q5 = bond * np.cos((np.pi / 6.0) - q1) / c * 2.0 * np.pi h1 = abs(t) / abs(np.sin(q3)) h2 = bond * np.sin((np.pi / 6.0) - q1) ii = 0 x, y, z = [], [], [] for i in range(nn): x1, y1, z1 = 0, 0, 0 k = np.floor(i * abs(r) / h1) x1 = rs * np.cos(i * q4) y1 = rs * np.sin(i * q4) z1 = (i * abs(r) - k * h1) * np.sin(q3) kk2 = abs(np.floor((z1 + 0.0001) / t)) if z1 >= t - 0.0001: z1 -= t * kk2 elif z1 < 0: z1 += t * kk2 ii += 1 x.append(x1) y.append(y1) z.append(z1) z3 = (i * abs(r) - k * h1) * np.sin(q3) - h2 ii += 1 if z3 >= 0 and z3 < t: x2 = rs * np.cos(i * q4 + q5) y2 = rs * np.sin(i * q4 + q5) z2 = (i * abs(r) - k * h1) * np.sin(q3) - h2 x.append(x2) y.append(y2) z.append(z2) else: x2 = rs * np.cos(i * q4 + q5) y2 = rs * np.sin(i * q4 + q5) z2 = (i * abs(r) - (k + 1) * h1) * np.sin(q3) - h2 kk = abs(np.floor(z2 / t)) if z2 >= t - 0.0001: z2 -= t * kk elif z2 < 0: z2 += t * kk x.append(x2) y.append(y2) z.append(z2) ntotal = 2 * nn X = [] for i in range(ntotal): X.append([x[i], y[i], sign * z[i]]) if length > 1: xx = X[:] for mnp in range(2, length + 1): for i in range(len(xx)): X.append(xx[i][:2] + [xx[i][2] + (mnp - 1) * t]) TransVec = t NumAtom = ntotal * length Diameter = rs * 2 ChiralAngle = np.arctan((sq3 * n) / (2 * m + n)) / (np.pi * 180) cell = [Diameter * 2, Diameter * 2, length * t] atoms = Atoms(symbol + str(NumAtom), positions=X, cell=cell, pbc=[False, False, True]) atoms.center() if verbose: print 'translation vector =', TransVec print 'diameter = ', Diameter print 'chiral angle = ', ChiralAngle return atoms
def nanotube(n, m, length=1, bond=1.42, symbol="C", verbose=False): if n < m: m, n = n, m sign = -1 else: sign = 1 nk = 6000 sq3 = sqrt(3.0) a = sq3 * bond l2 = n * n + m * m + n * m l = sqrt(l2) dt = a * l / np.pi nd = gcd(n, m) if (n - m) % (3 * nd) == 0: ndr = 3 * nd else: ndr = nd nr = (2 * m + n) / ndr ns = -(2 * n + m) / ndr nt2 = 3 * l2 / ndr / ndr nt = np.floor(sqrt(nt2)) nn = 2 * l2 / ndr ichk = 0 if nr == 0: n60 = 1 else: n60 = nr * 4 absn = abs(n60) nnp = [] nnq = [] for i in range(-absn, absn + 1): for j in range(-absn, absn + 1): j2 = nr * j - ns * i if j2 == 1: j1 = m * i - n * j if j1 > 0 and j1 < nn: ichk += 1 nnp.append(i) nnq.append(j) if ichk == 0: raise RuntimeError("not found p, q strange!!") if ichk >= 2: raise RuntimeError("more than 1 pair p, q strange!!") nnnp = nnp[0] nnnq = nnq[0] if verbose: print "the symmetry vector is", nnnp, nnnq lp = nnnp * nnnp + nnnq * nnnq + nnnp * nnnq r = a * sqrt(lp) c = a * l t = sq3 * c / ndr if 2 * nn > nk: raise RuntimeError("parameter nk is too small!") rs = c / (2.0 * np.pi) if verbose: print "radius=", rs, t q1 = np.arctan((sq3 * m) / (2 * n + m)) q2 = np.arctan((sq3 * nnnq) / (2 * nnnp + nnnq)) q3 = q1 - q2 q4 = 2.0 * np.pi / nn q5 = bond * np.cos((np.pi / 6.0) - q1) / c * 2.0 * np.pi h1 = abs(t) / abs(np.sin(q3)) h2 = bond * np.sin((np.pi / 6.0) - q1) ii = 0 x, y, z = [], [], [] for i in range(nn): x1, y1, z1 = 0, 0, 0 k = np.floor(i * abs(r) / h1) x1 = rs * np.cos(i * q4) y1 = rs * np.sin(i * q4) z1 = (i * abs(r) - k * h1) * np.sin(q3) kk2 = abs(np.floor((z1 + 0.0001) / t)) if z1 >= t - 0.0001: z1 -= t * kk2 elif z1 < 0: z1 += t * kk2 ii += 1 x.append(x1) y.append(y1) z.append(z1) z3 = (i * abs(r) - k * h1) * np.sin(q3) - h2 ii += 1 if z3 >= 0 and z3 < t: x2 = rs * np.cos(i * q4 + q5) y2 = rs * np.sin(i * q4 + q5) z2 = (i * abs(r) - k * h1) * np.sin(q3) - h2 x.append(x2) y.append(y2) z.append(z2) else: x2 = rs * np.cos(i * q4 + q5) y2 = rs * np.sin(i * q4 + q5) z2 = (i * abs(r) - (k + 1) * h1) * np.sin(q3) - h2 kk = abs(np.floor(z2 / t)) if z2 >= t - 0.0001: z2 -= t * kk elif z2 < 0: z2 += t * kk x.append(x2) y.append(y2) z.append(z2) ntotal = 2 * nn X = [] for i in range(ntotal): X.append([x[i], y[i], sign * z[i]]) if length > 1: xx = X[:] for mnp in range(2, length + 1): for i in range(len(xx)): X.append(xx[i][:2] + [xx[i][2] + (mnp - 1) * t]) TransVec = t NumAtom = ntotal * length Diameter = rs * 2 ChiralAngle = np.arctan((sq3 * n) / (2 * m + n)) / (np.pi * 180) cell = [Diameter * 2, Diameter * 2, length * t] atoms = Atoms(symbol + str(NumAtom), positions=X, cell=cell, pbc=[False, False, True]) atoms.center() if verbose: print "translation vector =", TransVec print "diameter = ", Diameter print "chiral angle = ", ChiralAngle return atoms
def oriented_surface(lattice, indices, layers, vacuum=None, tol=1e-10, orient=(1, 0)): """Create surface from a given lattice and Miller indices. lattice: Atoms object or str Bulk lattice structure of alloy or pure metal. Note that the unit-cell must be the conventional cell - not the primitive cell. One can also give the chemical symbol as a string, in which case the correct bulk lattice will be generated automatically. indices: sequence of three int Surface normal in Miller indices (h,k,l). layers: int Number of equivalent layers of the slab. vacuum: float Amount of vacuum added on both sides of the slab. """ orient = np.asarray(orient) if orient.shape != (2, ) or not orient.any() or orient.dtype != int: raise ValueError('%s is an invalid orientation type' % orient) indices = np.asarray(indices) if indices.shape != (3, ) or not indices.any() or indices.dtype != int: raise ValueError('%s is an invalid surface type' % indices) if isinstance(lattice, basestring): lattice = bulk(lattice, cubic=True) h, k, l = indices m, n = orient h0, k0, l0 = (indices == 0) if h0 and k0 or h0 and l0 or k0 and l0: # if two indices are zero if not h0: c1, c2, c3 = [(0, 1, 0), (0, 0, 1), (1, 0, 0)] if not k0: c1, c2, c3 = [(0, 0, 1), (1, 0, 0), (0, 1, 0)] if not l0: c1, c2, c3 = [(1, 0, 0), (0, 1, 0), (0, 0, 1)] else: a1, a2, a3 = lattice.cell # RZK: determine two surface vectors p, q = ext_gcd(k, l) # dot(c1,c2) = k1+i*k2, i in Z # RZK: k1 = (p*t1 + q.t2).t3 k1 = np.dot(p * (k * a1 - h * a2) + q * (l * a1 - h * a3), l * a2 - k * a3) # RZK: k2 = (l*t1 + k.t2).t3 k2 = np.dot(l * (k * a1 - h * a2) - k * (l * a1 - h * a3), l * a2 - k * a3) if abs(k2) > tol: i = -int(round( k1 / k2)) # RZK: i -- c in the PDF -- determines the optimal basis p, q = p + i * l, q - i * k # RZK: determine the vacuum vector a, b = ext_gcd(p * k + q * l, h) c1 = (p * k + q * l, -p * h, -q * h) # RZK: optimal surface vector 1 c2 = np.array((0, l, -k)) // abs(gcd( l, k)) # RZK: surface vector 2 = normalized(t3) c3 = (b, a * p, a * q) # RZK: vacuum vector # RZK!!: the following lines are modified print("c1 =", c1, ", c2 =", c2, ", c3 =", c3) c1n = (m * c1[0] + n * c2[0], m * c1[1] + n * c2[1], m * c1[2] + n * c2[2]) c2n = (-n * c1[0] + m * c2[0], -n * c1[1] + m * c2[1], -n * c1[2] + m * c2[2]) print("c1n=", c1n, ", c2n=", c2n) surf = build(lattice, np.array([c1n, c2n, c3]), layers, tol) if vacuum is not None: surf.center(vacuum=vacuum, axis=2) return surf
def find_k_along_path(self, plot_BZ=True): """Finds the k-points along the bandpath present in the original calculation""" kd = self.kd acell_cv = self.acell_cv bcell_cv = self.bcell_cv kpoints = self.kpoints if plot_BZ: """Plotting the points in the Brillouin Zone""" kp_1bz = to1bz(kd.bzk_kc, acell_cv) bzk_kcv = np.dot(kd.bzk_kc, bcell_cv) kp_1bz_v = np.dot(kp_1bz, bcell_cv) import matplotlib.pyplot as plt plt.plot(bzk_kcv[:, 0], bzk_kcv[:, 1], 'xg') plt.plot(kp_1bz_v[:, 0], kp_1bz_v[:, 1], 'ob') for ik in range(1, len(kpoints)): kpoint1_v = np.dot(kpoints[ik], bcell_cv) kpoint2_v = np.dot(kpoints[ik - 1], bcell_cv) plt.plot([kpoint1_v[0], kpoint2_v[0]], [kpoint1_v[1], kpoint2_v[1]], '--vr') """Finding the points along given directions""" print('Finding the kpoints along the path') N_c = kd.N_c wpts_xc = kpoints x_x = [] k_xc = [] k_x = [] x = 0. X = [] for nwpt in range(1, len(wpts_xc)): X.append(x) to_c = wpts_xc[nwpt] from_c = wpts_xc[nwpt - 1] vec_c = to_c - from_c print('From ', from_c, ' to ', to_c) Nv_c = (vec_c * N_c).round().astype(int) Nv = abs(gcd(gcd(Nv_c[0], Nv_c[1]), Nv_c[2])) print(Nv, ' points found') dv_c = vec_c / Nv dv_v = np.dot(dv_c, bcell_cv) dx = np.linalg.norm(dv_v) if nwpt == len(wpts_xc) - 1: # X.append(Nv * dx) Nv += 1 for n in range(Nv): k_c = from_c + n * dv_c bzk_c = to1bz(np.array([k_c]), acell_cv)[0] ikpt = kd.where_is_q(bzk_c, kd.bzk_kc) x_x.append(x) k_xc.append(k_c) k_x.append(ikpt) x += dx X.append(x_x[-1]) if plot_BZ is True: for ik in range(len(k_xc)): ktemp_xcv = np.dot(k_xc[ik], bcell_cv) plt.plot(ktemp_xcv[0], ktemp_xcv[1], 'xr', markersize=10) plt.show() return x_x, k_xc, k_x, X
def prune_symmetries_atoms(self, spos_ac): """Remove symmetries that are not satisfied by the atoms.""" if len(spos_ac) == 0: return # Build lists of atom numbers for each type of atom - one # list for each combination of atomic number, setup type, # magnetic moment and basis set: a_ij = {} for a, id in enumerate(self.id_a): if id in a_ij: a_ij[id].append(a) else: a_ij[id] = [a] a_j = a_ij[self.id_a[0]] # just pick the first species # if supercell disable fractional translations: if not self.symmorphic: op_cc = np.identity(3, int) ftrans_sc = spos_ac[a_j[1:]] - spos_ac[a_j[0]] ftrans_sc -= np.rint(ftrans_sc) for ft_c in ftrans_sc: a_a = self.check_one_symmetry(spos_ac, op_cc, ft_c, a_ij) if a_a is not None: self.symmorphic = True break symmetries = [] ftsymmetries = [] # go through all possible symmetry operations for op_cc in self.op_scc: # first ignore fractional translations a_a = self.check_one_symmetry(spos_ac, op_cc, [0, 0, 0], a_ij) if a_a is not None: symmetries.append((op_cc, [0, 0, 0], a_a)) elif not self.symmorphic: # check fractional translations sposrot_ac = np.dot(spos_ac, op_cc) ftrans_jc = sposrot_ac[a_j] - spos_ac[a_j[0]] ftrans_jc -= np.rint(ftrans_jc) for ft_c in ftrans_jc: try: nom_c, denom_c = frac(ft_c, tol=self.tol) except ValueError: continue ft_c = nom_c / denom_c a_a = self.check_one_symmetry(spos_ac, op_cc, ft_c, a_ij) if a_a is not None: ftsymmetries.append((op_cc, ft_c, a_a)) for c, d in enumerate(denom_c): self.gcd_c[c] = gcd(self.gcd_c[c] * d, d) # Add symmetry operations with fractional translations at the end: symmetries.extend(ftsymmetries) self.op_scc = np.array([sym[0] for sym in symmetries]) self.ft_sc = np.array([sym[1] for sym in symmetries]) self.a_sa = np.array([sym[2] for sym in symmetries]) inv_cc = -np.eye(3, dtype=int) self.has_inversion = (self.op_scc == inv_cc).all(2).all(1).any()