示例#1
0
    def test_structure_transform(self):
        # Test trivial case
        trivial = self.fit_r4.structure_transform(self.structure,
                                                  self.structure.copy())
        self.assertArrayAlmostEqual(trivial, self.fit_r4)

        # Test simple rotation
        rot_symm_op = SymmOp.from_axis_angle_and_translation([1, 1, 1], 55.5)
        rot_struct = self.structure.copy()
        rot_struct.apply_operation(rot_symm_op)
        rot_tensor = self.fit_r4.rotate(rot_symm_op.rotation_matrix)
        trans_tensor = self.fit_r4.structure_transform(self.structure, rot_struct)
        self.assertArrayAlmostEqual(rot_tensor, trans_tensor)

        # Test supercell
        bigcell = self.structure.copy()
        bigcell.make_supercell([2, 2, 3])
        trans_tensor = self.fit_r4.structure_transform(self.structure, bigcell)
        self.assertArrayAlmostEqual(self.fit_r4, trans_tensor)

        # Test rotated primitive to conventional for fcc structure
        sn = self.get_structure("Sn")
        sn_prim = SpacegroupAnalyzer(sn).get_primitive_standard_structure()
        sn_prim.apply_operation(rot_symm_op)
        rotated = self.fit_r4.rotate(rot_symm_op.rotation_matrix)
        transformed = self.fit_r4.structure_transform(sn, sn_prim)
        self.assertArrayAlmostEqual(rotated, transformed)
    def test_fit(self):
        """
        Take two known matched structures
            1) Ensure match
            2) Ensure match after translation and rotations
            3) Ensure no-match after large site translation
            4) Ensure match after site shuffling
            """
        sm = StructureMatcher()

        self.assertTrue(sm.fit(self.struct_list[0], self.struct_list[1]))

        # Test rotational/translational invariance
        op = SymmOp.from_axis_angle_and_translation([0, 0, 1], 30, False,
                                                    np.array([0.4, 0.7, 0.9]))
        self.struct_list[1].apply_operation(op)
        self.assertTrue(sm.fit(self.struct_list[0], self.struct_list[1]))

        #Test failure under large atomic translation
        self.struct_list[1].translate_sites([0], [.4, .4, .2],
                                            frac_coords=True)
        self.assertFalse(sm.fit(self.struct_list[0], self.struct_list[1]))

        self.struct_list[1].translate_sites([0], [-.4, -.4, -.2],
                                            frac_coords=True)
        # random.shuffle(editor._sites)
        self.assertTrue(sm.fit(self.struct_list[0], self.struct_list[1]))
        #Test FrameworkComporator
        sm2 = StructureMatcher(comparator=FrameworkComparator())
        lfp = read_structure(os.path.join(test_dir, "LiFePO4.cif"))
        nfp = read_structure(os.path.join(test_dir, "NaFePO4.cif"))
        self.assertTrue(sm2.fit(lfp, nfp))
        self.assertFalse(sm.fit(lfp, nfp))

        #Test anonymous fit.
        self.assertEqual(sm.fit_anonymous(lfp, nfp),
                         {Composition("Li"): Composition("Na")})
        self.assertAlmostEqual(sm.get_minimax_rms_anonymous(lfp, nfp)[0],
                               0.096084154118549828)

        #Test partial occupancies.
        s1 = Structure([[3, 0, 0], [0, 3, 0], [0, 0, 3]],
                       [{"Fe": 0.5}, {"Fe": 0.5}, {"Fe": 0.5}, {"Fe": 0.5}],
                       [[0, 0, 0], [0.25, 0.25, 0.25],
                        [0.5, 0.5, 0.5], [0.75, 0.75, 0.75]])
        s2 = Structure([[3, 0, 0], [0, 3, 0], [0, 0, 3]],
                       [{"Fe": 0.25}, {"Fe": 0.5}, {"Fe": 0.5}, {"Fe": 0.75}],
                       [[0, 0, 0], [0.25, 0.25, 0.25],
                        [0.5, 0.5, 0.5], [0.75, 0.75, 0.75]])
        self.assertFalse(sm.fit(s1, s2))
        self.assertFalse(sm.fit(s2, s1))
        s2 = Structure([[3, 0, 0], [0, 3, 0], [0, 0, 3]],
                       [{"Fe": 0.25}, {"Fe": 0.25}, {"Fe": 0.25},
                        {"Fe": 0.25}],
                       [[0, 0, 0], [0.25, 0.25, 0.25],
                        [0.5, 0.5, 0.5], [0.75, 0.75, 0.75]])
        self.assertEqual(sm.fit_anonymous(s1, s2),
                         {Composition("Fe0.5"): Composition("Fe0.25")})

        self.assertAlmostEqual(sm.get_minimax_rms_anonymous(s1, s2)[0], 0)
    def test_init(self):
        fitter = StructureFitter(self.b, self.a)
        self.assertTrue(fitter.mapping_op != None, "No fit found!")

        #Now to try with rotated structure
        op = SymmOp.from_axis_angle_and_translation([0, 0, 1], 30, False, np.array([0, 0, 1]))
        editor = StructureEditor(self.a)
        editor.apply_operation(op)
        fitter = StructureFitter(self.b, editor.modified_structure)

        self.assertTrue(fitter.mapping_op != None, "No fit found!")

        #test with a supercell
        mod = SupercellMaker(self.a, scaling_matrix=[[2, 0, 0], [0, 1, 0], [0, 0, 1]])
        a_super = mod.modified_structure
        fitter = StructureFitter(self.b, a_super)
        self.assertTrue(fitter.mapping_op != None, "No fit found!")

        # Test with a structure with a translated point

        editor = StructureEditor(self.a)
        site = self.a[0]
        editor.delete_site(0)
        trans = np.random.randint(0, 1000, 3)
        editor.insert_site(0, site.species_and_occu, site.frac_coords + trans, False, False)
        fitter = StructureFitter(self.b, editor.modified_structure)
        self.assertTrue(fitter.mapping_op != None, "No fit found for translation {}!".format(trans))

        parser = CifParser(os.path.join(test_dir, "FePO4a.cif"))
        a = parser.get_structures()[0]
        parser = CifParser(os.path.join(test_dir, "FePO4b.cif"))
        b = parser.get_structures()[0]
        fitter = StructureFitter(b, a)
        self.assertTrue(fitter.mapping_op != None, "No fit found!")
示例#4
0
 def test_apply_operation(self):
     op = SymmOp.from_axis_angle_and_translation([0, 0, 1], 90)
     self.structure.apply_operation(op)
     self.assertArrayAlmostEqual(
         self.structure.lattice.matrix,
         [[0.000000, 3.840198, 0.000000],
          [-3.325710, 1.920099, 0.000000],
          [2.217138, -0.000000, 3.135509]], 5)
    def test_fit(self):
        """
        Take two known matched structures
            1) Ensure match
            2) Ensure match after translation and rotations
            3) Ensure no-match after large site translation
            4) Ensure match after site shuffling
            """
        sm = StructureMatcher()

        self.assertTrue(sm.fit(self.struct_list[0], self.struct_list[1]))

        # Test rotational/translational invariance
        op = SymmOp.from_axis_angle_and_translation([0, 0, 1], 30, False,
                                                    np.array([0.4, 0.7, 0.9]))
        self.struct_list[1].apply_operation(op)
        self.assertTrue(sm.fit(self.struct_list[0], self.struct_list[1]))

        #Test failure under large atomic translation
        self.struct_list[1].translate_sites([0], [.4, .4, .2],
                                            frac_coords=True)
        self.assertFalse(sm.fit(self.struct_list[0], self.struct_list[1]))

        self.struct_list[1].translate_sites([0], [-.4, -.4, -.2],
                                            frac_coords=True)
        # random.shuffle(editor._sites)
        self.assertTrue(sm.fit(self.struct_list[0], self.struct_list[1]))
        #Test FrameworkComporator
        sm2 = StructureMatcher(comparator=FrameworkComparator())
        lfp = self.get_structure("LiFePO4")
        nfp = self.get_structure("NaFePO4")
        self.assertTrue(sm2.fit(lfp, nfp))
        self.assertFalse(sm.fit(lfp, nfp))

        #Test anonymous fit.
        self.assertEqual(sm.fit_anonymous(lfp, nfp), True)
        self.assertAlmostEqual(sm.get_rms_anonymous(lfp, nfp)[0],
                               0.060895871160262717)

        #Test partial occupancies.
        s1 = Structure(Lattice.cubic(3),
                       [{"Fe": 0.5}, {"Fe": 0.5}, {"Fe": 0.5}, {"Fe": 0.5}],
                       [[0, 0, 0], [0.25, 0.25, 0.25],
                        [0.5, 0.5, 0.5], [0.75, 0.75, 0.75]])
        s2 = Structure(Lattice.cubic(3),
                       [{"Fe": 0.25}, {"Fe": 0.5}, {"Fe": 0.5}, {"Fe": 0.75}],
                       [[0, 0, 0], [0.25, 0.25, 0.25],
                        [0.5, 0.5, 0.5], [0.75, 0.75, 0.75]])
        self.assertFalse(sm.fit(s1, s2))
        self.assertFalse(sm.fit(s2, s1))
        s2 = Structure(Lattice.cubic(3),
                       [{"Mn": 0.5}, {"Mn": 0.5}, {"Mn": 0.5},
                        {"Mn": 0.5}],
                       [[0, 0, 0], [0.25, 0.25, 0.25],
                        [0.5, 0.5, 0.5], [0.75, 0.75, 0.75]])
        self.assertEqual(sm.fit_anonymous(s1, s2), True)

        self.assertAlmostEqual(sm.get_rms_anonymous(s1, s2)[0], 0)
    def __init__(self, axis, angle, angle_in_radians=False):
        """

        """
        self._axis = axis
        self._angle = angle
        self._angle_in_radians = angle_in_radians
        self._symmop = SymmOp.from_axis_angle_and_translation(
            self._axis, self._angle, self._angle_in_radians)
示例#7
0
    def __init__(self, axis, angle, angle_in_radians=False):
        """

        """
        self.axis = axis
        self.angle = angle
        self.angle_in_radians = angle_in_radians
        self._symmop = SymmOp.from_axis_angle_and_translation(
            self.axis, self.angle, self.angle_in_radians)
示例#8
0
    def test_list_based_functions(self):
        # zeroed
        tc = TensorCollection([1e-4 * Tensor(np.eye(3))] * 4)
        for t in tc.zeroed():
            self.assertArrayEqual(t, np.zeros((3, 3)))
        for t in tc.zeroed(1e-5):
            self.assertArrayEqual(t, 1e-4 * np.eye(3))
        self.list_based_function_check("zeroed", tc)
        self.list_based_function_check("zeroed", tc, tol=1e-5)

        # transform
        symm_op = SymmOp.from_axis_angle_and_translation(
            [0, 0, 1], 30, False, [0, 0, 1]
        )
        self.list_based_function_check("transform", self.seq_tc, symm_op=symm_op)

        # symmetrized
        self.list_based_function_check("symmetrized", self.seq_tc)

        # rotation
        a = 3.14 * 42.5 / 180
        rotation = SquareTensor(
            [[math.cos(a), 0, math.sin(a)], [0, 1, 0], [-math.sin(a), 0, math.cos(a)]]
        )
        self.list_based_function_check("rotate", self.diff_rank, matrix=rotation)

        # is_symmetric
        self.assertFalse(self.seq_tc.is_symmetric())
        self.assertTrue(self.diff_rank.is_symmetric())

        # fit_to_structure
        self.list_based_function_check("fit_to_structure", self.diff_rank, self.struct)
        self.list_based_function_check("fit_to_structure", self.seq_tc, self.struct)

        # fit_to_structure
        self.list_based_function_check("fit_to_structure", self.diff_rank, self.struct)
        self.list_based_function_check("fit_to_structure", self.seq_tc, self.struct)

        # voigt
        self.list_based_function_check("voigt", self.diff_rank)

        # is_voigt_symmetric
        self.assertTrue(self.diff_rank.is_voigt_symmetric())
        self.assertFalse(self.seq_tc.is_voigt_symmetric())

        # Convert to ieee
        for entry in self.ieee_data[:2]:
            xtal = entry["xtal"]
            tc = TensorCollection([entry["original_tensor"]] * 3)
            struct = entry["structure"]
            self.list_based_function_check("convert_to_ieee", tc, struct)

        # from_voigt
        tc_input = [t for t in np.random.random((3, 6, 6))]
        tc = TensorCollection.from_voigt(tc_input)
        for t_input, t in zip(tc_input, tc):
            self.assertArrayAlmostEqual(Tensor.from_voigt(t_input), t)
示例#9
0
 def _check_R2_axes_asym(self):
     """
     Test for 2-fold rotation along the principal axes. Used to handle
     asymetric top molecules.
     """
     for v in self.principal_axes:
         op = SymmOp.from_axis_angle_and_translation(v, 180)
         if self.is_valid_op(op):
             self.symmops.append(op)
             self.rot_sym.append((v, 2))
示例#10
0
 def _check_R2_axes_asym(self):
     """
     Test for 2-fold rotation along the principal axes. Used to handle
     asymetric top molecules.
     """
     for v in self.principal_axes:
         op = SymmOp.from_axis_angle_and_translation(v, 180)
         if self.is_valid_op(op):
             self.symmops.append(op)
             self.rot_sym.append((v, 2))
示例#11
0
    def test_list_based_functions(self):
        # zeroed
        tc = TensorCollection([1e-4*Tensor(np.eye(3))]*4)
        for t in tc.zeroed():
            self.assertArrayEqual(t, np.zeros((3, 3)))
        for t in tc.zeroed(1e-5):
            self.assertArrayEqual(t, 1e-4*np.eye(3))
        self.list_based_function_check("zeroed", tc)
        self.list_based_function_check("zeroed", tc, tol=1e-5)

        # transform
        symm_op = SymmOp.from_axis_angle_and_translation([0, 0, 1], 30,
                                                         False, [0, 0, 1])
        self.list_based_function_check("transform", self.seq_tc, symm_op=symm_op)

        # symmetrized
        self.list_based_function_check("symmetrized", self.seq_tc)

        # rotation
        a = 3.14 * 42.5 / 180
        rotation = SquareTensor([[math.cos(a), 0, math.sin(a)], [0, 1, 0],
                                 [-math.sin(a), 0, math.cos(a)]])
        self.list_based_function_check("rotate", self.diff_rank, matrix=rotation)

        # is_symmetric
        self.assertFalse(self.seq_tc.is_symmetric())
        self.assertTrue(self.diff_rank.is_symmetric())

        # fit_to_structure
        self.list_based_function_check("fit_to_structure", self.diff_rank, self.struct)
        self.list_based_function_check("fit_to_structure", self.seq_tc, self.struct)

        # fit_to_structure
        self.list_based_function_check("fit_to_structure", self.diff_rank, self.struct)
        self.list_based_function_check("fit_to_structure", self.seq_tc, self.struct)

        # voigt
        self.list_based_function_check("voigt", self.diff_rank)

        # is_voigt_symmetric
        self.assertTrue(self.diff_rank.is_voigt_symmetric())
        self.assertFalse(self.seq_tc.is_voigt_symmetric())

        # Convert to ieee
        for entry in self.ieee_data[:2]:
            xtal = entry['xtal']
            tc = TensorCollection([entry['original_tensor']]*3)
            struct = entry['structure']
            self.list_based_function_check("convert_to_ieee", tc, struct)

        # from_voigt
        tc_input = [t for t in np.random.random((3, 6, 6))]
        tc = TensorCollection.from_voigt(tc_input)
        for t_input, t in zip(tc_input, tc):
            self.assertArrayAlmostEqual(Tensor.from_voigt(t_input), t)
示例#12
0
 def __init__(self, axis, angle, angle_in_radians=False):
     """
     Args:
         axis (3x1 array): Axis of rotation, e.g., [1, 0, 0]
         angle (float): Angle to rotate
         angle_in_radians (bool): Set to True if angle is supplied in radians.
             Else degrees are assumed.
     """
     self.axis = axis
     self.angle = angle
     self.angle_in_radians = angle_in_radians
     self._symmop = SymmOp.from_axis_angle_and_translation(self.axis, self.angle, self.angle_in_radians)
示例#13
0
    def test_transform(self):
        # Rank 3
        tensor = Tensor(np.arange(0, 27).reshape(3, 3, 3))
        symm_op = SymmOp.from_axis_angle_and_translation([0, 0, 1], 30, False,
                                                         [0, 0, 1])
        new_tensor = tensor.transform(symm_op)

        self.assertArrayAlmostEqual(
            new_tensor, [[[-0.871, -2.884, -1.928], [-2.152, -6.665, -4.196],
                          [-1.026, -2.830, -1.572]],
                         [[0.044, 1.531, 1.804], [4.263, 21.008, 17.928],
                          [5.170, 23.026, 18.722]],
                         [[1.679, 7.268, 5.821], [9.268, 38.321, 29.919],
                          [8.285, 33.651, 26.000]]], 3)
示例#14
0
    def _find_spherical_axes(self):
        """
        Looks for R5, R4, R3 and R2 axes in speherical top molecules.  Point
        group T molecules have only one unique 3-fold and one unique 2-fold
        axis. O molecules have one unique 4, 3 and 2-fold axes. I molecules
        have a unique 5-fold axis.
        """
        rot_present = defaultdict(bool)
        origin_site, dist_el_sites = cluster_sites(self.centered_mol, self.tol)
        test_set = min(dist_el_sites.values(), key=lambda s: len(s))
        coords = [s.coords for s in test_set]
        for c1, c2, c3 in itertools.combinations(coords, 3):
            for cc1, cc2 in itertools.combinations([c1, c2, c3], 2):
                if not rot_present[2]:
                    test_axis = cc1 + cc2
                    if np.linalg.norm(test_axis) > self.tol:
                        op = SymmOp.from_axis_angle_and_translation(test_axis,
                                                                    180)
                        rot_present[2] = self.is_valid_op(op)
                        if rot_present[2]:
                            self.symmops.append(op)
                            self.rot_sym.append((test_axis, 2))

            test_axis = np.cross(c2 - c1, c3 - c1)
            if np.linalg.norm(test_axis) > self.tol:
                for r in (3, 4, 5):
                    if not rot_present[r]:
                        op = SymmOp.from_axis_angle_and_translation(
                            test_axis, 360 / r)
                        rot_present[r] = self.is_valid_op(op)
                        if rot_present[r]:
                            self.symmops.append(op)
                            self.rot_sym.append((test_axis, r))
                            break
            if rot_present[2] and rot_present[3] and (
                        rot_present[4] or rot_present[5]):
                break
示例#15
0
    def _find_spherical_axes(self):
        """
        Looks for R5, R4, R3 and R2 axes in speherical top molecules.  Point
        group T molecules have only one unique 3-fold and one unique 2-fold
        axis. O molecules have one unique 4, 3 and 2-fold axes. I molecules
        have a unique 5-fold axis.
        """
        rot_present = defaultdict(bool)
        origin_site, dist_el_sites = cluster_sites(self.centered_mol, self.tol)
        test_set = min(dist_el_sites.values(), key=lambda s: len(s))
        coords = [s.coords for s in test_set]
        for c1, c2, c3 in itertools.combinations(coords, 3):
            for cc1, cc2 in itertools.combinations([c1, c2, c3], 2):
                if not rot_present[2]:
                    test_axis = cc1 + cc2
                    if np.linalg.norm(test_axis) > self.tol:
                        op = SymmOp.from_axis_angle_and_translation(
                            test_axis, 180)
                        rot_present[2] = self.is_valid_op(op)
                        if rot_present[2]:
                            self.symmops.append(op)
                            self.rot_sym.append((test_axis, 2))

            test_axis = np.cross(c2 - c1, c3 - c1)
            if np.linalg.norm(test_axis) > self.tol:
                for r in (3, 4, 5):
                    if not rot_present[r]:
                        op = SymmOp.from_axis_angle_and_translation(
                            test_axis, 360 / r)
                        rot_present[r] = self.is_valid_op(op)
                        if rot_present[r]:
                            self.symmops.append(op)
                            self.rot_sym.append((test_axis, r))
                            break
            if rot_present[2] and rot_present[3] and (rot_present[4]
                                                      or rot_present[5]):
                break
示例#16
0
 def _check_perpendicular_r2_axis(self, axis):
     """
     Checks for R2 axes perpendicular to unique axis.  For handling
     symmetric top molecules.
     """
     min_set = self._get_smallest_set_not_on_axis(axis)
     for s1, s2 in itertools.combinations(min_set, 2):
         test_axis = np.cross(s1.coords - s2.coords, axis)
         if np.linalg.norm(test_axis) > self.tol:
             op = SymmOp.from_axis_angle_and_translation(test_axis, 180)
             r2present = self.is_valid_op(op)
             if r2present:
                 self.symmops.append(op)
                 self.rot_sym.append((test_axis, 2))
                 return True
示例#17
0
 def __init__(self, axis, angle, angle_in_radians=False):
     """
     Args:
         axis:
             Axis of rotation, e.g., [1, 0, 0]
         angle:
             Angle to rotate
         angle_in_radians:
             Set to True if angle is supplied in radians. Else degrees are
             assumed.
     """
     self._axis = axis
     self._angle = angle
     self._angle_in_radians = angle_in_radians
     self._symmop = SymmOp.from_axis_angle_and_translation(self._axis, self._angle, self._angle_in_radians)
示例#18
0
 def _check_perpendicular_r2_axis(self, axis):
     """
     Checks for R2 axes perpendicular to unique axis.  For handling
     symmetric top molecules.
     """
     min_set = self._get_smallest_set_not_on_axis(axis)
     for s1, s2 in itertools.combinations(min_set, 2):
         test_axis = np.cross(s1.coords - s2.coords, axis)
         if np.linalg.norm(test_axis) > self.tol:
             op = SymmOp.from_axis_angle_and_translation(test_axis, 180)
             r2present = self.is_valid_op(op)
             if r2present:
                 self.symmops.append(op)
                 self.rot_sym.append((test_axis, 2))
                 return True
示例#19
0
    def test_apply_operation(self):
        op = SymmOp.from_axis_angle_and_translation([0, 0, 1], 90)
        s = self.structure.copy()
        s.apply_operation(op)
        self.assertArrayAlmostEqual(
            s.lattice.matrix,
            [[0.000000, 3.840198, 0.000000], [-3.325710, 1.920099, 0.000000],
             [2.217138, -0.000000, 3.135509]], 5)

        op = SymmOp([[1, 1, 0, 0.5], [1, 0, 0, 0.5], [0, 0, 1, 0.5],
                     [0, 0, 0, 1]])
        s = self.structure.copy()
        s.apply_operation(op, fractional=True)
        self.assertArrayAlmostEqual(
            s.lattice.matrix,
            [[5.760297, 3.325710, 0.000000], [3.840198, 0.000000, 0.000000],
             [0.000000, -2.217138, 3.135509]], 5)
示例#20
0
    def test_transform(self):
        # Rank 3
        tensor = TensorBase(np.arange(0, 27).reshape(3, 3, 3))
        symm_op = SymmOp.from_axis_angle_and_translation([0, 0, 1], 30,
                                                         False, [0, 0, 1])
        new_tensor = tensor.transform(symm_op)

        self.assertArrayAlmostEqual(new_tensor,
                                    [[[-0.871, -2.884, -1.928],
                                      [-2.152, -6.665, -4.196],
                                      [-1.026, -2.830, -1.572]],
                                     [[0.044, 1.531, 1.804],
                                      [4.263, 21.008, 17.928],
                                      [5.170, 23.026, 18.722]],
                                     [[1.679, 7.268, 5.821],
                                      [9.268, 38.321, 29.919],
                                      [8.285, 33.651, 26.000]]], 3)
示例#21
0
 def _check_rot_sym(self, axis):
     """
     Determines the rotational symmetry about supplied axis.  Used only for
     symmetric top molecules which has possible rotational symmetry
     operations > 2.
     """
     min_set = self._get_smallest_set_not_on_axis(axis)
     max_sym = len(min_set)
     for i in range(max_sym, 0, -1):
         if max_sym % i != 0:
             continue
         op = SymmOp.from_axis_angle_and_translation(axis, 360 / i)
         rotvalid = self.is_valid_op(op)
         if rotvalid:
             self.symmops.append(op)
             self.rot_sym.append((axis, i))
             return i
     return 1
示例#22
0
 def _check_rot_sym(self, axis):
     """
     Determines the rotational symmetry about supplied axis.  Used only for
     symmetric top molecules which has possible rotational symmetry
     operations > 2.
     """
     min_set = self._get_smallest_set_not_on_axis(axis)
     max_sym = len(min_set)
     for i in range(max_sym, 0, -1):
         if max_sym % i != 0:
             continue
         op = SymmOp.from_axis_angle_and_translation(axis, 360 / i)
         rotvalid = self.is_valid_op(op)
         if rotvalid:
             self.symmops.append(op)
             self.rot_sym.append((axis, i))
             return i
     return 1
示例#23
0
    def test_apply_operation(self):
        op = SymmOp.from_axis_angle_and_translation([0, 0, 1], 90)
        s = self.structure.copy()
        s.apply_operation(op)
        self.assertArrayAlmostEqual(
            s.lattice.matrix,
            [[0.000000, 3.840198, 0.000000],
             [-3.325710, 1.920099, 0.000000],
             [2.217138, -0.000000, 3.135509]], 5)

        op = SymmOp([[1, 1, 0, 0.5], [1, 0, 0, 0.5], [0, 0, 1, 0.5],
                     [0, 0, 0, 1]])
        s = self.structure.copy()
        s.apply_operation(op, fractional=True)
        self.assertArrayAlmostEqual(
            s.lattice.matrix,
            [[5.760297, 3.325710, 0.000000],
             [3.840198, 0.000000, 0.000000],
             [0.000000, -2.217138, 3.135509]], 5)
示例#24
0
 def cover_surface(self, site_indices):
     """
     puts the ligand molecule on the given list of site indices
     """
     num_atoms = len(self.ligand)
     normal = self.normal
     # get a vector that points from one atom in the botton plane
     # to one atom on the top plane. This is required to make sure
     # that the surface normal points outwards from the surface on
     #  to which we want to adsorb the ligand
     vec_vac = self.cart_coords[self.top_atoms[0]] - \
         self.cart_coords[self.bottom_atoms[0]]
     # mov_vec = the vector along which the ligand will be displaced
     mov_vec = normal * self.displacement
     angle = get_angle(vec_vac, self.normal)
     # flip the orientation of normal if it is not pointing in
     # the right direction.
     if (angle > 90):
         normal_frac = self.lattice.get_fractional_coords(normal)
         normal_frac[2] = -normal_frac[2]
         normal = self.lattice.get_cartesian_coords(normal_frac)
         mov_vec = normal * self.displacement
     # get the index corresponding to the given atomic species in
     # the ligand that will bond with the surface on which the
     # ligand will be adsorbed
     adatom_index = self.get_index(self.adatom_on_lig)
     adsorbed_ligands_coords = []
     # set the ligand coordinates for each adsorption site on
     # the surface
     for sindex in site_indices:
         # align the ligand wrt the site on the surface to which
         # it will be adsorbed
         origin = self.cart_coords[sindex]
         self.ligand.translate_sites(list(range(num_atoms)),
                                     origin - self.ligand[
                                         adatom_index].coords)
         # displace the ligand by the given amount in the direction
         # normal to surface
         self.ligand.translate_sites(list(range(num_atoms)), mov_vec)
         # vector pointing from the adatom_on_lig to the
         # ligand center of mass
         vec_adatom_cm = self.ligand.center_of_mass - \
             self.ligand[adatom_index].coords
         # rotate the ligand with respect to a vector that is
         # normal to the vec_adatom_cm and the normal to the surface
         # so that the ligand center of mass is aligned along the
         # outward normal to the surface
         origin = self.ligand[adatom_index].coords
         angle = get_angle(vec_adatom_cm, normal)
         if 1 < abs(angle % 180) < 179:
             # For angles which are not 0 or 180,
             # perform a rotation about the origin along an axis
             # perpendicular to both bonds to align bonds.
             axis = np.cross(vec_adatom_cm, normal)
             op = SymmOp.from_origin_axis_angle(origin, axis, angle)
             self.ligand.apply_operation(op)
         elif abs(abs(angle) - 180) < 1:
             # We have a 180 degree angle.
             # Simply do an inversion about the origin
             for i in range(len(self.ligand)):
                 self.ligand[i] = (self.ligand[i].species_and_occu,
                                   origin - (
                                       self.ligand[i].coords - origin))
         # x - y - shifts
         x = self.x_shift
         y = self.y_shift
         rot = self.rot
         if x:
             self.ligand.translate_sites(list(range(num_atoms)),
                                         np.array([x, 0, 0]))
         if y:
             self.ligand.translate_sites(list(range(num_atoms)),
                                         np.array([0, y, 0]))
         if rot:
             self.ligand.apply_operation(
                 SymmOp.from_axis_angle_and_translation(
                     (1, 0, 0), rot[0], angle_in_radians=False,
                     translation_vec=(0, 0, 0)))
             self.ligand.apply_operation(
                 SymmOp.from_axis_angle_and_translation(
                     (0, 1, 0), rot[1], angle_in_radians=False,
                     translation_vec=(0, 0, 0)))
             self.ligand.apply_operation(
                 SymmOp.from_axis_angle_and_translation(
                     (0, 0, 1), rot[2], angle_in_radians=False,
                     translation_vec=(0, 0, 0)))
         # 3d numpy array
         adsorbed_ligands_coords.append(self.ligand.cart_coords)
         # extend the slab structure with the adsorbant atoms
     adsorbed_ligands_coords = np.array(adsorbed_ligands_coords)
     for j in range(len(site_indices)):
         [self.append(self.ligand.species_and_occu[i],
                      adsorbed_ligands_coords[j, i, :],
                      coords_are_cartesian=True)
          for i in range(num_atoms)]
示例#25
0
    def test_fit(self):
        """
        Take two known matched structures
            1) Ensure match
            2) Ensure match after translation and rotations
            3) Ensure no-match after large site translation
            4) Ensure match after site shuffling
            """
        sm = StructureMatcher()

        self.assertTrue(sm.fit(self.struct_list[0], self.struct_list[1]))

        # Test rotational/translational invariance
        op = SymmOp.from_axis_angle_and_translation([0, 0, 1], 30, False,
                                                    np.array([0.4, 0.7, 0.9]))
        self.struct_list[1].apply_operation(op)
        self.assertTrue(sm.fit(self.struct_list[0], self.struct_list[1]))

        #Test failure under large atomic translation
        self.struct_list[1].translate_sites([0], [.4, .4, .2],
                                            frac_coords=True)
        self.assertFalse(sm.fit(self.struct_list[0], self.struct_list[1]))

        self.struct_list[1].translate_sites([0], [-.4, -.4, -.2],
                                            frac_coords=True)
        # random.shuffle(editor._sites)
        self.assertTrue(sm.fit(self.struct_list[0], self.struct_list[1]))
        #Test FrameworkComporator
        sm2 = StructureMatcher(comparator=FrameworkComparator())
        lfp = self.get_structure("LiFePO4")
        nfp = self.get_structure("NaFePO4")
        self.assertTrue(sm2.fit(lfp, nfp))
        self.assertFalse(sm.fit(lfp, nfp))

        #Test anonymous fit.
        self.assertEqual(sm.fit_anonymous(lfp, nfp), True)
        self.assertAlmostEqual(
            sm.get_rms_anonymous(lfp, nfp)[0], 0.060895871160262717)

        #Test partial occupancies.
        s1 = Structure(Lattice.cubic(3), [{
            "Fe": 0.5
        }, {
            "Fe": 0.5
        }, {
            "Fe": 0.5
        }, {
            "Fe": 0.5
        }], [[0, 0, 0], [0.25, 0.25, 0.25], [0.5, 0.5, 0.5],
             [0.75, 0.75, 0.75]])
        s2 = Structure(Lattice.cubic(3), [{
            "Fe": 0.25
        }, {
            "Fe": 0.5
        }, {
            "Fe": 0.5
        }, {
            "Fe": 0.75
        }], [[0, 0, 0], [0.25, 0.25, 0.25], [0.5, 0.5, 0.5],
             [0.75, 0.75, 0.75]])
        self.assertFalse(sm.fit(s1, s2))
        self.assertFalse(sm.fit(s2, s1))
        s2 = Structure(Lattice.cubic(3), [{
            "Mn": 0.5
        }, {
            "Mn": 0.5
        }, {
            "Mn": 0.5
        }, {
            "Mn": 0.5
        }], [[0, 0, 0], [0.25, 0.25, 0.25], [0.5, 0.5, 0.5],
             [0.75, 0.75, 0.75]])
        self.assertEqual(sm.fit_anonymous(s1, s2), True)

        self.assertAlmostEqual(sm.get_rms_anonymous(s1, s2)[0], 0)
示例#26
0
 def test_apply_operation(self):
     op = SymmOp.from_axis_angle_and_translation([0, 0, 1], 90)
     self.mol.apply_operation(op)
     self.assertArrayAlmostEqual(self.mol[2].coords,
                                 [0.000000, 1.026719, -0.363000])
示例#27
0
 def setUp(self):
     self.op = SymmOp.from_axis_angle_and_translation([0, 0, 1], 30, False,
                                                      [0, 0, 1])
示例#28
0
 def setUp(self):
     self.op = SymmOp.from_axis_angle_and_translation([0, 0, 1], 30, False,
                                                      [0, 0, 1])
示例#29
0
def coloumb_configured_interface(iface, random=True,
                                 translations= None,
                                 rotations=None,
                                 samples=10, lowest=5, ecut=None):
    """
    Creates Ligand Slab interfaces of user specified translations 
    and rotations away from the initial guess of binding site 
    configuration, returns lowest energy structure according to 
    Coulomb model
    
    Args:
         Interface: Interface object: initial interface object 
         random: True for using Gaussian sampled random numbers for 
                 rotations and translations 
         translations: list of [x,y,z] translations to be performed
         rotation: list of [a,b,c] rotations to be performed w.r.t 
                   Ligand axis
         samples: number of interfaces to create
         lowest: number of structures to return according to order of 
                 minimum energies

    Returns: 
         list of lowest energy interface objects 
    """
    ifaces= []
    transform= []
    for i in range(samples): 
        if random: 
            x = np.random.normal() # shift along x direction  
            y = np.random.normal() # shift along y direction 
            z = np.random.normal() # shift aling z direction 
            a= SymmOp.from_axis_angle_and_translation(axis=[1,0,0],\
                              angle=np.random.normal(0,180))
            b= SymmOp.from_axis_angle_and_translation(axis=[0,1,0],\
                              angle=np.random.normal(0,180))
            c= SymmOp.from_axis_angle_and_translation(axis=[0,0,1],\
                              angle=np.random.normal(0,180))
            ligand=iface.ligand
            ligand.apply_operation(a)
            ligand.apply_operation(b)
            ligand.apply_operation(c)
               
        # check if created interface maintains the ligand adsorbed
        # over the surface 
        for j in iface.top_atoms: 
            if not iface.cart_coords[j][2] + iface.displacement > \
                               min(ligand.cart_coords[:,2]):
                transform.append(True)
        if all(transform): 
            iface= Interface(iface.strt, hkl=iface.hkl,
                             min_thick=iface.min_thick,
                             min_vac=iface.min_vac,
                             supercell=iface.supercell,
                             surface_coverage=iface.surface_coverage,
                             ligand=iface.ligand, displacement=z,
                             adatom_on_lig=iface.adatom_on_lig, 
                             adsorb_on_species=iface.adsorb_on_species,
                             primitive= False, from_ase=True,
                             x_shift=x, y_shift=y)
            iface.create_interface()
            energy= iface.calc_energy()
            iface.sort()
            if energy<ecut:
                ifaces.append((energy,iface))
           # ifaces.zip(energy, iface)
    return ifaces 
示例#30
0
def get_grain_boundary_interface(structure=None, hkl_pair= {'hkl': [[1,0,0],[1,1,0]],\
                                 'thickness':[10,10]}, twist = 0, tilt = 0, separation=0):
    """
    Args:
        structure: pymatgen structure to create grain boundary in
        hkl_pair:  dict of {'hkl':thickness}
        twist:     twist in degrees
        tilt:      tilt in degrees
    """

    structure = get_struct_from_mp(structure, MAPI_KEY="")
    sa = SpacegroupAnalyzer(structure)
    structure_conventional = sa.get_conventional_standard_structure()
    structure = structure_conventional.copy()
    structure.sort()

    #creation of lower part of grain boundary
    lower= Interface(structure,\
    hkl = hkl_pair['hkl'][0],
    min_thick = hkl_pair['thickness'][0],
    min_vac = separation+hkl_pair['thickness'][1],
    primitive = False, from_ase = True, center_slab=False)

    lower.to(fmt="poscar", filename="POSCAR_lower.vasp")

    #creation of upper part of grain boundary
    upper= Interface(structure,\
    hkl = hkl_pair['hkl'][1],
    min_thick = hkl_pair['thickness'][1],
    min_vac = 0,
    primitive = False, from_ase = True)

    #find top atoms reference of lower part of gb
    substrate_top_z = np.max(np.array([site.coords for site in lower])[:, 2])

    # define twist and tilt vectors
    twist_shift_normal = lower.lattice.matrix[2,:]/\
                         np.linalg.norm(lower.lattice.matrix[2,:])
    tilt_normal = upper.lattice.matrix[1,:]/\
                  np.linalg.norm(upper.lattice.matrix[2,:])

    #define twist operation SymmOp object
    twist_op = SymmOp.from_axis_angle_and_translation(axis= twist_shift_normal,\
                angle=twist, angle_in_radians=False,translation_vec=(0, 0, 0))
    #define tilt operation SymmOp object
    tilt_op = SymmOp.from_axis_angle_and_translation(axis= tilt_normal,\
                angle=tilt, angle_in_radians=False,translation_vec=(0, 0, 0))
    upper.apply_operation(twist_op)
    upper.to(fmt="poscar", filename="POSCAR_upper.vasp")
    upper.apply_operation(tilt_op)

    #define shift separation along twist vector normal to upper plane
    shift = -1 * twist_shift_normal / np.linalg.norm(
        twist_shift_normal) * separation
    #define origin to shift w.r.t top of the lower grain
    origin = np.array([0, 0, substrate_top_z])
    #shift sites in upper
    for site in upper:
        new_coords = site.coords - origin + shift
        lower.append(site.specie, new_coords, coords_are_cartesian=True)
    return lower
示例#31
0
 def cover_surface(self, site_indices):
     """
     puts the ligand molecule on the given list of site indices
     """
     num_atoms = len(self.ligand)
     normal = self.normal
     # get a vector that points from one atom in the botton plane
     # to one atom on the top plane. This is required to make sure
     # that the surface normal points outwards from the surface on
     #  to which we want to adsorb the ligand
     vec_vac = self.cart_coords[self.top_atoms[0]] - \
         self.cart_coords[self.bottom_atoms[0]]
     # mov_vec = the vector along which the ligand will be displaced
     mov_vec = normal * self.displacement
     angle = get_angle(vec_vac, self.normal)
     # flip the orientation of normal if it is not pointing in
     # the right direction.
     if (angle > 90):
         normal_frac = self.lattice.get_fractional_coords(normal)
         normal_frac[2] = -normal_frac[2]
         normal = self.lattice.get_cartesian_coords(normal_frac)
         mov_vec = normal * self.displacement
     # get the index corresponding to the given atomic species in
     # the ligand that will bond with the surface on which the
     # ligand will be adsorbed
     adatom_index = self.get_index(self.adatom_on_lig)
     adsorbed_ligands_coords = []
     # set the ligand coordinates for each adsorption site on
     # the surface
     for sindex in site_indices:
         # align the ligand wrt the site on the surface to which
         # it will be adsorbed
         origin = self.cart_coords[sindex]
         self.ligand.translate_sites(
             list(range(num_atoms)),
             origin - self.ligand[adatom_index].coords)
         # displace the ligand by the given amount in the direction
         # normal to surface
         self.ligand.translate_sites(list(range(num_atoms)), mov_vec)
         # vector pointing from the adatom_on_lig to the
         # ligand center of mass
         vec_adatom_cm = self.ligand.center_of_mass - \
             self.ligand[adatom_index].coords
         # rotate the ligand with respect to a vector that is
         # normal to the vec_adatom_cm and the normal to the surface
         # so that the ligand center of mass is aligned along the
         # outward normal to the surface
         origin = self.ligand[adatom_index].coords
         angle = get_angle(vec_adatom_cm, normal)
         if 1 < abs(angle % 180) < 179:
             # For angles which are not 0 or 180,
             # perform a rotation about the origin along an axis
             # perpendicular to both bonds to align bonds.
             axis = np.cross(vec_adatom_cm, normal)
             op = SymmOp.from_origin_axis_angle(origin, axis, angle)
             self.ligand.apply_operation(op)
         elif abs(abs(angle) - 180) < 1:
             # We have a 180 degree angle.
             # Simply do an inversion about the origin
             for i in range(len(self.ligand)):
                 self.ligand[i] = (self.ligand[i].species_and_occu, origin -
                                   (self.ligand[i].coords - origin))
         # x - y - shifts
         x = self.x_shift
         y = self.y_shift
         rot = self.rot
         if x:
             self.ligand.translate_sites(list(range(num_atoms)),
                                         np.array([x, 0, 0]))
         if y:
             self.ligand.translate_sites(list(range(num_atoms)),
                                         np.array([0, y, 0]))
         if rot:
             self.ligand.apply_operation(
                 SymmOp.from_axis_angle_and_translation(
                     (1, 0, 0),
                     rot[0],
                     angle_in_radians=False,
                     translation_vec=(0, 0, 0)))
             self.ligand.apply_operation(
                 SymmOp.from_axis_angle_and_translation(
                     (0, 1, 0),
                     rot[1],
                     angle_in_radians=False,
                     translation_vec=(0, 0, 0)))
             self.ligand.apply_operation(
                 SymmOp.from_axis_angle_and_translation(
                     (0, 0, 1),
                     rot[2],
                     angle_in_radians=False,
                     translation_vec=(0, 0, 0)))
         # 3d numpy array
         adsorbed_ligands_coords.append(self.ligand.cart_coords)
         # extend the slab structure with the adsorbant atoms
     adsorbed_ligands_coords = np.array(adsorbed_ligands_coords)
     for j in range(len(site_indices)):
         [
             self.append(self.ligand.species_and_occu[i],
                         adsorbed_ligands_coords[j, i, :],
                         coords_are_cartesian=True)
             for i in range(num_atoms)
         ]
示例#32
0
def coloumb_configured_interface(iface, random=True,
                                 translations=None,
                                 rotations=None,
                                 samples=10, lowest=5, ecut=None):
    """
    Creates Ligand Slab interfaces of user specified translations 
    and rotations away from the initial guess of binding site 
    configuration, returns lowest energy structure according to 
    Coulomb model
    
    Args:
         Interface: Interface object: initial interface object 
         random: True for using Gaussian sampled random numbers for 
                 rotations and translations 
         translations: list of [x,y,z] translations to be performed
         rotation: list of [a,b,c] rotations to be performed w.r.t 
                   Ligand axis
         samples: number of interfaces to create
         lowest: number of structures to return according to order of 
                 minimum energies

    Returns: 
         list of lowest energy interface objects 
    """
    ifaces = []
    transform = []
    for i in range(samples):
        if random:
            x = np.random.normal()  # shift along x direction
            y = np.random.normal()  # shift along y direction
            z = np.random.normal()  # shift aling z direction
            a = SymmOp.from_axis_angle_and_translation(axis=[1, 0, 0], \
                                                       angle=np.random.normal(0, 180))
            b = SymmOp.from_axis_angle_and_translation(axis=[0, 1, 0], \
                                                       angle=np.random.normal(0, 180))
            c = SymmOp.from_axis_angle_and_translation(axis=[0, 0, 1], \
                                                       angle=np.random.normal(0, 180))
            ligand = iface.ligand
            ligand.apply_operation(a)
            ligand.apply_operation(b)
            ligand.apply_operation(c)

        # check if created interface maintains the ligand adsorbed
        # over the surface 
        for j in iface.top_atoms:
            if not iface.cart_coords[j][2] + iface.displacement > \
                    min(ligand.cart_coords[:, 2]):
                transform.append(True)
        if all(transform):
            iface = Interface(iface.strt, hkl=iface.hkl,
                              min_thick=iface.min_thick,
                              min_vac=iface.min_vac,
                              supercell=iface.supercell,
                              surface_coverage=iface.surface_coverage,
                              ligand=iface.ligand, displacement=z,
                              adatom_on_lig=iface.adatom_on_lig,
                              adsorb_on_species=iface.adsorb_on_species,
                              primitive=False, from_ase=True,
                              x_shift=x, y_shift=y)
            iface.create_interface()
            energy = iface.calc_energy()
            iface.sort()
            if energy < ecut:
                ifaces.append((energy, iface))
                # ifaces.zip(energy, iface)
    return ifaces
示例#33
0
 def test_apply_operation(self):
     op = SymmOp.from_axis_angle_and_translation([0, 0, 1], 90)
     self.mol.apply_operation(op)
     self.assertArrayAlmostEqual(self.mol[2].coords,
                                 [0.000000, 1.026719, -0.363000])
def get_grain_boundary_interface(structure=None, hkl_pair= {'hkl': [[1,0,0],[1,1,0]],\
                                 'thickness':[10,10]}, twist = 0, tilt = 0, separation=0):
    """
    Args:
        structure: pymatgen structure to create grain boundary in
        hkl_pair:  dict of {'hkl':thickness}
        twist:     twist in degrees
        tilt:      tilt in degrees
    """


    structure = get_struct_from_mp(structure, MAPI_KEY="")
    sa = SpacegroupAnalyzer(structure)
    structure_conventional = sa.get_conventional_standard_structure()
    structure = structure_conventional.copy()
    structure.sort()

    #creation of lower part of grain boundary
    lower= Interface(structure,\
    hkl = hkl_pair['hkl'][0],
    min_thick = hkl_pair['thickness'][0],
    min_vac = separation+hkl_pair['thickness'][1],
    primitive = False, from_ase = True, center_slab=False)

    lower.to(fmt="poscar", filename="POSCAR_lower.vasp")

    #creation of upper part of grain boundary
    upper= Interface(structure,\
    hkl = hkl_pair['hkl'][1],
    min_thick = hkl_pair['thickness'][1],
    min_vac = 0,
    primitive = False, from_ase = True)

    #find top atoms reference of lower part of gb
    substrate_top_z = np.max(np.array([site.coords for site in lower])[:,2])

    # define twist and tilt vectors
    twist_shift_normal = lower.lattice.matrix[2,:]/\
                         np.linalg.norm(lower.lattice.matrix[2,:])
    tilt_normal = upper.lattice.matrix[1,:]/\
                  np.linalg.norm(upper.lattice.matrix[2,:])

    #define twist operation SymmOp object
    twist_op = SymmOp.from_axis_angle_and_translation(axis= twist_shift_normal,\
                angle=twist, angle_in_radians=False,translation_vec=(0, 0, 0))
    #define tilt operation SymmOp object
    tilt_op = SymmOp.from_axis_angle_and_translation(axis= tilt_normal,\
                angle=tilt, angle_in_radians=False,translation_vec=(0, 0, 0))
    upper.apply_operation(twist_op)
    upper.to(fmt="poscar", filename="POSCAR_upper.vasp")
    upper.apply_operation(tilt_op)

    #define shift separation along twist vector normal to upper plane
    shift = -1*twist_shift_normal/np.linalg.norm(twist_shift_normal) * separation
    #define origin to shift w.r.t top of the lower grain 
    origin = np.array([0,0, substrate_top_z])
    #shift sites in upper 
    for site in upper:
        new_coords = site.coords - origin  +  shift
        lower.append(site.specie, new_coords, coords_are_cartesian=True)
    return lower