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,27 @@
1
+ r"""
2
+ ===============================================================================
3
+ Submodule -- throat_vector
4
+ ===============================================================================
5
+
6
+ """
7
+ import scipy as _sp
8
+
9
+ def pore_to_pore(geometry,network,**kwargs):
10
+ r"""
11
+ Calculates throat vector as straight path between connected pores.
12
+
13
+ Notes
14
+ -----
15
+ There is an important impicit assumption here: the positive direction is
16
+ taken as the direction from the pore with the lower index to the higher.
17
+ This corresponds to the pores in the 1st and 2nd columns of the
18
+ 'conns' array as stored on the network.
19
+ """
20
+ throats = network.throats(geometry.name)
21
+ pores = network.find_connected_pores(throats,flatten=False)
22
+ C0 = network['pore.coords'][pores,0]
23
+ C1 = network['pore.coords'][pores,1]
24
+ V = C1 - C0
25
+ L = _sp.array(_sp.sqrt(_sp.sum(V[:,:]**2,axis=1)),ndmin=1)
26
+ value = V/_sp.array(L,ndmin=2).T
27
+ return value
@@ -0,0 +1,19 @@
1
+ r"""
2
+ ===============================================================================
3
+ throat_vertices -- update throat vertices from Vornoi object
4
+ ===============================================================================
5
+
6
+ """
7
+ import scipy as _sp
8
+
9
+ def voronoi(network,
10
+ geometry,
11
+ **kwargs):
12
+ r"""
13
+ Update the pore vertices from the voronoi vertices
14
+ """
15
+ throats = geometry.map_throats(network,geometry.throats())
16
+ value = _sp.ndarray(len(throats),dtype=object)
17
+ for i in range(len(throats)):
18
+ value[i]=_sp.asarray(list(network["throat.vert_index"][throats[i]].values()))
19
+ return value
@@ -0,0 +1,45 @@
1
+ r"""
2
+ ===============================================================================
3
+ Submodule -- throat_volume
4
+ ===============================================================================
5
+
6
+ """
7
+ import scipy as _sp
8
+
9
+ def cylinder(geometry,
10
+ throat_length='throat.length',
11
+ throat_diameter='throat.diameter',
12
+ **kwargs):
13
+ r"""
14
+ Calculate throat diameter from seeds for a cylindrical throat
15
+ - note: this will need to account for volume taken up by spherical pore bodies
16
+ """
17
+ leng = geometry[throat_length]
18
+ diam = geometry[throat_diameter]
19
+ value = _sp.pi/4*leng*diam**2
20
+ return value
21
+
22
+ def cuboid(geometry,
23
+ throat_length='throat.length',
24
+ throat_diameter='throat.diameter',
25
+ **kwargs):
26
+ r"""
27
+ Calculate throat volume of cuboidal throat
28
+ - note: this will need to account for volume taken up by spherical pore bodies
29
+ """
30
+ leng = geometry[throat_length]
31
+ diam = geometry[throat_diameter]
32
+ value = leng*diam**2
33
+ return value
34
+
35
+ def extrusion(geometry,
36
+ throat_length='throat.length',
37
+ throat_area='throat.area',
38
+ **kwargs):
39
+ r"""
40
+ Calculate volume from the throat area and the throat length
41
+ """
42
+ leng = geometry[throat_length]
43
+ area = geometry[throat_area]
44
+ value = leng*area
45
+ return value
@@ -0,0 +1,316 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ ===============================================================================
4
+ Cubic: Generate lattice-like networks
5
+ ===============================================================================
6
+
7
+ """
8
+ import numpy as np
9
+ import scipy as sp
10
+ import OpenPNM.Utilities.misc as misc
11
+ from OpenPNM.Network import GenericNetwork
12
+ from OpenPNM.Base import logging
13
+ logger = logging.getLogger(__name__)
14
+
15
+ class Cubic(GenericNetwork):
16
+ r"""
17
+ This class generates a cubic network of the specified size and shape.
18
+ Alternatively, an arbitrary domain shape defined by a supplied template.
19
+
20
+ Parameters
21
+ ----------
22
+ name : string
23
+ A unique name for the network
24
+
25
+ shape : tuple of ints
26
+ The (i,j,k) size and shape of the network.
27
+
28
+ connectivity : int
29
+ The number of connections to neighboring pores. Connections are made
30
+ symmetrically to any combination of face, edge or corners neighbors.
31
+
32
+ Options are:
33
+
34
+ - 6: Faces only
35
+ - 8: Corners only
36
+ - 12: Edges Only
37
+ - 14: Faces and Corners
38
+ - 18: Faces and Edges
39
+ - 20: Edges and Corners
40
+ - 26: Faces, Edges and Corners
41
+
42
+ template : array of booleans
43
+ An (i,j,k) array with True where the Network should be defiend and
44
+ False elsewhere. This approach is useful for creating networks of non-
45
+ cuboid shape like spheres or cylinders, but still with a cubic lattice
46
+ topology.
47
+
48
+ Examples
49
+ --------
50
+ >>> import OpenPNM
51
+ >>> pn = OpenPNM.Network.Cubic(shape=[3,4,5])
52
+ >>> pn.Np
53
+ 60
54
+
55
+ It is also possible to create Networks with cubic connectivity but
56
+ non-Cubic shape by provding an array with True values where the network
57
+ should exist to the ``template`` argument. The example below produces a sphere:
58
+
59
+ >>> img = sp.ones([11,11,11])
60
+ >>> img[5,5,5] = 0
61
+ >>> from scipy.ndimage import distance_transform_bf as dt
62
+ >>> img = dt(img) < 5 # Create a sphere of True
63
+ >>> pn = OpenPNM.Network.Cubic(template=img)
64
+ >>> pn.Np
65
+ 485
66
+
67
+ If random distributions of coordination number is desired, one option is
68
+ to create a Cubic network with many connections and the trim some:
69
+
70
+ >>> pn = OpenPNM.Network.Cubic(shape=[5,5,5],connectivity=26)
71
+ >>> Nt_original = pn.Nt
72
+ >>> mod = OpenPNM.Network.models.pore_topology.reduce_coordination
73
+ >>> pn.add_model(propname='throat.to_drop',model=mod,z=10,mode='random')
74
+ >>> pn.trim(throats=pn['throat.to_drop'])
75
+ >>> pn.Nt < Nt_original
76
+ True
77
+ """
78
+ def __init__(self, shape=None, template=None, spacing=1, connectivity=6, **kwargs):
79
+ super(Cubic, self).__init__(**kwargs)
80
+
81
+ if shape is not None:
82
+ arr = np.atleast_3d(np.empty(shape))
83
+ elif template is not None:
84
+ arr = sp.array(template,ndmin=3,dtype=bool)
85
+ else:
86
+ arr = np.atleast_3d(np.empty([1,1,1]))
87
+
88
+ self._shape = sp.shape(arr) # Store original network shape
89
+ self._spacing = spacing # Store network spacing instead of calculating it
90
+
91
+ points = np.array([i for i,v in np.ndenumerate(arr)], dtype=float)
92
+ points += 0.5
93
+ points *= spacing
94
+
95
+ I = np.arange(arr.size).reshape(arr.shape)
96
+
97
+ face_joints = [
98
+ (I[:,:,:-1], I[:,:,1:]),
99
+ (I[:,:-1], I[:,1:]),
100
+ (I[:-1], I[1:]),
101
+ ]
102
+
103
+ corner_joints = [
104
+ (I[:-1,:-1,:-1], I[1:,1:,1:]),
105
+ (I[:-1,:-1,1:], I[1:,1:,:-1]),
106
+ (I[:-1,1:,:-1], I[1:,:-1,1:]),
107
+ (I[1:,:-1,:-1], I[:-1,1:,1:]),
108
+ ]
109
+
110
+ edge_joints = [
111
+ (I[:,:-1,:-1], I[:,1:,1:]),
112
+ (I[:,:-1,1:], I[:,1:,:-1]),
113
+ (I[:-1,:,:-1], I[1:,:,1:]),
114
+ (I[1:,:,:-1], I[:-1,:,1:]),
115
+ (I[1:,1:,:], I[:-1,:-1,:]),
116
+ (I[1:,:-1,:], I[:-1,1:,:]),
117
+ ]
118
+
119
+ if connectivity == 6:
120
+ joints = face_joints
121
+ elif connectivity == 8:
122
+ joints = corner_joints
123
+ elif connectivity == 12:
124
+ joints = corner_joints
125
+ elif connectivity == 14:
126
+ joints = face_joints + corner_joints
127
+ elif connectivity == 18:
128
+ joints = face_joints + edge_joints
129
+ elif connectivity == 20:
130
+ joints = edge_joints + corner_joints
131
+ elif connectivity == 26:
132
+ joints = face_joints + corner_joints + edge_joints
133
+ else:
134
+ raise Exception('Invalid connectivity receieved. Must be 6, 8, 12, 14, 18, 20 or 26')
135
+
136
+ I = np.arange(arr.size).reshape(arr.shape)
137
+ tails, heads = [], []
138
+ for T,H in joints:
139
+ tails.extend(T.flat)
140
+ heads.extend(H.flat)
141
+ pairs = np.vstack([tails, heads]).T
142
+
143
+ self['pore.coords'] = points
144
+ self['throat.conns'] = pairs
145
+ self['pore.all'] = np.ones(len(self['pore.coords']), dtype=bool)
146
+ self['throat.all'] = np.ones(len(self['throat.conns']), dtype=bool)
147
+ self['pore.index'] = sp.arange(0,len(self['pore.coords']))
148
+
149
+ x,y,z = self['pore.coords'].T
150
+ self['pore.internal'] = self['pore.all']
151
+ self['pore.front'] = x <= x.min()
152
+ self['pore.back'] = x >= x.max()
153
+ self['pore.left'] = y <= y.min()
154
+ self['pore.right'] = y >= y.max()
155
+ self['pore.bottom'] = z <= z.min()
156
+ self['pore.top'] = z >= z.max()
157
+
158
+ #If an image was sent as 'template', then trim network to image shape
159
+ if template is not None:
160
+ self.trim(~arr.flatten())
161
+
162
+ def add_boundaries(self):
163
+ r'''
164
+ This method uses ``clone_pores`` to clone the surface pores (labeled
165
+ 'left','right', etc), then shifts them to the periphery of the domain,
166
+ and gives them the label 'right_face', 'left_face', etc.
167
+ '''
168
+ x,y,z = self['pore.coords'].T
169
+
170
+ Lc = sp.amax(sp.diff(x)) #this currently works but is very fragile
171
+
172
+ offset = {}
173
+ offset['front'] = offset['left'] = offset['bottom'] = [0,0,0]
174
+ offset['back'] = [x.max()+Lc/2,0,0]
175
+ offset['right'] = [0,y.max()+Lc/2,0]
176
+ offset['top'] = [0,0,z.max()+Lc/2]
177
+
178
+ scale = {}
179
+ scale['front'] = scale['back'] = [0,1,1]
180
+ scale['left'] = scale['right'] = [1,0,1]
181
+ scale['bottom'] = scale['top'] = [1,1,0]
182
+
183
+ for label in ['front','back','left','right','bottom','top']:
184
+ ps = self.pores(label)
185
+ self.clone_pores(pores=ps,apply_label=[label+'_boundary','boundary'])
186
+ #Translate cloned pores
187
+ ind = self.pores(label+'_boundary')
188
+ coords = self['pore.coords'][ind]
189
+ coords = coords*scale[label] + offset[label]
190
+ self['pore.coords'][ind] = coords
191
+
192
+ def asarray(self,values):
193
+ r'''
194
+ Retreive values as a rectangular array, rather than the OpenPNM list format
195
+
196
+ Parameters
197
+ ----------
198
+ values : array_like
199
+ The values from the network (in a list) to insert into the array
200
+
201
+ Notes
202
+ -----
203
+ This method can break on networks that have had boundaries added. It
204
+ will usually work IF the list of values came only from 'internal' pores.
205
+ '''
206
+ if sp.shape(values)[0] > self.num_pores('internal'):
207
+ raise Exception('The received values are bigger than the original network')
208
+ Ps = sp.array(self['pore.index'][self.pores('internal')],dtype=int)
209
+ arr = sp.ones(self._shape)*sp.nan
210
+ ind = sp.unravel_index(Ps,self._shape)
211
+ arr[ind[0],ind[1],ind[2]] = values
212
+ return arr
213
+
214
+ def fromarray(self,array,propname):
215
+ r'''
216
+ Apply data to the network based on a rectangular array filled with
217
+ values. Each array location corresponds to a pore in the network.
218
+
219
+ Parameters
220
+ ----------
221
+ array : array_like
222
+ The rectangular array containing the values to be added to the
223
+ network. This array must be the same shape as the original network.
224
+
225
+ propname : string
226
+ The name of the pore property being added.
227
+ '''
228
+ array = sp.atleast_3d(array)
229
+ if sp.shape(array) != self._shape:
230
+ raise Exception('The received array does not match the original network')
231
+ temp = array.flatten()
232
+ Ps = sp.array(self['pore.index'][self.pores('internal')],dtype=int)
233
+ propname = 'pore.' + propname.split('.')[-1]
234
+ self[propname] = sp.nan
235
+ self[propname][self.pores('internal')] = temp[Ps]
236
+
237
+ def domain_length(self,face_1,face_2):
238
+ r'''
239
+ Calculate the distance between two faces of the network
240
+
241
+ Parameters
242
+ ----------
243
+ face_1 and face_2 : array_like
244
+ Lists of pores belonging to opposite faces of the network
245
+
246
+ Returns
247
+ -------
248
+ The length of the domain in the specified direction
249
+
250
+ Notes
251
+ -----
252
+ - Does not yet check if input faces are perpendicular to each other
253
+ '''
254
+ #Ensure given points are coplanar before proceeding
255
+ if misc.iscoplanar(self['pore.coords'][face_1]) and misc.iscoplanar(self['pore.coords'][face_2]):
256
+ #Find distance between given faces
257
+ x = self['pore.coords'][face_1]
258
+ y = self['pore.coords'][face_2]
259
+ Ds = misc.dist(x,y)
260
+ L = sp.median(sp.amin(Ds,axis=0))
261
+ else:
262
+ logger.warning('The supplied pores are not coplanar. Length will be approximate.')
263
+ f1 = self['pore.coords'][face_1]
264
+ f2 = self['pore.coords'][face_2]
265
+ distavg = [0,0,0]
266
+ distavg[0] = sp.absolute(sp.average(f1[:,0]) - sp.average(f2[:,0]))
267
+ distavg[1] = sp.absolute(sp.average(f1[:,1]) - sp.average(f2[:,1]))
268
+ distavg[2] = sp.absolute(sp.average(f1[:,2]) - sp.average(f2[:,2]))
269
+ L = max(distavg)
270
+ return L
271
+
272
+
273
+ def domain_area(self,face):
274
+ r'''
275
+ Calculate the area of a given network face
276
+
277
+ Parameters
278
+ ----------
279
+ face : array_like
280
+ List of pores of pore defining the face of interest
281
+
282
+ Returns
283
+ -------
284
+ The area of the specified face
285
+ '''
286
+ coords = self['pore.coords'][face]
287
+ rads = self['pore.diameter'][face]/2.
288
+ # calculate the area of the 3 principle faces of the bounding cuboid
289
+ dx = max(coords[:,0]+rads) - min(coords[:,0]-rads)
290
+ dy = max(coords[:,1]+rads) - min(coords[:,1]-rads)
291
+ dz = max(coords[:,2]+rads) - min(coords[:,2]-rads)
292
+ yz = dy*dz # x normal
293
+ xz = dx*dz # y normal
294
+ xy = dx*dy # z normal
295
+ # find the directions parallel to the plane
296
+ directions = sp.where([yz,xz,xy]!=max([yz,xz,xy]))[0]
297
+ try:
298
+ # now, use the whole network to do the area calculation
299
+ coords = self['pore.coords']
300
+ rads = self['pore.diameter']/2.
301
+ d0 = (max(coords[:,directions[0]]+rads) - min(coords[:,directions[0]]-rads))
302
+ d1 = (max(coords[:,directions[1]]+rads) - min(coords[:,directions[1]]-rads))
303
+ A = d0*d1
304
+ except:
305
+ # if that fails, use the max face area of the bounding cuboid
306
+ A = max([yz,xz,xy])
307
+ if not misc.iscoplanar(self['pore.coords'][face]):
308
+ logger.warning('The supplied pores are not coplanar. Area will be approximate')
309
+ pass
310
+ return A
311
+
312
+
313
+ if __name__ == '__main__':
314
+ import doctest
315
+ doctest.testmod(verbose=True)
316
+
@@ -0,0 +1,127 @@
1
+ """
2
+ ===============================================================================
3
+ DelaunayCubic: Generate semi-random networks based on Delaunay Tessellations and perturbed cubic lattices
4
+ ===============================================================================
5
+
6
+ """
7
+ import OpenPNM
8
+ import scipy as sp
9
+ import sys
10
+ import numpy as np
11
+ from OpenPNM.Network.__Delaunay__ import Delaunay
12
+ from OpenPNM.Base import logging
13
+ logger = logging.getLogger(__name__)
14
+
15
+ class DelaunayCubic(Delaunay):
16
+ r"""
17
+ This class contains the methods for creating a *Delaunay* network topology
18
+ based connecting pores with a Delaunay tessellation.
19
+
20
+ This Subclass of Delaunay generates points on a cubic lattice and then perturbs them to prevent degeneracy
21
+
22
+
23
+ Parameters
24
+ ----------
25
+ name : string
26
+ A unique name for the network
27
+
28
+ Examples
29
+ --------
30
+ >>> import OpenPNM
31
+ >>> pn = OpenPNM.Network.DelaunayCubic(shape=[5,5,5], spacing=[4e-5,4e-5,4e-5],jiggle_factor=0.01)
32
+ >>> pn.num_pores()
33
+ 125
34
+
35
+ """
36
+
37
+ def __init__(self,shape=None, template=None, spacing=[1,1,1],jiggle_factor=0.1,arrangement='SC',**kwargs):
38
+ '''
39
+ Create Delauny network object
40
+ '''
41
+ if shape is not None:
42
+ self._arr = np.atleast_3d(np.empty(shape))
43
+ elif template is not None:
44
+ self._arr = sp.array(template,ndmin=3,dtype=bool)
45
+ else:
46
+ self._arr = np.atleast_3d(np.empty([3,3,3]))
47
+
48
+ self._shape = sp.shape(self._arr) # Store original network shape
49
+ self._spacing = sp.asarray(spacing) # Store network spacing instead of calculating it
50
+ self._num_pores = np.prod(np.asarray(self._shape))
51
+ self._domain_size = np.asarray(self._shape)*self._spacing
52
+ self._jiggle_factor = jiggle_factor
53
+ self._arrangement = arrangement
54
+ super(DelaunayCubic,self).__init__(num_pores=self._num_pores,domain_size=self._domain_size,**kwargs)
55
+
56
+
57
+ def _generate_pores(self):
58
+ r"""
59
+ Generate the pores with numbering scheme.
60
+ """
61
+
62
+ points = np.array([i for i,v in np.ndenumerate(self._arr)], dtype=float)
63
+ points += 0.5
64
+
65
+ "-----------------------------------------------------------------------------------"
66
+ "2D Orthorhombic adjustment - shift even rows back a bit and odd rows forward a bit"
67
+ " 0 0 0 "
68
+ " 0 0 0 0 "
69
+ " 0 0 0 "
70
+ if self._arrangement == 'O':
71
+ shift_y=np.array([0,0.25,0])
72
+ shift_x=np.array([0.25,0,0])
73
+ points[(points[:,0] % 2 == 0)] -= shift_y
74
+ points[(points[:,2] % 2 != 0)] -= shift_x
75
+ points[(points[:,0] % 2 != 0)] += shift_y
76
+ points[(points[:,2] % 2 == 0)] += shift_x
77
+ "-----------------------------------------------------------------------------------"
78
+ "BCC = Body Centre Cubic "
79
+ if self._arrangement == 'BCC':
80
+ body_points=[]
81
+ for i in range(1,self._shape[0]):
82
+ for j in range(1,self._shape[1]):
83
+ for k in range(1,self._shape[2]):
84
+ body_points.append([i,j,k])
85
+ body_points = np.asarray(body_points)
86
+ points = np.concatenate((points,body_points))
87
+ "-----------------------------------------------------------------------------------"
88
+ "FCC = Face Centre Cubic "
89
+ if self._arrangement == 'FCC':
90
+ face_points=[]
91
+ for i in range(1,self._shape[0]):
92
+ for j in range(1,self._shape[1]):
93
+ for k in range(1,self._shape[2]):
94
+ left = [i-0.5,j,k]
95
+ right = [i+0.5,j,k]
96
+ back = [i,j-0.5,k]
97
+ front = [i,j+0.5,k]
98
+ bottom = [i,j,k-0.5]
99
+ top = [i,j,k+0.5]
100
+ if left not in face_points:
101
+ face_points.append(left)
102
+ if right not in face_points:
103
+ face_points.append(right)
104
+ if back not in face_points:
105
+ face_points.append(back)
106
+ if front not in face_points:
107
+ face_points.append(front)
108
+ if bottom not in face_points:
109
+ face_points.append(bottom)
110
+ if top not in face_points:
111
+ face_points.append(top)
112
+ face_points = np.asarray(face_points)
113
+ points = np.concatenate((points,face_points))
114
+
115
+ jiggle = (np.random.rand(len(points),3)-0.5)*self._jiggle_factor
116
+ points += jiggle
117
+ points *= self._spacing
118
+
119
+ self['pore.coords'] = points
120
+ logger.debug(sys._getframe().f_code.co_name+": End of method")
121
+
122
+
123
+
124
+ if __name__ == '__main__':
125
+ #Run doc tests
126
+ import doctest
127
+ doctest.testmod(verbose=True)