示例#1
0
    def test_intersection(self):
        h1 = Halfspace.from_hyperplane([[1, 0, 0], [0, 1, 0]], [1, 1, 1],
                                       [0.9, 0.9, 0.9], True)
        h2 = Halfspace.from_hyperplane([[0, 1, 0], [0, 0, 1]], [1, 1, 1],
                                       [0.9, 0.9, 0.9], True)
        h3 = Halfspace.from_hyperplane([[0, 0, 1], [1, 0, 0]], [1, 1, 1],
                                       [0.9, 0.9, 0.9], True)
        h4 = Halfspace.from_hyperplane([[-1, 0, 1], [0, -1, 1]], [1, 1, 0],
                                       [0.9, 0.9, 0.9], True)

        hi = HalfspaceIntersection([h1, h2, h3, h4], [0.9, 0.9, 0.9])
        self.assertTrue(np.allclose(np.sum(hi.vertices, axis=0), [3, 3, 3]))

        h5 = Halfspace.from_hyperplane([[1, 0, 0], [0, 1, 0]], [1, 2, 2],
                                       [0.9, 0.9, 0.9], True)
        hi = HalfspaceIntersection([h5, h2, h3, h4], [0.9, 0.9, 0.9])
        self.assertTrue(np.allclose(np.sum(hi.vertices, axis=0), [2, 2, 6]))

        for h, vs in zip(hi.halfspaces, hi.facets_by_halfspace):
            for v in vs:
                self.assertAlmostEqual(
                    np.dot(h.normal, hi.vertices[v]) + h.offset, 0)
        for v, hss in zip(hi.vertices, hi.facets_by_vertex):
            for i in hss:
                hs = hi.halfspaces[i]
                self.assertAlmostEqual(np.dot(hs.normal, v) + hs.offset, 0)
示例#2
0
 def test_infinite_vertex(self):
     h1 = Halfspace.from_hyperplane([[1,0,0], [0,1,0]], [1,1,1], [0.9, 0.9, 0.9], True)
     h2 = Halfspace.from_hyperplane([[0,1,0], [0,0,1]], [1,1,1], [0.9, 0.9, 0.9], True)
     h3 = Halfspace.from_hyperplane([[0,0,1], [1,0,0]], [1,1,1], [0.9, 0.9, 0.9], True)
     h4 = Halfspace.from_hyperplane([[1,0,0], [0,1,0]], [2,2,2], [0.9, 0.9, 0.9], True)
     
     hi = HalfspaceIntersection([h1, h2, h3, h4], [0.9, 0.9, 0.9])
     self.assertTrue(np.allclose(np.sum(hi.vertices, axis = 0), [np.inf,np.inf,np.inf]))
示例#3
0
 def test_halfspace(self):
     h1 = Halfspace.from_hyperplane([[0, 1, 0], [1, 0, 0]], [1, 1, -100],
                                    [2, 2, 2], True)
     self.assertTrue(all(h1.normal == [0, 0, -1]))
     self.assertEqual(h1.offset, -100)
     h2 = Halfspace.from_hyperplane([[0, 1, 0], [1, 0, 0]], [1, 1, -100],
                                    [2, 2, 2], False)
     self.assertEqual(h2.offset, 100)
示例#4
0
 def test_non_unit_normals(self):
     h1 = Halfspace([3, 0], -3)
     h2 = Halfspace([0, 2], 2)
     h3 = Halfspace([-2, -1], 0)
     hi = HalfspaceIntersection([h1, h2, h3], [0.9, -1.1])
     self.assertTrue(
         np.any(np.all(hi.vertices == np.array([1, -2]), axis=1)))
     self.assertTrue(
         np.any(np.all(hi.vertices == np.array([1, -1]), axis=1)))
示例#5
0
    def test_infinite_vertex(self):
        h1 = Halfspace.from_hyperplane([[1, 0, 0], [0, 1, 0]], [1, 1, 1],
                                       [0.9, 0.9, 0.9], True)
        h2 = Halfspace.from_hyperplane([[0, 1, 0], [0, 0, 1]], [1, 1, 1],
                                       [0.9, 0.9, 0.9], True)
        h3 = Halfspace.from_hyperplane([[0, 0, 1], [1, 0, 0]], [1, 1, 1],
                                       [0.9, 0.9, 0.9], True)
        h4 = Halfspace.from_hyperplane([[1, 0, 0], [0, 1, 0]], [2, 2, 2],
                                       [0.9, 0.9, 0.9], True)

        hi = HalfspaceIntersection([h1, h2, h3, h4], [0.9, 0.9, 0.9])
        self.assertTrue(
            np.allclose(np.sum(hi.vertices, axis=0), [np.inf, np.inf, np.inf]))
示例#6
0
 def constraint(self, p, normal, offset):
     "Return halfspace that constrains this point to lie inside the half-plane."
     # (s*a + t*b + x) * nx + (-t*a + s*b + y) * ny <= offset
     # (a * nx + b * ny) * s + (b * nx - a * ny) * t + nx * x + ny * y <= offset
     return Halfspace([
         np.dot(p, normal), p[1] * normal[0] - p[0] * normal[1], normal[0],
         normal[1]
     ], offset)
示例#7
0
    def test_intersection(self):
        h1 = Halfspace.from_hyperplane([[1,0,0], [0,1,0]], [1,1,1], [0.9, 0.9, 0.9], True)
        h2 = Halfspace.from_hyperplane([[0,1,0], [0,0,1]], [1,1,1], [0.9, 0.9, 0.9], True)
        h3 = Halfspace.from_hyperplane([[0,0,1], [1,0,0]], [1,1,1], [0.9, 0.9, 0.9], True)
        h4 = Halfspace.from_hyperplane([[-1,0,1], [0,-1,1]], [1,1,0], [0.9, 0.9, 0.9], True)

        hi = HalfspaceIntersection([h1, h2, h3, h4], [0.9, 0.9, 0.9])
        self.assertTrue(np.allclose(np.sum(hi.vertices, axis = 0), [3,3,3]))

        h5 = Halfspace.from_hyperplane([[1,0,0], [0,1,0]], [1,2,2], [0.9, 0.9, 0.9], True)
        hi = HalfspaceIntersection([h5, h2, h3, h4], [0.9, 0.9, 0.9])
        self.assertTrue(np.allclose(np.sum(hi.vertices, axis = 0), [2,2,6]))

        for h, vs in zip(hi.halfspaces, hi.facets_by_halfspace):
            for v in vs:
                self.assertAlmostEqual(np.dot(h.normal, hi.vertices[v]) + h.offset, 0) 
        for v, hss in zip(hi.vertices, hi.facets_by_vertex):
            for i in hss:
                hs = hi.halfspaces[i]
                self.assertAlmostEqual(np.dot(hs.normal, v) + hs.offset, 0)
示例#8
0
    def test_intersection2d(self):
        h1 = Halfspace([1, 0], -1)
        h2 = Halfspace([0, 1], 1)
        h3 = Halfspace([-2, -1], 0)
        h_redundant = Halfspace([1, 0], -2)
        hi = HalfspaceIntersection([h1, h2, h_redundant, h3], [0.9, -1.1])

        for h, vs in zip(hi.halfspaces, hi.facets_by_halfspace):
            for v in vs:
                self.assertAlmostEqual(
                    np.dot(h.normal, hi.vertices[v]) + h.offset, 0)
        for v, hss in zip(hi.vertices, hi.facets_by_vertex):
            for i in hss:
                hs = hi.halfspaces[i]
                self.assertAlmostEqual(np.dot(hs.normal, v) + hs.offset, 0)

        #redundant halfspace should have no vertices
        self.assertEqual(len(hi.facets_by_halfspace[2]), 0)

        self.assertTrue(
            np.any(np.all(hi.vertices == np.array([1, -2]), axis=1)))
        self.assertTrue(
            np.any(np.all(hi.vertices == np.array([1, -1]), axis=1)))
示例#9
0
 def vertices(self):
     """
     Calls qhull for determining the vertices of the polytope (it computes the vertices only when called).
     """
     if self._vertices is None:
         if self.empty:
             self._vertices = []
             return self._vertices
         halfspaces = []
         for i in range(0, self.n_facets):
             halfspace = Halfspace(self.A[i,:].tolist(), (-self.b[i,0]).tolist())
             halfspaces.append(halfspace)
         polyhedron_qhull = HalfspaceIntersection(halfspaces, self.center.flatten().tolist())
         self._vertices = polyhedron_qhull.vertices
     return self._vertices
示例#10
0
def visualize_3d_polytope(p, name, visualizer):
    p = reorder_coordinates_visualizer(p)
    halfspaces = []
    # change of coordinates because qhull is stupid...
    b_qhull = p.rhs_min - p.lhs_min.dot(p.center)
    for i in range(p.lhs_min.shape[0]):
        halfspace = Halfspace(p.lhs_min[i, :].tolist(),
                              (-b_qhull[i, 0]).tolist())
        halfspaces.append(halfspace)
    p_qhull = HalfspaceIntersection(
        halfspaces,
        np.zeros(p.center.shape).flatten().tolist())
    vertices = p_qhull.vertices + np.hstack(
        [p.center] * len(p_qhull.vertices)).T
    mesh = Mesh(vertices.tolist(), p_qhull.facets_by_halfspace)
    visualizer[name].setgeometry(mesh)
    return visualizer
示例#11
0
 def vertices(self):
     """
     Calls qhull for determining the vertices of the polytope (it computes the vertices only when called).
     """
     if self._vertices is None:
         if self.n_variables == 1:
             self._vertices = [np.array([[self.rhs_min[i,0]/self.lhs_min[i,0]]]) for i in [0,1]]
             return self._vertices
         if self.empty:
             self._vertices = []
             return self._vertices
         halfspaces = []
         # change of coordinates because qhull is stupid...
         b_qhull = self.rhs_min - self.lhs_min.dot(self.center)
         for i in range(self.lhs_min.shape[0]):
             halfspace = Halfspace(self.lhs_min[i,:].tolist(), (-b_qhull[i,0]).tolist())
             halfspaces.append(halfspace)
         polyhedron_qhull = HalfspaceIntersection(halfspaces, np.zeros(self.center.shape).flatten().tolist())
         self._vertices = polyhedron_qhull.vertices
         self._vertices += np.repeat(self.center.T, self._vertices.shape[0], axis=0)
         self._vertices = [np.reshape(vertex, (vertex.shape[0],1)) for vertex in self._vertices]
     return self._vertices
示例#12
0
    def get_chempot_range_map(self, limits=[[-2,16], [-4,4]]):
        """
        Returns a chemical potential range map for each stable entry.

        Args:
            elements: Sequence of elements to be considered as independent
                variables. E.g., if you want to show the stability ranges of
                all Li-Co-O phases wrt to uLi and uO, you will supply
                [Element("Li"), Element("O")]

        Returns:
            Returns a dict of the form {entry: [simplices]}. The list of
            simplices are the sides of the N-1 dim polytope bounding the
            allowable chemical potential range of each entry.
        """
        tol = PourbaixAnalyzer.numerical_tol
        all_chempots = []
        facets = self._pd.facets
        entries = self._pd.qhull_entries
        for facet in facets:
            chempots = self.get_facet_chempots(facet)
            chempots["H+"] /= -0.0591
            chempots["V"] = -chempots["V"]
            chempots["1"] = chempots["1"]
            all_chempots.append([chempots[el] for el in self._keys])

        basis_vecs = []
        on_plane_points = []
        # Create basis vectors
        for row in self._pd._qhull_data:
            on_plane_points.append([0, 0, row[2]])
            this_basis_vecs = []
            norm_vec = [-0.0591 * row[0], -1 * row[1], 1]
            if abs(norm_vec[0]) > tol:
                this_basis_vecs.append([-norm_vec[2]/norm_vec[0], 0, 1])
            if abs(norm_vec[1]) > tol:
                this_basis_vecs.append([0, -norm_vec[2]/norm_vec[1], 1])
            if len(this_basis_vecs) == 0:
                basis_vecs.append([[1, 0, 0], [0, 1, 0]])
            elif len(this_basis_vecs) == 1:
                if abs(this_basis_vecs[0][0]) < tol:
                    this_basis_vecs.append([1, 0, 0])
                else:
                    this_basis_vecs.append([0, 1, 0])
                basis_vecs.append(this_basis_vecs)
            else:
                basis_vecs.append(this_basis_vecs)

        # Find point in half-space in which optimization is desired
        ph_max_contrib = -1 * max([abs(0.0591 * row[0])
                                    for row in self._pd._qhull_data]) * limits[0][1] 
        V_max_contrib = -1 * max([abs(row[1]) for row in self._pd._qhull_data]) * limits[1][1]
        g_max = (-1 * max([abs(pt[2]) for pt in on_plane_points])
                  + ph_max_contrib + V_max_contrib) - 10
        point_in_region = [7, 0, g_max]

        # Append border hyperplanes along limits
        for i in xrange(len(limits)):
            for j in xrange(len(limits[i])):
                basis_vec_1 = [0.0] * 3
                basis_vec_2 = [0.0] * 3
                point = [0.0] * 3
                basis_vec_1[2] = 1.0
                basis_vec_2[2] = 0.0
                for axis in xrange(len(limits)):
                    if axis is not i:
                        basis_vec_1[axis] = 0.0
                        basis_vec_2[axis] = 1.0
                basis_vecs.append([basis_vec_1, basis_vec_2])
                point[i] = limits[i][j]
                on_plane_points.append(point)

        # Hyperplane enclosing the very bottom
        basis_vecs.append([[1, 0, 0], [0, 1, 0]])
        on_plane_points.append([0, 0, 2 * g_max])
        hyperplane_list = [Halfspace.from_hyperplane(basis_vecs[i], on_plane_points[i], point_in_region)
                            for i in xrange(len(basis_vecs))]
        hs_int = HalfspaceIntersection(hyperplane_list, point_in_region)
        int_points = hs_int.vertices
        pourbaix_domains = {}
        self.pourbaix_domain_vertices = {}

        for i in xrange(len(self._pd._qhull_data)):
            vertices = [[int_points[vert][0], int_points[vert][1]] for vert in
                         hs_int.facets_by_halfspace[i]]
            if len(vertices) < 1:
                continue
            pourbaix_domains[self._pd._qhull_entries[i]] = ConvexHull(vertices).simplices

            # Need to order vertices for highcharts area plot
            cx = sum([vert[0] for vert in vertices]) / len(vertices)
            cy = sum([vert[1] for vert in vertices]) / len(vertices)
            point_comp = lambda x, y: x[0]*y[1] - x[1]*y[0]
            vert_center = [[v[0] - cx, v[1] - cy] for v in vertices]
            vert_center.sort(key=cmp_to_key(point_comp))
            self.pourbaix_domain_vertices[self._pd._qhull_entries[i]] =\
             [[v[0] + cx, v[1] + cy] for v in vert_center]

        self.pourbaix_domains = pourbaix_domains
        return pourbaix_domains
示例#13
0
    def get_chempot_range_map(self, limits=[[-2,16], [-4,4]]):
        """
        Returns a chemical potential range map for each stable entry.

        Args:
            elements: Sequence of elements to be considered as independent
                variables. E.g., if you want to show the stability ranges of
                all Li-Co-O phases wrt to uLi and uO, you will supply
                [Element("Li"), Element("O")]

        Returns:
            Returns a dict of the form {entry: [simplices]}. The list of
            simplices are the sides of the N-1 dim polytope bounding the
            allowable chemical potential range of each entry.
        """
        tol = PourbaixAnalyzer.numerical_tol
        all_chempots = []
        facets = self._pd.facets
        for facet in facets:
            chempots = self.get_facet_chempots(facet)
            chempots["H+"] /= -0.0591
            chempots["V"] = -chempots["V"]
            chempots["1"] = chempots["1"]
            all_chempots.append([chempots[el] for el in self._keys])

        basis_vecs = []
        on_plane_points = []
        # Create basis vectors
        for entry in self._pd.stable_entries:
            ie = self._pd.qhull_entries.index(entry)
            row = self._pd._qhull_data[ie]
            on_plane_points.append([0, 0, row[2]])
            this_basis_vecs = []
            norm_vec = [-0.0591 * row[0], -1 * row[1], 1]
            if abs(norm_vec[0]) > tol:
                this_basis_vecs.append([-norm_vec[2]/norm_vec[0], 0, 1])
            if abs(norm_vec[1]) > tol:
                this_basis_vecs.append([0, -norm_vec[2]/norm_vec[1], 1])
            if len(this_basis_vecs) == 0:
                basis_vecs.append([[1, 0, 0], [0, 1, 0]])
            elif len(this_basis_vecs) == 1:
                if abs(this_basis_vecs[0][0]) < tol:
                    this_basis_vecs.append([1, 0, 0])
                else:
                    this_basis_vecs.append([0, 1, 0])
                basis_vecs.append(this_basis_vecs)
            else:
                basis_vecs.append(this_basis_vecs)

        # Find point in half-space in which optimization is desired
        ph_max_contrib = -1 * max([abs(0.0591 * row[0])
                                    for row in self._pd._qhull_data]) * limits[0][1]
        V_max_contrib = -1 * max([abs(row[1]) for row in self._pd._qhull_data]) * limits[1][1]
        g_max = (-1 * max([abs(pt[2]) for pt in on_plane_points])
                  + ph_max_contrib + V_max_contrib) - 10
        point_in_region = [7, 0, g_max]

        # Append border hyperplanes along limits
        for i in range(len(limits)):
            for j in range(len(limits[i])):
                basis_vec_1 = [0.0] * 3
                basis_vec_2 = [0.0] * 3
                point = [0.0] * 3
                basis_vec_1[2] = 1.0
                basis_vec_2[2] = 0.0
                for axis in range(len(limits)):
                    if axis is not i:
                        basis_vec_1[axis] = 0.0
                        basis_vec_2[axis] = 1.0
                basis_vecs.append([basis_vec_1, basis_vec_2])
                point[i] = limits[i][j]
                on_plane_points.append(point)

        # Hyperplane enclosing the very bottom
        basis_vecs.append([[1, 0, 0], [0, 1, 0]])
        on_plane_points.append([0, 0, 2 * g_max])
        hyperplane_list = [Halfspace.from_hyperplane(basis_vecs[i], on_plane_points[i], point_in_region)
                            for i in range(len(basis_vecs))]
        hs_int = HalfspaceIntersection(hyperplane_list, point_in_region)
        int_points = hs_int.vertices
        pourbaix_domains = {}
        self.pourbaix_domain_vertices = {}

        for i in range(len(self._pd.stable_entries)):
            vertices = [[int_points[vert][0], int_points[vert][1]] for vert in
                         hs_int.facets_by_halfspace[i]]
            if len(vertices) < 1:
                continue
            pourbaix_domains[self._pd.stable_entries[i]] = ConvexHull(vertices).simplices

            # Need to order vertices for highcharts area plot
            cx = sum([vert[0] for vert in vertices]) / len(vertices)
            cy = sum([vert[1] for vert in vertices]) / len(vertices)
            point_comp = lambda x, y: x[0]*y[1] - x[1]*y[0]
            vert_center = [[v[0] - cx, v[1] - cy] for v in vertices]
            vert_center.sort(key=cmp_to_key(point_comp))
            self.pourbaix_domain_vertices[self._pd.stable_entries[i]] =\
             [[v[0] + cx, v[1] + cy] for v in vert_center]

        self.pourbaix_domains = pourbaix_domains
        return pourbaix_domains
示例#14
0
 def test_halfspace(self):
     h1 = Halfspace.from_hyperplane([[0,1,0], [1,0,0]], [1,1,-100], [2,2,2], True)
     self.assertTrue(all(h1.normal == [0,0,-1]))
     self.assertEqual(h1.offset, -100)
     h2 = Halfspace.from_hyperplane([[0,1,0], [1,0,0]], [1,1,-100], [2,2,2], False)
     self.assertEqual(h2.offset, 100)