示例#1
0
 def _set_voronoi_bond_orders(self):
     '''
     approximate bond order, from purely geometric voronoi solid angles'
     returns
     def bond_order(cd):
     '''
     p = self.positions
     bond_orders = []
     o_index = p.shape[1] / 2
     n_images = p.shape[1]
     for i in range(p.shape[2]):
         #[atomj * image, axis]
         vt = VoronoiTess(p[:, :, i].reshape((-1, 3)))
         bo = np.zeros([p.shape[0] * p.shape[1]] * 2)
         vts = np.array(vt.vertices)
         for (k1, k2), v in vt.ridges.items():
             if (k1 % n_images != o_index) and (k2 % n_images != o_index):
                 continue
             if -10.101 in vts[v]:
                 continue
             val = solid_angle(vt.points[k1], vts[v])
             bo[k1, k2] = val
             bo[k2, k1] = val
         nshape = (p.shape[0], p.shape[0], p.shape[1], 1)
         bond_orders.append(bo[o_index::n_images].reshape(nshape))
     self._voronoi_bond_orders = np.concatenate(bond_orders, -1)
示例#2
0
    def setup_voronoi_list(self, indices, voronoi_cutoff):
        """
        Set up of the voronoi list of neighbours by calling qhull
        :param indices: indices of the sites for which the Voronoi is needed
        :param voronoi_cutoff: Voronoi cutoff for the search of neighbours
        :raise RuntimeError: If an infinite vertex is found in the voronoi construction
        """
        self.voronoi_list = [None] * len(self.structure)
        logging.info('Getting all neighbors in structure')
        struct_neighbors = self.structure.get_all_neighbors(voronoi_cutoff,
                                                            include_index=True)
        t1 = time.clock()
        logging.info('Setting up Voronoi list :')

        for jj, isite in enumerate(indices):
            logging.info(
                '  - Voronoi analysis for site #{:d} ({:d}/{:d})'.format(
                    isite, jj + 1, len(indices)))
            site = self.structure[isite]
            neighbors1 = [(site, 0.0, isite)]
            neighbors1.extend(struct_neighbors[isite])
            distances = [i[1] for i in sorted(neighbors1, key=lambda s: s[1])]
            neighbors = [i[0] for i in sorted(neighbors1, key=lambda s: s[1])]
            qvoronoi_input = [s.coords for s in neighbors]
            voro = VoronoiTess(qvoronoi_input)
            all_vertices = voro.vertices

            results = []
            maxangle = 0.0
            mindist = 10000.0
            for nn, vind in list(voro.ridges.items()):
                if 0 in nn:
                    if 0 in vind:
                        raise RuntimeError("This structure is pathological,"
                                           " infinite vertex in the voronoi "
                                           "construction")

                    facets = [all_vertices[i] for i in vind]
                    try:
                        sa = solid_angle(site.coords, facets)
                    except ValueError:
                        sa = my_solid_angle(site.coords, facets)
                    maxangle = max([sa, maxangle])
                    mindist = min([mindist, distances[nn[1]]])
                    for iii, sss in enumerate(self.structure):
                        if neighbors[nn[1]].is_periodic_image(sss):
                            myindex = iii
                            break
                    results.append((neighbors[nn[1]], {
                        'angle': sa,
                        'distance': distances[nn[1]],
                        'index': myindex
                    }))
            for (nn, dd) in results:
                dd['weighted_angle'] = dd['angle'] / maxangle
                dd['weighted_distance'] = dd['distance'] / mindist
            self.voronoi_list[isite] = results
        t2 = time.clock()
        logging.info('Voronoi list set up in {:.2f} seconds'.format(t2 - t1))
示例#3
0
    def setup_voronoi_list(self, indices, voronoi_cutoff):
        """
        Set up of the voronoi list of neighbours by calling qhull
        :param indices: indices of the sites for which the Voronoi is needed
        :param voronoi_cutoff: Voronoi cutoff for the search of neighbours
        :raise RuntimeError: If an infinite vertex is found in the voronoi construction
        """
        self.voronoi_list2 = [None] * len(self.structure)
        logging.info('Getting all neighbors in structure')
        struct_neighbors = self.structure.get_all_neighbors(voronoi_cutoff, include_index=True)
        t1 = time.clock()
        logging.info('Setting up Voronoi list :')

        for jj, isite in enumerate(indices):
            logging.info('  - Voronoi analysis for site #{:d} ({:d}/{:d})'.format(isite, jj+1, len(indices)))
            site = self.structure[isite]
            neighbors1 = [(site, 0.0, isite)]
            neighbors1.extend(struct_neighbors[isite])
            distances = [i[1] for i in sorted(neighbors1, key=lambda s: s[1])]
            neighbors = [i[0] for i in sorted(neighbors1, key=lambda s: s[1])]
            qvoronoi_input = [s.coords for s in neighbors]
            voro = Voronoi(points=qvoronoi_input, qhull_options="o Fv")
            all_vertices = voro.vertices

            results2 = []
            maxangle = 0.0
            mindist = 10000.0
            for iridge, ridge_points in enumerate(voro.ridge_points):
                if 0 in ridge_points:
                    ridge_vertices_indices = voro.ridge_vertices[iridge]
                    if -1 in ridge_vertices_indices:
                        raise RuntimeError("This structure is pathological,"
                                           " infinite vertex in the voronoi "
                                           "construction")

                    ridge_point2 = max(ridge_points)
                    facets = [all_vertices[i] for i in ridge_vertices_indices]
                    try:
                        sa = solid_angle(site.coords, facets)
                    except ValueError:
                        sa = my_solid_angle(site.coords, facets)
                    maxangle = max([sa, maxangle])

                    mindist = min([mindist, distances[ridge_point2]])
                    for iii, sss in enumerate(self.structure):
                        if neighbors[ridge_point2].is_periodic_image(sss):
                            myindex = iii
                            break
                    results2.append({'site': neighbors[ridge_point2],
                                     'angle': sa,
                                     'distance': distances[ridge_point2],
                                     'index': myindex})
            for dd in results2:
                dd['normalized_angle'] = dd['angle'] / maxangle
                dd['normalized_distance'] = dd['distance'] / mindist
            self.voronoi_list2[isite] = results2
        t2 = time.clock()
        logging.info('Voronoi list set up in {:.2f} seconds'.format(t2-t1))
示例#4
0
 def test_solid_angle(self):
     center = [2.294508207929496, 4.4078057081404, 2.299997773791287]
     coords = [[1.627286218099362, 3.081185538926995, 3.278749383217061],
               [1.776793751092763, 2.93741167455471, 3.058701096568852],
               [3.318412187495734, 2.997331084033472, 2.022167590167672],
               [3.874524708023352, 4.425301459451914, 2.771990305592935],
               [2.055778446743566, 4.437449313863041, 4.061046832034642]]
     self.assertAlmostEqual(solid_angle(center, coords), 1.83570965938, 7,
                            "Wrong result returned by solid_angle")
 def test_solid_angle(self):
     center = [2.294508207929496, 4.4078057081404, 2.299997773791287]
     coords = [[1.627286218099362, 3.081185538926995, 3.278749383217061],
               [1.776793751092763, 2.93741167455471, 3.058701096568852],
               [3.318412187495734, 2.997331084033472, 2.022167590167672],
               [3.874524708023352, 4.425301459451914, 2.771990305592935],
               [2.055778446743566, 4.437449313863041, 4.061046832034642]]
     self.assertAlmostEqual(solid_angle(center, coords), 1.83570965938, 7,
                            "Wrong result returned by solid_angle")
    def _delaunay_midpoints(self, structure):
        """
        returns the midpoints of the delaunay triangulation for a structure. 
        returns in the format of a list of lists, where the first index 
        corresponds to the index of the site in the original structure that 
        neighbors the point. I.e. dms[0] is the list of delaunay midpoints 
        around the site structure[0]
        
        We can't simply use the ridges from the voronoi tesselation because
        the ridges don't include nearest neighbors with a solid angle of 0
        (whose voronoi volumes are edge sharing)
        """
        logging.debug("Starting calculating Delaunay points")
        all_coords = self._fake_periodic(structure)
        vt = VoronoiTess(all_coords)
        dt = DelaunayTri(all_coords)

        v_array = np.array(vt.vertices)
        p_array = np.array(vt.points)
        dms = [[] for i in range(len(structure))]

        for simplex in dt.vertices:
            if min(simplex) >= len(structure):
                continue
            for pt1, pt2 in itertools.permutations(simplex, 2):
                if pt1 >= len(structure):
                    continue
                center = structure[pt1].coords

                # get points that make up the shared plane
                if pt2 > pt1:
                    vertices = vt.ridges.get((pt1, pt2), None)
                else:
                    vertices = vt.ridges.get((pt2, pt1), None)

                # get the solid angle, if pt1 and pt2 share a plane
                if vertices is not None:
                    sa = solid_angle(center, v_array[vertices])
                else:
                    sa = 0

                new_coord = (p_array[pt1] + p_array[pt2]) / 2
                if sa >= self._msa:
                    dms[pt1].append(new_coord)

        logging.debug("Finished calculating Delaunay points")

        return dms
示例#7
0
def get_voronoi_dicts(structure,
                      cutoff_radius=VORONOI_CUTOFF_RADIUS,
                      cutoff_weight_fraction=VORONOI_CUTOFF_WEIGHT_FRACTION):
    voronoi_finder = VoronoiCoordFinder(structure)

    voronoi_finder.cutoff = cutoff_radius

    voronoi_finder_2 = VoronoiNN()
    voronoi_finder_2.cutoff = cutoff_radius

    all_neighbor_sites = {}
    all_neighbor_pairs = {}

    for center_site_index in range(0, len(structure.sites)):
        neighbor_sites_dict = {}
        neighbor_pairs_list = []
        # print "center_site_index: ", center_site_index

        # Construct initial voronoi polyhedra using cutoff_radius
        neighborhood_sites = [structure[center_site_index]
                              ]  # begin list with center site

        polyhedra_sites = voronoi_finder.get_voronoi_polyhedra(
            center_site_index)

        polyhedra_sites_2 = voronoi_finder_2.get_voronoi_polyhedra(
            structure, center_site_index)

        cutoff_weight = cutoff_weight_fraction * sum(polyhedra_sites.values())
        for neighbor_site, neighbor_weight in polyhedra_sites.items():
            if neighbor_weight > cutoff_weight:
                neighborhood_sites.append(neighbor_site)

        # Re-tesselate only with sites that also meet cutoff_weight_fraction criteria
        voronoi_input_coords = [site.coords for site in neighborhood_sites]
        try:
            voronoi_tess = VoronoiTess(voronoi_input_coords)
        except IndexError:
            raise RuntimeError('VoronoiTess: details unknown')

        local_solid_angles = []
        center_coords = structure[center_site_index].coords
        n_neighborhood_sites = len(neighborhood_sites)
        n_voronoi_vertices = len(voronoi_tess.vertices)
        neighbor_lookup = np.zeros(shape=(n_voronoi_vertices,
                                          n_voronoi_vertices, 2),
                                   dtype=np.int8)

        # Loop over neighbor sites (which surrond center_site) to:
        # - calculate solid angles
        # - construct neighbor_lookup array (which maps each voronoi edge to two adjacent neighbors)
        for neighbor_index in range(1, n_neighborhood_sites):
            facet_vertex_list = voronoi_tess.ridges[(
                0, neighbor_index)]  # 0 = center site
            if 0 in facet_vertex_list:
                raise RuntimeError(
                    "Pathological structure: voronoi facet includes vertex at infinity"
                )

            # Calculate solid angle of facet between center site and this neighbor site
            facet_coords = [
                voronoi_tess.vertices[i] for i in facet_vertex_list
            ]
            local_solid_angles.append(solid_angle(center_coords, facet_coords))

            # Add this voronoi ridge to neighbor_lookup array, to identify adjacent voronoi facets
            n_vertices = len(facet_vertex_list)
            for vertex1_index in range(0, n_vertices):
                vertex2_index = vertex1_index + 1
                if vertex2_index == n_vertices:
                    vertex2_index = 0  # wrap vertex2_index

                # Properly order vertex indicies to only use upper triangle of neighbor_lookup array
                (low_vert_index,
                 high_vert_index) = (facet_vertex_list[vertex1_index],
                                     facet_vertex_list[vertex2_index])
                if low_vert_index > high_vert_index:
                    (low_vert_index, high_vert_index) = (high_vert_index,
                                                         low_vert_index)

                # Store adjacent voronoi neighbors on different levels of neighbor_lookup, at location defined
                # by common voronoi edge running between low_vert_index (row) and high_vert_index (column).
                if neighbor_lookup[low_vert_index, high_vert_index, 0] == 0:
                    neighbor_lookup[low_vert_index, high_vert_index,
                                    0] = neighbor_index  # first neighbor
                else:
                    neighbor_lookup[low_vert_index, high_vert_index,
                                    1] = neighbor_index  # second neighbor

        # Loop over neighbor sites again to construct neighbor_sites_dict with solid angle weights
        max_local_solid_angle = max(local_solid_angles)
        for neighbor_index in range(1, n_neighborhood_sites):
            # Note: neighborhood_sites (which starts with center) is one longer than local_solid_angles
            neighbor_sites_dict[neighborhood_sites[neighbor_index]] = \
                local_solid_angles[neighbor_index - 1] / max_local_solid_angle

        # Loop through upper triangle of neighbor_lookup and build a list of tuples of neighbor pair sites
        for low_vert_index in range(1, n_voronoi_vertices):
            for high_vert_index in range(low_vert_index + 1,
                                         n_voronoi_vertices):
                neighbor1_index = neighbor_lookup[low_vert_index,
                                                  high_vert_index, 0]
                neighbor2_index = neighbor_lookup[low_vert_index,
                                                  high_vert_index, 1]
                if neighbor1_index > 0 and neighbor2_index > 0:  # Both are non-zero
                    neighbor_pairs_list.append(
                        (neighborhood_sites[neighbor1_index],
                         neighborhood_sites[neighbor2_index]))
                elif neighbor1_index != 0 or neighbor2_index != 0:  # Only one is non-zero
                    raise RuntimeError(
                        "Unexpected neighbor_lookup matrix: non-paired edge")

        # Append per site values
        all_neighbor_sites[
            structure.sites[center_site_index]] = neighbor_sites_dict
        all_neighbor_pairs[
            structure.sites[center_site_index]] = neighbor_pairs_list

    return (all_neighbor_sites, all_neighbor_pairs)