openpnm 1.0.0__zip

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. OpenPNM-1.1/MANIFEST.in +2 -0
  2. OpenPNM-1.1/OpenPNM/Algorithms/__FickianDiffusion__.py +67 -0
  3. OpenPNM-1.1/OpenPNM/Algorithms/__FourierConduction__.py +63 -0
  4. OpenPNM-1.1/OpenPNM/Algorithms/__GenericAlgorithm__.py +235 -0
  5. OpenPNM-1.1/OpenPNM/Algorithms/__GenericLinearTransport__.py +641 -0
  6. OpenPNM-1.1/OpenPNM/Algorithms/__InvasionPercolationForImbibition__.py +703 -0
  7. OpenPNM-1.1/OpenPNM/Algorithms/__InvasionPercolationTimed__.py +702 -0
  8. OpenPNM-1.1/OpenPNM/Algorithms/__InvasionPercolation__.py +156 -0
  9. OpenPNM-1.1/OpenPNM/Algorithms/__OhmicConduction__.py +64 -0
  10. OpenPNM-1.1/OpenPNM/Algorithms/__OrdinaryPercolation__.py +402 -0
  11. OpenPNM-1.1/OpenPNM/Algorithms/__StokesFlow__.py +64 -0
  12. OpenPNM-1.1/OpenPNM/Algorithms/__Tortuosity__.py +91 -0
  13. OpenPNM-1.1/OpenPNM/Algorithms/__init__.py +48 -0
  14. OpenPNM-1.1/OpenPNM/Base/__Controller__.py +480 -0
  15. OpenPNM-1.1/OpenPNM/Base/__Core__.py +1522 -0
  16. OpenPNM-1.1/OpenPNM/Base/__ModelsDict__.py +345 -0
  17. OpenPNM-1.1/OpenPNM/Base/__Tools__.py +72 -0
  18. OpenPNM-1.1/OpenPNM/Base/__init__.py +32 -0
  19. OpenPNM-1.1/OpenPNM/Geometry/__Boundary__.py +80 -0
  20. OpenPNM-1.1/OpenPNM/Geometry/__Cube_and_Cuboid__.py +64 -0
  21. OpenPNM-1.1/OpenPNM/Geometry/__GenericGeometry__.py +106 -0
  22. OpenPNM-1.1/OpenPNM/Geometry/__SGL10__.py +67 -0
  23. OpenPNM-1.1/OpenPNM/Geometry/__Stick_and_Ball__.py +68 -0
  24. OpenPNM-1.1/OpenPNM/Geometry/__TestGeometry__.py +51 -0
  25. OpenPNM-1.1/OpenPNM/Geometry/__Toray090__.py +68 -0
  26. OpenPNM-1.1/OpenPNM/Geometry/__Voronoi__.py +98 -0
  27. OpenPNM-1.1/OpenPNM/Geometry/__init__.py +47 -0
  28. OpenPNM-1.1/OpenPNM/Geometry/models/__init__.py +33 -0
  29. OpenPNM-1.1/OpenPNM/Geometry/models/pore_area.py +27 -0
  30. OpenPNM-1.1/OpenPNM/Geometry/models/pore_centroid.py +35 -0
  31. OpenPNM-1.1/OpenPNM/Geometry/models/pore_diameter.py +127 -0
  32. OpenPNM-1.1/OpenPNM/Geometry/models/pore_misc.py +55 -0
  33. OpenPNM-1.1/OpenPNM/Geometry/models/pore_seed.py +212 -0
  34. OpenPNM-1.1/OpenPNM/Geometry/models/pore_surface_area.py +28 -0
  35. OpenPNM-1.1/OpenPNM/Geometry/models/pore_vertices.py +19 -0
  36. OpenPNM-1.1/OpenPNM/Geometry/models/pore_volume.py +133 -0
  37. OpenPNM-1.1/OpenPNM/Geometry/models/throat_area.py +47 -0
  38. OpenPNM-1.1/OpenPNM/Geometry/models/throat_centroid.py +80 -0
  39. OpenPNM-1.1/OpenPNM/Geometry/models/throat_diameter.py +106 -0
  40. OpenPNM-1.1/OpenPNM/Geometry/models/throat_length.py +95 -0
  41. OpenPNM-1.1/OpenPNM/Geometry/models/throat_misc.py +42 -0
  42. OpenPNM-1.1/OpenPNM/Geometry/models/throat_normal.py +31 -0
  43. OpenPNM-1.1/OpenPNM/Geometry/models/throat_offset_vertices.py +191 -0
  44. OpenPNM-1.1/OpenPNM/Geometry/models/throat_perimeter.py +26 -0
  45. OpenPNM-1.1/OpenPNM/Geometry/models/throat_seed.py +12 -0
  46. OpenPNM-1.1/OpenPNM/Geometry/models/throat_shape_factor.py +37 -0
  47. OpenPNM-1.1/OpenPNM/Geometry/models/throat_surface_area.py +44 -0
  48. OpenPNM-1.1/OpenPNM/Geometry/models/throat_vector.py +27 -0
  49. OpenPNM-1.1/OpenPNM/Geometry/models/throat_vertices.py +19 -0
  50. OpenPNM-1.1/OpenPNM/Geometry/models/throat_volume.py +45 -0
  51. OpenPNM-1.1/OpenPNM/Network/__Cubic__.py +316 -0
  52. OpenPNM-1.1/OpenPNM/Network/__DelaunayCubic__.py +127 -0
  53. OpenPNM-1.1/OpenPNM/Network/__Delaunay__.py +600 -0
  54. OpenPNM-1.1/OpenPNM/Network/__GenericNetwork__.py +1184 -0
  55. OpenPNM-1.1/OpenPNM/Network/__MatFile__.py +331 -0
  56. OpenPNM-1.1/OpenPNM/Network/__TestNet__.py +109 -0
  57. OpenPNM-1.1/OpenPNM/Network/__init__.py +40 -0
  58. OpenPNM-1.1/OpenPNM/Network/models/__init__.py +12 -0
  59. OpenPNM-1.1/OpenPNM/Network/models/pore_topology.py +106 -0
  60. OpenPNM-1.1/OpenPNM/Phases/__Air__.py +63 -0
  61. OpenPNM-1.1/OpenPNM/Phases/__GenericPhase__.py +146 -0
  62. OpenPNM-1.1/OpenPNM/Phases/__Mercury__.py +71 -0
  63. OpenPNM-1.1/OpenPNM/Phases/__TestPhase__.py +46 -0
  64. OpenPNM-1.1/OpenPNM/Phases/__Water__.py +56 -0
  65. OpenPNM-1.1/OpenPNM/Phases/__init__.py +38 -0
  66. OpenPNM-1.1/OpenPNM/Phases/models/__init__.py +22 -0
  67. OpenPNM-1.1/OpenPNM/Phases/models/contact_angle.py +34 -0
  68. OpenPNM-1.1/OpenPNM/Phases/models/density.py +81 -0
  69. OpenPNM-1.1/OpenPNM/Phases/models/diffusivity.py +95 -0
  70. OpenPNM-1.1/OpenPNM/Phases/models/electrical_conductivity.py +10 -0
  71. OpenPNM-1.1/OpenPNM/Phases/models/misc.py +125 -0
  72. OpenPNM-1.1/OpenPNM/Phases/models/molar_density.py +69 -0
  73. OpenPNM-1.1/OpenPNM/Phases/models/molar_mass.py +31 -0
  74. OpenPNM-1.1/OpenPNM/Phases/models/surface_tension.py +104 -0
  75. OpenPNM-1.1/OpenPNM/Phases/models/thermal_conductivity.py +98 -0
  76. OpenPNM-1.1/OpenPNM/Phases/models/vapor_pressure.py +69 -0
  77. OpenPNM-1.1/OpenPNM/Phases/models/viscosity.py +103 -0
  78. OpenPNM-1.1/OpenPNM/Physics/__GenericPhysics__.py +111 -0
  79. OpenPNM-1.1/OpenPNM/Physics/__Standard__.py +51 -0
  80. OpenPNM-1.1/OpenPNM/Physics/__TestPhysics__.py +50 -0
  81. OpenPNM-1.1/OpenPNM/Physics/__init__.py +30 -0
  82. OpenPNM-1.1/OpenPNM/Physics/models/__init__.py +18 -0
  83. OpenPNM-1.1/OpenPNM/Physics/models/capillary_pressure.py +122 -0
  84. OpenPNM-1.1/OpenPNM/Physics/models/diffusive_conductance.py +82 -0
  85. OpenPNM-1.1/OpenPNM/Physics/models/electrical_conductance.py +59 -0
  86. OpenPNM-1.1/OpenPNM/Physics/models/generic_source_term.py +564 -0
  87. OpenPNM-1.1/OpenPNM/Physics/models/hydraulic_conductance.py +76 -0
  88. OpenPNM-1.1/OpenPNM/Physics/models/multiphase.py +133 -0
  89. OpenPNM-1.1/OpenPNM/Physics/models/thermal_conductance.py +67 -0
  90. OpenPNM-1.1/OpenPNM/Postprocessing/Graphics.py +251 -0
  91. OpenPNM-1.1/OpenPNM/Postprocessing/Plots.py +369 -0
  92. OpenPNM-1.1/OpenPNM/Postprocessing/__init__.py +10 -0
  93. OpenPNM-1.1/OpenPNM/Utilities/IO.py +277 -0
  94. OpenPNM-1.1/OpenPNM/Utilities/Shortcuts.py +17 -0
  95. OpenPNM-1.1/OpenPNM/Utilities/__init__.py +16 -0
  96. OpenPNM-1.1/OpenPNM/Utilities/misc.py +226 -0
  97. OpenPNM-1.1/OpenPNM/Utilities/transformations.py +1923 -0
  98. OpenPNM-1.1/OpenPNM/Utilities/vertexops.py +824 -0
  99. OpenPNM-1.1/OpenPNM/__init__.py +56 -0
  100. OpenPNM-1.1/OpenPNM.egg-info/PKG-INFO +11 -0
  101. OpenPNM-1.1/OpenPNM.egg-info/SOURCES.txt +107 -0
  102. OpenPNM-1.1/OpenPNM.egg-info/dependency_links.txt +1 -0
  103. OpenPNM-1.1/OpenPNM.egg-info/requires.txt +1 -0
  104. OpenPNM-1.1/OpenPNM.egg-info/top_level.txt +1 -0
  105. OpenPNM-1.1/PKG-INFO +11 -0
  106. OpenPNM-1.1/README.txt +88 -0
  107. OpenPNM-1.1/setup.cfg +7 -0
  108. OpenPNM-1.1/setup.py +39 -0
@@ -0,0 +1,331 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ ===============================================================================
4
+ MatFile: Subclass to import Networks from a Matlab 'mat' file
5
+ ===============================================================================
6
+
7
+ """
8
+ import scipy as sp
9
+ import scipy.io as spio
10
+ import os
11
+ from OpenPNM.Network import GenericNetwork
12
+ import OpenPNM.Geometry
13
+ import OpenPNM.Utilities.misc as misc
14
+ from OpenPNM.Base import logging
15
+ logger = logging.getLogger(__name__)
16
+
17
+ class MatFile(GenericNetwork):
18
+ r'''
19
+ MatFile - constructs a pore network from a perfectly formatted .mat file (MATLAB)
20
+ Create network from Matlab file. Returns OpenPNM.Network.GenericNetwork()
21
+ object. The extra data of 'type' will trigger internal and boundary pores.
22
+
23
+ Parameters
24
+ ----------
25
+ filename : string
26
+ filename = 'standard_cubic_5x5x5.mat' (default)
27
+ Name of mat file
28
+ path : string
29
+ path='' (default)
30
+ the full path to the mat file on your computer
31
+ leaving blank searches for the file in the local directory
32
+ xtra_pore_data : list of strings
33
+ xtra_pore_data = ['type','shape','material']
34
+ any additional props to look for in the dictionary
35
+ xtra_throat_data : list of strings
36
+ xtra_throat_data = ['type','shape','material']
37
+ any additional props to look for in the dictionary
38
+
39
+ Examples
40
+ ---------
41
+ >>> import OpenPNM, os
42
+ >>> fname = 'test_pn' # or 'test_pn.mat'
43
+ >>> longpath = os.path.abspath(__file__) # line needed for auto-tests
44
+ >>> path,file = os.path.split(longpath) #unfortunately, auto-tests fail without this. Just type in the path of your own file, or leave it blank to search in your current directory.
45
+ >>> pn = OpenPNM.Network.MatFile(filename=fname,path=path,xtra_pore_data='type',xtra_throat_data='type')
46
+
47
+ Notes
48
+ ------
49
+ Matfiles should include the following variables
50
+
51
+ +----------------+------------+----------------------------------+
52
+ | Variable Name | Value | Description |
53
+ +================+============+==================================+
54
+ | pcoords | <Npx3> | physical coordinates, in meters, |
55
+ | | float | of pores to be imported |
56
+ +----------------+------------+----------------------------------+
57
+ | pdiameter | <Npx1> | pore diamters, in meters |
58
+ | | float | |
59
+ +----------------+------------+----------------------------------+
60
+ | pvolume | <Npx1> | pore volumes, in cubic meters |
61
+ | | float | |
62
+ +----------------+------------+----------------------------------+
63
+ | pnumbering | <Npx1> | = 0:1:Np-1 |
64
+ | | int | |
65
+ +----------------+------------+----------------------------------+
66
+ | ptype | <Npx1> | (optional) designates surfaces |
67
+ | | int | of pores in network. |
68
+ | | | (more details below) |
69
+ +----------------+------------+----------------------------------+
70
+ | tconnections | <Ntx2> | pore numbers of the two pores |
71
+ | | int | that each throat connects |
72
+ +----------------+------------+----------------------------------+
73
+ | tdiameter | <Ntx1> | throat diameters, in meters |
74
+ | | float | |
75
+ +----------------+------------+----------------------------------+
76
+ | tnumbering | <Ntx1> | = 0:1:Nt-1 |
77
+ | | int | |
78
+ +----------------+------------+----------------------------------+
79
+ | ttype | <Ntx1> | (optional) designates surfaces |
80
+ | | int | of throats in network. |
81
+ | | | (more details below) |
82
+ +----------------+------------+----------------------------------+
83
+
84
+
85
+ '''
86
+ def __init__(self,filename='', path='', xtra_pore_data=None, xtra_throat_data=None,**kwargs):
87
+
88
+ r"""
89
+ """
90
+ super(MatFile,self).__init__(**kwargs)
91
+ if filename == '':
92
+ return
93
+ if path == '':
94
+ path = os.path.abspath('.')
95
+ self._path = path
96
+ filepath = os.path.join(self._path,filename)
97
+ self._xtra_pore_data=xtra_pore_data
98
+ self._xtra_throat_data=xtra_throat_data
99
+ self._dictionary=spio.loadmat(filepath)
100
+
101
+ self._Np=sp.size(self._dictionary['pnumbering'])
102
+ self._Nt=sp.size(self._dictionary['tnumbering'])
103
+
104
+ #Run through generation steps
105
+ self._add_pores()
106
+ self._add_throats()
107
+ self._remove_disconnected_clusters()
108
+ self._add_xtra_pore_data()
109
+ self._add_xtra_throat_data()
110
+ self._add_geometry()
111
+
112
+ def _add_pores(self):
113
+ Pind = sp.arange(0,self._Np)
114
+ self['pore.all'] = sp.ones_like(Pind,dtype=bool)
115
+ logger.info('Writing pore data')
116
+ self['pore.coords']=sp.array(self._dictionary['pcoords'],float)
117
+
118
+ def _add_throats(self):
119
+ Tind = sp.arange(0,self._Nt)
120
+ self['throat.all']=sp.ones_like(Tind,dtype=bool)
121
+ logger.info('Writing throat data')
122
+ self['throat.conns']=sp.array(self._dictionary['tconnections'],int)
123
+
124
+ def _remove_disconnected_clusters(self):
125
+ bad_pores = sp.array([],dtype=int)
126
+ self._pore_map = self.pores()
127
+ self._throat_map = self.throats()
128
+ health = self.check_network_health()
129
+ if health['disconnected_clusters'] == []:
130
+ self._throat_map = self.throats()
131
+ self._pore_map = self.pores()
132
+ else:
133
+ Np = self.num_pores()
134
+ Nt = self.num_throats()
135
+ cluster_sizes = [sp.shape(x)[0] for x in health['disconnected_clusters']]
136
+ acceptable_size = min([min([50,Np/2]),max(cluster_sizes)]) # 50 or less, if it's a really small network.
137
+ #step through each cluster of pores. If its a small cluster, add it to the list
138
+ for cluster in health['disconnected_clusters']:
139
+ if sp.shape(cluster)[0] < acceptable_size:
140
+ bad_pores = sp.append(bad_pores,sp.ravel(cluster))
141
+ bad_throats = sp.unique(self.find_neighbor_throats(bad_pores))
142
+ #Create map for pores
143
+ if sp.shape(bad_pores)[0] > 0:
144
+ i = 0
145
+ self._pore_map = sp.zeros((Np-sp.shape(bad_pores)[0],),dtype=int)
146
+ for pore in self.pores():
147
+ if pore not in bad_pores:
148
+ self._pore_map[i] = pore
149
+ i += 1
150
+ #Create map for throats
151
+ if sp.shape(bad_throats)[0] > 0:
152
+ i = 0
153
+ self._throat_map = sp.zeros((Nt-sp.shape(bad_throats)[0],),dtype=int)
154
+ for throat in self.throats():
155
+ if throat not in bad_throats:
156
+ self._throat_map[i] = throat
157
+ i += 1
158
+ #Fix the pore transformer
159
+ try:
160
+ if sp.shape(bad_pores)[0] > 0:
161
+ i = 0
162
+ old_transform = self._dictionary['pname_transform']
163
+ self._dictionary['pname_transform'] = sp.zeros((Np-sp.shape(bad_pores)[0],),dtype=int)
164
+ for pore in self.pores():
165
+ if pore not in bad_pores:
166
+ self._dictionary['pname_transform'][i] = old_transform[pore]
167
+ i += 1
168
+ except:
169
+ logger.info('Could not update pname_transform. Imported network may not have had it.')
170
+ pass
171
+ self.trim(pores=bad_pores)
172
+
173
+ def _add_geometry(self):
174
+ try:
175
+ boundary_pores = sp.where(self['pore.type']!=0)[0]
176
+ boundary_throats = sp.where(self['throat.type']!=0)[0]
177
+ self['throat.top'] = sp.ravel(self['throat.type']==1)
178
+ self['throat.bottom'] = sp.ravel(self['throat.type']==6)
179
+ self['throat.left'] = sp.ravel(self['throat.type']==2)
180
+ self['throat.right'] = sp.ravel(self['throat.type']==5)
181
+ self['throat.front'] = sp.ravel(self['throat.type']==3)
182
+ self['throat.back'] = sp.ravel(self['throat.type']==4)
183
+ self['pore.top'] = self.tomask(pores=sp.ravel(self.find_connected_pores(self.throats('top'))))
184
+ self['pore.bottom'] = self.tomask(sp.ravel(self.find_connected_pores(self.throats('bottom'))))
185
+ self['pore.left'] = self.tomask(sp.ravel(self.find_connected_pores(self.throats('left'))))
186
+ self['pore.right'] = self.tomask(sp.ravel(self.find_connected_pores(self.throats('right'))))
187
+ self['pore.front'] = self.tomask(sp.ravel(self.find_connected_pores(self.throats('front'))))
188
+ self['pore.back'] = self.tomask(sp.ravel(self.find_connected_pores(self.throats('back'))))
189
+ add_boundaries = True
190
+ except:
191
+ boundary_pores = sp.array([])
192
+ boundary_throats = sp.array([])
193
+ logger.info('No boundary pores added.')
194
+ add_boundaries = False
195
+ Ps = sp.where([pore not in boundary_pores for pore in self.pores()])[0]
196
+ Ts = sp.where([throat not in boundary_throats for throat in self.throats()])[0]
197
+ geom = OpenPNM.Geometry.GenericGeometry(network=self,pores=Ps,throats=Ts,name='internal')
198
+ geom['pore.volume'] = sp.ravel(sp.array(self._dictionary['pvolume'][self._pore_map[Ps]],float))
199
+ geom['pore.diameter'] = sp.ravel(sp.array(self._dictionary['pdiameter'][self._pore_map[Ps]],float))
200
+ geom['throat.diameter'] = sp.ravel(sp.array(self._dictionary['tdiameter'][self._throat_map[Ts]],float))
201
+ geom.add_model(propname='pore.area',model=OpenPNM.Geometry.models.pore_area.spherical)
202
+ geom.add_model(propname='throat.area',model=OpenPNM.Geometry.models.throat_area.cylinder)
203
+
204
+ if add_boundaries:
205
+ boun = OpenPNM.Geometry.Boundary(network=self,pores=boundary_pores,throats=boundary_throats,name='boundary')
206
+ self['pore.top_boundary']=self.tomask(pores=self.pores(['top','boundary'],mode='intersection'))
207
+ self['pore.bottom_boundary']=self.tomask(pores=self.pores(['bottom','boundary'],mode='intersection'))
208
+ self['pore.left_boundary']=self.tomask(pores=self.pores(['left','boundary'],mode='intersection'))
209
+ self['pore.right_boundary']=self.tomask(pores=self.pores(['right','boundary'],mode='intersection'))
210
+ self['pore.front_boundary']=self.tomask(pores=self.pores(['front','boundary'],mode='intersection'))
211
+ self['pore.back_boundary']=self.tomask(pores=self.pores(['back','boundary'],mode='intersection'))
212
+
213
+ self['throat.top_boundary']=self.tomask(throats=self.throats(['top','boundary'],mode='intersection'))
214
+ self['throat.bottom_boundary']=self.tomask(throats=self.throats(['bottom','boundary'],mode='intersection'))
215
+ self['throat.left_boundary']=self.tomask(throats=self.throats(['left','boundary'],mode='intersection'))
216
+ self['throat.right_boundary']=self.tomask(throats=self.throats(['right','boundary'],mode='intersection'))
217
+ self['throat.front_boundary']=self.tomask(throats=self.throats(['front','boundary'],mode='intersection'))
218
+ self['throat.back_boundary']=self.tomask(throats=self.throats(['back','boundary'],mode='intersection'))
219
+
220
+ def _add_xtra_pore_data(self):
221
+ xpdata = self._xtra_pore_data
222
+ if xpdata is not None:
223
+ if type(xpdata) is type([]):
224
+ for pdata in xpdata:
225
+ try:
226
+ self['pore.'+pdata]=self._dictionary['p'+pdata][self._pore_map]
227
+ except:
228
+ logger.warning('Could not add pore data: '+pdata+' to network')
229
+ pass
230
+ else:
231
+ try:
232
+ self['pore.'+xpdata]=self._dictionary['p'+xpdata][self._pore_map]
233
+ except:
234
+ logger.warning('Could not add pore data: '+xpdata+' to network')
235
+ pass
236
+
237
+ def _add_xtra_throat_data(self):
238
+ xtdata = self._xtra_throat_data
239
+ if xtdata is not None:
240
+ if type(xtdata) is type([]):
241
+ for tdata in xtdata:
242
+ try:
243
+ self['throat.'+tdata]=self._dictionary['t'+tdata][self._throat_map]
244
+ except:
245
+ logger.warning('Could not add throat data: '+tdata+' to network')
246
+ pass
247
+ else:
248
+ try:
249
+ self['throat.'+xtdata]=self._dictionary['t'+xtdata][self._throat_map]
250
+ except:
251
+ logger.warning('Could not add throat data: '+xtdata+' to network')
252
+ pass
253
+
254
+ def domain_length(self,face_1,face_2):
255
+ r'''
256
+ Calculate the distance between two faces of the network
257
+
258
+ Parameters
259
+ ----------
260
+ face_1 and face_2 : array_like
261
+ Lists of pores belonging to opposite faces of the network
262
+
263
+ Returns
264
+ -------
265
+ The length of the domain in the specified direction
266
+
267
+ Notes
268
+ -----
269
+ - Does not yet check if input faces are perpendicular to each other
270
+ '''
271
+ #Ensure given points are coplanar before proceeding
272
+ if misc.iscoplanar(self['pore.coords'][face_1]) and misc.iscoplanar(self['pore.coords'][face_2]):
273
+ #Find distance between given faces
274
+ x = self['pore.coords'][face_1]
275
+ y = self['pore.coords'][face_2]
276
+ Ds = misc.dist(x,y)
277
+ L = sp.median(sp.amin(Ds,axis=0))
278
+ else:
279
+ logger.warning('The supplied pores are not coplanar. Length will be approximate.')
280
+ f1 = self['pore.coords'][face_1]
281
+ f2 = self['pore.coords'][face_2]
282
+ distavg = [0,0,0]
283
+ distavg[0] = sp.absolute(sp.average(f1[:,0]) - sp.average(f2[:,0]))
284
+ distavg[1] = sp.absolute(sp.average(f1[:,1]) - sp.average(f2[:,1]))
285
+ distavg[2] = sp.absolute(sp.average(f1[:,2]) - sp.average(f2[:,2]))
286
+ L = max(distavg)
287
+ return L
288
+
289
+
290
+ def domain_area(self,face):
291
+ r'''
292
+ Calculate the area of a given network face
293
+
294
+ Parameters
295
+ ----------
296
+ face : array_like
297
+ List of pores of pore defining the face of interest
298
+
299
+ Returns
300
+ -------
301
+ The area of the specified face
302
+ '''
303
+ coords = self['pore.coords'][face]
304
+ rads = self['pore.diameter'][face]/2.
305
+ # calculate the area of the 3 principle faces of the bounding cuboid
306
+ dx = max(coords[:,0]+rads) - min(coords[:,0]-rads)
307
+ dy = max(coords[:,1]+rads) - min(coords[:,1]-rads)
308
+ dz = max(coords[:,2]+rads) - min(coords[:,2]-rads)
309
+ yz = dy*dz # x normal
310
+ xz = dx*dz # y normal
311
+ xy = dx*dy # z normal
312
+ # find the directions parallel to the plane
313
+ directions = sp.where([yz,xz,xy]!=max([yz,xz,xy]))[0]
314
+ try:
315
+ # now, use the whole network to do the area calculation
316
+ coords = self['pore.coords']
317
+ rads = self['pore.diameter']/2.
318
+ d0 = (max(coords[:,directions[0]]+rads) - min(coords[:,directions[0]]-rads))
319
+ d1 = (max(coords[:,directions[1]]+rads) - min(coords[:,directions[1]]-rads))
320
+ A = d0*d1
321
+ except:
322
+ # if that fails, use the max face area of the bounding cuboid
323
+ A = max([yz,xz,xy])
324
+ if not misc.iscoplanar(self['pore.coords'][face]):
325
+ logger.warning('The supplied pores are not coplanar. Area will be approximate')
326
+ pass
327
+ return A
328
+
329
+ if __name__ == '__main__':
330
+ import doctest
331
+ doctest.testmod(verbose=True)
@@ -0,0 +1,109 @@
1
+ """
2
+ ===============================================================================
3
+ TestNet: Generate simple cubic network for testing purposes
4
+ ===============================================================================
5
+
6
+ """
7
+
8
+ import scipy as sp
9
+ from OpenPNM.Network import GenericNetwork
10
+ from OpenPNM.Base import logging
11
+ logger = logging.getLogger(__name__)
12
+
13
+ class TestNet(GenericNetwork):
14
+ r"""
15
+ A small cubic network for quick testing purposes
16
+
17
+ Parameters
18
+ ----------
19
+ This class accepts no arguments
20
+
21
+ """
22
+
23
+ def __init__(self,**kwargs):
24
+ super(TestNet, self).__init__(**kwargs)
25
+ self.generate()
26
+
27
+ def generate(self):
28
+ '''
29
+ Create test network, of cubic geometry [5,5,5]
30
+
31
+ Parameters
32
+ ----------
33
+ This network type accepts no arguments
34
+ '''
35
+ self._generate_setup()
36
+ self._generate_pores()
37
+ self._generate_throats()
38
+ self._add_labels()
39
+ return self
40
+
41
+ def _generate_setup(self):
42
+ r"""
43
+ Perform applicable preliminary checks and calculations required for generation
44
+ """
45
+ self._Nx = 5
46
+ self._Ny = 5
47
+ self._Nz = 5
48
+ self._Lc = 1
49
+ self._Lx = sp.float16(self._Nx*self._Lc)
50
+ self._Ly = sp.float16(self._Ny*self._Lc)
51
+ self._Lz = sp.float16(self._Nz*self._Lc)
52
+
53
+ def _generate_pores(self):
54
+ r"""
55
+ Generate the pores (coordinates, numbering and types)
56
+ """
57
+ Nx = self._Nx
58
+ Ny = self._Ny
59
+ Nz = self._Nz
60
+ Lc = self._Lc
61
+ Np = Nx*Ny*Nz
62
+ ind = sp.arange(0,Np)
63
+ self['pore.all'] = sp.ones_like(ind,dtype=bool)
64
+ pore_coords = Lc/2+Lc*sp.array(sp.unravel_index(ind, dims=(Nx, Ny, Nz), order='F'),dtype=sp.float64).T
65
+ self['pore.coords'] = pore_coords
66
+
67
+ def _generate_throats(self):
68
+ r"""
69
+ Generate the throats (connections, numbering and types)
70
+ """
71
+ Nx = self._Nx
72
+ Ny = self._Ny
73
+ Nz = self._Nz
74
+ Np = Nx*Ny*Nz
75
+ ind = sp.arange(0,Np)
76
+ #Generate throats based on pattern of the adjacency matrix
77
+ tpore1_1 = ind[(ind%Nx)<(Nx-1)]
78
+ tpore2_1 = tpore1_1 + 1
79
+ tpore1_2 = ind[(ind%(Nx*Ny))<(Nx*(Ny-1))]
80
+ tpore2_2 = tpore1_2 + Nx
81
+ tpore1_3 = ind[(ind%Np)<(Nx*Ny*(Nz-1))]
82
+ tpore2_3 = tpore1_3 + Nx*Ny
83
+ tpore1 = sp.hstack((tpore1_1,tpore1_2,tpore1_3))
84
+ tpore2 = sp.hstack((tpore2_1,tpore2_2,tpore2_3))
85
+ connections = sp.vstack((tpore1,tpore2)).T
86
+ connections = connections[sp.lexsort((connections[:, 1], connections[:, 0]))]
87
+ self['throat.all'] = sp.ones_like(sp.arange(0,sp.shape(tpore1)[0]),dtype=bool)
88
+ self['throat.conns'] = connections
89
+
90
+ def _add_labels(self):
91
+ coords = self['pore.coords']
92
+ self['pore.front'] = self.tomask(coords[:,0]<=self._Lc)
93
+ self['pore.left'] = self.tomask(coords[:,1]<=self._Lc)
94
+ self['pore.bottom'] = self.tomask(coords[:,2]<=self._Lc)
95
+ self['pore.back'] = self.tomask(coords[:,0]>=(self._Lc*(self._Nx-1)))
96
+ self['pore.right'] = self.tomask(coords[:,1]>=(self._Lc*(self._Ny-1)))
97
+ self['pore.top'] = self.tomask(coords[:,2]>=(self._Lc*(self._Nz-1)))
98
+ for item in ['top','bottom','left','right','front','back']:
99
+ ps = self.pores(item)
100
+ ts = self.find_neighbor_throats(ps)
101
+ ps = self.find_connected_pores(ts)
102
+ ps0 = self['pore.'+item][ps[:,0]]
103
+ ps1 = self['pore.'+item][ps[:,1]]
104
+ ts = ts[ps1*ps0]
105
+ self['throat.'+item] = self.tomask(throats=ts)
106
+ if __name__ == '__main__':
107
+ import OpenPNM
108
+ pn = OpenPNM.Network.TestNet()
109
+ print(pn.name)
@@ -0,0 +1,40 @@
1
+ r"""
2
+ ###############################################################################
3
+ :mod:`OpenPNM.Network`: Classes related the creation of network topology
4
+ ###############################################################################
5
+
6
+ Contents
7
+ --------
8
+ **GenericNetwork** -- Contains many methods ` for working with the topology of the
9
+ networks
10
+
11
+ **Subclasses** -- Inherit from GenericNetwork, and contain additional methods for
12
+ actually generating topology.
13
+
14
+ Classes
15
+ -------
16
+
17
+ .. autoclass:: GenericNetwork
18
+ :members:
19
+
20
+ .. autoclass:: Cubic
21
+ :members:
22
+
23
+ .. autoclass:: Delaunay
24
+ :members:
25
+
26
+ .. autoclass:: DelaunayCubic
27
+ :members:
28
+
29
+ .. autoclass:: MatFile
30
+ :members:
31
+
32
+ """
33
+
34
+ from .__GenericNetwork__ import GenericNetwork
35
+ from .__Cubic__ import Cubic
36
+ from .__Delaunay__ import Delaunay
37
+ from .__DelaunayCubic__ import DelaunayCubic
38
+ from .__MatFile__ import MatFile
39
+ from .__TestNet__ import TestNet
40
+ from . import models
@@ -0,0 +1,12 @@
1
+ r"""
2
+ *******************************************************************************
3
+ models -- Models for calculating additional network topology properties
4
+ *******************************************************************************
5
+
6
+ Contents
7
+ --------
8
+ This module contains methods for calculating extra topology information
9
+
10
+ """
11
+
12
+ from . import pore_topology
@@ -0,0 +1,106 @@
1
+ r"""
2
+ ===============================================================================
3
+ pore_topology -- functions for monitoring and adjusting topology
4
+ ===============================================================================
5
+
6
+ """
7
+ import scipy as _sp
8
+
9
+ def get_subscripts(network,
10
+ shape,
11
+ **kwargs):
12
+ r'''
13
+ Return the 3D subscripts (i,j,k) into the cubic network
14
+
15
+ Parameters
16
+ ----------
17
+ shape : list
18
+ The (i,j,k) shape of the network in number of pores in each direction
19
+
20
+ '''
21
+ if network.num_pores('internal') != _sp.prod(shape):
22
+ print('Supplied shape does not match Network size, cannot proceed')
23
+ else:
24
+ template = _sp.atleast_3d(_sp.empty(shape))
25
+ a = _sp.indices(_sp.shape(template))
26
+ i = a[0].flatten()
27
+ j = a[1].flatten()
28
+ k = a[2].flatten()
29
+ ind = _sp.vstack((i,j,k)).T
30
+ vals = _sp.ones((network.Np,3))*_sp.nan
31
+ vals[network.pores('internal')] = ind
32
+ return vals
33
+
34
+ def adjust_spacing(network,
35
+ new_spacing,
36
+ **kwargs):
37
+ r'''
38
+ Adjust the the pore-to-pore lattice spacing on a cubic network
39
+
40
+ Parameters
41
+ ----------
42
+ new_spacing : float
43
+ The new lattice spacing to apply
44
+
45
+ Notes
46
+ -----
47
+ At present this method only applies a uniform spacing in all directions.
48
+ This is a limiation of OpenPNM Cubic Networks in general, and not of the
49
+ method.
50
+ '''
51
+ coords = network['pore.coords']
52
+ try:
53
+ spacing = network._spacing
54
+ coords = coords/spacing*new_spacing
55
+ network._spacing = new_spacing
56
+ except:
57
+ pass
58
+ return coords
59
+
60
+ def reduce_coordination(network,
61
+ z,
62
+ mode='random',
63
+ **kwargs):
64
+ r'''
65
+ Reduce the coordination number to the specified z value
66
+
67
+ Parameters
68
+ ----------
69
+ z : int
70
+ The coordination number or number of throats connected a pore
71
+
72
+ mode : string, optional
73
+ Controls the logic used to trim connections. Options are:
74
+
75
+ - 'random': (default) Throats will be randomly removed to achieve a coordination of z
76
+ - 'max': All pores will be adjusted to have a maximum coordination of z (not implemented yet)
77
+
78
+ Returns
79
+ -------
80
+ A label array indicating which throats should be trimmed to achieve desired
81
+ coordination.
82
+
83
+ Notes
84
+ -----
85
+ Pores with only 1 throat will be ignored in all calculations since these
86
+ are generally boundary pores.
87
+
88
+ '''
89
+ T_trim = ~network['throat.all']
90
+ T_nums = network.num_neighbors(network.pores())
91
+ #Find protected throats
92
+ T_keep = network.find_neighbor_throats(pores=(T_nums==1))
93
+ if mode == 'random':
94
+ z_ave = _sp.average(T_nums[T_nums>1])
95
+ f_trim = (z_ave - z)/z_ave
96
+ T_trim = _sp.rand(network.Nt)<f_trim
97
+ T_trim = T_trim*(~network.tomask(throats=T_keep))
98
+ if mode == 'max':
99
+ pass
100
+ return T_trim
101
+
102
+
103
+
104
+
105
+
106
+
@@ -0,0 +1,63 @@
1
+ # -*- coding: utf-8 -*-
2
+ from OpenPNM.Phases import GenericPhase
3
+ from OpenPNM.Phases import models as fm
4
+
5
+ class Air(GenericPhase):
6
+ r"""
7
+ Creates Phase object with preset models and values for air
8
+
9
+ Parameters
10
+ ----------
11
+ network : OpenPNM Network object
12
+ The network to which this phase object will be attached.
13
+
14
+ Notes
15
+ -----
16
+ The initial properties are all at std conditions of T = 298 K and P = 1 atm.
17
+
18
+ References
19
+ ----------
20
+ [1] E.W. Lemmon and R.T. Jacobsen, "Viscosity and Thermal Conductivity
21
+ Equations for Nitrogen, Oxygen, Argon, and Air", Int. J. of Thermophysics,
22
+ Vol. 25, No. 1, January 2004, pp. 21-69
23
+
24
+ Examples
25
+ --------
26
+ >>> import OpenPNM
27
+ >>> pn = OpenPNM.Network.TestNet()
28
+ >>> air = OpenPNM.Phases.Air(network=pn)
29
+
30
+ """
31
+ def __init__(self,name=None,**kwargs):
32
+ super(Air,self).__init__(name=name,**kwargs)
33
+ self._generate()
34
+
35
+ def _generate(self):
36
+ self['pore.molecular_weight'] = 0.02896 # kg/mol
37
+ self['pore.critical_pressure'] = 3.786E6 # Pa
38
+ self['pore.critical_temperature'] = 132.5 # K
39
+ self['pore.critical_volume'] = 0.002917 # kg/m3
40
+ self['pore.contact_angle'] = 110.0 # Degree
41
+ self.models.add(propname='pore.density',
42
+ model=fm.density.ideal_gas) # kg/m3
43
+ self.models.add(propname='pore.molar_density',
44
+ model=fm.molar_density.ideal_gas) # mol/m3
45
+ self.models.add(propname='pore.diffusivity',
46
+ model=fm.diffusivity.fuller,
47
+ MA=0.032,
48
+ MB=0.028,
49
+ vA=16.6,
50
+ vB=17.9)
51
+ self.models.add(propname='pore.thermal_conductivity', # W/m.K
52
+ model=fm.misc.polynomial,
53
+ poreprop='pore.temperature',
54
+ a=[0.00422791,0.0000789606,-1.56383E-08])
55
+ self.models.add(propname='pore.viscosity', # kg/m.s
56
+ model=fm.misc.polynomial,
57
+ poreprop='pore.temperature',
58
+ a=[0.00000182082,6.51815E-08,-3.48553E-11,1.11409E-14])
59
+
60
+ if __name__ =="__main__":
61
+ import OpenPNM
62
+ pn = OpenPNM.Network.TestNet()
63
+ air = OpenPNM.Phases.Air(network=pn)