Пример #1
0
    def fit(self, p: Molecule):
        """Order, rotate and transform all of the matched `p` molecule
        according to the given `threshold`.

        Args:
            p: a `Molecule` object what will be matched with the target one.

        Returns:
            Array of the possible matches where the elements are:
                p_prime: Rotated and translated of the `p` `Molecule` object
                rmsd: Root-mean-square-deviation between `p_prime` and the `target`
        """
        out = []
        for inds in self.permutations(p):
            p_prime = p.copy()
            p_prime._sites = [p_prime[i] for i in inds]

            U, V, rmsd = super().match(p_prime)

            # Rotate and translate matrix `p` onto the target molecule.
            # P' = P * U + V
            for site in p_prime:
                site.coords = np.dot(site.coords, U) + V

            out.append((p_prime, rmsd))

        return out
Пример #2
0
    def fit(self, p: Molecule):
        """Rotate and transform `p` molecule according to the best match.

        Args:
            p: a `Molecule` object what will be matched with the target one.

        Returns:
            p_prime: Rotated and translated of the `p` `Molecule` object
            rmsd: Root-mean-square-deviation between `p_prime` and the `target`
        """
        U, V, rmsd = self.match(p)

        # Rotate and translate matrix `p` onto the target molecule.
        # P' = P * U + V
        p_prime = p.copy()
        for site in p_prime:
            site.coords = np.dot(site.coords, U) + V

        return p_prime, rmsd
Пример #3
0
    def match(self, p: Molecule):
        """Similar as `KabschMatcher.match` but this method also finds all of the
        possible atomic orders according to the `threshold`.

        Args:
            p: a `Molecule` object what will be matched with the target one.

        Returns:
            Array of the possible matches where the elements are:
                inds: The indices of atoms
                U: 3x3 rotation matrix
                V: Translation vector
                rmsd: Root mean squared deviation between P and Q
        """
        out = []
        for inds in self.permutations(p):
            p_prime = p.copy()
            p_prime._sites = [p_prime[i] for i in inds]

            U, V, rmsd = super().match(p_prime)

            out.append((inds, U, V, rmsd))

        return out
Пример #4
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