Example #1
0
    def test_equality(self):
        E1 = np.random.random((3, 3))
        L1 = Lattice(E1)
        E2 = np.random.random((4, 4))
        L2 = Lattice(E2)

        self.assertFalse(L1 == L2)
        self.assertFalse(L2 == E1)

        A = [[0, 1, 0], [1, 0, 0], [0, 0, 1]]
        L2 = Lattice(np.dot(E1, A))
        self.assertTrue(L1 == L2)
        self.assertFalse(L1 == E2)
Example #2
0
    def test_construction(self):
        E = np.eye(4).tolist()
        L = Lattice(E)
        self.assertEqual(L.dimension(), 4)
        self.assertListEqual(L.base()[:, 0].tolist(), [1, 0, 0, 0])

        # not matrix
        E = "adfda"
        self.assertRaises(ValueError, Lattice, E)

        # det E = 0
        E = [[1, 0, 0], [0, 0, 0], [0, 0, 1]]
        self.assertRaises(ValueError, Lattice, E)

        # 0 dimension
        E = []
        self.assertRaises(ValueError, Lattice, E)
Example #3
0
    def test_construction(self):
        E = np.eye(4).tolist()
        L = Lattice(E)
        self.assertEqual(L.dimension(), 4)
        self.assertListEqual(L.base()[:, 0].tolist(), [1, 0, 0, 0])

        # not matrix
        E = "adfda"
        self.assertRaises(ValueError, Lattice, E)

        # det E = 0
        E = [[1, 0, 0], [0, 0, 0], [0, 0, 1]]
        self.assertRaises(ValueError, Lattice, E)

        # 0 dimension
        E = []
        self.assertRaises(ValueError, Lattice, E)
Example #4
0
def lat_opt(E1, E2r, **kwargs):
    '''
    find the optimal lattice invarient shear move E1 as close as possible to E2
    allowed kwargs:
     - LG2: special lattice group of E2r
     - nsol: number of solutions
     - dist: choose from "Cauchy", "Ericksen" and "strain", default is "Cauchy"
     - hdlr: logger handler, default is basicConfigure
     - logfile: log file
     - loglevel: log level for the log file
     - disp: display level, 0 - none, 1 - brief, 2 - verbose
     - maxiter: maximum iteration depth, default is 3
     - ihnf: number of the HNF
    '''
    '''
    ===========
    Preparation
    ===========
    '''
    def print_ary(A):
        return "{:s}".format(A.tolist())

    def maxiter_by_nsol(nsol):
        """
        automatically choose maxiter by nsol
        """
        if nsol < 3:
            return 3
        if nsol < 10:
            return 4
        return 5

    # read kwargs
    nsol = kwargs['nsol'] if 'nsol' in kwargs else 1
    global miniter, maxiter
    maxiter = kwargs['maxiter'] if 'maxiter' in kwargs else maxiter_by_nsol(
        nsol)
    miniter = kwargs['miniter'] if 'miniter' in kwargs else 3
    disp = kwargs['disp'] if 'disp' in kwargs else 1
    if 'logfile' in kwargs:
        logging.basicConfig(level=logging.INFO)
        logger.propagate = False
        logfile = kwargs['logfile']
        fhdlr = logging.FileHandler(logfile, mode='a')
        fhdlr.setLevel(kwargs['loglevel'] if 'loglevel' in
                       kwargs else logging.INFO)
        fhdlr.setFormatter(logging.Formatter(' %(message)s'))
        logger.addHandler(fhdlr)

    if 'ihnf' in kwargs:
        logger.info("Processing the HNF No. {:d}".format(kwargs['ihnf'] + 1))
        if disp > 0:
            print("Processing the HNF No. {:d}".format(kwargs['ihnf'] + 1))

    # get dimension of the problem
    dim = len(E1)
    SLNode.dim = dim

    # start timer
    t_start = timer()

    # LLL-reduction
    Er1 = LLL(E1)
    # starting point
    lo = np.array(np.rint(np.dot(la.inv(E1), Er1)), dtype='int')

    # determine distance function
    distance = kwargs['dist'] if 'dist' in kwargs else 'Cauchy'

    logger.debug("distance is \"{:s}\"".format(distance))

    # distance functions
    if distance == 'Ericksen':
        dist = lambda x: Eric_dist(x, E1, E2r)
    if distance == 'strain':
        E2inv = la.inv(E2r)
        dist = lambda x: strain_dist(x, E1, E2inv)
    if distance == 'Cauchy':
        E2inv = la.inv(E2r)
        dist = lambda x: Cauchy_dist(x, E1, E2inv)

    # lattice groups
    LG1 = Lattice(E1).getspeciallatticegroup().matrices()
    SOLG2 = kwargs['SOLG2'] if 'SOLG2' in kwargs else Lattice(
        E2r).getspeciallatticegroup().matrices()

    SLNODE_CACHE = {'dist': dist, 'lg1': LG1, 'lg2': SOLG2}
    DFS_CACHE = {'counter': 0}
    '''
    ====================
    Preparation - finish
    ====================
    '''
    '''
    ==============
    Core procedure
    ==============
    '''
    # initialization
    global dopt, lopt, depth
    dopt = []
    lopt = []
    depth = 0

    # DEBUG
    global nlocmin
    nlocmin = 0

    # # look for new minnode
    # minnode_changed = True

    # for each new solution, store all symmetry related l's in memory
    EXT_SOLS = {}

    def ext_sols(l):
        for c in (q1.dot(l).dot(q2) for q1 in LG1 for q2 in SOLG2):
            EXT_SOLS[c.tostring()] = True

    def truncate_sols():
        global dopt, lopt
        # delete last one as long as it is not the same as the supposed tail
        while len(dopt) > nsol and dopt[-1] > dopt[nsol - 1]:
            dopt.pop(-1)
            lopt.pop(-1)

    # update strategy
    def update_solutions(tree):
        global dopt, lopt
        # otherwise, update existing solutions
        if len(dopt) > 0 and tree.elem.tostring() not in EXT_SOLS:
            for i, d in enumerate(dopt):
                if tree.elem_dist <= d:
                    dopt.insert(i, tree.elem_dist)
                    lopt.insert(i, tree.elem)
                    ext_sols(tree.elem)
                    truncate_sols()
                    return True
            if len(dopt) < nsol:
                dopt.append(tree.elem_dist)
                lopt.append(tree.elem)
                ext_sols(tree.elem)
                return True
        # directly append if it is the first one
        elif len(dopt) == 0:
            dopt.append(tree.elem_dist)
            lopt.append(tree.elem)
            ext_sols(tree.elem)
            return True
        return False

    def bfs(source):
        """
        breath first search of solutions
        :return: new starting point or None
        """
        global dopt, lopt, depth, miniter, maxiter

        EXPLORED = {}
        # bfs search from minnode
        EXPLORED[source.elem.tostring()] = True
        roots = [source]
        update_solutions(source)
        logger.debug("loop starts with the first trial {:s} => {:g}".format(
            str(source.elem.flatten()), source.elem_dist))
        updated = True

        depth = 0
        while depth < miniter or (updated and depth < maxiter):
            # while depth < maxiter:
            # update roots, generator first
            t0 = timer()
            # clear update flag
            updated = False
            # change depth tracker
            depth += 1
            # going down on the tree by iteration
            new_roots = []

            for root in roots:
                for gen, elem in root.children:
                    hashcode = elem.tostring()
                    if not hashcode in EXPLORED:
                        EXPLORED[hashcode] = True
                        t = SLNode(elem,
                                   SLNODE_CACHE,
                                   parent=gen,
                                   grandpa=root.parent)
                        new_roots.append(t)

                        # if in min iter
                        if depth <= miniter:
                            potential_newstart = dfs(t, DFS_CACHE)
                            if potential_newstart.elem_dist < source.elem_dist:
                                # a new starting point
                                del EXPLORED
                                return potential_newstart

                        # try to update the solution if the node element is closer than the last solution
                        if update_solutions(t):
                            updated = True

            roots = new_roots
            # debug messages
            update_msg = "found update" if updated else "no update"
            logger.debug(
                "number of roots at depth {:d} is {:d}, construction time: {:g}, {:s}."
                .format(depth, len(roots),
                        timer() - t0, update_msg))

        # all done
        del EXPLORED
        return None

    logger.debug("starting point: {:s}".format(str(lo.flatten())))
    new_start = SLNode(lo, SLNODE_CACHE)
    nrestart = 0

    while new_start is not None:
        # local minimization
        minnode = dfs(new_start, DFS_CACHE)
        # DEBUG
        nrestart += 1
        # BFS
        new_start = bfs(minnode)

    DFS_CACHE = {'counter': 0}
    SLNODE_CACHE = {'dist': dist, 'lg1': LG1, 'lg2': SOLG2}

    logger.debug("restarted {:d} times in total".format(nrestart))

    # if depth == maxiter and updated:
    #     lprint("DEBUG: maximum depth {:d} reached before solutions guaranteed".format(maxiter), 2)
    '''
    =======================
    Core procedure - finish
    =======================
    '''
    # finish timer
    t_elapsed = timer() - t_start

    if 'ihnf' in kwargs:
        logger.debug("HNF No. {:d} finished.".format(kwargs['ihnf'] + 1))
    for d, l in zip(dopt, lopt):
        logger.debug("{:.4f}, {:s}".format(d, str(l.flatten())))

    final_msg = "{:d} / {:d} solution(s) found by {:d} iterations and in {:g} sec.".format(
        len(dopt), nsol, depth, t_elapsed)
    if 'ihnf' in kwargs:
        final_msg = "HNF No. {:d}: ".format(kwargs['ihnf'] + 1) + final_msg
    logger.info(final_msg)
    if disp > 1:
        print(final_msg)
    return {'lopt': lopt, 'dopt': dopt}
Example #5
0
    def test_groups(self):
        L = Lattice(np.eye(4))
        self.assertRaises(AttributeError, L.Laue_group)
        self.assertRaises(AttributeError, L.point_group)
        self.assertRaises(AttributeError, L.special_lattice_group)
        self.assertRaises(AttributeError, L.lattice_group)

        # fcc with a = 2
        E = [[1., 0., 1.], [1., 1., 0.], [0., 1., 1.]]
        L = Lattice(E)
        Q = [[0., 1., 0.], [1., 0., 0.], [0., 0., -1.]]
        self.assertTrue(L.inpointgroup(Q))
        self.assertEqual(L.Laue_group().order(), 24)
        self.assertEqual(L.point_group().order(), 48)
        self.assertEqual(L.special_lattice_group().order(), 24)
        self.assertEqual(L.lattice_group().order(), 48)

        PG1 = L.point_group()
        self.assertTrue(PG1.hassubgroup(PG1))

        # monoclinic
        E = [[2., 0., 0.20934382], [0., 3., 0.], [0., 0., 3.99451814]]
        L = Lattice(E)
        self.assertFalse(L.inpointgroup(Q))
        self.assertEqual(L.Laue_group().order(), 2)
        self.assertEqual(L.point_group().order(), 4)
        self.assertEqual(L.special_lattice_group().order(), 2)
        self.assertEqual(L.lattice_group().order(), 4)

        PG2 = L.point_group()
        self.assertTrue(PG1.hassubgroup(PG2))

        # hexagonal, a = 2, c = 3
        E = [[2., 1., 0.], [0., np.sqrt(3), 0.], [0., 0., 3.]]
        L = Lattice(E)
        self.assertEqual(L.Laue_group().order(), 12)
        self.assertEqual(L.point_group().order(), 24)
        self.assertEqual(L.special_lattice_group().order(), 12)
        self.assertEqual(L.lattice_group().order(), 24)
        for Q in HEX_LAUE_GROUP.matrices():
            self.assertTrue(L.inpointgroup(Q))

        PG3 = L.point_group()
        self.assertFalse(PG1.hassubgroup(PG3))

        # rounding tolerance of floating numbers
        E = [[2., 1., 0.], [0., 1.73205081, 0.], [0., 0., 3.]]
        L = Lattice(E)
        self.assertEqual(L.Laue_group().order(), 12)
        self.assertEqual(L.point_group().order(), 24)
        self.assertEqual(L.special_lattice_group().order(), 12)
        self.assertEqual(L.lattice_group().order(), 24)
        Q = HEX_LAUE_GROUP.matrices()[6]
        self.assertTrue(L.inpointgroup(Q))

        # a random lattice
        E = 4 * np.random.rand(3, 3)
        while la.det(E) <= 0:
            E = 4 * np.random.rand(3, 3)
        L = Lattice(E)
        # lattice_group, point_group relationship
        PG = L.point_group().matrices()
        LG = L.lattice_group().matrices()

        LGlist = [m.tolist() for m in LG]
        LaueG = [m.tolist() for m in L.Laue_group().matrices()]
        SLG = [m.tolist() for m in L.special_lattice_group().matrices()]
        for Q in PG:
            self.assertEqual(L, Lattice(Q.dot(L.base())))
            self.assertTrue(np.array_equal(Q.T.dot(Q), np.eye(3)))
            self.assertTrue(L.inpointgroup(Q))
            if Q.tolist() in LaueG:
                self.assertTrue(la.det(Q) == 1)
            else:
                self.assertTrue(la.det(Q) == -1)
            # QE = EM
            M = np.rint(la.inv(E).dot(Q.dot(E)))
            self.assertTrue(M.tolist() in LGlist)
            self.assertTrue(L.inlatticegroup(M))

        for M in LG:
            self.assertEqual(L, Lattice(L.base().dot(M)))
            if M.tolist() in SLG:
                self.assertTrue(la.det(M) == 1)
            else:
                self.assertTrue(la.det(M) == -1)
            # QE = EM
            Q = E.dot(M).dot(la.inv(E))
            self.assertTrue(L.inpointgroup(Q))
Example #6
0
    def test_2D(self):
        # square
        E = np.array([[2, 0], [0, 2]])
        L = Lattice(E)
        PG1 = L.point_group()

        # centered rectangle
        E = np.array([[1., -1.], [1.5, 1.5]])
        L = Lattice(E)
        self.assertEqual(L.dimension(), 2)
        PG_expected = [[[1, 0], [0, 1]], [[-1, 0], [0, -1]], [[1, 0], [0, -1]],
                       [[-1, 0], [0, 1]]]
        PG2 = L.point_group()
        for Q in PG2.matrices():
            self.assertTrue(Q.tolist() in PG_expected)

        self.assertTrue(PG1.hassubgroup(PG2))

        # hexagonal
        E = [[2., 1.], [0., 1.73205081]]
        L = Lattice(E)
        self.assertEqual(L.Laue_group().order(), 6)
        self.assertEqual(L.point_group().order(), 12)

        # a random lattice
        E = 10 * np.random.rand(2, 2)
        while la.det(E) <= 0:
            E = 10 * np.random.rand(2, 2)
        L = Lattice(E)
        # lattice_group, point_group relationship
        PG = L.point_group().matrices()
        LG = L.lattice_group().matrices()

        LaueG = [m.tolist() for m in L.Laue_group().matrices()]
        SLG = [m.tolist() for m in L.special_lattice_group().matrices()]
        for Q in PG:
            self.assertTrue(L.inpointgroup(Q))
            if Q.tolist() in LaueG:
                self.assertTrue(la.det(Q) == 1)
            else:
                self.assertTrue(la.det(Q) == -1)
            # QE = EM
            M = np.rint(la.inv(E).dot(Q.dot(E)))
            self.assertTrue(L.inlatticegroup(M))

        for M in LG:
            self.assertEqual(L, Lattice(L.base().dot(M)))
            if M.tolist() in SLG:
                self.assertTrue(la.det(M) == 1)
            else:
                self.assertTrue(la.det(M) == -1)
            # QE = EM
            Q = E.dot(M).dot(la.inv(E))
            self.assertTrue(L.inpointgroup(Q))
Example #7
0
    def test_groups(self):
        L = Lattice(np.eye(4))
        self.assertRaises(AttributeError, L.Laue_group)
        self.assertRaises(AttributeError, L.point_group)
        self.assertRaises(AttributeError, L.special_lattice_group)
        self.assertRaises(AttributeError, L.lattice_group)

        # fcc with a = 2
        E = [[1., 0., 1.], [1., 1., 0.], [0., 1., 1.]]
        L = Lattice(E)
        Q = [[0., 1., 0.], [1., 0., 0.], [0., 0., -1.]]
        self.assertTrue(L.inpointgroup(Q))
        self.assertEqual(L.Laue_group().order(), 24)
        self.assertEqual(L.point_group().order(), 48)
        self.assertEqual(L.special_lattice_group().order(), 24)
        self.assertEqual(L.lattice_group().order(), 48)

        PG1 = L.point_group()
        self.assertTrue(PG1.hassubgroup(PG1))

        # monoclinic
        E = [[2., 0., 0.20934382], [0., 3., 0.], [0., 0., 3.99451814]]
        L = Lattice(E)
        self.assertFalse(L.inpointgroup(Q))
        self.assertEqual(L.Laue_group().order(), 2)
        self.assertEqual(L.point_group().order(), 4)
        self.assertEqual(L.special_lattice_group().order(), 2)
        self.assertEqual(L.lattice_group().order(), 4)

        PG2 = L.point_group()
        self.assertTrue(PG1.hassubgroup(PG2))

        # hexagonal, a = 2, c = 3
        E = [[2., 1., 0.], [0., np.sqrt(3), 0.], [0., 0., 3.]]
        L = Lattice(E)
        self.assertEqual(L.Laue_group().order(), 12)
        self.assertEqual(L.point_group().order(), 24)
        self.assertEqual(L.special_lattice_group().order(), 12)
        self.assertEqual(L.lattice_group().order(), 24)
        for Q in HEX_LAUE_GROUP.matrices():
            self.assertTrue(L.inpointgroup(Q))

        PG3 = L.point_group()
        self.assertFalse(PG1.hassubgroup(PG3))

        # rounding tolerance of floating numbers
        E = [[2., 1., 0.], [0., 1.73205081, 0.], [0., 0., 3.]]
        L = Lattice(E)
        self.assertEqual(L.Laue_group().order(), 12)
        self.assertEqual(L.point_group().order(), 24)
        self.assertEqual(L.special_lattice_group().order(), 12)
        self.assertEqual(L.lattice_group().order(), 24)
        Q = HEX_LAUE_GROUP.matrices()[6]
        self.assertTrue(L.inpointgroup(Q))

        # a random lattice
        E = 4 * np.random.rand(3, 3)
        while la.det(E) <= 0:
            E = 4 * np.random.rand(3, 3)
        L = Lattice(E)
        # lattice_group, point_group relationship
        PG = L.point_group().matrices()
        LG = L.lattice_group().matrices()

        LGlist = [m.tolist() for m in LG]
        LaueG = [m.tolist() for m in L.Laue_group().matrices()]
        SLG = [m.tolist() for m in L.special_lattice_group().matrices()]
        for Q in PG:
            self.assertEqual(L, Lattice(Q.dot(L.base())))
            self.assertTrue(np.array_equal(Q.T.dot(Q), np.eye(3)))
            self.assertTrue(L.inpointgroup(Q))
            if Q.tolist() in LaueG:
                self.assertTrue(la.det(Q) == 1)
            else:
                self.assertTrue(la.det(Q) == -1)
            # QE = EM
            M = np.rint(la.inv(E).dot(Q.dot(E)))
            self.assertTrue(M.tolist() in LGlist)
            self.assertTrue(L.inlatticegroup(M))

        for M in LG:
            self.assertEqual(L, Lattice(L.base().dot(M)))
            if M.tolist() in SLG:
                self.assertTrue(la.det(M) == 1)
            else:
                self.assertTrue(la.det(M) == -1)
            # QE = EM
            Q = E.dot(M).dot(la.inv(E))
            self.assertTrue(L.inpointgroup(Q))
Example #8
0
    def test_2D(self):
        # square
        E = np.array([[2, 0], [0, 2]])
        L = Lattice(E)
        PG1 = L.point_group()

        # centered rectangle
        E = np.array([[1., -1.], [1.5, 1.5]])
        L = Lattice(E)
        self.assertEqual(L.dimension(), 2)
        PG_expected = [
            [[1, 0], [0, 1]],
            [[-1, 0], [0, -1]],
            [[1, 0], [0, -1]],
            [[-1, 0], [0, 1]]
        ]
        PG2 = L.point_group()
        for Q in PG2.matrices():
            self.assertTrue(Q.tolist() in PG_expected)

        self.assertTrue(PG1.hassubgroup(PG2))

        # hexagonal
        E = [[2., 1.], [0., 1.73205081]]
        L = Lattice(E)
        self.assertEqual(L.Laue_group().order(), 6)
        self.assertEqual(L.point_group().order(), 12)

        # a random lattice
        E = 10 * np.random.rand(2, 2)
        while la.det(E) <= 0:
            E = 10 * np.random.rand(2, 2)
        L = Lattice(E)
        # lattice_group, point_group relationship
        PG = L.point_group().matrices()
        LG = L.lattice_group().matrices()

        LaueG = [m.tolist() for m in L.Laue_group().matrices()]
        SLG = [m.tolist() for m in L.special_lattice_group().matrices()]
        for Q in PG:
            self.assertTrue(L.inpointgroup(Q))
            if Q.tolist() in LaueG:
                self.assertTrue(la.det(Q) == 1)
            else:
                self.assertTrue(la.det(Q) == -1)
            # QE = EM
            M = np.rint(la.inv(E).dot(Q.dot(E)))
            self.assertTrue(L.inlatticegroup(M))

        for M in LG:
            self.assertEqual(L, Lattice(L.base().dot(M)))
            if M.tolist() in SLG:
                self.assertTrue(la.det(M) == 1)
            else:
                self.assertTrue(la.det(M) == -1)
            # QE = EM
            Q = E.dot(M).dot(la.inv(E))
            self.assertTrue(L.inpointgroup(Q))