예제 #1
0
 def create(self,
            elems,
            mean,
            sigma,
            layer_height=0.1,
            start_height=1.0,
            max_height=3.5):
     self.elems = elems
     self.n = len(elems)
     self.atoms = np.zeros((self.n, 3))
     # surface part
     # enlarge surface to avoid drop off
     surfabak = np.array(self.surf.atoms)
     surfebak = np.array(self.surf.elems)
     atomsu = np.zeros((surfabak.shape[0] * 18, 3))
     elemsu = []
     cellmat = to_cellmat(self.surf.cell)
     cellmat[2, 2] = self.surf.cellz
     for ix, x in enumerate([-1, 0, 1]):
         for iy, y in enumerate([-1, 0, 1]):
             for iz, z in enumerate([-1, 0]):
                 ik = ix * 6 + iy * 2 + iz
                 surfadd = np.array(
                     [x * cellmat[0] + y * cellmat[1] + z * cellmat[2]])
                 atomsu[ik * surfabak.shape[0]:(ik + 1) * surfabak.shape[0]] = \
                     surfabak + surfadd
                 elemsu += list(surfebak)
     elemsu = np.array(elemsu)
     zmax = self.surf.atoms.max(axis=0)[2]
     xs_core = [
         ia for ia, a in enumerate(self.surf.atoms)
         if a[2] >= zmax - layer_height
     ]
     xs_other = [ia for ia, a in enumerate(atomsu) if ia not in xs_core]
     soelems, soatoms = elemsu[xs_other], atomsu[xs_other]
     suelems, suatoms = self.surf.elems[xs_core], self.surf.atoms[xs_core]
     cura = 0  # current atom
     while cura != self.n:
         if cura == 0:
             qua, exr = True, None
         else:
             qua, exr = False, self.ext_range
         xatom = self.add_atom_f(self.elems[cura], self.elems, cura, mean, sigma, suelems, \
             suatoms, soelems=soelems, soatoms=soatoms, atst=[cellmat, zmax, start_height, \
             max_height], quarter=qua, ext_range=exr)
         xatom = self.image_ex(xatom, self.surf.cell)
         self.atoms[cura] = np.array(xatom)
         agatom, agelem = self.image_cr(xatom, self.elems[cura],
                                        self.surf.cell)
         soatoms = np.array(list(soatoms) + list(agatom))
         soelems = np.array(list(soelems) + list(agelem))
         cura += 1
     return self
예제 #2
0
 def __init__(self, clu):
     self.clu = clu
     self.finalfactor = 1.2
     super(ConnectivityCheck, self).__init__(clu.n)
     self.sur = []
     if isinstance(clu, ClusterAtSurface):
         cellmat = to_cellmat(clu.surf.cell)
         for ix in [-1, 0, 1]:
             for iy in [-1, 0, 1]:
                 self.sur.append(ix * cellmat[0] + iy * cellmat[1])
     else:
         self.sur.append(np.array([0.0, 0.0, 0.0]))
예제 #3
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
예제 #4
0
 def __init__(self, clu, ffactor):
     self.clu = clu
     self.finalfactor = ffactor
     self.steplength = 0.05
     self.traj = []
     self.maxiter = 1000
     self.sur = []
     if isinstance(clu, ClusterAtSurface):
         cellmat = to_cellmat(clu.surf.cell)
         for ix in [-1, 0, 1]:
             for iy in [-1, 0, 1]:
                 if ix == 0 and iy == 0:
                     continue
                 self.sur.append(ix * cellmat[0] + iy * cellmat[1])
예제 #5
0
 def build_surf_ref(self):
     cax = self.clus
     surf = cax[0].surf
     # align atoms
     eles, ne = elem_num(cax[0].elems)
     cellmat = to_cellmat(surf.cell)
     for i in [0, -1]:
         _, b = surface_compare(cax[i], self.ref_structs[i], ne, eles, 0.5)
         self.adjust_surf(cax[i], self.ref_structs[i], b)
     mdiff, _ = km_comp(cax[0].atoms, cax[-1].atoms, ne, eles, cellmat)
     lscax = [cax]
     nmax = self.nimages + 1
     assert (len(self.ref_structs) == nmax + 1)
     uimgs = []
     mishort = 0
     for cax in lscax:
         imgs = []
         for i in range(0, nmax + 1):
             if i == 0:
                 cc = cax[0]
             elif i == nmax:
                 cc = cax[1]
             else:
                 cc = self.ref_structs[i]
             cc = copy.deepcopy(cc)
             cc.surf.forces = None
             if cc.mag is None:
                 cc.mag = 0.0
             cc.label = "CONN-%d-%d:%%d.%d:%.2f" % (self.endp[0],
                                                    self.endp[1], i, cc.mag)
             imgs.append(cc)
         uimgs.append(imgs)
     return uimgs, [
         self.endp[0], self.endp[1],
         len(uimgs), 1, mishort, 0, 0, mdiff
     ]
예제 #6
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)
예제 #7
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]
예제 #8
0
    def interp_surf(self, ibest=None):
        if ibest is None:
            ibest = self.max_trials_surf
        cax = self.clus
        surf = cax[0].surf
        # align atoms
        eles, ne = elem_num(cax[0].elems)
        cellmat = to_cellmat(surf.cell)
        lscax = []
        mdiff = None
        mdmax = None
        misinglelong = 0
        if len(cax) == 2:
            bs = surface_compare(cax[0],
                                 cax[1],
                                 ne,
                                 eles,
                                 self.max_diff + 0.1,
                                 best=ibest)
            for md, b in bs:
                if len(lscax) != 0 and (md > self.max_diff
                                        or md > mdiff * 1.5):
                    break
                cxx = copy.deepcopy(cax)
                self.adjust_surf(cxx[0], cxx[1], b)
                mdx = np.linalg.norm(cxx[0].atoms - cxx[1].atoms, axis=1).max()
                if len(lscax) != 0 and (mdx > self.max_diff * 4):
                    misinglelong += 1
                    break
                lscax.append(cxx)
                if mdiff is None or md < mdiff:
                    mdiff = md
                if mdmax is None or mdx < mdmax:
                    mdmax = mdx
        else:
            for cai in range(len(cax) - 1, 0, -1):
                _, b = surface_compare(cax[cai - 1], cax[cai], ne, eles,
                                       self.max_diff + 0.1)
                self.adjust_surf(cax[cai - 1], cax[cai], b)
            mdiff, _ = km_comp(cax[0].atoms, cax[-1].atoms, ne, eles, cellmat)
            lscax.append(cax)

        # construct final images
        nmax = self.nimages + 1
        dc = 1.0 * nmax / (len(cax) - 1)
        for cax in lscax:
            for cai in range(0, len(cax)):
                cax[cai].idx = cai * dc

        uimgs = []
        mishort = 0
        for cax in lscax:
            imgs = []
            ishort = False
            for i in range(0, nmax + 1):
                cc = ClusterAtSurface(cax[0].n, copy.deepcopy(cax[0].surf))
                cc.elems = cax[0].elems
                for cai in range(1, len(cax)):
                    if cax[cai].idx >= i - 1E-8:
                        break
                cx, cy = cax[cai - 1], cax[cai]
                rx = (cax[cai].idx - i) / dc
                cc.atoms = cx.atoms * rx + cy.atoms * (1 - rx)
                cc.surf.atoms = cx.surf.atoms * rx + cy.surf.atoms * (1 - rx)
                cc.mag = None
                if np.abs(rx - 1) < 1E-8:
                    cc.mag, cc.energy = cx.mag, cx.energy
                    cc.surf.forces = cx.surf.forces
                elif np.abs(rx) < 1E-8:
                    cc.mag, cc.energy = cy.mag, cy.energy
                    cc.surf.forces = cy.surf.forces
                else:
                    cc.surf.forces = None
                if cc.mag is None:
                    cc.mag = 0.0
                cc.label = "CONN-%d-%d:%%d.%d:%.2f" % (self.endp[0],
                                                       self.endp[1], i, cc.mag)
                if i != 0 and i != nmax:
                    pcc = PreOptimization(cc,
                                          self.adjusted_short_length_factor)
                    pcc.maxiter = 12
                    lpp = pcc.opt()
                    if not lpp:
                        ishort = True
                        break
                    cc = pcc.traj[-1]
                imgs.append(cc)
            if not ishort:
                uimgs.append(imgs)
            else:
                mishort += 1
        return uimgs, [
            self.endp[0], self.endp[1],
            len(uimgs), ibest, mishort, misinglelong, 0, mdiff
        ]