Example #1
0
def surface_adjust(a, b):
    assert isinstance(a, Surface)
    assert isinstance(b, Surface)
    adir = to_direct(a.atoms, a.cell)
    bdir = to_direct(b.atoms, b.cell)
    for i in range(a.n):
        for k in range(2):
            adir[i, k] += num_adjust(bdir[i, k] - adir[i, k], 1.0)
    a.atoms = to_cartesian(adir, a.cell)
Example #2
0
def enlarge(c, size, cell):
    satoms = []
    catoms = []
    selems = []
    celems = []
    sforces = []
    cforces = []
    diratoms = to_direct(c.atoms, cell)
    for x in range(size[0]):
        for y in range(size[1]):
            for z in range(size[2]):
                xatoms = diratoms + np.array([[x, y, z]], dtype=float)
                satoms += list(xatoms[:c.surfnum])
                catoms += list(xatoms[c.surfnum:])
                selems += list(c.elems[:c.surfnum])
                celems += list(c.elems[c.surfnum:])
                if c.forces is not None:
                    sforces += list(c.forces[:c.surfnum])
                    cforces += list(c.forces[c.surfnum:])
    c.atoms = to_cartesian(np.array(satoms + catoms), cell)
    c.elems = np.array(selems + celems)
    if c.forces is not None:
        c.forces = np.array(sforces + cforces)
    c.n = len(c.atoms)
    c.surfnum = c.surfnum * size[0] * size[1] * size[2]
Example #3
0
 def image_cr(self, atomx, elemx, cell):
     adir = []
     xdir = to_direct(np.array([atomx]), cell)[0]
     for x in [-1, 0, 1]:
         for y in [-1, 0, 1]:
             if x == 0 and y == 0:
                 continue
             aadd = np.array([[x, y, 0.0]])
             adir.append(xdir + aadd)
     atoms = to_cartesian(np.array(adir), cell)
     return atoms, np.array([elemx] * len(adir))
Example #4
0
def surface_match(a, b, dmax, dmin=1E-2, nd=20):
    from cluster.base import elem_num
    assert isinstance(a, Surface)
    assert isinstance(b, Surface)
    adir = to_direct(a.atoms, a.cell)
    bdir = to_direct(b.atoms, a.cell)
    if len(a.elems) == len(b.elems):
        # efficient way
        assert (a.elems == b.elems).all()
        cellmat = to_cellmat(a.cell)
        eles, ne = elem_num(a.elems)
        ww = weights(a.atoms, b.atoms, ne, eles, cellmat)
        v, vx = kmc_comp(ww, ne, eles)
        vg = np.zeros(vx.shape, dtype=int)
        for i, ii in enumerate(vx):
            vg[ii - 1] = i + 1
        return v, vg
    else:
        # old way
        cl = np.linalg.norm(to_cellmat(a.cell), axis=1)
        dstep = (dmax / dmin)**(1.0 / nd)
        d = dmin
        mt = [-1] * a.n
        mx = range(b.n)
        cell = [1.0, 1.0, None]
        for _ in range(nd):
            for i in range(a.n):
                if mt[i] == -1:
                    for ij, j in enumerate(mx):
                        if check_imagex(adir[i], a.elems[i], bdir[j],
                                        b.elems[j], cell, d, cl):
                            mt[i] = j
                            del mx[ij]
                            break
            if len(mx) == 0:
                break
            d *= dstep
        # diff, march indices
        return d, np.array(mt) + 1
Example #5
0
def surface_align(cc, deep=True):
    assert isinstance(cc, ClusterAtSurface)
    if cc.n == 0:
        return
    # part 1: put cluster fragments together (using supercell periodicity)
    # atoms having a distance less than 1/3 cell are considered connected
    # method: using disjointset finding all fragments
    # move all other atoms closer to the center of the biggest fragment
    if cc.n > 1:
        cdir = to_direct(cc.atoms, cc.surf.cell)
        disj = DisjointSet(len(cdir))
        for ii, i in enumerate(cdir):
            for jj, j in enumerate(cdir[:ii]):
                if np.linalg.norm(i - j) < 1.0 / 3.0:
                    disj.union(ii, jj)
        roots, rootn = [], []
        for ii, i in enumerate(cdir):
            ik = disj.find(ii)
            if ik not in roots:
                roots.append(ik)
                rootn.append(1)
            else:
                rootn[roots.index(disj.find(ik))] += 1
        rootm = max(zip(roots, rootn), key=lambda x: x[1])
        rootc = np.zeros(3)
        for ii, i in enumerate(cdir):
            if disj.find(ii) == rootm[0]:
                rootc += i
        rootc /= rootm[1]
        for ii, i in enumerate(cdir):
            if disj.find(ii) == rootm[0]:
                continue
            for k in range(2):
                cdir[ii, k] += num_adjust(rootc[k] - cdir[ii, k], 1.0)
        cc.atoms = to_cartesian(cdir, cc.surf.cell)
    # part 2: put cluster closer to center of surface (using unitcell periodicity)
    # can make the surface atoms indeices disordered
    surf = cc.surf
    if deep:
        ucellmat = to_cellmat(surf.unit_cell)
        ucell = np.diag(to_direct(ucellmat, surf.cell))
        cdir = to_direct(cc.atoms, surf.cell)
        # space group transition reference atoms must be taken from space_group_ref
        ctrref = surf.space_group_ref
        scent = np.array([0.50, 0.50])
        cxdmin = []
        sg = SymOpsHall[surf.space_group]
        sg = [[x.strip() for x in s] for s in sg if s[2].strip() == 'z']
        for s in sg:
            cx = np.array(cdir)
            cx[:, 0:2] -= ctrref
            cx = apply_trans(cx, s, ucell)
            cx[:, 0:2] += ctrref
            # for unit-cell periodicity, cluster must be moved as a whole
            # for supercell periodicity, atoms can be moved singlely and dim by dim
            ccent = cx.mean(axis=0)
            for k in range(2):
                ccent[k] += num_adjust(scent[k] - ccent[k], ucell[k])
            cxd = np.linalg.norm(scent[0:2] - ccent[0:2])
            cxcar = to_cartesian(cx - cx.mean(axis=0) + ccent, surf.cell)
            if len(cxdmin) == 0 or cxd < cxdmin[0]:
                cxdmin = [cxd, cxcar, s, -cx.mean(axis=0) + ccent]
        cc.atoms = cxdmin[1]
    # part 3: move surface atoms accodingly and also make surface boundary atoms better
    csdir = to_direct(surf.atoms, surf.cell)
    if deep:
        csdir[:, 0:2] -= ctrref
        csdir = apply_trans(csdir, cxdmin[2], ucell)
        csdir[:, 0:2] += ctrref
        csdir += cxdmin[3]
    for ii, _ in enumerate(csdir):
        for k in range(2):
            csdir[ii, k] += num_adjust(TOLS - csdir[ii, k], 1.0)
    surf.atoms = to_cartesian(csdir, surf.cell)
Example #6
0
def surface_compare(a, b, ne, eles, _, best=None):
    assert isinstance(a, ClusterAtSurface)
    assert isinstance(b, ClusterAtSurface)
    ufactor = 0.3
    adir = to_direct(a.atoms, a.surf.cell)
    bdir = to_direct(b.atoms, b.surf.cell)
    bcent = bdir.mean(axis=0)
    bxcar = b.atoms
    surf = a.surf
    cellmat = to_cellmat(surf.cell)
    ucellmat = to_cellmat(surf.unit_cell)
    ucell = np.diag(to_direct(ucellmat, surf.cell))
    # space group transition reference atoms must be taken from space_group_ref
    atrref = surf.space_group_ref
    xvmins = []
    sg = SymOpsHall[surf.space_group]
    sg = [[x.strip() for x in s] for s in sg if s[2].strip() == 'z']
    for s in sg:
        ax = np.array(adir)
        ax[:, 0:2] -= atrref
        ax = apply_trans(ax, s, ucell)
        ax[:, 0:2] += atrref
        # for unit-cell periodicity, cluster must be moved as a whole
        # for supercell periodicity, atoms can be moved singlely and dim by dim
        acentpre = ax.mean(axis=0)
        dss = [[0.0], [0.0]]
        for k in range(2):
            acentpre[k] += num_adjust(bcent[k] - acentpre[k], ucell[k])
            if bcent[k] > acentpre[k] + ufactor * ucell[k]:
                dss[k].append(1.0)
            elif bcent[k] < acentpre[k] - ufactor * ucell[k]:
                dss[k].append(-1.0)
        for dx in dss[0]:
            for dy in dss[1]:
                dxy = np.array([dx * ucell[0], dy * ucell[1], 0.0])
                acent = acentpre + dxy
                axcar = to_cartesian(ax - ax.mean(axis=0) + acent, surf.cell)
                ww = weights(axcar, bxcar, ne, eles, cellmat)
                if best is None:
                    v, vx = kmc_comp(ww, ne, eles)
                    opmin = [s, vx, -ax.mean(axis=0) + acent, axcar]
                    xvmins.append([v, opmin])
                else:
                    v, vx = kmc_comp_best(best, ww, ne, eles)
                    for ij in range(best):
                        opmin = [s, vx[:, ij], -ax.mean(axis=0) + acent, axcar]
                        xvmins.append([v[ij], opmin])
    xvmins.sort(key=lambda x: x[0])
    if best is not None:
        xvmins = xvmins[:best]
    else:
        xvmins = xvmins[:1]
    for v, opmin in xvmins:
        if opmin is not None:
            asdir = to_direct(a.surf.atoms, surf.cell)
            asdir[:, 0:2] -= atrref
            asdir = apply_trans(asdir, opmin[0], ucell)
            asdir[:, 0:2] += atrref
            asdir += opmin[2]
            for ii, _ in enumerate(asdir):
                for k in range(2):
                    asdir[ii, k] += num_adjust(TOLS - asdir[ii, k], 1.0)
            ascar = to_cartesian(asdir, surf.cell)
            opmin.append(ascar)
    if best is not None:
        return xvmins
    else:
        return xvmins[0]
Example #7
0
 def image_ex(self, atomx, cell):
     xdir = to_direct(np.array([atomx]), cell)[0]
     for k in range(2):
         xdir[k] += num_adjust(0.5 - xdir[k], 1.0)
     return to_cartesian(np.array([xdir]), cell)[0]