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.
- OpenPNM-1.1/MANIFEST.in +2 -0
- OpenPNM-1.1/OpenPNM/Algorithms/__FickianDiffusion__.py +67 -0
- OpenPNM-1.1/OpenPNM/Algorithms/__FourierConduction__.py +63 -0
- OpenPNM-1.1/OpenPNM/Algorithms/__GenericAlgorithm__.py +235 -0
- OpenPNM-1.1/OpenPNM/Algorithms/__GenericLinearTransport__.py +641 -0
- OpenPNM-1.1/OpenPNM/Algorithms/__InvasionPercolationForImbibition__.py +703 -0
- OpenPNM-1.1/OpenPNM/Algorithms/__InvasionPercolationTimed__.py +702 -0
- OpenPNM-1.1/OpenPNM/Algorithms/__InvasionPercolation__.py +156 -0
- OpenPNM-1.1/OpenPNM/Algorithms/__OhmicConduction__.py +64 -0
- OpenPNM-1.1/OpenPNM/Algorithms/__OrdinaryPercolation__.py +402 -0
- OpenPNM-1.1/OpenPNM/Algorithms/__StokesFlow__.py +64 -0
- OpenPNM-1.1/OpenPNM/Algorithms/__Tortuosity__.py +91 -0
- OpenPNM-1.1/OpenPNM/Algorithms/__init__.py +48 -0
- OpenPNM-1.1/OpenPNM/Base/__Controller__.py +480 -0
- OpenPNM-1.1/OpenPNM/Base/__Core__.py +1522 -0
- OpenPNM-1.1/OpenPNM/Base/__ModelsDict__.py +345 -0
- OpenPNM-1.1/OpenPNM/Base/__Tools__.py +72 -0
- OpenPNM-1.1/OpenPNM/Base/__init__.py +32 -0
- OpenPNM-1.1/OpenPNM/Geometry/__Boundary__.py +80 -0
- OpenPNM-1.1/OpenPNM/Geometry/__Cube_and_Cuboid__.py +64 -0
- OpenPNM-1.1/OpenPNM/Geometry/__GenericGeometry__.py +106 -0
- OpenPNM-1.1/OpenPNM/Geometry/__SGL10__.py +67 -0
- OpenPNM-1.1/OpenPNM/Geometry/__Stick_and_Ball__.py +68 -0
- OpenPNM-1.1/OpenPNM/Geometry/__TestGeometry__.py +51 -0
- OpenPNM-1.1/OpenPNM/Geometry/__Toray090__.py +68 -0
- OpenPNM-1.1/OpenPNM/Geometry/__Voronoi__.py +98 -0
- OpenPNM-1.1/OpenPNM/Geometry/__init__.py +47 -0
- OpenPNM-1.1/OpenPNM/Geometry/models/__init__.py +33 -0
- OpenPNM-1.1/OpenPNM/Geometry/models/pore_area.py +27 -0
- OpenPNM-1.1/OpenPNM/Geometry/models/pore_centroid.py +35 -0
- OpenPNM-1.1/OpenPNM/Geometry/models/pore_diameter.py +127 -0
- OpenPNM-1.1/OpenPNM/Geometry/models/pore_misc.py +55 -0
- OpenPNM-1.1/OpenPNM/Geometry/models/pore_seed.py +212 -0
- OpenPNM-1.1/OpenPNM/Geometry/models/pore_surface_area.py +28 -0
- OpenPNM-1.1/OpenPNM/Geometry/models/pore_vertices.py +19 -0
- OpenPNM-1.1/OpenPNM/Geometry/models/pore_volume.py +133 -0
- OpenPNM-1.1/OpenPNM/Geometry/models/throat_area.py +47 -0
- OpenPNM-1.1/OpenPNM/Geometry/models/throat_centroid.py +80 -0
- OpenPNM-1.1/OpenPNM/Geometry/models/throat_diameter.py +106 -0
- OpenPNM-1.1/OpenPNM/Geometry/models/throat_length.py +95 -0
- OpenPNM-1.1/OpenPNM/Geometry/models/throat_misc.py +42 -0
- OpenPNM-1.1/OpenPNM/Geometry/models/throat_normal.py +31 -0
- OpenPNM-1.1/OpenPNM/Geometry/models/throat_offset_vertices.py +191 -0
- OpenPNM-1.1/OpenPNM/Geometry/models/throat_perimeter.py +26 -0
- OpenPNM-1.1/OpenPNM/Geometry/models/throat_seed.py +12 -0
- OpenPNM-1.1/OpenPNM/Geometry/models/throat_shape_factor.py +37 -0
- OpenPNM-1.1/OpenPNM/Geometry/models/throat_surface_area.py +44 -0
- OpenPNM-1.1/OpenPNM/Geometry/models/throat_vector.py +27 -0
- OpenPNM-1.1/OpenPNM/Geometry/models/throat_vertices.py +19 -0
- OpenPNM-1.1/OpenPNM/Geometry/models/throat_volume.py +45 -0
- OpenPNM-1.1/OpenPNM/Network/__Cubic__.py +316 -0
- OpenPNM-1.1/OpenPNM/Network/__DelaunayCubic__.py +127 -0
- OpenPNM-1.1/OpenPNM/Network/__Delaunay__.py +600 -0
- OpenPNM-1.1/OpenPNM/Network/__GenericNetwork__.py +1184 -0
- OpenPNM-1.1/OpenPNM/Network/__MatFile__.py +331 -0
- OpenPNM-1.1/OpenPNM/Network/__TestNet__.py +109 -0
- OpenPNM-1.1/OpenPNM/Network/__init__.py +40 -0
- OpenPNM-1.1/OpenPNM/Network/models/__init__.py +12 -0
- OpenPNM-1.1/OpenPNM/Network/models/pore_topology.py +106 -0
- OpenPNM-1.1/OpenPNM/Phases/__Air__.py +63 -0
- OpenPNM-1.1/OpenPNM/Phases/__GenericPhase__.py +146 -0
- OpenPNM-1.1/OpenPNM/Phases/__Mercury__.py +71 -0
- OpenPNM-1.1/OpenPNM/Phases/__TestPhase__.py +46 -0
- OpenPNM-1.1/OpenPNM/Phases/__Water__.py +56 -0
- OpenPNM-1.1/OpenPNM/Phases/__init__.py +38 -0
- OpenPNM-1.1/OpenPNM/Phases/models/__init__.py +22 -0
- OpenPNM-1.1/OpenPNM/Phases/models/contact_angle.py +34 -0
- OpenPNM-1.1/OpenPNM/Phases/models/density.py +81 -0
- OpenPNM-1.1/OpenPNM/Phases/models/diffusivity.py +95 -0
- OpenPNM-1.1/OpenPNM/Phases/models/electrical_conductivity.py +10 -0
- OpenPNM-1.1/OpenPNM/Phases/models/misc.py +125 -0
- OpenPNM-1.1/OpenPNM/Phases/models/molar_density.py +69 -0
- OpenPNM-1.1/OpenPNM/Phases/models/molar_mass.py +31 -0
- OpenPNM-1.1/OpenPNM/Phases/models/surface_tension.py +104 -0
- OpenPNM-1.1/OpenPNM/Phases/models/thermal_conductivity.py +98 -0
- OpenPNM-1.1/OpenPNM/Phases/models/vapor_pressure.py +69 -0
- OpenPNM-1.1/OpenPNM/Phases/models/viscosity.py +103 -0
- OpenPNM-1.1/OpenPNM/Physics/__GenericPhysics__.py +111 -0
- OpenPNM-1.1/OpenPNM/Physics/__Standard__.py +51 -0
- OpenPNM-1.1/OpenPNM/Physics/__TestPhysics__.py +50 -0
- OpenPNM-1.1/OpenPNM/Physics/__init__.py +30 -0
- OpenPNM-1.1/OpenPNM/Physics/models/__init__.py +18 -0
- OpenPNM-1.1/OpenPNM/Physics/models/capillary_pressure.py +122 -0
- OpenPNM-1.1/OpenPNM/Physics/models/diffusive_conductance.py +82 -0
- OpenPNM-1.1/OpenPNM/Physics/models/electrical_conductance.py +59 -0
- OpenPNM-1.1/OpenPNM/Physics/models/generic_source_term.py +564 -0
- OpenPNM-1.1/OpenPNM/Physics/models/hydraulic_conductance.py +76 -0
- OpenPNM-1.1/OpenPNM/Physics/models/multiphase.py +133 -0
- OpenPNM-1.1/OpenPNM/Physics/models/thermal_conductance.py +67 -0
- OpenPNM-1.1/OpenPNM/Postprocessing/Graphics.py +251 -0
- OpenPNM-1.1/OpenPNM/Postprocessing/Plots.py +369 -0
- OpenPNM-1.1/OpenPNM/Postprocessing/__init__.py +10 -0
- OpenPNM-1.1/OpenPNM/Utilities/IO.py +277 -0
- OpenPNM-1.1/OpenPNM/Utilities/Shortcuts.py +17 -0
- OpenPNM-1.1/OpenPNM/Utilities/__init__.py +16 -0
- OpenPNM-1.1/OpenPNM/Utilities/misc.py +226 -0
- OpenPNM-1.1/OpenPNM/Utilities/transformations.py +1923 -0
- OpenPNM-1.1/OpenPNM/Utilities/vertexops.py +824 -0
- OpenPNM-1.1/OpenPNM/__init__.py +56 -0
- OpenPNM-1.1/OpenPNM.egg-info/PKG-INFO +11 -0
- OpenPNM-1.1/OpenPNM.egg-info/SOURCES.txt +107 -0
- OpenPNM-1.1/OpenPNM.egg-info/dependency_links.txt +1 -0
- OpenPNM-1.1/OpenPNM.egg-info/requires.txt +1 -0
- OpenPNM-1.1/OpenPNM.egg-info/top_level.txt +1 -0
- OpenPNM-1.1/PKG-INFO +11 -0
- OpenPNM-1.1/README.txt +88 -0
- OpenPNM-1.1/setup.cfg +7 -0
- OpenPNM-1.1/setup.py +39 -0
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
r"""
|
|
2
|
+
===============================================================================
|
|
3
|
+
Submodule -- generic_source_term
|
|
4
|
+
===============================================================================
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import scipy as _sp
|
|
9
|
+
|
|
10
|
+
def linear(physics,
|
|
11
|
+
phase,
|
|
12
|
+
A1='',
|
|
13
|
+
A2='',
|
|
14
|
+
x='',
|
|
15
|
+
return_rate=True,
|
|
16
|
+
**kwargs):
|
|
17
|
+
r"""
|
|
18
|
+
For the following source term:
|
|
19
|
+
.. math::
|
|
20
|
+
r = A_{1} x + A_{2}
|
|
21
|
+
If return_rate is True, it returns the value of source term for the provided x in each pore.
|
|
22
|
+
If return_rate is False, it calculates the slope and intercept for the following linear form :
|
|
23
|
+
.. math::
|
|
24
|
+
r = S_{1} x + S_{2}
|
|
25
|
+
|
|
26
|
+
Parameters
|
|
27
|
+
----------
|
|
28
|
+
A1 , A2 : string
|
|
29
|
+
The property name of the coefficients in the source term model. With A2 set to zero
|
|
30
|
+
this equation takes on the familiar for of r=kx.
|
|
31
|
+
x : string or float/int or array/list
|
|
32
|
+
The property name or numerical value or array for the main quantity
|
|
33
|
+
Notes
|
|
34
|
+
-----
|
|
35
|
+
Because this source term is linear in concentration (x) is it not necessary
|
|
36
|
+
to iterate during the solver step. Thus, when using the
|
|
37
|
+
``set_source_term`` method for an algorithm, it is recommended to set the ``maxiter``
|
|
38
|
+
argument to 0. This will save 1 unncessary solution of the system, since
|
|
39
|
+
the solution would coverge after the first pass anyway.
|
|
40
|
+
|
|
41
|
+
"""
|
|
42
|
+
if x=='':
|
|
43
|
+
X = _sp.ones(physics.Np)*_sp.nan
|
|
44
|
+
else:
|
|
45
|
+
if type(x)==str:
|
|
46
|
+
x = 'pore.'+x.split('.')[-1]
|
|
47
|
+
try: X = physics[x]
|
|
48
|
+
except: raise Exception(physics.name+' does not have the pore property :'+x+'!')
|
|
49
|
+
else:
|
|
50
|
+
X = _sp.array(x)
|
|
51
|
+
|
|
52
|
+
length_X = _sp.size(X)
|
|
53
|
+
if length_X!=physics.Np:
|
|
54
|
+
if length_X==1:
|
|
55
|
+
X = X*_sp.ones(physics.Np)
|
|
56
|
+
elif length_X>=phase.Np:
|
|
57
|
+
X = X[physics.map_pores()]
|
|
58
|
+
else: raise Exception('Wrong size for the numerical array of x!')
|
|
59
|
+
|
|
60
|
+
if A1 == '': a1 = 0
|
|
61
|
+
else:
|
|
62
|
+
if type(A1)==str:
|
|
63
|
+
A1 = 'pore.'+A1.split('.')[-1]
|
|
64
|
+
try: a1 = physics[A1]
|
|
65
|
+
except: raise Exception(physics.name+'/'+phase.name+' does not have the pore property :'+A1+'!')
|
|
66
|
+
else: raise Exception('A1 can be only string!')
|
|
67
|
+
|
|
68
|
+
if A2 == '': a2 = 0
|
|
69
|
+
else:
|
|
70
|
+
if type(A2)==str:
|
|
71
|
+
A2 = 'pore.'+A2.split('.')[-1]
|
|
72
|
+
try: a2 = physics[A2]
|
|
73
|
+
except: raise Exception(physics.name+'/'+phase.name+' does not have the pore property :'+A2+'!')
|
|
74
|
+
else: raise Exception('A2 can be only string!')
|
|
75
|
+
|
|
76
|
+
if return_rate:
|
|
77
|
+
return(a1*X**a2)
|
|
78
|
+
else:
|
|
79
|
+
S1 = a1
|
|
80
|
+
S2 = a2
|
|
81
|
+
return(_sp.vstack((S1,S2)).T)
|
|
82
|
+
|
|
83
|
+
def power_law(physics,
|
|
84
|
+
phase,
|
|
85
|
+
A1='',
|
|
86
|
+
A2='',
|
|
87
|
+
A3='',
|
|
88
|
+
x='',
|
|
89
|
+
return_rate=True,
|
|
90
|
+
**kwargs):
|
|
91
|
+
r"""
|
|
92
|
+
For the following source term:
|
|
93
|
+
.. math::
|
|
94
|
+
r = A_{1} x^{A_{2}} + A_{3}
|
|
95
|
+
If return_rate is True, it returns the value of source term for the provided x in each pore.
|
|
96
|
+
If return_rate is False, it calculates the slope and intercept for the following linear form :
|
|
97
|
+
.. math::
|
|
98
|
+
r = S_{1} x + S_{2}
|
|
99
|
+
|
|
100
|
+
Parameters
|
|
101
|
+
----------
|
|
102
|
+
A1 -> A3 : string
|
|
103
|
+
The property name of the coefficients in the source term model
|
|
104
|
+
x : string or float/int or array/list
|
|
105
|
+
The property name or numerical value or array for the main quantity
|
|
106
|
+
Notes
|
|
107
|
+
-----
|
|
108
|
+
|
|
109
|
+
"""
|
|
110
|
+
if x=='':
|
|
111
|
+
X = _sp.ones(physics.Np)*_sp.nan
|
|
112
|
+
# length_X = _sp.size(x)
|
|
113
|
+
else:
|
|
114
|
+
if type(x)==str:
|
|
115
|
+
x = 'pore.'+x.split('.')[-1]
|
|
116
|
+
try: X = physics[x]
|
|
117
|
+
except: raise Exception(physics.name+' does not have the pore property :'+x+'!')
|
|
118
|
+
else:
|
|
119
|
+
X = _sp.array(x)
|
|
120
|
+
|
|
121
|
+
length_X = _sp.size(X)
|
|
122
|
+
if length_X!=physics.Np:
|
|
123
|
+
if length_X==1:
|
|
124
|
+
X = X*_sp.ones(physics.Np)
|
|
125
|
+
elif length_X>=phase.Np:
|
|
126
|
+
X = X[physics.map_pores()]
|
|
127
|
+
else: raise Exception('Wrong size for the numerical array of x!')
|
|
128
|
+
|
|
129
|
+
if A1 == '': a1 = 0
|
|
130
|
+
else:
|
|
131
|
+
if type(A1)==str:
|
|
132
|
+
A1 = 'pore.'+A1.split('.')[-1]
|
|
133
|
+
try: a1 = physics[A1]
|
|
134
|
+
except: raise Exception(physics.name+'/'+phase.name+' does not have the pore property :'+A1+'!')
|
|
135
|
+
else: raise Exception('A1 can be only string!')
|
|
136
|
+
|
|
137
|
+
if A2 == '': a2 = 0
|
|
138
|
+
else:
|
|
139
|
+
if type(A2)==str:
|
|
140
|
+
A2 = 'pore.'+A2.split('.')[-1]
|
|
141
|
+
try: a2 = physics[A2]
|
|
142
|
+
except: raise Exception(physics.name+'/'+phase.name+' does not have the pore property :'+A2+'!')
|
|
143
|
+
else: raise Exception('A2 can be only string!')
|
|
144
|
+
|
|
145
|
+
if A3 == '': a3 = 0
|
|
146
|
+
else:
|
|
147
|
+
if type(A3)==str:
|
|
148
|
+
A3 = 'pore.'+A3.split('.')[-1]
|
|
149
|
+
try: a3 = physics[A3]
|
|
150
|
+
except: raise Exception(physics.name+'/'+phase.name+' does not have the pore property :'+A3+'!')
|
|
151
|
+
else: raise Exception('A3 can be only string!')
|
|
152
|
+
|
|
153
|
+
if return_rate:
|
|
154
|
+
return(a1*X**a2 +a3)
|
|
155
|
+
else:
|
|
156
|
+
S1 = a1*a2*X**(a2-1)
|
|
157
|
+
S2 = a1*X**a2*(1-a2)+a3
|
|
158
|
+
return(_sp.vstack((S1,S2)).T)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def exponential(physics,
|
|
162
|
+
phase,
|
|
163
|
+
A1='',
|
|
164
|
+
A2='',
|
|
165
|
+
A3='',
|
|
166
|
+
A4='',
|
|
167
|
+
A5='',
|
|
168
|
+
A6='',
|
|
169
|
+
x='',
|
|
170
|
+
return_rate=True,
|
|
171
|
+
**kwargs):
|
|
172
|
+
r"""
|
|
173
|
+
For the following source term:
|
|
174
|
+
.. math::
|
|
175
|
+
r = A_{1} A_{2}^{( A_{3} x^{ A_{4} } + A_{5})} + A_{6}
|
|
176
|
+
If return_rate is True, it returns the value of source term for the provided x in each pore.
|
|
177
|
+
If return_rate is False, it calculates the slope and intercept for the following linear form :
|
|
178
|
+
.. math::
|
|
179
|
+
r = S_{1} x + S_{2}
|
|
180
|
+
|
|
181
|
+
Parameters
|
|
182
|
+
----------
|
|
183
|
+
A1 -> A6 : string
|
|
184
|
+
The property name of the coefficients in the source term model
|
|
185
|
+
x : string or float/int or array/list
|
|
186
|
+
The property name or numerical value or array for the main quantity
|
|
187
|
+
Notes
|
|
188
|
+
-----
|
|
189
|
+
|
|
190
|
+
"""
|
|
191
|
+
if x=='':
|
|
192
|
+
X = _sp.ones(physics.Np)*_sp.nan
|
|
193
|
+
# length_X = _sp.size(x)
|
|
194
|
+
else:
|
|
195
|
+
if type(x)==str:
|
|
196
|
+
x = 'pore.'+x.split('.')[-1]
|
|
197
|
+
try: X = physics[x]
|
|
198
|
+
except: raise Exception(physics.name+' does not have the pore property :'+x+'!')
|
|
199
|
+
else:
|
|
200
|
+
X = _sp.array(x)
|
|
201
|
+
|
|
202
|
+
length_X = _sp.size(X)
|
|
203
|
+
if length_X!=physics.Np:
|
|
204
|
+
if length_X==1:
|
|
205
|
+
X = X*_sp.ones(physics.Np)
|
|
206
|
+
elif length_X>=phase.Np:
|
|
207
|
+
X = X[physics.map_pores()]
|
|
208
|
+
else: raise Exception('Wrong size for the numerical array of x!')
|
|
209
|
+
|
|
210
|
+
if A1 == '': a1 = 1
|
|
211
|
+
else:
|
|
212
|
+
if type(A1)==str:
|
|
213
|
+
A1 = 'pore.'+A1.split('.')[-1]
|
|
214
|
+
try: a1 = physics[A1]
|
|
215
|
+
except: raise Exception(physics.name+'/'+phase.name+' does not have the pore property :'+A1+'!')
|
|
216
|
+
else: raise Exception('A1 can be only string!')
|
|
217
|
+
|
|
218
|
+
if A2 == '': a2 = 0
|
|
219
|
+
else:
|
|
220
|
+
if type(A2)==str:
|
|
221
|
+
A2 = 'pore.'+A2.split('.')[-1]
|
|
222
|
+
try: a2 = physics[A2]
|
|
223
|
+
except: raise Exception(physics.name+'/'+phase.name+' does not have the pore property :'+A2+'!')
|
|
224
|
+
else: raise Exception('A2 can be only string!')
|
|
225
|
+
|
|
226
|
+
if A3 == '': a3 = 0
|
|
227
|
+
else:
|
|
228
|
+
if type(A3)==str:
|
|
229
|
+
A3 = 'pore.'+A3.split('.')[-1]
|
|
230
|
+
try: a3 = physics[A3]
|
|
231
|
+
except: raise Exception(physics.name+'/'+phase.name+' does not have the pore property :'+A3+'!')
|
|
232
|
+
else: raise Exception('A3 can be only string!')
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
if A4 == '': a4 = 0
|
|
236
|
+
else:
|
|
237
|
+
if type(A4)==str:
|
|
238
|
+
A4 = 'pore.'+A4.split('.')[-1]
|
|
239
|
+
try: a4 = physics[A4]
|
|
240
|
+
except: raise Exception(physics.name+'/'+phase.name+' does not have the pore property :'+A4+'!')
|
|
241
|
+
else: raise Exception('A4 can be only string!')
|
|
242
|
+
|
|
243
|
+
if A5 == '': a5 = 0
|
|
244
|
+
else:
|
|
245
|
+
if type(A5)==str:
|
|
246
|
+
A5 = 'pore.'+A5.split('.')[-1]
|
|
247
|
+
try: a5 = physics[A5]
|
|
248
|
+
except: raise Exception(physics.name+'/'+phase.name+' does not have the pore property :'+A5+'!')
|
|
249
|
+
else: raise Exception('A5 can be only string!')
|
|
250
|
+
|
|
251
|
+
if A6 == '': a6 = 0
|
|
252
|
+
else:
|
|
253
|
+
if type(A6)==str:
|
|
254
|
+
A6 = 'pore.'+A6.split('.')[-1]
|
|
255
|
+
try: a6 = physics[A6]
|
|
256
|
+
except: raise Exception(physics.name+'/'+phase.name+' does not have the pore property :'+A6+'!')
|
|
257
|
+
else: raise Exception('A6 can be only string!')
|
|
258
|
+
|
|
259
|
+
if return_rate:
|
|
260
|
+
return(a1*a2**(a3*X**a4 +a5)+a6)
|
|
261
|
+
else:
|
|
262
|
+
S1 = a1*a3*a4*_sp.log(a2)*a2**(a3*X**a4+a5)*X**(a4-1)
|
|
263
|
+
S2 = a1*a2**(a3*X**a4+a5)*(1-a3*a4*_sp.log(a2)*X**a4)+a6
|
|
264
|
+
return(_sp.vstack((S1,S2)).T)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def natural_exponential(physics,
|
|
268
|
+
phase,
|
|
269
|
+
A1='',
|
|
270
|
+
A2='',
|
|
271
|
+
A3='',
|
|
272
|
+
A4='',
|
|
273
|
+
A5='',
|
|
274
|
+
x='',
|
|
275
|
+
return_rate=True,
|
|
276
|
+
**kwargs):
|
|
277
|
+
r"""
|
|
278
|
+
For the following source term:
|
|
279
|
+
.. math::
|
|
280
|
+
r = A_{1} exp( A_{2} x^{ A_{3} } + A_{4} )+ A_{5}
|
|
281
|
+
If return_rate is True, it returns the value of source term for the provided x in each pore.
|
|
282
|
+
If return_rate is False, it calculates the slope and intercept for the following linear form :
|
|
283
|
+
.. math::
|
|
284
|
+
r = S_{1} x + S_{2}
|
|
285
|
+
|
|
286
|
+
Parameters
|
|
287
|
+
----------
|
|
288
|
+
A1 -> A5 : string
|
|
289
|
+
The property name of the coefficients in the source term model
|
|
290
|
+
x : string or float/int or array/list
|
|
291
|
+
The property name or numerical value or array for the main quantity
|
|
292
|
+
Notes
|
|
293
|
+
-----
|
|
294
|
+
|
|
295
|
+
"""
|
|
296
|
+
if x=='':
|
|
297
|
+
X = _sp.ones(physics.Np)*_sp.nan
|
|
298
|
+
# length_X = _sp.size(x)
|
|
299
|
+
else:
|
|
300
|
+
if type(x)==str:
|
|
301
|
+
x = 'pore.'+x.split('.')[-1]
|
|
302
|
+
try: X = physics[x]
|
|
303
|
+
except: raise Exception(physics.name+' does not have the pore property :'+x+'!')
|
|
304
|
+
else:
|
|
305
|
+
X = _sp.array(x)
|
|
306
|
+
|
|
307
|
+
length_X = _sp.size(X)
|
|
308
|
+
if length_X!=physics.Np:
|
|
309
|
+
if length_X==1:
|
|
310
|
+
X = X*_sp.ones(physics.Np)
|
|
311
|
+
elif length_X>=phase.Np:
|
|
312
|
+
X = X[physics.map_pores()]
|
|
313
|
+
else: raise Exception('Wrong size for the numerical array of x!')
|
|
314
|
+
|
|
315
|
+
if A1 == '': a1 = 1
|
|
316
|
+
else:
|
|
317
|
+
if type(A1)==str:
|
|
318
|
+
A1 = 'pore.'+A1.split('.')[-1]
|
|
319
|
+
try: a1 = physics[A1]
|
|
320
|
+
except: raise Exception(physics.name+'/'+phase.name+' does not have the pore property :'+A1+'!')
|
|
321
|
+
else: raise Exception('A1 can be only string!')
|
|
322
|
+
|
|
323
|
+
if A2 == '': a2 = 0
|
|
324
|
+
else:
|
|
325
|
+
if type(A2)==str:
|
|
326
|
+
A2 = 'pore.'+A2.split('.')[-1]
|
|
327
|
+
try: a2 = physics[A2]
|
|
328
|
+
except: raise Exception(physics.name+'/'+phase.name+' does not have the pore property :'+A2+'!')
|
|
329
|
+
else: raise Exception('A2 can be only string!')
|
|
330
|
+
|
|
331
|
+
if A3 == '': a3 = 0
|
|
332
|
+
else:
|
|
333
|
+
if type(A3)==str:
|
|
334
|
+
A3 = 'pore.'+A3.split('.')[-1]
|
|
335
|
+
try: a3 = physics[A3]
|
|
336
|
+
except: raise Exception(physics.name+'/'+phase.name+' does not have the pore property :'+A3+'!')
|
|
337
|
+
else: raise Exception('A3 can be only string!')
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
if A4 == '': a4 = 0
|
|
341
|
+
else:
|
|
342
|
+
if type(A4)==str:
|
|
343
|
+
A4 = 'pore.'+A4.split('.')[-1]
|
|
344
|
+
try: a4 = physics[A4]
|
|
345
|
+
except: raise Exception(physics.name+'/'+phase.name+' does not have the pore property :'+A4+'!')
|
|
346
|
+
else: raise Exception('A4 can be only string!')
|
|
347
|
+
|
|
348
|
+
if A5 == '': a5 = 0
|
|
349
|
+
else:
|
|
350
|
+
if type(A5)==str:
|
|
351
|
+
A5 = 'pore.'+A5.split('.')[-1]
|
|
352
|
+
try: a5 = physics[A5]
|
|
353
|
+
except: raise Exception(physics.name+'/'+phase.name+' does not have the pore property :'+A5+'!')
|
|
354
|
+
else: raise Exception('A5 can be only string!')
|
|
355
|
+
|
|
356
|
+
if return_rate:
|
|
357
|
+
return(a1*_sp.exp(a2*X**a3+a4) +a5)
|
|
358
|
+
else:
|
|
359
|
+
S1 = a1*a2*a3*X**(a3-1)*_sp.exp(a2*X**a3+a4)
|
|
360
|
+
S2 = a1*_sp.exp(a2*X**a3+a4)*(1-a2*a3*X**a3)+a5
|
|
361
|
+
return(_sp.vstack((S1,S2)).T)
|
|
362
|
+
|
|
363
|
+
def logarithm(physics,
|
|
364
|
+
phase,
|
|
365
|
+
A1='',
|
|
366
|
+
A2='',
|
|
367
|
+
A3='',
|
|
368
|
+
A4='',
|
|
369
|
+
A5='',
|
|
370
|
+
A6='',
|
|
371
|
+
x='',
|
|
372
|
+
return_rate=True,
|
|
373
|
+
**kwargs):
|
|
374
|
+
r"""
|
|
375
|
+
For the following source term:
|
|
376
|
+
.. math::
|
|
377
|
+
r = A_{1} Log_{ A_{2} }( A_{3} x^{ A_{4} }+ A_{5})+ A_{6}
|
|
378
|
+
If return_rate is True, it returns the value of source term for the provided x in each pore.
|
|
379
|
+
If return_rate is False, it calculates the slope and intercept for the following linear form :
|
|
380
|
+
.. math::
|
|
381
|
+
r = S_{1} x + S_{2}
|
|
382
|
+
|
|
383
|
+
Parameters
|
|
384
|
+
----------
|
|
385
|
+
A1 -> A6 : string
|
|
386
|
+
The property name of the coefficients in the source term model
|
|
387
|
+
x : string or float/int or array/list
|
|
388
|
+
The property name or numerical value or array for the main quantity
|
|
389
|
+
Notes
|
|
390
|
+
-----
|
|
391
|
+
|
|
392
|
+
"""
|
|
393
|
+
if x=='':
|
|
394
|
+
X = _sp.ones(physics.Np)*_sp.nan
|
|
395
|
+
# length_X = _sp.size(x)
|
|
396
|
+
else:
|
|
397
|
+
if type(x)==str:
|
|
398
|
+
x = 'pore.'+x.split('.')[-1]
|
|
399
|
+
try: X = physics[x]
|
|
400
|
+
except: raise Exception(physics.name+' does not have the pore property :'+x+'!')
|
|
401
|
+
else:
|
|
402
|
+
X = _sp.array(x)
|
|
403
|
+
|
|
404
|
+
length_X = _sp.size(X)
|
|
405
|
+
if length_X!=physics.Np:
|
|
406
|
+
if length_X==1:
|
|
407
|
+
X = X*_sp.ones(physics.Np)
|
|
408
|
+
elif length_X>=phase.Np:
|
|
409
|
+
X = X[physics.map_pores()]
|
|
410
|
+
else: raise Exception('Wrong size for the numerical array of x!')
|
|
411
|
+
|
|
412
|
+
if A1 == '': a1 = 1
|
|
413
|
+
else:
|
|
414
|
+
if type(A1)==str:
|
|
415
|
+
A1 = 'pore.'+A1.split('.')[-1]
|
|
416
|
+
try: a1 = physics[A1]
|
|
417
|
+
except: raise Exception(physics.name+'/'+phase.name+' does not have the pore property :'+A1+'!')
|
|
418
|
+
else: raise Exception('A1 can be only string!')
|
|
419
|
+
|
|
420
|
+
if A2 == '': a2 = 0
|
|
421
|
+
else:
|
|
422
|
+
if type(A2)==str:
|
|
423
|
+
A2 = 'pore.'+A2.split('.')[-1]
|
|
424
|
+
try: a2 = physics[A2]
|
|
425
|
+
except: raise Exception(physics.name+'/'+phase.name+' does not have the pore property :'+A2+'!')
|
|
426
|
+
else: raise Exception('A2 can be only string!')
|
|
427
|
+
|
|
428
|
+
if A3 == '': a3 = 0
|
|
429
|
+
else:
|
|
430
|
+
if type(A3)==str:
|
|
431
|
+
A3 = 'pore.'+A3.split('.')[-1]
|
|
432
|
+
try: a3 = physics[A3]
|
|
433
|
+
except: raise Exception(physics.name+'/'+phase.name+' does not have the pore property :'+A3+'!')
|
|
434
|
+
else: raise Exception('A3 can be only string!')
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
if A4 == '': a4 = 0
|
|
438
|
+
else:
|
|
439
|
+
if type(A4)==str:
|
|
440
|
+
A4 = 'pore.'+A4.split('.')[-1]
|
|
441
|
+
try: a4 = physics[A4]
|
|
442
|
+
except: raise Exception(physics.name+'/'+phase.name+' does not have the pore property :'+A4+'!')
|
|
443
|
+
else: raise Exception('A4 can be only string!')
|
|
444
|
+
|
|
445
|
+
if A5 == '': a5 = 0
|
|
446
|
+
else:
|
|
447
|
+
if type(A5)==str:
|
|
448
|
+
A5 = 'pore.'+A5.split('.')[-1]
|
|
449
|
+
try: a5 = physics[A5]
|
|
450
|
+
except: raise Exception(physics.name+'/'+phase.name+' does not have the pore property :'+A5+'!')
|
|
451
|
+
else: raise Exception('A5 can be only string!')
|
|
452
|
+
|
|
453
|
+
if A6 == '': a6 = 0
|
|
454
|
+
else:
|
|
455
|
+
if type(A6)==str:
|
|
456
|
+
A6 = 'pore.'+A6.split('.')[-1]
|
|
457
|
+
try: a6 = physics[A6]
|
|
458
|
+
except: raise Exception(physics.name+'/'+phase.name+' does not have the pore property :'+A6+'!')
|
|
459
|
+
else: raise Exception('A6 can be only string!')
|
|
460
|
+
|
|
461
|
+
if return_rate:
|
|
462
|
+
return(a1*_sp.log(a3*X**a4 +a5)/_sp.log(a2)+a6)
|
|
463
|
+
else:
|
|
464
|
+
S1 = a1*a3*a4*X**(a4-1)/(_sp.log(a2)*(a3*X**a4+a5))
|
|
465
|
+
S2 = a1*_sp.log(a3*X**a4+a5)/_sp.log(a2)+a6-a1*a3*a4*X**a4/(_sp.log(a2)*(a3*X**a4+a5))
|
|
466
|
+
return(_sp.vstack((S1,S2)).T)
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
def natural_logarithm(physics,
|
|
470
|
+
phase,
|
|
471
|
+
A1='',
|
|
472
|
+
A2='',
|
|
473
|
+
A3='',
|
|
474
|
+
A4='',
|
|
475
|
+
A5='',
|
|
476
|
+
x='',
|
|
477
|
+
return_rate=True,
|
|
478
|
+
**kwargs):
|
|
479
|
+
r"""
|
|
480
|
+
For the following source term:
|
|
481
|
+
.. math::
|
|
482
|
+
r = A_{1} Ln( A_{2} x^{ A_{3} }+ A_{4})+ A_{5}
|
|
483
|
+
If return_rate is True, it returns the value of source term for the provided x in each pore.
|
|
484
|
+
If return_rate is False, it calculates the slope and intercept for the following linear form :
|
|
485
|
+
.. math::
|
|
486
|
+
r = S_{1} x + S_{2}
|
|
487
|
+
|
|
488
|
+
Parameters
|
|
489
|
+
----------
|
|
490
|
+
A1 -> A5 : string
|
|
491
|
+
The property name of the coefficients in the source term model
|
|
492
|
+
x : string or float/int or array/list
|
|
493
|
+
The property name or numerical value or array for the main quantity
|
|
494
|
+
Notes
|
|
495
|
+
-----
|
|
496
|
+
|
|
497
|
+
"""
|
|
498
|
+
if x=='':
|
|
499
|
+
X = _sp.ones(physics.Np)*_sp.nan
|
|
500
|
+
# length_X = _sp.size(x)
|
|
501
|
+
else:
|
|
502
|
+
if type(x)==str:
|
|
503
|
+
x = 'pore.'+x.split('.')[-1]
|
|
504
|
+
try: X = physics[x]
|
|
505
|
+
except: raise Exception(physics.name+' does not have the pore property :'+x+'!')
|
|
506
|
+
else:
|
|
507
|
+
X = _sp.array(x)
|
|
508
|
+
|
|
509
|
+
length_X = _sp.size(X)
|
|
510
|
+
if length_X!=physics.Np:
|
|
511
|
+
if length_X==1:
|
|
512
|
+
X = X*_sp.ones(physics.Np)
|
|
513
|
+
elif length_X>=phase.Np:
|
|
514
|
+
X = X[physics.map_pores()]
|
|
515
|
+
else: raise Exception('Wrong size for the numerical array of x!')
|
|
516
|
+
|
|
517
|
+
if A1 == '': a1 = 1
|
|
518
|
+
else:
|
|
519
|
+
if type(A1)==str:
|
|
520
|
+
A1 = 'pore.'+A1.split('.')[-1]
|
|
521
|
+
try: a1 = physics[A1]
|
|
522
|
+
except: raise Exception(physics.name+'/'+phase.name+' does not have the pore property :'+A1+'!')
|
|
523
|
+
else: raise Exception('A1 can be only string!')
|
|
524
|
+
|
|
525
|
+
if A2 == '': a2 = 0
|
|
526
|
+
else:
|
|
527
|
+
if type(A2)==str:
|
|
528
|
+
A2 = 'pore.'+A2.split('.')[-1]
|
|
529
|
+
try: a2 = physics[A2]
|
|
530
|
+
except: raise Exception(physics.name+'/'+phase.name+' does not have the pore property :'+A2+'!')
|
|
531
|
+
else: raise Exception('A2 can be only string!')
|
|
532
|
+
|
|
533
|
+
if A3 == '': a3 = 0
|
|
534
|
+
else:
|
|
535
|
+
if type(A3)==str:
|
|
536
|
+
A3 = 'pore.'+A3.split('.')[-1]
|
|
537
|
+
try: a3 = physics[A3]
|
|
538
|
+
except: raise Exception(physics.name+'/'+phase.name+' does not have the pore property :'+A3+'!')
|
|
539
|
+
else: raise Exception('A3 can be only string!')
|
|
540
|
+
|
|
541
|
+
|
|
542
|
+
if A4 == '': a4 = 0
|
|
543
|
+
else:
|
|
544
|
+
if type(A4)==str:
|
|
545
|
+
A4 = 'pore.'+A4.split('.')[-1]
|
|
546
|
+
try: a4 = physics[A4]
|
|
547
|
+
except: raise Exception(physics.name+'/'+phase.name+' does not have the pore property :'+A4+'!')
|
|
548
|
+
else: raise Exception('A4 can be only string!')
|
|
549
|
+
|
|
550
|
+
if A5 == '': a5 = 0
|
|
551
|
+
else:
|
|
552
|
+
if type(A5)==str:
|
|
553
|
+
A5 = 'pore.'+A5.split('.')[-1]
|
|
554
|
+
try: a5 = physics[A5]
|
|
555
|
+
except: raise Exception(physics.name+'/'+phase.name+' does not have the pore property :'+A5+'!')
|
|
556
|
+
else: raise Exception('A5 can be only string!')
|
|
557
|
+
|
|
558
|
+
|
|
559
|
+
if return_rate:
|
|
560
|
+
return(a1*_sp.log(a2*X**a3 +a4)+a5)
|
|
561
|
+
else:
|
|
562
|
+
S1 = a1*a2*a3*X**(a3-1)/(a2*X**a3+a4)
|
|
563
|
+
S2 = a1*_sp.log(a2*X**a3+a4)+a5-a1*a2*a3*X**a3/(a2*X**a3+a4)
|
|
564
|
+
return(_sp.vstack((S1,S2)).T)
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
r"""
|
|
2
|
+
===============================================================================
|
|
3
|
+
Submodule -- hydraulic_conductance
|
|
4
|
+
===============================================================================
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import scipy as _sp
|
|
9
|
+
import OpenPNM.Utilities.misc as misc
|
|
10
|
+
|
|
11
|
+
def hagen_poiseuille(physics,
|
|
12
|
+
phase,
|
|
13
|
+
network,
|
|
14
|
+
pore_diameter='pore.diameter',
|
|
15
|
+
pore_viscosity='pore.viscosity',
|
|
16
|
+
throat_length='throat.length',
|
|
17
|
+
throat_diameter='throat.diameter',
|
|
18
|
+
calc_pore_len=True,
|
|
19
|
+
**kwargs):
|
|
20
|
+
r"""
|
|
21
|
+
Calculates the hydraulic conductivity of throat assuming cylindrical
|
|
22
|
+
geometry using the Hagen-Poiseuille model
|
|
23
|
+
|
|
24
|
+
Parameters
|
|
25
|
+
----------
|
|
26
|
+
network : OpenPNM Network Object
|
|
27
|
+
|
|
28
|
+
phase : OpenPNM Phase Object
|
|
29
|
+
|
|
30
|
+
Notes
|
|
31
|
+
-----
|
|
32
|
+
(1) This function requires that all the necessary phase properties already
|
|
33
|
+
be calculated.
|
|
34
|
+
|
|
35
|
+
(2) This function calculates the specified property for the *entire*
|
|
36
|
+
network then extracts the values for the appropriate throats at the end.
|
|
37
|
+
|
|
38
|
+
"""
|
|
39
|
+
#Get Nt-by-2 list of pores connected to each throat
|
|
40
|
+
Ps = network['throat.conns']
|
|
41
|
+
#Get properties in every pore in the network
|
|
42
|
+
mup = phase[pore_viscosity]
|
|
43
|
+
mut = phase.interpolate_data(mup)
|
|
44
|
+
pdia = network[pore_diameter]
|
|
45
|
+
if calc_pore_len:
|
|
46
|
+
lengths = misc.conduit_lengths(network,mode='centroid')
|
|
47
|
+
plen1 = lengths[:,0]
|
|
48
|
+
plen2 = lengths[:,2]
|
|
49
|
+
else:
|
|
50
|
+
plen1 = (0.5*pdia[Ps[:,0]])
|
|
51
|
+
plen2 = (0.5*pdia[Ps[:,1]])
|
|
52
|
+
#remove any non-positive lengths
|
|
53
|
+
plen1[plen1<=0]=1e-12
|
|
54
|
+
plen2[plen2<=0]=1e-12
|
|
55
|
+
#Find g for half of pore 1
|
|
56
|
+
gp1 = _sp.pi*(pdia[Ps[:,0]])**4/(128*plen1*mut)
|
|
57
|
+
gp1[_sp.isnan(gp1)] = _sp.inf
|
|
58
|
+
gp1[~(gp1>0)] = _sp.inf #Set 0 conductance pores (boundaries) to inf
|
|
59
|
+
|
|
60
|
+
#Find g for half of pore 2
|
|
61
|
+
#gp2 = 2.28*(pdia[pores[:,1]]/2)**4/(pdia[pores[:,1]]*mut)
|
|
62
|
+
gp2 = _sp.pi*(pdia[Ps[:,1]])**4/(128*plen2*mut)
|
|
63
|
+
gp2[_sp.isnan(gp2)] = _sp.inf
|
|
64
|
+
gp2[~(gp2>0)] = _sp.inf #Set 0 conductance pores (boundaries) to inf
|
|
65
|
+
#Find g for full throat
|
|
66
|
+
tdia = network[throat_diameter]
|
|
67
|
+
tlen = network[throat_length]
|
|
68
|
+
#remove any non-positive lengths
|
|
69
|
+
tlen[tlen<=0] = 1e-12
|
|
70
|
+
gt = _sp.pi*(tdia)**4/(128*tlen*mut)
|
|
71
|
+
gt[~(gt>0)] = _sp.inf #Set 0 conductance pores (boundaries) to inf
|
|
72
|
+
value = (1/gt + 1/gp1 + 1/gp2)**(-1)
|
|
73
|
+
value = value[phase.throats(physics.name)]
|
|
74
|
+
return value
|
|
75
|
+
|
|
76
|
+
|