Exemplo n.º 1
0
    def do(self):
        cache = context.application.cache
        parent = cache.node

        unit_cell = None
        if isinstance(parent, UnitCell):
            unit_cell = parent

        Atom = context.application.plugins.get_node("Atom")
        atoms = []
        coordinates = []
        for child in parent.children:
            if isinstance(child, Atom):
                atoms.append(child)
                coordinates.append(child.transformation.t)
        coordinates = numpy.array(coordinates)

        cf = ClusterFactory()
        for i0, i1, delta, distance in PairSearchIntra(
                coordinates, periodic.max_radius * 0.4, unit_cell):
            atom0 = atoms[i0]
            atom1 = atoms[i1]
            if atom0.number == atom1.number:
                if distance < periodic[atom0.number].vdw_radius * 0.4:
                    cf.add_related(atom0, atom1)
        clusters = cf.get_clusters()
        del cf

        # define the new singles
        singles = []
        for cluster in clusters:
            number = iter(cluster.items).next().number
            single = Atom(name="Single " + periodic[number].symbol)
            single.set_number(number)
            singles.append((single, list(cluster.items)))

        # calculate their positions
        for single, overlappers in singles:
            # in the following algorithm, we suppose that the cluster of
            # atoms is small compared to the parent's periodic sizes
            # (if the parent is a periodic system)
            first_pos = overlappers[0].transformation.t
            delta_to_mean = numpy.zeros(3, float)
            for atom in overlappers[1:]:
                delta_to_mean += parent.shortest_vector(atom.transformation.t -
                                                        first_pos)
            delta_to_mean /= float(len(overlappers))
            single.set_transformation(Translation(first_pos + delta_to_mean))

        # modify the model
        for single, overlappers in singles:
            lowest_index = min([atom.get_index() for atom in overlappers])
            primitive.Add(single, parent, index=lowest_index)
            for atom in overlappers:
                while len(atom.references) > 0:
                    primitive.SetTarget(atom.references[0], single)
                primitive.Delete(atom)
Exemplo n.º 2
0
    def do(self):
        cache = context.application.cache
        parent = cache.node

        unit_cell = None
        if isinstance(parent, UnitCell):
            unit_cell = parent

        Atom = context.application.plugins.get_node("Atom")
        atoms = []
        coordinates = []
        for child in parent.children:
            if isinstance(child, Atom):
                atoms.append(child)
                coordinates.append(child.transformation.t)
        coordinates = numpy.array(coordinates)

        cf = ClusterFactory()
        for i0, i1, delta, distance in PairSearchIntra(coordinates, periodic.max_radius*0.4, unit_cell):
            atom0 = atoms[i0]
            atom1 = atoms[i1]
            if atom0.number == atom1.number:
                if distance < periodic[atom0.number].vdw_radius*0.4:
                    cf.add_related(atom0, atom1)
        clusters = cf.get_clusters()
        del cf

        # define the new singles
        singles = []
        for cluster in clusters:
            number = iter(cluster.items).next().number
            single = Atom(name="Single " + periodic[number].symbol)
            single.set_number(number)
            singles.append((single, list(cluster.items)))

        # calculate their positions
        for single, overlappers in singles:
            # in the following algorithm, we suppose that the cluster of
            # atoms is small compared to the parent's periodic sizes
            # (if the parent is a periodic system)
            first_pos = overlappers[0].transformation.t
            delta_to_mean = numpy.zeros(3, float)
            for atom in overlappers[1:]:
                delta_to_mean += parent.shortest_vector(atom.transformation.t - first_pos)
            delta_to_mean /= float(len(overlappers))
            single.set_transformation(Translation(first_pos + delta_to_mean))

        # modify the model
        for single, overlappers in singles:
            lowest_index = min([atom.get_index() for atom in overlappers])
            primitive.Add(single, parent, index=lowest_index)
            for atom in overlappers:
                while len(atom.references) > 0:
                    primitive.SetTarget(atom.references[0], single)
                primitive.Delete(atom)
Exemplo n.º 3
0
    def remove_duplicate(self, threshold=0.1):
        '''Return a system object in which the duplicate atoms and bonds are removed.

           **Optional argument:**

           threshold
                The minimum distance between two atoms that are supposed to be
                different.

           When it makes sense, properties of overlapping atoms are averaged
           out. In other cases, the atom with the lowest index in a cluster of
           overlapping atoms defines the new value of a property.
        '''
        # compute distances
        ndist = (self.natom*(self.natom-1))/2
        if ndist == 0: # single atom systems, go home ...
            return
        dists = np.zeros(ndist)
        self.cell.compute_distances(dists, self.pos)

        # find clusters of overlapping atoms
        from molmod import ClusterFactory
        cf = ClusterFactory()
        counter = 0
        for i0 in xrange(self.natom):
            for i1 in xrange(i0):
                if dists[counter] < threshold:
                    cf.add_related(i0, i1)
                counter += 1
        clusters = [c.items for c in cf.get_clusters()]

        # make a mapping from new to old atoms
        newold = {}
        oldnew = {}
        counter = 0
        for cluster in clusters: # all merged atoms come first
            newold[counter] = sorted(cluster)
            for item in cluster:
                oldnew[item] = counter
            counter += 1
        if len(clusters) > 0:
            old_reduced = set.union(*clusters)
        else:
            old_reduced = []
        for item in xrange(self.natom): # all remaining atoms follow
            if item not in old_reduced:
                newold[counter] = [item]
                oldnew[item] = counter
                counter += 1
        natom = len(newold)

        def reduce_int_array(old):
            if old is None:
                return None
            else:
                new = np.zeros(natom, old.dtype)
                for inew, iolds in newold.iteritems():
                    new[inew] = old[iolds[0]]
                return new

        def reduce_float_array(old):
            if old is None:
                return None
            else:
                new = np.zeros(natom, old.dtype)
                for inew, iolds in newold.iteritems():
                    new[inew] = old[iolds].mean()
                return new

        def reduce_float_matrix(old):
            '''Reduce array with dim=2'''
            if old is None:
                return None
            else:
                new = np.zeros((natom,np.shape(old)[1]), old.dtype)
                for inew, iolds in newold.iteritems():
                    new[inew] = old[iolds].mean(axis=0)
                return new

        # trivial cases
        numbers = reduce_int_array(self.numbers)
        scope_ids = reduce_int_array(self.scope_ids)
        ffatype_ids = reduce_int_array(self.ffatype_ids)
        charges = reduce_float_array(self.charges)
        radii = reduce_float_array(self.radii)
        dipoles = reduce_float_matrix(self.dipoles)
        radii2 = reduce_float_array(self.radii2)
        masses = reduce_float_array(self.masses)

        # create averaged positions
        pos = np.zeros((natom, 3), float)
        for inew, iolds in newold.iteritems():
            # move to the same image
            oldposs = self.pos[iolds].copy()
            assert oldposs.ndim == 2
            ref = oldposs[0]
            for oldpos in oldposs[1:]:
                delta = oldpos-ref
                self.cell.mic(delta)
                oldpos[:] = delta+ref
            # compute mean position
            pos[inew] = oldposs.mean(axis=0)

        # create reduced list of bonds
        if self.bonds is None:
            bonds = None
        else:
            bonds = set((oldnew[ia], oldnew[ib]) for ia, ib in self.bonds)
            bonds = np.array([bond for bond in bonds])

        return self.__class__(numbers, pos, self.scopes, scope_ids, self.ffatypes, ffatype_ids, bonds, self.cell.rvecs, charges, radii, dipoles, radii2, masses)
Exemplo n.º 4
0
    def remove_duplicate(self, threshold=0.1):
        '''Return a system object in which the duplicate atoms and bonds are removed.

           **Optional argument:**

           threshold
                The minimum distance between two atoms that are supposed to be
                different.

           When it makes sense, properties of overlapping atoms are averaged
           out. In other cases, the atom with the lowest index in a cluster of
           overlapping atoms defines the new value of a property.
        '''
        # compute distances
        ndist = (self.natom * (self.natom - 1)) // 2
        if ndist == 0:  # single atom systems, go home ...
            return
        dists = np.zeros(ndist)
        self.cell.compute_distances(dists, self.pos)

        # find clusters of overlapping atoms
        from molmod import ClusterFactory
        cf = ClusterFactory()
        counter = 0
        for i0 in range(self.natom):
            for i1 in range(i0):
                if dists[counter] < threshold:
                    cf.add_related(i0, i1)
                counter += 1
        clusters = [c.items for c in cf.get_clusters()]

        # make a mapping from new to old atoms
        newold = {}
        oldnew = {}
        counter = 0
        for cluster in clusters:  # all merged atoms come first
            newold[counter] = sorted(cluster)
            for item in cluster:
                oldnew[item] = counter
            counter += 1
        if len(clusters) > 0:
            old_reduced = set.union(*clusters)
        else:
            old_reduced = []
        for item in range(self.natom):  # all remaining atoms follow
            if item not in old_reduced:
                newold[counter] = [item]
                oldnew[item] = counter
                counter += 1
        natom = len(newold)

        def reduce_int_array(old):
            if old is None:
                return None
            else:
                new = np.zeros(natom, old.dtype)
                for inew, iolds in newold.items():
                    new[inew] = old[iolds[0]]
                return new

        def reduce_float_array(old):
            if old is None:
                return None
            else:
                new = np.zeros(natom, old.dtype)
                for inew, iolds in newold.items():
                    new[inew] = old[iolds].mean()
                return new

        def reduce_float_matrix(old):
            '''Reduce array with dim=2'''
            if old is None:
                return None
            else:
                new = np.zeros((natom, np.shape(old)[1]), old.dtype)
                for inew, iolds in newold.items():
                    new[inew] = old[iolds].mean(axis=0)
                return new

        # trivial cases
        numbers = reduce_int_array(self.numbers)
        scope_ids = reduce_int_array(self.scope_ids)
        ffatype_ids = reduce_int_array(self.ffatype_ids)
        charges = reduce_float_array(self.charges)
        radii = reduce_float_array(self.radii)
        valence_charges = reduce_float_array(self.valence_charges)
        dipoles = reduce_float_matrix(self.dipoles)
        radii2 = reduce_float_array(self.radii2)
        masses = reduce_float_array(self.masses)

        # create averaged positions
        pos = np.zeros((natom, 3), float)
        for inew, iolds in newold.items():
            # move to the same image
            oldposs = self.pos[iolds].copy()
            assert oldposs.ndim == 2
            ref = oldposs[0]
            for oldpos in oldposs[1:]:
                delta = oldpos - ref
                self.cell.mic(delta)
                oldpos[:] = delta + ref
            # compute mean position
            pos[inew] = oldposs.mean(axis=0)

        # create reduced list of bonds
        if self.bonds is None:
            bonds = None
        else:
            bonds = set((oldnew[ia], oldnew[ib]) for ia, ib in self.bonds)
            bonds = np.array([bond for bond in bonds])

        return self.__class__(numbers, pos, self.scopes, scope_ids,
                              self.ffatypes, ffatype_ids, bonds,
                              self.cell.rvecs, charges, radii, valence_charges,
                              dipoles, radii2, masses)