def domain_length(self, face_1, face_2): r""" Returns the distance between two faces No coplanar checking this is done in vertex_dimension """ L = vo.vertex_dimension(self, face_1, face_2, parm='length') return L
def test_simple_cubic(self): pn = OpenPNM.Network.DelaunayCubic(shape=[3, 3, 3]) pn.add_boundaries() B1 = pn.pores("top_boundary") B2 = pn.pores("bottom_boundary") assert vo.vertex_dimension(pn, B1, B2, 'minmax') == [0.0, 3.0, 0.0, 3.0, 0.0, 3.0] assert pn.num_pores() == 81
def domain_area(self, face): r""" Returns the area of a face No coplanar checking this is done in vertex_dimension """ A = vo.vertex_dimension(self, face, parm='area') return A
def domain_area(self,face): r""" Returns the area of a face No coplanar checking this is done in vertex_dimension Example -------- >>> import OpenPNM >>> pn = OpenPNM.Network.Delaunay(num_pores=100, domain_size=[3,2,1]) >>> pn.add_boundaries() >>> B1 = pn.pores("left_boundary") >>> B2 = pn.pores("right_boundary") >>> pn.domain_area(B1) 3.0 """ A = vo.vertex_dimension(self,face,parm='area') return A
def domain_length(self,face_1,face_2): r""" Returns the distance between two faces No coplanar checking this is done in vertex_dimension Example -------- >>> import OpenPNM >>> pn = OpenPNM.Network.Delaunay(num_pores=100, domain_size=[3,2,1]) >>> pn.add_boundaries() >>> B1 = pn.pores("left_boundary") >>> B2 = pn.pores("right_boundary") >>> pn.domain_length(B1,B2) 2.0 """ L = vo.vertex_dimension(self,face_1,face_2,parm='length') return L
def _calc_eff_prop(self, check_health=False): r""" This returns the main parameters for calculating the effective property in a linear transport equation. It also checks for the proper boundary conditions, inlets and outlets. Parameters ---------- check_health : boolean(optional) It analyzes the inlet and outlet pores to check their spatial positions """ try: self[self._quantity] except KeyError: raise Exception('The algorithm has not been run yet. Cannot ' + 'calculate effective property.') # Determine boundary conditions by analyzing algorithm object Ps = self.pores('pore.Dirichlet') BCs = sp.unique(self['pore.bcval_Dirichlet'][Ps]) if sp.shape(BCs)[0] != 2: raise Exception('The supplied algorithm did not have appropriate' + ' BCs') inlets = sp.where(self['pore.' + 'bcval_Dirichlet'] == sp.amax(BCs))[0] outlets = sp.where(self['pore.' + 'bcval_Dirichlet'] == sp.amin(BCs))[0] # Analyze input and output pores if check_health: # Check for coplanarity if self._net.iscoplanar(inlets) is False: raise Exception('The inlet pores do not define a plane. ' + 'Effective property will be approximation') if self._net.iscoplanar(outlets) is False: raise Exception('The outlet pores do not define a plane. ' + 'Effective property will be approximation') # Ensure pores are on a face of domain # (only 1 non-self neighbor each) PnI = self._net.find_neighbor_pores(pores=inlets, mode='not_intersection', excl_self=True) if sp.shape(PnI) != sp.shape(inlets): logger.warning('The inlet pores have too many neighbors. ' + 'Internal pores appear to be selected.') pass PnO = self._net.find_neighbor_pores(pores=outlets, mode='not_intersection', excl_self=True) if sp.shape(PnO) != sp.shape(outlets): logger.warning('The outlet pores have too many neighbors. ' + 'Internal pores appear to be selected.') pass # Fetch area and length of domain if 'pore.vert_index' in self._net.props(): A = vo.vertex_dimension(network=self._net, face1=inlets, parm='area') L = vo.vertex_dimension(network=self._net, face1=inlets, face2=outlets, parm='length') else: A = self._net.domain_area(face=inlets) L = self._net.domain_length(face_1=inlets, face_2=outlets) flow = self.rate(pores=inlets) D = sp.sum(flow)*L/A/(BCs[0] - BCs[1]) return D
def add_boundaries(self): r""" This method identifies pores in the original Voronoi object that straddle a boundary imposed by the reflection. The pore inside the original set of pores (with index 0 - Np) is identified and the coordinates are saved. The vertices making up the boundary throat are retrieved from the ridge_dict values and these are used to identify which boundary the throat sits at. A new pore and new connection is created with coordinates lying on the boundary plane. N.B This method will only work properly if the original network remains unaltered i.e. not trimmed or extended This preserves the connection between pore index on the network object and the Voronoi object The point of using this method is so that the throat vertices created by the Voronoi object are preserved This method will create boundary pores at the centre of the voronoi faces that align with the outer planes of the domain. The original pores in the domain are labelled internal and the boundary pores are labelled external Examples -------- >>> import OpenPNM >>> pn = OpenPNM.Network.Delaunay(num_pores=100, ... domain_size=[0.0001,0.0001,0.0001]) >>> pn.add_boundaries() >>> pn.num_pores('boundary') > 0 True """ bound_conns = [] bound_coords = [] bound_vert_index = [] throat_vert_index = [] # Find boundary extent [x_min, x_max, y_min, y_max, z_min, z_max] = \ vo.vertex_dimension(self, self.pores(), parm='minmax') min_point = np.around(np.array([x_min, y_min, z_min]), 10) max_point = np.around(np.array([x_max, y_max, z_max]), 10) Np = self.num_pores() Nt = self.num_throats() new_throat_count = 0 # ridge_dict contains a dictionary where the key is a set of 2 neighbouring # pores and the value is the vertex indices that form the throat or ridge # between them for p, v in self._vor.ridge_dict.items(): # If the vertex with index -1 is contained in list then the ridge is # unbounded - ignore these if np.all(np.asarray(v) >= 0): # Boundary throats will be those connecting one pore inside the # original set and one out if (p[0] in range(Np) and p[1] not in range(Np)) or \ (p[0] not in range(Np) and p[1] in range(Np)): # The dictionary key is not in numerical order so find the pore # index inside if p[0] in range(Np): my_pore = p[0] else: my_pore = p[1] my_pore_coord = self["pore.coords"][my_pore] new_pore_coord = my_pore_coord.copy() # Rounding necessary here to identify the plane as Voronoi can # have 1e-17 and smaller errors throat_verts = np.around(self._vor.vertices[v], 10) # Find which plane we are aligned with (if any) and align # new_pore with throat plane if len(np.unique(throat_verts[:, 0])) == 1: new_pore_coord[0] = np.unique(throat_verts[:, 0]) elif len(np.unique(throat_verts[:, 1])) == 1: new_pore_coord[1] = np.unique(throat_verts[:, 1]) elif len(np.unique(throat_verts[:, 2])) == 1: new_pore_coord[2] = np.unique(throat_verts[:, 2]) else: new_pore_coord = np.mean(throat_verts, axis=0) pass bound_coords.append(new_pore_coord) bound_conns.append( np.array([my_pore, new_throat_count + Np])) bound_vert_index.append(dict(zip(v, throat_verts))) throat_vert_index.append(dict(zip(v, throat_verts))) new_throat_count += 1 # Add new pores and connections self.extend(pore_coords=bound_coords, throat_conns=bound_conns) # Record new number of pores Mp = self.num_pores() Mt = self.num_throats() new_pore_ids = np.arange(Np, Mp) new_throat_ids = np.arange(Nt, Mt) # Identify which boundary the pore sits on front = self.pores()[self['pore.coords'][:, 0] == min_point[0]] back = self.pores()[self['pore.coords'][:, 0] == max_point[0]] left = self.pores()[self['pore.coords'][:, 1] == min_point[1]] right = self.pores()[self['pore.coords'][:, 1] == max_point[1]] bottom = self.pores()[self['pore.coords'][:, 2] == min_point[2]] top = self.pores()[self['pore.coords'][:, 2] == max_point[2]] if len(top) == 0: top = self.pores()[self['pore.coords'][:, 2] == np.asarray( bound_coords)[:, 2].max()] # Assign labels self['pore.boundary'] = False self['pore.boundary'][new_pore_ids] = True self['throat.boundary'] = False self['throat.boundary'][new_throat_ids] = True self['pore.right_boundary'] = False self['pore.left_boundary'] = False self['pore.front_boundary'] = False self['pore.back_boundary'] = False self['pore.top_boundary'] = False self['pore.bottom_boundary'] = False self['pore.right_boundary'][right] = True self['pore.left_boundary'][left] = True self['pore.front_boundary'][front] = True self['pore.back_boundary'][back] = True self['pore.top_boundary'][top] = True self['pore.bottom_boundary'][bottom] = True # Save the throat verts self["pore.vert_index"][new_pore_ids] = bound_vert_index self["throat.vert_index"][new_throat_ids] = throat_vert_index
def _calc_eff_prop(self, check_health=False): r""" This returns the main parameters for calculating the effective property in a linear transport equation. It also checks for the proper boundary conditions, inlets and outlets. Parameters ---------- check_health : boolean (optional) It analyzes the inlet and outlet pores to check their spatial positions """ try: self[self._quantity] except KeyError: raise Exception('The algorithm has not been run yet. Cannot ' + 'calculate effective property.') # Determine boundary conditions by analyzing algorithm object Ps = self.pores('pore.Dirichlet') BCs = sp.unique(self['pore.bcval_Dirichlet'][Ps]) if sp.shape(BCs)[0] != 2: raise Exception('The supplied algorithm did not have appropriate' + ' BCs') inlets = sp.where(self['pore.' + 'bcval_Dirichlet'] == sp.amax(BCs))[0] outlets = sp.where(self['pore.' + 'bcval_Dirichlet'] == sp.amin(BCs))[0] # Analyze input and output pores if check_health: # Check for coplanarity if self._net.iscoplanar(inlets) is False: raise Exception('The inlet pores do not define a plane. ' + 'Effective property will be approximation') if self._net.iscoplanar(outlets) is False: raise Exception('The outlet pores do not define a plane. ' + 'Effective property will be approximation') # Ensure pores are on a face of domain # (only 1 non-self neighbor each) PnI = self._net.find_neighbor_pores(pores=inlets, mode='not_intersection', excl_self=True) if sp.shape(PnI) != sp.shape(inlets): logger.warning('The inlet pores have too many neighbors. ' + 'Internal pores appear to be selected.') pass PnO = self._net.find_neighbor_pores(pores=outlets, mode='not_intersection', excl_self=True) if sp.shape(PnO) != sp.shape(outlets): logger.warning('The outlet pores have too many neighbors. ' + 'Internal pores appear to be selected.') pass # Fetch area and length of domain if 'pore.vert_index' in self._net.props(): A = vo.vertex_dimension(network=self._net, face1=inlets, parm='area') L = vo.vertex_dimension(network=self._net, face1=inlets, face2=outlets, parm='length') else: A = self._net.domain_area(face=inlets) L = self._net.domain_length(face_1=inlets, face_2=outlets) flow = self.rate(pores=inlets) D = sp.sum(flow) * L / A / (BCs[0] - BCs[1]) return D
def add_boundaries(self): r""" This method identifies pores in the original Voronoi object that straddle a boundary imposed by the reflection The pore inside the original set of pores (with index 0 - Np) is identified and the coordinates are saved The vertices making up the boundary throat are retrieved from the ridge_dict values and these are used to identify which boundary the throat sits at. A new pore and new connection is created with coordinates lying on the boundary plane N.B This method will only work properly if the original network remains unaltered i.e. not trimmed or extended This preserves the connection between pore index on the network object and the Voronoi object The point of using this method is so that the throat vertices created by the Voronoi object are preserved This method will create boundary pores at the centre of the voronoi faces that align with the outer planes of the domain. The original pores in the domain are labelled internal and the boundary pores are labelled external Examples -------- >>> import OpenPNM >>> pn = OpenPNM.Network.Delaunay(num_pores=100, domain_size=[0.0001,0.0001,0.0001]) >>> pn.add_boundaries() >>> pn.num_pores("boundary")>0 True """ bound_conns=[] bound_coords=[] bound_vert_index=[] throat_vert_index=[] #Find boundary extent [x_min,x_max,y_min,y_max,z_min,z_max]=vo.vertex_dimension(self,self.pores(),parm='minmax') min_point = np.around(np.array([x_min,y_min,z_min]),10) max_point = np.around(np.array([x_max,y_max,z_max]),10) Np = self.num_pores() Nt = self.num_throats() new_throat_count = 0 # ridge_dict contains a dictionary where the key is a set of 2 neighbouring pores and the value is the vertex indices # that form the throat or ridge between them for p,v in self._vor.ridge_dict.items(): # if the vertex with index -1 is contained in list then the ridge is unbounded - ignore these if np.all(np.asarray(v) >=0): #boundary throats will be those connecting one pore inside the original set and one out if (p[0] in range(Np) and p[1] not in range(Np)) or\ (p[0] not in range(Np) and p[1] in range(Np)): # the dictionary key is not in numerical order so find the pore index inside if p[0] in range(Np): my_pore=p[0] else: my_pore=p[1] my_pore_coord = self["pore.coords"][my_pore] new_pore_coord = my_pore_coord.copy() #rounding necessary here to identify the plane as Voronoi can have 1e-17 and smaller errors throat_verts = np.around(self._vor.vertices[v],10) #find which plane we are aligned with (if any) and align new_pore with throat plane if len(np.unique(throat_verts[:,0])) == 1: new_pore_coord[0]=np.unique(throat_verts[:,0]) elif len(np.unique(throat_verts[:,1])) == 1: new_pore_coord[1]=np.unique(throat_verts[:,1]) elif len(np.unique(throat_verts[:,2])) == 1: new_pore_coord[2]=np.unique(throat_verts[:,2]) else: new_pore_coord = throat_verts.mean() bound_coords.append(new_pore_coord) bound_conns.append(np.array([my_pore,new_throat_count+Np])) bound_vert_index.append(dict(zip(v,throat_verts))) throat_vert_index.append(dict(zip(v,throat_verts))) new_throat_count += 1 #Add new pores and connections self.extend(pore_coords=bound_coords, throat_conns=bound_conns) #Record new number of pores Mp = self.num_pores() Mt = self.num_throats() new_pore_ids = np.arange(Np,Mp) new_throat_ids = np.arange(Nt,Mt) #Identify which boundary the pore sits on front = self.pores()[self['pore.coords'][:,0]==min_point[0]] back = self.pores()[self['pore.coords'][:,0]==max_point[0]] left = self.pores()[self['pore.coords'][:,1]==min_point[1]] right = self.pores()[self['pore.coords'][:,1]==max_point[1]] bottom = self.pores()[self['pore.coords'][:,2]==min_point[2]] top = self.pores()[self['pore.coords'][:,2]==max_point[2]] #Assign labels self['pore.boundary'] = False self['pore.boundary'][new_pore_ids] = True self['pore.right_boundary'] = False self['pore.left_boundary'] = False self['pore.front_boundary'] = False self['pore.back_boundary'] = False self['pore.top_boundary'] = False self['pore.bottom_boundary'] = False self['pore.right_boundary'][right] = True self['pore.left_boundary'][left] = True self['pore.front_boundary'][front] = True self['pore.back_boundary'][back] = True self['pore.top_boundary'][top] = True self['pore.bottom_boundary'][bottom] = True #Save the throat verts self["pore.vert_index"][new_pore_ids] = bound_vert_index self["throat.vert_index"][new_throat_ids] = throat_vert_index