示例#1
0
    def test_find_all_mappings(self):
        m = np.array([[0.1, 0.2, 0.3], [-0.1, 0.2, 0.7], [0.6, 0.9, 0.2]])
        latt = Lattice(m)

        op = SymmOp.from_origin_axis_angle([0, 0, 0], [2, -1, 3], 40)
        rot = op.rotation_matrix
        scale = np.array([[0, 2, 0], [1, 1, 0], [0,0,1]])

        latt2 = Lattice(np.dot(rot, np.dot(scale, m).T).T)

        for (aligned_out, rot_out, scale_out) in latt.find_all_mappings(latt2):
            self.assertArrayAlmostEqual(np.inner(latt2.matrix, rot_out),
                                        aligned_out.matrix, 5)
            self.assertArrayAlmostEqual(np.dot(scale_out, latt.matrix),
                                        aligned_out.matrix)
            self.assertArrayAlmostEqual(aligned_out.lengths_and_angles, latt2.lengths_and_angles)
            self.assertFalse(np.allclose(aligned_out.lengths_and_angles,
                                         latt.lengths_and_angles))

        latt = Lattice.orthorhombic(9, 9, 5)
        self.assertEqual(len(list(latt.find_all_mappings(latt))), 16)

        #catch the singular matrix error
        latt = Lattice.from_lengths_and_angles([1,1,1], [10,10,10])
        for l, _, _ in latt.find_all_mappings(latt, ltol=0.05, atol=11):
            self.assertTrue(isinstance(l, Lattice))
示例#2
0
    def fit_with_mapper(self, mapper):
        coords = [[0.000000, 0.000000, 0.000000],
                  [0.000000, 0.000000, 1.089000],
                  [1.026719, 0.000000, -0.363000],
                  [-0.513360, -0.889165, -0.363000],
                  [-0.513360, 0.889165, -0.363000]]
        mol1 = Molecule(["C", "H", "H", "H", "H"], coords)
        op = SymmOp.from_origin_axis_angle([0, 0, 0], [0.1, 0.2, 0.3], 60)
        rotcoords = [op.operate(c) for c in coords]
        mol2 = Molecule(["C", "H", "H", "H", "H"], rotcoords)
        mm = MoleculeMatcher(mapper=mapper)
        self.assertTrue(mm.fit(mol1, mol2))

        mol1 = Molecule.from_file(os.path.join(test_dir, "benzene1.xyz"))
        mol2 = Molecule.from_file(os.path.join(test_dir, "benzene2.xyz"))
        self.assertTrue(mm.fit(mol1, mol2))

        mol1 = Molecule.from_file(os.path.join(test_dir, "benzene1.xyz"))
        mol2 = Molecule.from_file(os.path.join(test_dir, "t2.xyz"))
        self.assertFalse(mm.fit(mol1, mol2))

        mol1 = Molecule.from_file(os.path.join(test_dir, "c1.xyz"))
        mol2 = Molecule.from_file(os.path.join(test_dir, "c2.xyz"))
        self.assertTrue(mm.fit(mol1, mol2))

        mol1 = Molecule.from_file(os.path.join(test_dir, "t3.xyz"))
        mol2 = Molecule.from_file(os.path.join(test_dir, "t4.xyz"))
        self.assertTrue(mm.fit(mol1, mol2))

        mol1 = Molecule.from_file(os.path.join(test_dir, "j1.xyz"))
        mol2 = Molecule.from_file(os.path.join(test_dir, "j2.xyz"))
        self.assertTrue(mm.fit(mol1, mol2))

        mol1 = Molecule.from_file(os.path.join(test_dir, "ethene1.xyz"))
        mol2 = Molecule.from_file(os.path.join(test_dir, "ethene2.xyz"))
        self.assertTrue(mm.fit(mol1, mol2))

        mol1 = Molecule.from_file(os.path.join(test_dir, "toluene1.xyz"))
        mol2 = Molecule.from_file(os.path.join(test_dir, "toluene2.xyz"))
        self.assertTrue(mm.fit(mol1, mol2))

        mol1 = Molecule.from_file(os.path.join(test_dir, "cyclohexane1.xyz"))
        mol2 = Molecule.from_file(os.path.join(test_dir, "cyclohexane2.xyz"))
        self.assertTrue(mm.fit(mol1, mol2))

        mol1 = Molecule.from_file(os.path.join(test_dir, "oxygen1.xyz"))
        mol2 = Molecule.from_file(os.path.join(test_dir, "oxygen2.xyz"))
        self.assertTrue(mm.fit(mol1, mol2))

        mm = MoleculeMatcher(tolerance=0.001, mapper=mapper)
        mol1 = Molecule.from_file(os.path.join(test_dir, "t3.xyz"))
        mol2 = Molecule.from_file(os.path.join(test_dir, "t4.xyz"))
        self.assertFalse(mm.fit(mol1, mol2))
示例#3
0
    def test_find_mapping(self):
        m = np.array([[0.1, 0.2, 0.3], [-0.1, 0.2, 0.7], [0.6, 0.9, 0.2]])
        latt = Lattice(m)

        op = SymmOp.from_origin_axis_angle([0, 0, 0], [2, 3, 3], 35)
        rot = op.rotation_matrix
        scale = np.array([[1, 1, 0], [0, 1, 0], [0, 0, 1]])

        latt2 = Lattice(np.dot(rot, np.dot(scale, m).T).T)
        (latt, rot, scale2) = latt2.find_mapping(latt)
        self.assertAlmostEqual(abs(np.linalg.det(rot)), 1)
        self.assertTrue(np.allclose(scale2, scale) or
                        np.allclose(scale2, -scale))
示例#4
0
文件: utils.py 项目: cchenae/pymatgen
    def _align_monomer(self, monomer, mon_vector, move_direction):
        """
        rotate the monomer so that it is aligned along the move direction

        Args:
            monomer (Molecule)
            mon_vector (numpy.array): molecule vector that starts from the
                start atom index to the end atom index
            move_direction (numpy.array): the direction of the polymer chain
                extension
        """
        axis = np.cross(mon_vector, move_direction)
        origin = monomer[self.start].coords
        angle = get_angle(mon_vector, move_direction)
        op = SymmOp.from_origin_axis_angle(origin, axis, angle)
        monomer.apply_operation(op)
示例#5
0
    def test_find_mapping(self):
        m = np.array([[0.1, 0.2, 0.3], [-0.1, 0.2, 0.7], [0.6, 0.9, 0.2]])
        latt = Lattice(m)

        op = SymmOp.from_origin_axis_angle([0, 0, 0], [2, 3, 3], 35)
        rot = op.rotation_matrix
        scale = np.array([[1, 1, 0], [0, 1, 0], [0, 0, 1]])

        latt2 = Lattice(np.dot(rot, np.dot(scale, m).T).T)
        (aligned_out, rot_out, scale_out) = latt2.find_mapping(latt)
        self.assertAlmostEqual(abs(np.linalg.det(rot)), 1)

        rotated = SymmOp.from_rotation_and_translation(rot_out).operate_multi(latt.matrix)

        self.assertArrayAlmostEqual(rotated, aligned_out.matrix)
        self.assertArrayAlmostEqual(np.dot(scale_out, latt2.matrix), aligned_out.matrix)
        self.assertArrayAlmostEqual(aligned_out.lengths_and_angles, latt.lengths_and_angles)
        self.assertFalse(np.allclose(aligned_out.lengths_and_angles,
                                     latt2.lengths_and_angles))
示例#6
0
    def test_rotated_molecule(self):

        coords = [
            [0.000000, 0.000000, 0.000000],
            [0.000000, 0.000000, 1.089000],
            [1.026719, 0.000000, -0.363000],
            [-0.513360, -0.889165, -0.363000],
            [-0.513360, 0.889165, -0.363000],
        ]

        op = SymmOp.from_origin_axis_angle([0, 0, 0], [0.1, 0.2, 0.3], 60)
        rotcoords = [op.operate(c) for c in coords]

        mol1 = Molecule(["C", "H", "H", "H", "H"], coords)
        mol2 = Molecule(["C", "H", "H", "H", "H"], rotcoords)

        mm = GeneticOrderMatcher(mol1, threshold=0.3)
        _, rmsd = mm.fit(mol2)[0]
        self.assertAlmostEqual(rmsd, 0.0, places=6)
示例#7
0
    def test_find_mapping(self):
        m = np.array([[0.1, 0.2, 0.3], [-0.1, 0.2, 0.7], [0.6, 0.9, 0.2]])
        latt = Lattice(m)

        op = SymmOp.from_origin_axis_angle([0, 0, 0], [2, 3, 3], 35)
        rot = op.rotation_matrix
        scale = np.array([[1, 1, 0], [0, 1, 0], [0, 0, 1]])

        latt2 = Lattice(np.dot(rot, np.dot(scale, m).T).T)
        (aligned_out, rot_out, scale_out) = latt2.find_mapping(latt)
        self.assertAlmostEqual(abs(np.linalg.det(rot)), 1)

        rotated = SymmOp.from_rotation_and_translation(rot_out).operate_multi(latt.matrix)

        self.assertArrayAlmostEqual(rotated, aligned_out.matrix)
        self.assertArrayAlmostEqual(np.dot(scale_out, latt2.matrix), aligned_out.matrix)
        self.assertArrayAlmostEqual(aligned_out.lengths_and_angles, latt.lengths_and_angles)
        self.assertFalse(np.allclose(aligned_out.lengths_and_angles,
                                     latt2.lengths_and_angles))
示例#8
0
    def test_find_all_mappings(self):
        m = np.array([[0.1, 0.2, 0.3], [-0.1, 0.2, 0.7], [0.6, 0.9, 0.2]])
        latt = Lattice(m)

        op = SymmOp.from_origin_axis_angle([0, 0, 0], [2, -1, 3], 40)
        rot = op.rotation_matrix
        scale = np.array([[0, 2, 0], [1, 1, 0], [0, 0, 1]])

        latt2 = Lattice(np.dot(rot, np.dot(scale, m).T).T)

        for (aligned_out, rot_out, scale_out) in latt.find_all_mappings(latt2):
            self.assertArrayAlmostEqual(np.inner(latt2.matrix, rot_out), aligned_out.matrix, 5)
            self.assertArrayAlmostEqual(np.dot(scale_out, latt.matrix), aligned_out.matrix)
            self.assertArrayAlmostEqual(aligned_out.parameters, latt2.parameters)
            self.assertFalse(np.allclose(aligned_out.parameters, latt.parameters))

        latt = Lattice.orthorhombic(9, 9, 5)
        self.assertEqual(len(list(latt.find_all_mappings(latt))), 16)

        # catch the singular matrix error
        latt = Lattice.from_parameters(1, 1, 1, 10, 10, 10)
        for l, _, _ in latt.find_all_mappings(latt, ltol=0.05, atol=11):
            self.assertTrue(isinstance(l, Lattice))
示例#9
0
    def test_find_all_mappings(self):
        m = np.array([[0.1, 0.2, 0.3], [-0.1, 0.2, 0.7], [0.6, 0.9, 0.2]])
        latt = Lattice(m)

        op = SymmOp.from_origin_axis_angle([0, 0, 0], [2, -1, 3], 40)
        rot = op.rotation_matrix
        scale = np.array([[0, 2, 0], [1, 1, 0], [0, 0, 1]])

        latt2 = Lattice(np.dot(rot, np.dot(scale, m).T).T)

        for (aligned_out, rot_out, scale_out) in latt.find_all_mappings(latt2):
            self.assertArrayAlmostEqual(np.inner(latt2.matrix, rot_out),
                                        aligned_out.matrix)
            self.assertArrayAlmostEqual(np.dot(scale_out, latt.matrix),
                                        aligned_out.matrix)
            self.assertArrayAlmostEqual(aligned_out.lengths_and_angles,
                                        latt2.lengths_and_angles)
            self.assertFalse(
                np.allclose(aligned_out.lengths_and_angles,
                            latt.lengths_and_angles))

        latt = Lattice.orthorhombic(9, 9, 5)
        self.assertEqual(len(list(latt.find_all_mappings(latt))), 16)
示例#10
0
 def rotate_mols(self):
     """
     rotate the molecules wrt each other using the provided info
     """
     # rotate the molecules around an axis that is
     # perpendicular to the molecular axes
     if self.angle:
         for mol in range(len(self.mols)):
             for ind_key, rot in self.angle[str(mol)].items():
                 perp_vec = np.cross(self.mol_vecs[int(ind_key)],
                                     self.mol_vecs[mol])
                 # if the vectors are parllel,
                 # then perp_vec = (-y, x, 0)
                 if np.abs(np.dot(self.mol_vecs[int(ind_key)],
                                  self.mol_vecs[mol]) - \
                                           np.linalg.norm(self.mol_vecs[mol]) ** 2) < 1e-6:
                     perp_vec = np.array([-self.mol_vecs[mol][1],
                                          self.mol_vecs[mol][0], 0])
                     org_pt = self.vec_indices[mol][0]
                     op = SymmOp.from_origin_axis_angle(
                             self.mols[mol].cart_coords[org_pt],
                             axis=perp_vec, angle=rot)
                     self.mols[mol].apply_operation(op)
示例#11
0
 def rotate_mols(self):
     """
     rotate the molecules wrt each other using the provided info
     """
     # rotate the molecules around an axis that is
     # perpendicular to the molecular axes
     if self.angle:
         for mol in range(len(self.mols)):
             for ind_key, rot in self.angle[str(mol)].items():
                 perp_vec = np.cross(self.mol_vecs[int(ind_key)],
                                     self.mol_vecs[mol])
                 # if the vectors are parllel,
                 # then perp_vec = (-y, x, 0)
                 if np.abs(np.dot(self.mol_vecs[int(ind_key)],
                                  self.mol_vecs[mol]) - \
                                           np.linalg.norm(self.mol_vecs[mol]) ** 2) < 1e-6:
                     perp_vec = np.array([-self.mol_vecs[mol][1],
                                          self.mol_vecs[mol][0], 0])
                     org_pt = self.vec_indices[mol][0]
                     op = SymmOp.from_origin_axis_angle(
                             self.mols[mol].cart_coords[org_pt],
                             axis=perp_vec, angle=rot)
                     self.mols[mol].apply_operation(op)
示例#12
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)]
示例#13
0
    def parse_coords(coord_lines):
        """
        Helper method to parse coordinates.
        """
        paras = {}
        var_pattern = re.compile("^([A-Za-z]+\S*)[\s=,]+([\d\-\.]+)$")
        for l in coord_lines:
            m = var_pattern.match(l.strip())
            if m:
                paras[m.group(1)] = float(m.group(2))

        species = []
        coords = []
        # Stores whether a Zmatrix format is detected. Once a zmatrix format
        # is detected, it is assumed for the remaining of the parsing.
        zmode = False
        for l in coord_lines:
            l = l.strip()
            if not l:
                break
            if (not zmode) and GaussianInput.xyz_patt.match(l):
                m = GaussianInput.xyz_patt.match(l)
                species.append(m.group(1))
                toks = re.split("[,\s]+", l.strip())
                if len(toks) > 4:
                    coords.append([float(i) for i in toks[2:5]])
                else:
                    coords.append([float(i) for i in toks[1:4]])
            elif GaussianInput.zmat_patt.match(l):
                zmode = True
                toks = re.split("[,\s]+", l.strip())
                species.append(toks[0])
                toks.pop(0)
                if len(toks) == 0:
                    coords.append(np.array([0, 0, 0]))
                else:
                    nn = []
                    parameters = []
                    while len(toks) > 1:
                        ind = toks.pop(0)
                        data = toks.pop(0)
                        try:
                            nn.append(int(ind))
                        except ValueError:
                            nn.append(species.index(ind) + 1)
                        try:
                            val = float(data)
                            parameters.append(val)
                        except ValueError:
                            if data.startswith("-"):
                                parameters.append(-paras[data[1:]])
                            else:
                                parameters.append(paras[data])
                    if len(nn) == 1:
                        coords.append(np.array([0, 0, parameters[0]]))
                    elif len(nn) == 2:
                        coords1 = coords[nn[0] - 1]
                        coords2 = coords[nn[1] - 1]
                        bl = parameters[0]
                        angle = parameters[1]
                        axis = [0, 1, 0]
                        op = SymmOp.from_origin_axis_angle(
                            coords1, axis, angle, False)
                        coord = op.operate(coords2)
                        vec = coord - coords1
                        coord = vec * bl / np.linalg.norm(vec) + coords1
                        coords.append(coord)
                    elif len(nn) == 3:
                        coords1 = coords[nn[0] - 1]
                        coords2 = coords[nn[1] - 1]
                        coords3 = coords[nn[2] - 1]
                        bl = parameters[0]
                        angle = parameters[1]
                        dih = parameters[2]
                        v1 = coords3 - coords2
                        v2 = coords1 - coords2
                        axis = np.cross(v1, v2)
                        op = SymmOp.from_origin_axis_angle(
                            coords1, axis, angle, False)
                        coord = op.operate(coords2)
                        v1 = coord - coords1
                        v2 = coords1 - coords2
                        v3 = np.cross(v1, v2)
                        adj = get_angle(v3, axis)
                        axis = coords1 - coords2
                        op = SymmOp.from_origin_axis_angle(
                            coords1, axis, dih - adj, False)
                        coord = op.operate(coord)
                        vec = coord - coords1
                        coord = vec * bl / np.linalg.norm(vec) + coords1
                        coords.append(coord)

        def parse_species(sp_str):
            """
            The species specification can take many forms. E.g.,
            simple integers representing atomic numbers ("8"),
            actual species string ("C") or a labelled species ("C1").
            Sometimes, the species string is also not properly capitalized,
            e.g, ("c1"). This method should take care of these known formats.
            """
            try:
                return int(sp_str)
            except ValueError:
                sp = re.sub("\d", "", sp_str)
                return sp.capitalize()

        species = [parse_species(sp) for sp in species]

        return Molecule(species, coords)
示例#14
0
    def fit_with_mapper(self, mapper):
        coords = [[0.000000, 0.000000, 0.000000],
                  [0.000000, 0.000000, 1.089000],
                  [1.026719, 0.000000, -0.363000],
                  [-0.513360, -0.889165, -0.363000],
                  [-0.513360, 0.889165, -0.363000]]
        mol1 = Molecule(["C", "H", "H", "H", "H"], coords)
        op = SymmOp.from_origin_axis_angle([0, 0, 0], [0.1, 0.2, 0.3], 60)
        rotcoords = [op.operate(c) for c in coords]
        mol2 = Molecule(["C", "H", "H", "H", "H"], rotcoords)
        mm = MoleculeMatcher(mapper=mapper)
        self.assertTrue(mm.fit(mol1, mol2))

        mol1 = BabelMolAdaptor.from_file(os.path.join(
            test_dir, "benzene1.xyz")).pymatgen_mol
        mol2 = BabelMolAdaptor.from_file(os.path.join(
            test_dir, "benzene2.xyz")).pymatgen_mol
        self.assertTrue(mm.fit(mol1, mol2))

        mol1 = BabelMolAdaptor.from_file(os.path.join(
            test_dir, "benzene1.xyz")).pymatgen_mol
        mol2 = BabelMolAdaptor.from_file(os.path.join(test_dir,
                                                      "t2.xyz")).pymatgen_mol
        self.assertFalse(mm.fit(mol1, mol2))

        mol1 = BabelMolAdaptor.from_file(os.path.join(test_dir,
                                                      "c1.xyz")).pymatgen_mol
        mol2 = BabelMolAdaptor.from_file(os.path.join(test_dir,
                                                      "c2.xyz")).pymatgen_mol
        self.assertTrue(mm.fit(mol1, mol2))

        mol1 = BabelMolAdaptor.from_file(os.path.join(test_dir,
                                                      "t3.xyz")).pymatgen_mol
        mol2 = BabelMolAdaptor.from_file(os.path.join(test_dir,
                                                      "t4.xyz")).pymatgen_mol
        self.assertTrue(mm.fit(mol1, mol2))

        mol1 = BabelMolAdaptor.from_file(os.path.join(test_dir,
                                                      "j1.xyz")).pymatgen_mol
        mol2 = BabelMolAdaptor.from_file(os.path.join(test_dir,
                                                      "j2.xyz")).pymatgen_mol
        self.assertTrue(mm.fit(mol1, mol2))

        mol1 = BabelMolAdaptor.from_file(os.path.join(
            test_dir, "ethene1.xyz")).pymatgen_mol
        mol2 = BabelMolAdaptor.from_file(os.path.join(
            test_dir, "ethene2.xyz")).pymatgen_mol
        self.assertTrue(mm.fit(mol1, mol2))

        mol1 = BabelMolAdaptor.from_file(os.path.join(
            test_dir, "toluene1.xyz")).pymatgen_mol
        mol2 = BabelMolAdaptor.from_file(os.path.join(
            test_dir, "toluene2.xyz")).pymatgen_mol
        self.assertTrue(mm.fit(mol1, mol2))

        mol1 = BabelMolAdaptor.from_file(
            os.path.join(test_dir, "cyclohexane1.xyz")).pymatgen_mol
        mol2 = BabelMolAdaptor.from_file(
            os.path.join(test_dir, "cyclohexane2.xyz")).pymatgen_mol
        self.assertTrue(mm.fit(mol1, mol2))

        mol1 = BabelMolAdaptor.from_file(os.path.join(
            test_dir, "oxygen1.xyz")).pymatgen_mol
        mol2 = BabelMolAdaptor.from_file(os.path.join(
            test_dir, "oxygen2.xyz")).pymatgen_mol
        self.assertTrue(mm.fit(mol1, mol2))

        mm = MoleculeMatcher(tolerance=0.001, mapper=mapper)
        mol1 = BabelMolAdaptor.from_file(os.path.join(test_dir,
                                                      "t3.xyz")).pymatgen_mol
        mol2 = BabelMolAdaptor.from_file(os.path.join(test_dir,
                                                      "t4.xyz")).pymatgen_mol
        self.assertFalse(mm.fit(mol1, mol2))
示例#15
0
    def parse_coords(coord_lines):
        """
        Helper method to parse coordinates.
        """
        paras = {}
        var_pattern = re.compile("^([A-Za-z]+\S*)[\s=,]+([\d\-\.]+)$")
        for l in coord_lines:
            m = var_pattern.match(l.strip())
            if m:
                paras[m.group(1)] = float(m.group(2))

        species = []
        coords = []
        # Stores whether a Zmatrix format is detected. Once a zmatrix format
        # is detected, it is assumed for the remaining of the parsing.
        zmode = False
        for l in coord_lines:
            l = l.strip()
            if not l:
                break
            if (not zmode) and GaussianInput.xyz_patt.match(l):
                m = GaussianInput.xyz_patt.match(l)
                species.append(m.group(1))
                toks = re.split("[,\s]+", l.strip())
                if len(toks) > 4:
                    coords.append(map(float, toks[2:5]))
                else:
                    coords.append(map(float, toks[1:4]))
            elif GaussianInput.zmat_patt.match(l):
                zmode = True
                toks = re.split("[,\s]+", l.strip())
                species.append(toks[0])
                toks.pop(0)
                if len(toks) == 0:
                    coords.append(np.array([0, 0, 0]))
                else:
                    nn = []
                    parameters = []
                    while len(toks) > 1:
                        ind = toks.pop(0)
                        data = toks.pop(0)
                        try:
                            nn.append(int(ind))
                        except ValueError:
                            nn.append(species.index(ind) + 1)
                        try:
                            val = float(data)
                            parameters.append(val)
                        except ValueError:
                            if data.startswith("-"):
                                parameters.append(-paras[data[1:]])
                            else:
                                parameters.append(paras[data])
                    if len(nn) == 1:
                        coords.append(np.array([0, 0, parameters[0]]))
                    elif len(nn) == 2:
                        coords1 = coords[nn[0] - 1]
                        coords2 = coords[nn[1] - 1]
                        bl = parameters[0]
                        angle = parameters[1]
                        axis = [0, 1, 0]
                        op = SymmOp.from_origin_axis_angle(coords1, axis, angle, False)
                        coord = op.operate(coords2)
                        vec = coord - coords1
                        coord = vec * bl / np.linalg.norm(vec) + coords1
                        coords.append(coord)
                    elif len(nn) == 3:
                        coords1 = coords[nn[0] - 1]
                        coords2 = coords[nn[1] - 1]
                        coords3 = coords[nn[2] - 1]
                        bl = parameters[0]
                        angle = parameters[1]
                        dih = parameters[2]
                        v1 = coords3 - coords2
                        v2 = coords1 - coords2
                        axis = np.cross(v1, v2)
                        op = SymmOp.from_origin_axis_angle(coords1, axis, angle, False)
                        coord = op.operate(coords2)
                        v1 = coord - coords1
                        v2 = coords1 - coords2
                        v3 = np.cross(v1, v2)
                        adj = get_angle(v3, axis)
                        axis = coords1 - coords2
                        op = SymmOp.from_origin_axis_angle(coords1, axis, dih - adj, False)
                        coord = op.operate(coord)
                        vec = coord - coords1
                        coord = vec * bl / np.linalg.norm(vec) + coords1
                        coords.append(coord)

        def parse_species(sp_str):
            """
            The species specification can take many forms. E.g.,
            simple integers representing atomic numbers ("8"),
            actual species string ("C") or a labelled species ("C1").
            Sometimes, the species string is also not properly capitalized,
            e.g, ("c1"). This method should take care of these known formats.
            """
            try:
                return int(sp_str)
            except ValueError:
                sp = re.sub("\d", "", sp_str)
                return sp.capitalize()

        species = map(parse_species, species)

        return Molecule(species, coords)
示例#16
0
    def add_water_monolayer(self, distance=2.85):
        """
        Function that finds the number of water molecules necessary to create
        a monolayer on the slab surface and then orients these essentially
        equally spaced at distance from the surface

        O is always facing outward for easier convergence. This may lead to some
        inaccurate early guesses of structure though.

        At the end a random rotation is applied to make the water at least somewhat random
        Obviously, a relax or MD run is necessary to get equilibrium positions.

        author: Quinn Campbell [email protected]
        """
        slab = self.slab
        water = Molecule(
            "HHO",
            [[-0.7598, 0.0, -0.5841], [0.7598, 0.0, -0.5841], [0, 0, 0]])
        min_z = 1000.0
        max_z = -10.0
        water_distance = distance

        for site in slab:
            coord = site.coords
            if coord[2] < min_z:
                min_z = coord[2]
            if coord[2] > max_z:
                max_z = coord[2]
        a = slab.lattice.matrix[0]
        b = slab.lattice.matrix[1]
        norm_a = np.linalg.norm(a)
        norm_b = np.linalg.norm(b)
        site = a * random.random() + b * random.random() + [
            0.0, 0.0, max_z + water_distance
        ]
        sop = SymmOp.from_origin_axis_angle(origin=[0, 0, 0],
                                            axis=[1, 1, 1],
                                            angle=random.random() * 140.0 -
                                            70.0)
        wat = water.copy()
        wat.apply_operation(sop)
        ads_structure = self.add_adsorbate(wat, site)
        wat_mono_density = 7.5  # in units of angstrom squared. Still up for finding exact number
        wat_mol_a = int(round(norm_a / math.sqrt(wat_mono_density)))
        wat_mol_b = int(round(norm_b / math.sqrt(wat_mono_density)))
        for i in range(wat_mol_a):
            for j in range(wat_mol_b):
                if i == 0 and j == 0:
                    pass
                else:
                    if i % 2 == 1:
                        new_coord = site + float(i) / float(wat_mol_a) * a + (
                            float(j) / float(wat_mol_b) + 1.0 /
                            (float(wat_mol_b) * 2.0)) * b
                    else:
                        new_coord = site + float(i) / float(
                            wat_mol_a) * a + float(j) / float(wat_mol_b) * b
                    sop = SymmOp.from_origin_axis_angle(
                        origin=[0, 0, 0],
                        axis=[1, 1, 1],
                        angle=random.random() * 140.0 - 70.0)
                    wat = water.copy()
                    wat.apply_operation(sop)
                    ads_structure = asf.add_adsorbate(wat, new_coord)
                asf = AdsorbateSiteFinder(ads_structure)

        ads_structure = asf.mirror_adsorbates()

        return ads_structure
示例#17
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)
         ]
示例#18
0
    def parse_coords(coord_lines):
        """
        Helper method to parse coordinates.
        """
        paras = {}
        var_pattern = re.compile("^\s*([A-Za-z]+\S*)[\s=,]+([\d\-\.]+)\s*$")
        for l in coord_lines:
            m = var_pattern.match(l.strip())
            if m:
                paras[m.group(1)] = float(m.group(2))
        zmat_patt = re.compile("^\s*([A-Za-z]+)[\w\d\-\_]*([\s,]+(\w+)[\s,]+(\w+))*[\-\.\s,\w]*$")
        mixed_species_patt = re.compile("([A-Za-z]+)[\d\-\_]+")
        xyz_patt = re.compile("^\s*([A-Za-z]+[\w\d\-\_]*)\s+([\d\.eE\-]+)\s+([\d\.eE\-]+)\s+([\d\.eE\-]+)[\-\.\s,\w.]*$")

        parsed_species = []
        species = []
        coords = []

        for l in coord_lines:
            l = l.strip()
            if l == "":
                break
            if xyz_patt.match(l):
                m = xyz_patt.match(l)
                m2 = mixed_species_patt.match(m.group(1))
                if m2:
                    parsed_species.append(m.group(1))
                    species.append(m2.group(1))
                else:
                    species.append(m.group(1))

                toks = re.split("[,\s]+", l.strip())
                if len(toks) > 4:
                    coords.append(map(float, toks[2:5]))
                else:
                    coords.append(map(float, toks[1:4]))
            elif zmat_patt.match(l):
                toks = re.split("[,\s]+", l.strip())
                m = mixed_species_patt.match(toks[0])
                if m:
                    parsed_species.append(toks[0])
                    species.append(m.group(1))
                else:
                    species.append(toks[0])
                toks.pop(0)
                if len(toks) == 0:
                    coords.append(np.array([0, 0, 0]))
                else:
                    nn = []
                    parameters = []
                    while len(toks) > 0:
                        ind = toks.pop(0)
                        data = toks.pop(0)
                        try:
                            int(ind)
                            nn.append(int(ind))
                        except:
                            nn.append(parsed_species.index(ind))
                        parameters.append(paras[data])
                    if len(nn) == 1:
                        coords.append(np.array([0, 0, parameters[0]]))
                    elif len(nn) == 2:
                        coords1 = coords[nn[0] - 1]
                        coords2 = coords[nn[1] - 1]
                        bl = parameters[0]
                        angle = parameters[1]
                        axis = [0, 1, 0]
                        coord = SymmOp.from_origin_axis_angle(coords1, axis, angle, False).operate(coords2)
                        vec = coord - coords1
                        coord = vec * bl / np.linalg.norm(vec) + coords1
                        coords.append(coord)
                    elif len(nn) == 3:
                        coords1 = coords[nn[0] - 1]
                        coords2 = coords[nn[1] - 1]
                        coords3 = coords[nn[2] - 1]
                        bl = parameters[0]
                        angle = parameters[1]
                        dih = parameters[2]
                        v1 = coords3 - coords2
                        v2 = coords1 - coords2
                        axis = np.cross(v1, v2)
                        coord = SymmOp.from_origin_axis_angle(coords1, axis, angle, False).operate(coords2)
                        v1 = coord - coords1
                        v2 = coords1 - coords2
                        v3 = np.cross(v1, v2)
                        d = np.dot(v3, axis) / np.linalg.norm(v3) / np.linalg.norm(axis)
                        if d > 1:
                            d = 1
                        elif d < -1:
                            d = -1
                        adj = math.acos(d) * 180 / math.pi
                        axis = coords1 - coords2
                        coord = SymmOp.from_origin_axis_angle(coords1, axis, dih - adj, False).operate(coord)
                        vec = coord - coords1
                        coord = vec * bl / np.linalg.norm(vec) + coords1
                        coords.append(coord)

        return Molecule(species, coords)