def __init__(self, entries, elements=None): """ Standard constructor for phase diagram. Args: entries: A list of PDEntry-like objects having an energy, energy_per_atom and composition. elements: Optional list of elements in the phase diagram. If set to None, the elements are determined from the the entries themselves. """ if elements is None: elements = set() map(elements.update, [entry.composition.elements for entry in entries]) elements = list(elements) # Qhull seems to be sensitive to choice of independent composition # components due to numerical issues in higher dimensions. The # code permutes the element sequence until one that works is found. dim = len(elements) el_refs = {} for el in elements: el_entries = filter(lambda e: e.composition.is_element and e.composition.elements[0] == el, entries) if len(el_entries) == 0: raise PhaseDiagramError( "There are no entries associated with terminal {}." .format(el)) el_refs[el] = min(el_entries, key=lambda e: e.energy_per_atom) data = [] for entry in entries: comp = entry.composition row = map(comp.get_atomic_fraction, elements) row.append(entry.energy_per_atom) data.append(row) data = np.array(data) self.all_entries_hulldata = data[:, 1:] # Calculate formation energies and remove positive formation energy # entries vec = [el_refs[el].energy_per_atom for el in elements] + [-1] form_e = -np.dot(data, vec) ind = np.where(form_e <= -self.formation_energy_tol)[0].tolist() ind.extend(map(entries.index, el_refs.values())) qhull_entries = [entries[i] for i in ind] qhull_data = data[ind][:, 1:] if len(qhull_data) == dim: self.facets = [range(dim)] else: facets = ConvexHull(qhull_data, joggle=True).vertices finalfacets = [] for facet in facets: is_non_element_facet = any( (len(qhull_entries[i].composition) > 1 for i in facet)) if is_non_element_facet: m = qhull_data[facet] m[:, -1] = 1 if abs(np.linalg.det(m)) > 1e-8: finalfacets.append(facet) self.facets = finalfacets self.all_entries = entries self.qhull_data = qhull_data self.dim = dim self.el_refs = el_refs self.elements = elements self.qhull_entries = qhull_entries
def draw_dual_transform(): xlb = 0 xrb = 10 ylb = 0 yrb = 10 A = np.array([-4, -1, -1, -0.25, 1, 0.5]) B = np.array([1, 1, 1, 1, 1, 1]) C = np.array([5, -5, 0, -3, -10, -10]) CLR = np.array(["red", "yellow", "brown", "green", "blue", "grey"]) HP = [] X = A / B Y = C / B ch = ConvexHull(np.transpose([X, Y])) ax = plt.subplot(1, 2, 1) for a, b, c, clr in zip(A, B, C, CLR): HP.append(HalfPlane(a, b, c)) HP[len(HP) - 1].draw(bclr=clr, left_b=xlb, right_b=xrb) ax.text(3, 2, "$\mathcal{LE}$") ax.axis([xlb, xrb, ylb, yrb]) bx = plt.subplot(1, 2, 2) bx.text(-2, 2, "$\mathcal{UH}$") leftX = 500 rightX = -500 leftInd = 0 rightInd = 0 bottomHP = HalfPlane(0, -1, 0) P = [] for v in ch.vertices: if X[v[0]] > X[v[1]]: P.append(HP[v[0]].intersect(HP[v[1]])) bx.plot(X[v], Y[v], color="black", linewidth=3) if X[v[0]] > rightX: rightX = X[v[0]] rightInd = v[0] if X[v[1]] < leftX: leftX = X[v[1]] leftInd = v[1] P.append(HP[leftInd].intersect(bottomHP)) P.append(HP[rightInd].intersect(bottomHP)) P.sort(key=lambda p: p.x) for i in range(len(P) - 1): ax.plot([P[i].x, P[i + 1].x], [P[i].y, P[i + 1].y], color="black", linewidth=3) for x, y, clr in zip(X, Y, CLR): bx.plot(x, y, color=clr, marker="o") plt.show()
s = Simplex(coords) print('volume of simplex', s.volume()) print(s.inertia(s.centroid())) # t = Polyeder(coords) # #print t.volume() # print ('volume', t.volume_by_cm()) print('####### third example unit cube #########') coords.append([0, 1, 1]) coords.append([1, 0, 1]) coords.append([1, 1, 0]) coords.append([1, 1, 1]) p = ConvexHull(coords) # #print p.volume() print('volume', p.volume()) print('volume_divergence_theorem', p.volume_divergence_theorem()) I, v = p.inertia(p.centroid()) print('inertia:') print(I) I_check = numpy.zeros((3, 3)) I_check[0, 0] = (1 + 1) / 12.0 I_check[1, 1] = (1 + 1) / 12.0 I_check[2, 2] = (1 + 1) / 12.0 #print('I_check',I_check) #print('check',I_check-I) print('error', numpy.linalg.norm(I_check - I) / numpy.linalg.norm(I_check))
def _make_pourbaixdiagram(self): """ Calculates entries on the convex hull in the dual space. """ stable_entries = set() self._qhull_data = self._create_conv_hull_data() dim = len(self._qhull_data[0]) if len(self._qhull_data) < dim: raise Exception("Can only do elements with at-least 3 entries" " for now") if len(self._qhull_data) == dim: self._facets = [list(range(dim))] else: facets_pyhull = np.array(ConvexHull(self._qhull_data).vertices) self._facets = np.sort(np.array(facets_pyhull)) logger.debug("Final facets are\n{}".format(self._facets)) logger.debug("Removing vertical facets...") vert_facets_removed = list() for facet in self._facets: facetmatrix = np.zeros((len(facet), len(facet))) count = 0 for vertex in facet: facetmatrix[count] = np.array(self._qhull_data[vertex]) facetmatrix[count, dim - 1] = 1 count += 1 if abs(np.linalg.det(facetmatrix)) > 1e-8: vert_facets_removed.append(facet) else: logger.debug("Removing vertical facet : {}".format(facet)) logger.debug("Removing UCH facets by eliminating normal.z >0 ...") # Find center of hull vertices = set() for facet in vert_facets_removed: for vertex in facet: vertices.add(vertex) c = [0.0, 0.0, 0.0] c[0] = np.average( [self._qhull_data[vertex][0] for vertex in vertices]) c[1] = np.average( [self._qhull_data[vertex][1] for vertex in vertices]) c[2] = np.average( [self._qhull_data[vertex][2] for vertex in vertices]) # Shift origin to c new_qhull_data = np.array(self._qhull_data) for vertex in vertices: new_qhull_data[vertex] -= c # For each facet, find normal n, find dot product with P, and # check if this is -ve final_facets = list() for facet in vert_facets_removed: a = new_qhull_data[facet[1]] - new_qhull_data[facet[0]] b = new_qhull_data[facet[2]] - new_qhull_data[facet[0]] n = np.cross(a, b) val = np.dot(n, new_qhull_data[facet[0]]) if val < 0: n = -n if n[2] <= 0: final_facets.append(facet) else: logger.debug("Removing UCH facet : {}".format(facet)) final_facets = np.array(final_facets) self._facets = final_facets stable_vertices = set() for facet in self._facets: for vertex in facet: stable_vertices.add(vertex) stable_entries.add(self._qhull_entries[vertex]) self._stable_entries = stable_entries self._vertices = stable_vertices
def qhull(self): self.convexHull = ConvexHull([[vertex.x, vertex.y] for vertex in self.Vertices]) for segment in self.convexHull.vertices: self.ch_poly.append( Segment(self.Vertices[segment[0]], self.Vertices[segment[1]]))
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
def convex_hull(points): hull = ConvexHull(points) vertices = set(i for v in hull.vertices for i in v) return [hull.points[i] for i in vertices]
s = Simplex(coords) print('volume of simplex',s.volume()) print(s.inertia(s.centroid())) # t = Polyeder(coords) # #print t.volume() # print ('volume', t.volume_by_cm()) print('####### third example unit cube #########') coords.append([0,1,1]) coords.append([1,0,1]) coords.append([1,1,0]) coords.append([1,1,1]) p = ConvexHull(coords) # #print p.volume() print ('volume', p.volume()) print ('volume_divergence_theorem', p.volume_divergence_theorem()) I,v=p.inertia(p.centroid()) print('inertia:') print(I) I_check= numpy.zeros((3,3)) I_check[0,0] = (1+1)/12.0 I_check[1,1] = (1+1)/12.0 I_check[2,2] = (1+1)/12.0 #print('I_check',I_check) #print('check',I_check-I) print('error',numpy.linalg.norm(I_check-I)/numpy.linalg.norm(I_check))
def convex_hull(points): vertices = ConvexHull(points).vertices return [ points[idx] for idx in set([point for pair in vertices for point in pair]) ]
def detect_contact(self): """ This function is responsible for detecting the contact forces between the robot's fingers and the object, in every simulation loop. It also calculates the score of the grasp based on the prefered method (inner product/ convex hull) and checks for finger collisions """ global sim counter = 0 contact_force = [0]*len(self.finger_geom) contact_list = [] contact_frame = 0 finger_collision = 0 for index in range(13): contact = sim.data.contact[index] """Check if this contact involves any of the robot's fingers and the object""" if contact.geom1 in self.finger_geom and contact.geom2 in self.object_geom: idx = self.finger_geom.index(contact.geom1) """ Check if this contact still exists. In mujoco, a contact remains in the contacts table, until it gets replaced. This means that we have to check if the contact is still relevant, by checking the contact.dist parameter. When a contact is present across multiple simulation steps, this parameter oscillates a bit, due to simulation imperfections. So if a contact is inactive, the parameter will have the same value between two successive steps. We use this property to identify active contacts """ if contact.dist != self.last_contact[idx]: self.contact_points[idx] = contact.dist counter +=1 contact_force_vector = np.array([0, 0, 0, 0, 0, 0], dtype=np.float64) functions.mj_contactForce(model, sim.data, index, contact_force_vector) contact_force[idx] = contact_force_vector[0] contact_list.append(self.Contact_point(force = contact_force_vector[0], frame = contact.frame, geom = contact.geom1, index = idx, coordinates = contact.pos, obj_geom = contact.geom2)) sim.data.contact[index].geom1 = 99 """Check for finger collision """ if contact.geom1 in self.finger_geom and contact.geom2 in self.finger_geom: finger_collision = 1 break for i in range(len(self.finger_geom)): self.last_contact[i] = self.contact_points[i] score = 0 hull = 0 """Calculate Inner Product/ Convex Hull score""" if self.convex_option == 0: for i in range(len(contact_list) -1): for j in range(i+1, len(contact_list)): a = contact_list[i].frame*contact_list[i].force b = contact_list[j].frame*contact_list[j].force prod = np.inner(a,b) score += -prod score = 1 - np.exp(-2*score/160000) score = max(score, 0) elif self.convex_option == 1: pts = [] for contact in contact_list: pts.append([contact.wrench[0][0], contact.wrench[0][1], contact.wrench[0][2]]) pts.append([contact.wrench[1][0], contact.wrench[1][1], contact.wrench[1][2]]) pts.append([contact.wrench[2][0], contact.wrench[2][1], contact.wrench[2][2]]) if len(pts)>5 and pts: try: hull = ConvexHull(pts) except AttributeError: pass return counter, contact_force, score, finger_collision, hull
"Please input the number of random 3D points you want to generate(random range from x, y:-10000 to 10000):" ) points = [] for i in range(int(n)): temp = [random.uniform(-10, 10), random.randint(-10, 10)] # random number generator temp.append(temp[0]**2 + temp[1]**2) points.append(temp) for pt in points: ax1.plot([pt[0]], [pt[1]], [0], 'ro') ax2.plot(pt[0], pt[1], 'ro') ax1.plot([pt[0]], [pt[1]], [pt[2]], 'ro') d = ConvexHull(points) central_point = [0, 0, 0] for simplex in d.simplices: for index in range(3): central_point[index] += (simplex.coords[0][index] + simplex.coords[1][index] + simplex.coords[2][index]) / 3 for index in range(3): central_point[index] /= len(d.simplices) lines = set() for simplex in d.simplices: if not downward(central_point, simplex.coords):
#!/usr/bin/python import sys import numpy as np import irtk from pyhull.convex_hull import ConvexHull from irtk.vtk2irtk import voxellise seg = irtk.imread(sys.argv[1]) output = sys.argv[2] ZYX = np.transpose(np.nonzero(seg)) pts = seg.ImageToWorld(ZYX[:, ::-1]) hull = ConvexHull(pts) img = voxellise(hull.points, hull.vertices, header=seg.get_header()) irtk.imwrite(output, img)
def get_vertices(data): return ConvexHull(data).vertices