def voronoi(geometry, **kwargs): r""" Use the Voronoi verts and throat normals to work out the area """ Nt = geometry.num_throats() verts = geometry['throat.offset_vertices'] normals = geometry['throat.normal'] area = _sp.ndarray(Nt) for i in range(Nt): if len(verts[i]) > 2: verts_2D = tr.rotate_and_chop(verts[i], normals[i], [0, 0, 1]) area[i] = vo.PolyArea2D(verts_2D) else: area[i] = 0.0 return area
def voronoi(geometry, **kwargs): r""" Use the Voronoi verts and throat normals to work out the perimeter """ Nt = geometry.num_throats() verts = geometry['throat.offset_vertices'] normals = geometry['throat.normal'] perimeter = _sp.ndarray(Nt) for i in range(Nt): if len(verts[i]) > 2: verts_2D = tr.rotate_and_chop(verts[i],normals[i],[0,0,1]) perimeter[i] = vo.PolyPerimeter2D(verts_2D) else: perimeter[i] = 0.0 return perimeter
def voronoi(geometry, **kwargs): r""" Use the Voronoi verts and throat normals to work out the perimeter """ Nt = geometry.num_throats() verts = geometry['throat.offset_vertices'] normals = geometry['throat.normal'] perimeter = _sp.ndarray(Nt) for i in range(Nt): if len(verts[i]) > 2: verts_2D = tr.rotate_and_chop(verts[i], normals[i], [0, 0, 1]) # Get in hull order hull = ConvexHull(verts_2D, qhull_options='QJ Pp') verts_2D = verts_2D[hull.vertices] perimeter[i] = vo.PolyPerimeter2D(verts_2D) else: perimeter[i] = 0.0 return perimeter
def print_throat(geom, throats_in): r""" Print a given throat or list of throats accepted as [1,2,3,...,n] e.g geom.print_throat([34,65,99]) Original vertices plus offset vertices are rotated to align with the z-axis and then printed in 2D """ import matplotlib.pyplot as plt throats = [] for throat in throats_in: if throat in range(geom.num_throats()): throats.append(throat) else: print("Throat: " + str(throat) + " not part of geometry") if len(throats) > 0: verts = geom['throat.vertices'][throats] offsets = geom['throat.offset_vertices'][throats] #image_offsets = geom['throat.image_analysis'][throats] normals = geom['throat.normal'][throats] coms = geom['throat.centroid'][throats] incentre = geom['throat.incentre'][throats] inradius = 0.5 * geom['throat.indiameter'][throats] for i in range(len(throats)): fig = plt.figure() vert_2D = tr.rotate_and_chop(verts[i], normals[i], [0, 0, 1]) hull = ConvexHull(vert_2D, qhull_options='QJ Pp') for simplex in hull.simplices: plt.plot(vert_2D[simplex, 0], vert_2D[simplex, 1], 'k-', linewidth=2) plt.scatter(vert_2D[:, 0], vert_2D[:, 1]) #centroid = vo.PolyWeightedCentroid2D(vert_2D[hull.vertices]) offset_2D = tr.rotate_and_chop(offsets[i], normals[i], [0, 0, 1]) offset_hull = ConvexHull(offset_2D, qhull_options='QJ Pp') for simplex in offset_hull.simplices: plt.plot(offset_2D[simplex, 0], offset_2D[simplex, 1], 'g-', linewidth=2) plt.scatter(offset_2D[:, 0], offset_2D[:, 1]) " Make sure the plot looks nice by finding the greatest range of points and setting the plot to look square" xmax = vert_2D[:, 0].max() xmin = vert_2D[:, 0].min() ymax = vert_2D[:, 1].max() ymin = vert_2D[:, 1].min() x_range = xmax - xmin y_range = ymax - ymin if (x_range > y_range): my_range = x_range else: my_range = y_range lower_bound_x = xmin - my_range * 0.5 upper_bound_x = xmin + my_range * 1.5 lower_bound_y = ymin - my_range * 0.5 upper_bound_y = ymin + my_range * 1.5 plt.axis( (lower_bound_x, upper_bound_x, lower_bound_y, upper_bound_y)) plt.grid(b=True, which='major', color='b', linestyle='-') centroid = tr.rotate_and_chop(coms[i], normals[i], [0, 0, 1]) incent = tr.rotate_and_chop(incentre[i], normals[i], [0, 0, 1]) plt.scatter(centroid[0][0], centroid[0][1]) #plt.scatter(centroid2[0],centroid2[1],c='r') "Plot incircle" t = np.linspace(0, 2 * np.pi, 200) u = inradius[i] * np.cos(t) + incent[0][0] v = inradius[i] * np.sin(t) + incent[0][1] plt.plot(u, v, 'r-') fig.show() else: print("Please provide throat indices")
def plot_pore(geometry, pores, fig=None, axis_bounds=None, include_points=False): r""" Print all throats around a given pore or list of pores accepted as [1, 2, 3, ..., n] e.g vo.print_pore(geom, [34, 65, 99]) Original vertices plus offset vertices used to create faces and then printed in 3D To print all pores (n) pore_range = np.arange(0,n-1,1) vo.print_pore(geom, pore_range) """ import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D from mpl_toolkits.mplot3d.art3d import Poly3DCollection if len(pores) > 0: net_pores = geometry.map_pores(geometry._net, pores) centroids = geometry['pore.centroid'][pores] coords = geometry._net['pore.coords'][net_pores] net_throats = geometry._net.find_neighbor_throats(pores=net_pores) throats = geometry._net.map_throats(geometry, net_throats, return_mapping=True)['target'] tcentroids = geometry["throat.centroid"][throats] # Can't create volume from one throat if 1 <= len(throats): verts = geometry['throat.vertices'][throats] normals = geometry['throat.normal'][throats] # Get verts in hull order ordered_verts = [] for i in range(len(verts)): vert_2D = tr.rotate_and_chop(verts[i], normals[i], [0, 0, 1]) hull = ConvexHull(vert_2D, qhull_options='QJ Pp') ordered_verts.append(verts[i][hull.vertices]) offsets = geometry['throat.offset_vertices'][throats] ordered_offs = [] for i in range(len(offsets)): offs_2D = tr.rotate_and_chop(offsets[i], normals[i], [0, 0, 1]) offs_hull = ConvexHull(offs_2D, qhull_options='QJ Pp') ordered_offs.append(offsets[i][offs_hull.vertices]) # Get domain extents for setting axis if axis_bounds is None: [xmin, xmax, ymin, ymax, zmin, zmax] = \ vertex_dimension(geometry._net, pores, parm='minmax') else: [xmin, xmax, ymin, ymax, zmin, zmax] = axis_bounds if fig is None: fig = plt.figure() ax = fig.gca(projection='3d') outer_items = Poly3DCollection(ordered_verts, linewidths=1, alpha=0.2, zsort='min') outer_face_colours = [(1, 0, 0, 0.01)] outer_items.set_facecolor(outer_face_colours) ax.add_collection(outer_items) inner_items = Poly3DCollection(ordered_offs, linewidths=1, alpha=0.2, zsort='min') inner_face_colours = [(0, 0, 1, 0.01)] inner_items.set_facecolor(inner_face_colours) ax.add_collection(inner_items) ax.set_xlim(xmin, xmax) ax.set_ylim(ymin, ymax) ax.set_zlim(zmin, zmax) if include_points: ax.scatter(centroids[:, 0], centroids[:, 1], centroids[:, 2], c='y') ax.scatter(tcentroids[:, 0], tcentroids[:, 1], tcentroids[:, 2], c='r') ax.scatter(coords[:, 0], coords[:, 1], coords[:, 2], c='b') ax.ticklabel_format(style='sci', scilimits=(0, 0)) else: plot_throat(geometry, throats, fig) else: print('Please provide pore indices') return fig
def plot_throat(geometry, throats, fig=None): r""" Print a given throat or list of throats accepted as [1, 2, 3, ..., n] Original vertices plus offset vertices are rotated to align with the z-axis and then printed in 2D e.g vo.print_throat(geom, [34, 65, 99]) """ import matplotlib.pyplot as plt throat_list = [] for throat in throats: if throat in range(geometry.num_throats()): throat_list.append(throat) else: print('Throat: ' + str(throat) + ' not part of geometry') if len(throat_list) > 0: verts = geometry['throat.vertices'][throat_list] offsets = geometry['throat.offset_vertices'][throat_list] normals = geometry['throat.normal'][throat_list] coms = geometry['throat.centroid'][throat_list] incentre = geometry['throat.incentre'][throat_list] inradius = 0.5*geometry['throat.indiameter'][throat_list] row_col = np.ceil(np.sqrt(len(throat_list))) for i in range(len(throat_list)): if fig is None: fig = plt.figure() ax = fig.add_subplot(row_col, row_col, i+1) vert_2D = tr.rotate_and_chop(verts[i], normals[i], [0, 0, 1]) hull = ConvexHull(vert_2D, qhull_options='QJ Pp') for simplex in hull.simplices: plt.plot(vert_2D[simplex, 0], vert_2D[simplex, 1], 'k-', linewidth=2) plt.scatter(vert_2D[:, 0], vert_2D[:, 1]) offset_2D = tr.rotate_and_chop(offsets[i], normals[i], [0, 0, 1]) offset_hull = ConvexHull(offset_2D, qhull_options='QJ Pp') for simplex in offset_hull.simplices: plt.plot(offset_2D[simplex, 0], offset_2D[simplex, 1], 'g-', linewidth=2) plt.scatter(offset_2D[:, 0], offset_2D[:, 1]) # Make sure the plot looks nice by finding the greatest range of points # and setting the plot to look square xmax = vert_2D[:, 0].max() xmin = vert_2D[:, 0].min() ymax = vert_2D[:, 1].max() ymin = vert_2D[:, 1].min() x_range = xmax - xmin y_range = ymax - ymin if (x_range > y_range): my_range = x_range else: my_range = y_range lower_bound_x = xmin - my_range*0.5 upper_bound_x = xmin + my_range*1.5 lower_bound_y = ymin - my_range*0.5 upper_bound_y = ymin + my_range*1.5 plt.axis((lower_bound_x, upper_bound_x, lower_bound_y, upper_bound_y)) plt.grid(b=True, which='major', color='b', linestyle='-') centroid = tr.rotate_and_chop(coms[i], normals[i], [0, 0, 1]) incent = tr.rotate_and_chop(incentre[i], normals[i], [0, 0, 1]) plt.scatter(centroid[0][0], centroid[0][1]) # Plot incircle t = np.linspace(0, 2*np.pi, 200) u = inradius[i]*np.cos(t)+incent[0][0] v = inradius[i]*np.sin(t)+incent[0][1] plt.plot(u, v, 'r-') ax.ticklabel_format(style='sci', scilimits=(0, 0)) else: print("Please provide throat indices") return fig
def incircle(geometry, **kwargs): r""" Calculate the incircle diameter by linear programming and the simplex search algorithm using the offset vertices generated by the voronoi diagram offsetting routine """ import warnings try: import pulp as pu Nt = geometry.num_throats() verts = geometry['throat.offset_vertices'] normals = geometry['throat.normal'] value = _sp.zeros(Nt) for i in range(Nt): if len(verts[i]) > 2: pts = tr.rotate_and_chop(verts[i],normals[i],[0,0,1]) "Work out central point to use as initial guess" C = np.mean(pts,axis=0) "Compute convex hull to find points lying on the hull in order" hull = ConvexHull(pts, qhull_options='QJ Pp') "For each simplex making up the hull collect the end points" A = pts[hull.vertices] B = pts[np.roll(hull.vertices,-1)] I = np.array([[0,1],[-1,0]]) "Normal of the simplices" N = np.dot((B-A),I) #L = np.sqrt(np.sum(np.square(N),axis=1)) "Normalize the normal vector" L = np.linalg.norm(N,axis=1) F = np.vstack((L,L)).T N /= F "Mid-points of the simplex" M = (B+A)/2 #C = np.mean(A) "If normals point out of hull change sign to point in" pointing_out = (np.sum((M-C)*N,axis=1)>0) N[pointing_out]*= -1 "Define Linear Program Variables" "The centre of the incircle adjustment" cx = pu.LpVariable("cx",None,None,pu.LpContinuous) cy = pu.LpVariable("cy",None,None,pu.LpContinuous) "Radius of the incircle" R = pu.LpVariable("R",0,None,pu.LpContinuous) "Slack variables for shortest distance between centre and simplices" S = pu.LpVariable.dict("SlackVariable",range(len(A)),0,None,pu.LpContinuous) "Set up LP problem" prob = pu.LpProblem("FindInRadius",pu.LpMaximize) "Objective Function" prob += R for j in range(len(A)): " Ni.(C-Ai)-Si = 0" prob += N[j][0]*(C[0]+cx) + N[j][1]*(C[1]+cy) - N[j][0]*A[j][0] - N[j][1]*A[j][1] - S[j] == 0 "Si >= R" prob += S[j] >= R "Solve the LP" with warnings.catch_warnings(): warnings.simplefilter("ignore") prob.solve() "As the radius is the objective function we can get it from the objective or as R.value()" value[i] = 2*R.value() else: value[i] = 0.0 return value except ImportError: print("Cannot use incircle method without installing pulp package")
def print_pore(geom,pores,fig=None,axis_bounds=None): r""" Print all throats around a given pore or list of pores accepted as [1,2,3,...,n] e.g geom.print_pore([34,65,99]) Original vertices plus offset vertices used to create faces and then printed in 3D To print all pores (n) pore_range = np.arange(0,n-1,1) geom.print_pore(pore_range) """ import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D from mpl_toolkits.mplot3d.art3d import Poly3DCollection return_fig=False if len(pores) > 0: net_pores = geom.map_pores(geom._net,pores) centroids = geom["pore.centroid"][pores] #centroids2 = self["pore.com"][pores] #for i,pore in enumerate(pores): # centroids[i]=self["pore.centroid"][pore] #coords = self._net["pore.coords"][net_pores] net_throats = geom._net.find_neighbor_throats(pores=net_pores) #for net_throat in net_throats: # try: # throats.append(geom['throat.map'].tolist().index(net_throat)) # except ValueError: # " Throat not in this geometry " throats = geom._net.map_throats(geom,net_throats,return_mapping=True)["target"] "Can't create volume from one throat" if len(throats)>=1: verts = geom['throat.vertices'][throats] normals = geom['throat.normal'][throats] " Get verts in hull order " ordered_verts=[] for i in range(len(verts)): vert_2D = tr.rotate_and_chop(verts[i],normals[i],[0,0,1]) hull = ConvexHull(vert_2D,qhull_options='QJ Pp') ordered_verts.append(verts[i][hull.vertices]) offsets = geom['throat.offset_vertices'][throats] ordered_offs=[] for i in range(len(offsets)): offs_2D = tr.rotate_and_chop(offsets[i],normals[i],[0,0,1]) offs_hull = ConvexHull(offs_2D,qhull_options='QJ Pp') ordered_offs.append(offsets[i][offs_hull.vertices]) "Get domain extents for setting axis " if axis_bounds is None: [xmin,xmax,ymin,ymax,zmin,zmax]= vertex_dimension(geom._net,pores,parm='minmax') else: [xmin,xmax,ymin,ymax,zmin,zmax]=axis_bounds if fig is None: fig = plt.figure() else: return_fig==True ax = fig.gca(projection='3d') outer_items = Poly3DCollection(ordered_verts,linewidths=1, alpha=0.2, zsort='min') outer_face_colours=[(1, 0, 0, 0.01)] outer_items.set_facecolor(outer_face_colours) ax.add_collection(outer_items) inner_items = Poly3DCollection(ordered_offs,linewidths=1, alpha=0.2, zsort='min') inner_face_colours=[(0, 0, 1, 0.01)] inner_items.set_facecolor(inner_face_colours) ax.add_collection(inner_items) ax.set_xlim(xmin,xmax) ax.set_ylim(ymin,ymax) ax.set_zlim(zmin,zmax) #ax.scatter(coords[:,0],coords[:,1],coords[:,2]) ax.scatter(centroids[:,0],centroids[:,1],centroids[:,2],c='y') #ax.scatter(centroids2[:,0],centroids2[:,1],centroids2[:,2],c='g') plt.show() else: print_throat(throats) else: print("Please provide pore indices") if return_fig == True: return fig
def print_throat(geom,throats_in): r""" Print a given throat or list of throats accepted as [1,2,3,...,n] e.g geom.print_throat([34,65,99]) Original vertices plus offset vertices are rotated to align with the z-axis and then printed in 2D """ import matplotlib.pyplot as plt throats = [] for throat in throats_in: if throat in range(geom.num_throats()): throats.append(throat) else: print("Throat: "+str(throat)+ " not part of geometry") if len(throats) > 0: verts = geom['throat.vertices'][throats] offsets = geom['throat.offset_vertices'][throats] #image_offsets = geom['throat.image_analysis'][throats] normals = geom['throat.normal'][throats] coms = geom['throat.centroid'][throats] incentre = geom['throat.incentre'][throats] inradius = 0.5*geom['throat.indiameter'][throats] for i in range(len(throats)): fig = plt.figure() vert_2D = tr.rotate_and_chop(verts[i],normals[i],[0,0,1]) hull = ConvexHull(vert_2D,qhull_options='QJ Pp') for simplex in hull.simplices: plt.plot(vert_2D[simplex,0], vert_2D[simplex,1], 'k-',linewidth=2) plt.scatter(vert_2D[:,0], vert_2D[:,1]) #centroid = vo.PolyWeightedCentroid2D(vert_2D[hull.vertices]) offset_2D = tr.rotate_and_chop(offsets[i],normals[i],[0,0,1]) offset_hull = ConvexHull(offset_2D,qhull_options='QJ Pp') for simplex in offset_hull.simplices: plt.plot(offset_2D[simplex,0], offset_2D[simplex,1], 'g-',linewidth=2) plt.scatter(offset_2D[:,0], offset_2D[:,1]) " Make sure the plot looks nice by finding the greatest range of points and setting the plot to look square" xmax = vert_2D[:,0].max() xmin = vert_2D[:,0].min() ymax = vert_2D[:,1].max() ymin = vert_2D[:,1].min() x_range = xmax - xmin y_range = ymax - ymin if (x_range > y_range): my_range = x_range else: my_range = y_range lower_bound_x = xmin - my_range*0.5 upper_bound_x = xmin + my_range*1.5 lower_bound_y = ymin - my_range*0.5 upper_bound_y = ymin + my_range*1.5 plt.axis((lower_bound_x,upper_bound_x,lower_bound_y,upper_bound_y)) plt.grid(b=True, which='major', color='b', linestyle='-') centroid = tr.rotate_and_chop(coms[i],normals[i],[0,0,1]) incent = tr.rotate_and_chop(incentre[i],normals[i],[0,0,1]) plt.scatter(centroid[0][0],centroid[0][1]) #plt.scatter(centroid2[0],centroid2[1],c='r') "Plot incircle" t = np.linspace(0,2*np.pi,200) u = inradius[i]*np.cos(t)+incent[0][0] v = inradius[i]*np.sin(t)+incent[0][1] plt.plot(u,v,'r-') fig.show() else: print("Please provide throat indices")