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,345 @@
|
|
|
1
|
+
'''
|
|
2
|
+
###############################################################################
|
|
3
|
+
ModelsDict: Abstract Class for Containing Models
|
|
4
|
+
###############################################################################
|
|
5
|
+
'''
|
|
6
|
+
import inspect
|
|
7
|
+
import scipy as sp
|
|
8
|
+
from collections import OrderedDict
|
|
9
|
+
from OpenPNM.Base import logging, Controller
|
|
10
|
+
logger = logging.getLogger()
|
|
11
|
+
|
|
12
|
+
class ModelWrapper(dict):
|
|
13
|
+
r"""
|
|
14
|
+
Accepts a model from the OpenPNM model library, as well as all required
|
|
15
|
+
and optional argumnents, then wraps it in a custom dictionary with
|
|
16
|
+
various methods for working with the models.
|
|
17
|
+
|
|
18
|
+
"""
|
|
19
|
+
def __init__(self,**kwargs):
|
|
20
|
+
self.update(**kwargs)
|
|
21
|
+
|
|
22
|
+
def __call__(self):
|
|
23
|
+
return self['model'](**self)
|
|
24
|
+
|
|
25
|
+
def __str__(self):
|
|
26
|
+
header = '-'*60
|
|
27
|
+
print(header)
|
|
28
|
+
print(self['model'].__module__+'.'+self['model'].__name__)
|
|
29
|
+
print(header)
|
|
30
|
+
print("{a:<20s} {b}".format(a='Argument Name',b='Value / (Default)'))
|
|
31
|
+
print(header)
|
|
32
|
+
# Scan default argument names and values of model
|
|
33
|
+
defs = {}
|
|
34
|
+
if self['model'].__defaults__ != None:
|
|
35
|
+
vals = list(inspect.getargspec(self['model']).defaults)
|
|
36
|
+
keys = inspect.getargspec(self['model']).args[-len(vals):]
|
|
37
|
+
# Put defaults into the dict
|
|
38
|
+
defs.update(zip(keys,vals))
|
|
39
|
+
keys = list(self.keys())
|
|
40
|
+
keys.sort()
|
|
41
|
+
for item in keys:
|
|
42
|
+
if item not in ['model','network','geometry','phase','physics','propname']:
|
|
43
|
+
if item not in defs.keys():
|
|
44
|
+
defs[item] = '---'
|
|
45
|
+
print("{a:<20s} {b} / ({c})".format(a=item, b=self[item], c=defs[item]))
|
|
46
|
+
print(header)
|
|
47
|
+
return ' '
|
|
48
|
+
|
|
49
|
+
def regenerate(self):
|
|
50
|
+
r'''
|
|
51
|
+
Regenerate the model
|
|
52
|
+
'''
|
|
53
|
+
master = self._find_master()
|
|
54
|
+
#Determine object type, and assign associated objects
|
|
55
|
+
self_type = [item.__name__ for item in master.__class__.__mro__]
|
|
56
|
+
kwargs = {}
|
|
57
|
+
if 'GenericGeometry' in self_type:
|
|
58
|
+
kwargs['network'] = master._net
|
|
59
|
+
kwargs['geometry'] = master
|
|
60
|
+
elif 'GenericPhase' in self_type:
|
|
61
|
+
kwargs['network'] = master._net
|
|
62
|
+
kwargs['phase'] = master
|
|
63
|
+
elif 'GenericPhysics' in self_type:
|
|
64
|
+
kwargs['network'] = master._net
|
|
65
|
+
kwargs['phase'] = master._phases[0]
|
|
66
|
+
kwargs['physics'] = master
|
|
67
|
+
else:
|
|
68
|
+
kwargs['network'] = master
|
|
69
|
+
kwargs.update(self)
|
|
70
|
+
return self['model'](**kwargs)
|
|
71
|
+
|
|
72
|
+
def _find_master(self):
|
|
73
|
+
ctrl = Controller()
|
|
74
|
+
master = []
|
|
75
|
+
for item in ctrl.keys():
|
|
76
|
+
if ctrl[item].models is not None:
|
|
77
|
+
for model in ctrl[item].models.keys():
|
|
78
|
+
if ctrl[item].models[model] is self:
|
|
79
|
+
master.append(ctrl[item])
|
|
80
|
+
if len(master) > 1:
|
|
81
|
+
raise Exception('More than one master found! This model dictionary has been associated with multiple objects. To use the same dictionary multiple times use the copy method.')
|
|
82
|
+
return master[0]
|
|
83
|
+
|
|
84
|
+
class ModelsDict(OrderedDict):
|
|
85
|
+
r"""
|
|
86
|
+
This custom dictionary stores the models that are associated with each
|
|
87
|
+
OpenPNM object. This is an ordered dict with a few additional methods.
|
|
88
|
+
This ModelsDict class can be created as a standalone object, then
|
|
89
|
+
associated with an OpenPNM object, and ModelsDicts from one object can
|
|
90
|
+
be copied and attached to another.
|
|
91
|
+
|
|
92
|
+
Examples
|
|
93
|
+
--------
|
|
94
|
+
>>> import OpenPNM
|
|
95
|
+
>>> pn = OpenPNM.Network.TestNet()
|
|
96
|
+
>>> Ps = pn.pores(labels='top',mode='not')
|
|
97
|
+
>>> geom = OpenPNM.Geometry.TestGeometry(network=pn,pores=Ps,throats=pn.Ts)
|
|
98
|
+
>>> print(geom.models) # Show models included on TestGeometry
|
|
99
|
+
------------------------------------------------------------
|
|
100
|
+
# Property Name Regeneration Mode
|
|
101
|
+
------------------------------------------------------------
|
|
102
|
+
0 pore.seed normal
|
|
103
|
+
1 throat.length normal
|
|
104
|
+
2 throat.seed normal
|
|
105
|
+
------------------------------------------------------------
|
|
106
|
+
|
|
107
|
+
It is possible to use the ModelsDict from one object with another object:
|
|
108
|
+
|
|
109
|
+
>>> Ps = pn.pores('top')
|
|
110
|
+
>>> boun = OpenPNM.Geometry.GenericGeometry(network=pn,pores=Ps)
|
|
111
|
+
>>> boun.models # The boun object has no models in its Models dict
|
|
112
|
+
ModelsDict()
|
|
113
|
+
>>> mod = geom.models.copy() # Create a copy of geom's models
|
|
114
|
+
>>> boun.models = mod # Use the same set of models on boun as geom
|
|
115
|
+
>>> print(boun.models)
|
|
116
|
+
------------------------------------------------------------
|
|
117
|
+
# Property Name Regeneration Mode
|
|
118
|
+
------------------------------------------------------------
|
|
119
|
+
0 pore.seed normal
|
|
120
|
+
1 throat.length normal
|
|
121
|
+
2 throat.seed normal
|
|
122
|
+
------------------------------------------------------------
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
"""
|
|
126
|
+
|
|
127
|
+
def __setitem__(self,propname,model):
|
|
128
|
+
temp = ModelWrapper(propname=propname,model=None)
|
|
129
|
+
temp.update(**model)
|
|
130
|
+
super(ModelsDict,self).__setitem__(propname,temp)
|
|
131
|
+
|
|
132
|
+
def __str__(self):
|
|
133
|
+
header = '-'*60
|
|
134
|
+
print(header)
|
|
135
|
+
print("{n:<5s} {a:<30s} {b:<20s}".format(n='#', a='Property Name', b='Regeneration Mode'))
|
|
136
|
+
print(header)
|
|
137
|
+
count = 0
|
|
138
|
+
for item in self.keys():
|
|
139
|
+
print("{n:<5d} {a:<30s} {b:<20s}".format(n=count, a=item, b=self[item]['regen_mode']))
|
|
140
|
+
count += 1
|
|
141
|
+
print(header)
|
|
142
|
+
return ' '
|
|
143
|
+
|
|
144
|
+
def keys(self):
|
|
145
|
+
return list(super(ModelsDict,self).keys())
|
|
146
|
+
|
|
147
|
+
def regenerate(self, props='', mode='inclusive'):
|
|
148
|
+
r'''
|
|
149
|
+
This updates properties using any models on the object that were
|
|
150
|
+
assigned using ``add_model``
|
|
151
|
+
|
|
152
|
+
Parameters
|
|
153
|
+
----------
|
|
154
|
+
props : string or list of strings
|
|
155
|
+
The names of the properties that should be updated, defaults to 'all'
|
|
156
|
+
mode : string
|
|
157
|
+
This controls which props are regenerated and how. Options are:
|
|
158
|
+
|
|
159
|
+
* 'inclusive': (default) This regenerates all given properties
|
|
160
|
+
* 'exclude': This generates all given properties EXCEPT the given ones
|
|
161
|
+
|
|
162
|
+
Examples
|
|
163
|
+
--------
|
|
164
|
+
>>> import OpenPNM
|
|
165
|
+
>>> pn = OpenPNM.Network.TestNet()
|
|
166
|
+
>>> geom = OpenPNM.Geometry.GenericGeometry(network=pn,pores=pn.pores(),throats=pn.throats())
|
|
167
|
+
>>> geom['pore.diameter'] = 1
|
|
168
|
+
>>> import OpenPNM.Geometry.models as gm # Import Geometry model library
|
|
169
|
+
>>> f = gm.pore_area.cubic
|
|
170
|
+
>>> geom.add_model(propname='pore.area',model=f) # Add model to Geometry object
|
|
171
|
+
>>> geom['pore.area'][0] # Look at area value in pore 0
|
|
172
|
+
1
|
|
173
|
+
>>> geom['pore.diameter'] = 2
|
|
174
|
+
>>> geom.models.regenerate() # Regenerate all models
|
|
175
|
+
>>> geom['pore.area'][0] # Look at pore area calculated with new diameter
|
|
176
|
+
4
|
|
177
|
+
|
|
178
|
+
'''
|
|
179
|
+
master = self._find_master()
|
|
180
|
+
if props == '': # If empty, assume all models are to be regenerated
|
|
181
|
+
props = list(self.keys())
|
|
182
|
+
for item in props: # Remove models if they are meant to be regenerated 'on_demand' only
|
|
183
|
+
if self[item]['regen_mode'] == 'on_demand':
|
|
184
|
+
props.remove(item)
|
|
185
|
+
elif type(props) == str:
|
|
186
|
+
props = [props]
|
|
187
|
+
if mode == 'exclude':
|
|
188
|
+
temp = list(self.keys())
|
|
189
|
+
for item in props:
|
|
190
|
+
temp.remove(item)
|
|
191
|
+
props = temp
|
|
192
|
+
for item in self.keys():
|
|
193
|
+
if self[item]['regen_mode'] == 'constant':
|
|
194
|
+
props.remove(item)
|
|
195
|
+
logger.info('Models are being recalculated in the following order: ')
|
|
196
|
+
count = 0
|
|
197
|
+
for item in props:
|
|
198
|
+
if item in list(self.keys()):
|
|
199
|
+
master[item] = self[item].regenerate()
|
|
200
|
+
logger.info(str(count)+' : '+item)
|
|
201
|
+
count += 1
|
|
202
|
+
else:
|
|
203
|
+
logger.warning('Requested proptery is not a dynamic model: '+item)
|
|
204
|
+
|
|
205
|
+
def add(self,propname,model,regen_mode='normal',**kwargs):
|
|
206
|
+
r'''
|
|
207
|
+
Add specified property estimation model to the object.
|
|
208
|
+
|
|
209
|
+
Parameters
|
|
210
|
+
----------
|
|
211
|
+
propname : string
|
|
212
|
+
The name of the property to use as dictionary key, such as
|
|
213
|
+
'pore.diameter' or 'throat.length'
|
|
214
|
+
|
|
215
|
+
model : function
|
|
216
|
+
The property estimation function to use
|
|
217
|
+
|
|
218
|
+
regen_mode : string
|
|
219
|
+
Controls when and if the property is regenerated. Options are:
|
|
220
|
+
|
|
221
|
+
* 'normal' : The property is stored as static data and is only regenerated when the object's ``regenerate`` is called
|
|
222
|
+
|
|
223
|
+
* 'constant' : The property is calculated once when this method is first run, but always maintains the same value
|
|
224
|
+
|
|
225
|
+
* 'deferred' : The model is stored on the object but not run until ``regenerate`` is called
|
|
226
|
+
|
|
227
|
+
* 'on_demand' : The model is stored on the object but not run, AND will only run if specifically requested in ``regenerate``
|
|
228
|
+
|
|
229
|
+
Notes
|
|
230
|
+
-----
|
|
231
|
+
This method is inherited by all net/geom/phys/phase objects. It takes
|
|
232
|
+
the received model and stores it on the object under private dictionary
|
|
233
|
+
called _models. This dict is an 'OrderedDict', so that the models can
|
|
234
|
+
be run in the same order they are added.
|
|
235
|
+
|
|
236
|
+
Examples
|
|
237
|
+
--------
|
|
238
|
+
>>> import OpenPNM
|
|
239
|
+
>>> pn = OpenPNM.Network.TestNet()
|
|
240
|
+
>>> geom = OpenPNM.Geometry.GenericGeometry(network=pn)
|
|
241
|
+
>>> import OpenPNM.Geometry.models as gm
|
|
242
|
+
>>> f = gm.pore_misc.random # Get model from Geometry library
|
|
243
|
+
>>> geom.add_model(propname='pore.seed',model=f)
|
|
244
|
+
>>> geom.models.keys() # Look in dict to verify model was added
|
|
245
|
+
['pore.seed']
|
|
246
|
+
>>> print(geom.models['pore.seed']) # Look at arguments for model
|
|
247
|
+
------------------------------------------------------------
|
|
248
|
+
OpenPNM.Geometry.models.pore_misc.random
|
|
249
|
+
------------------------------------------------------------
|
|
250
|
+
Argument Name Value / (Default)
|
|
251
|
+
------------------------------------------------------------
|
|
252
|
+
num_range [0, 1] / ([0, 1])
|
|
253
|
+
regen_mode normal / (---)
|
|
254
|
+
seed None / (None)
|
|
255
|
+
------------------------------------------------------------
|
|
256
|
+
|
|
257
|
+
'''
|
|
258
|
+
master = self._find_master()
|
|
259
|
+
if master == None:
|
|
260
|
+
logger.warning('ModelsDict has no master, changing regen_mode to deferred')
|
|
261
|
+
regen_mode = 'deferred'
|
|
262
|
+
#Build dictionary containing default model values, plus other required info
|
|
263
|
+
f = {'model':model,'regen_mode':regen_mode}
|
|
264
|
+
# Scan default argument names and values of model
|
|
265
|
+
if model.__defaults__ != None:
|
|
266
|
+
vals = list(inspect.getargspec(model).defaults)
|
|
267
|
+
keys = inspect.getargspec(model).args[-len(vals):]
|
|
268
|
+
# Put defaults into the dict
|
|
269
|
+
f.update(zip(keys,vals))
|
|
270
|
+
# Update dictionary with supplied arguments, overwriting defaults
|
|
271
|
+
f.update(**kwargs)
|
|
272
|
+
# Add model to ModelsDict
|
|
273
|
+
self[propname] = f
|
|
274
|
+
# Now generate data as necessary
|
|
275
|
+
if regen_mode in ['normal','constant']:
|
|
276
|
+
master[propname] = self[propname].regenerate()
|
|
277
|
+
if regen_mode in ['deferred','on_demand']:
|
|
278
|
+
pass
|
|
279
|
+
|
|
280
|
+
def remove(self,propname):
|
|
281
|
+
r'''
|
|
282
|
+
Removes selected model from the dictionary, as well as removing its
|
|
283
|
+
associated data from the master Core object.
|
|
284
|
+
|
|
285
|
+
Parameters
|
|
286
|
+
----------
|
|
287
|
+
propname : string
|
|
288
|
+
The name of the model to remove
|
|
289
|
+
'''
|
|
290
|
+
master = self._find_master()
|
|
291
|
+
temp = master.pop(propname,None)
|
|
292
|
+
del self[propname]
|
|
293
|
+
|
|
294
|
+
def reorder(self,new_order):
|
|
295
|
+
r'''
|
|
296
|
+
Reorders the models on the object to change the order in which they
|
|
297
|
+
are regenerated, where item 0 is calculated first.
|
|
298
|
+
|
|
299
|
+
Parameters
|
|
300
|
+
----------
|
|
301
|
+
new_order : dict
|
|
302
|
+
A dictionary containing the model name(s) as the key, and the
|
|
303
|
+
location(s) in the new order as the value
|
|
304
|
+
|
|
305
|
+
Examples
|
|
306
|
+
--------
|
|
307
|
+
>>> import OpenPNM
|
|
308
|
+
>>> pn = OpenPNM.Network.TestNet()
|
|
309
|
+
>>> geom = OpenPNM.Geometry.TestGeometry(network=pn,pores=pn.Ps,throats=pn.Ts)
|
|
310
|
+
>>> geom.models.keys()
|
|
311
|
+
['pore.seed', 'throat.seed', 'throat.length']
|
|
312
|
+
>>> geom.models.reorder({'pore.seed':1,'throat.length':0})
|
|
313
|
+
>>> geom.models.keys()
|
|
314
|
+
['throat.length', 'pore.seed', 'throat.seed']
|
|
315
|
+
|
|
316
|
+
'''
|
|
317
|
+
#Generate numbered list of current models
|
|
318
|
+
order = [item for item in list(self.keys())]
|
|
319
|
+
#Remove supplied models from list
|
|
320
|
+
for item in new_order:
|
|
321
|
+
order.remove(item)
|
|
322
|
+
#Add models back to list in new order
|
|
323
|
+
inv_dict = {v: k for k, v in new_order.items()}
|
|
324
|
+
for item in inv_dict:
|
|
325
|
+
order.insert(item,inv_dict[item])
|
|
326
|
+
#Now rebuild models OrderedDict in new order
|
|
327
|
+
for item in order:
|
|
328
|
+
self.move_to_end(item)
|
|
329
|
+
|
|
330
|
+
def _find_master(self):
|
|
331
|
+
ctrl = Controller()
|
|
332
|
+
master = []
|
|
333
|
+
for item in ctrl.keys():
|
|
334
|
+
if ctrl[item].models is self:
|
|
335
|
+
master.append(ctrl[item])
|
|
336
|
+
if len(master) > 1:
|
|
337
|
+
raise Exception('More than one master found! This model dictionary has been associated with multiple objects. To use the same dictionary multiple times use the copy method.')
|
|
338
|
+
return master[0]
|
|
339
|
+
|
|
340
|
+
if __name__ == '__main__':
|
|
341
|
+
pn = OpenPNM.Network.TestNet()
|
|
342
|
+
a = ModelsDict()
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
'''
|
|
2
|
+
###############################################################################
|
|
3
|
+
Tools: Useful classes for use throughout the project
|
|
4
|
+
###############################################################################
|
|
5
|
+
'''
|
|
6
|
+
import scipy as _sp
|
|
7
|
+
from collections import OrderedDict as _odict
|
|
8
|
+
|
|
9
|
+
class PrintableList(list):
|
|
10
|
+
def __str__(self):
|
|
11
|
+
count = 0
|
|
12
|
+
header = '-'*60
|
|
13
|
+
print('\n')
|
|
14
|
+
print(header)
|
|
15
|
+
self.sort()
|
|
16
|
+
for item in self:
|
|
17
|
+
count = count + 1
|
|
18
|
+
print(count,'\t: ',item)
|
|
19
|
+
return header
|
|
20
|
+
|
|
21
|
+
class PrintableDict(_odict):
|
|
22
|
+
def __repr__(self):
|
|
23
|
+
text = dict(self).__str__()
|
|
24
|
+
return text
|
|
25
|
+
|
|
26
|
+
def __str__(self):
|
|
27
|
+
header = '-'*60
|
|
28
|
+
print(header)
|
|
29
|
+
print("{a:<25s} {b:<25s}".format(a='key', b='value'))
|
|
30
|
+
print(header)
|
|
31
|
+
for item in self.keys():
|
|
32
|
+
print("{a:<25s} {b}".format(a=item, b=self[item]))
|
|
33
|
+
print(header)
|
|
34
|
+
return ''
|
|
35
|
+
|
|
36
|
+
class AttributVeiew(object):
|
|
37
|
+
def __init__(self, d):
|
|
38
|
+
temp = {}
|
|
39
|
+
for item in d:
|
|
40
|
+
if type(d[item][0]) == _sp.bool_:
|
|
41
|
+
key = 'label_'+item.replace('.','_')
|
|
42
|
+
else:
|
|
43
|
+
key = 'prop_'+item.replace('.','_')
|
|
44
|
+
temp[key] =d[item]
|
|
45
|
+
self.__dict__ = temp
|
|
46
|
+
|
|
47
|
+
class ClonedCore(dict):
|
|
48
|
+
def __init__(self,obj):
|
|
49
|
+
self.update(obj)
|
|
50
|
+
self.name = obj.name
|
|
51
|
+
|
|
52
|
+
class HealthDict(PrintableDict):
|
|
53
|
+
r'''
|
|
54
|
+
This class adds a 'health' check to a standard dictionary. This check
|
|
55
|
+
looks into the dict values, and considers empty lists as healthy and all
|
|
56
|
+
else as unhealthy. If one or more entries is 'unhealthy' the health method
|
|
57
|
+
returns False.
|
|
58
|
+
'''
|
|
59
|
+
def _get_health(self):
|
|
60
|
+
health = True
|
|
61
|
+
for item in self.keys():
|
|
62
|
+
if self[item] != []:
|
|
63
|
+
health = False
|
|
64
|
+
return health
|
|
65
|
+
|
|
66
|
+
health = property(fget=_get_health)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
r"""
|
|
2
|
+
###############################################################################
|
|
3
|
+
:mod:`OpenPNM.Base` -- Abstract Base Class, and Core Data Class
|
|
4
|
+
###############################################################################
|
|
5
|
+
|
|
6
|
+
.. autoclass:: OpenPNM.Base.Controller
|
|
7
|
+
:members:
|
|
8
|
+
:undoc-members:
|
|
9
|
+
:show-inheritance:
|
|
10
|
+
|
|
11
|
+
.. autoclass:: OpenPNM.Base.Core
|
|
12
|
+
:members:
|
|
13
|
+
:undoc-members:
|
|
14
|
+
:show-inheritance:
|
|
15
|
+
|
|
16
|
+
.. autoclass:: OpenPNM.Base.Tools
|
|
17
|
+
:members:
|
|
18
|
+
:undoc-members:
|
|
19
|
+
:show-inheritance:
|
|
20
|
+
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
import logging as logging
|
|
24
|
+
# set up logging to file - see previous section for more details
|
|
25
|
+
logging.basicConfig(level=logging.WARNING,
|
|
26
|
+
format='%(asctime)s | %(levelname)-8s | %(name)s.%(funcName)s | %(message)s',
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
from .__Controller__ import Controller
|
|
30
|
+
from .__ModelsDict__ import ModelsDict
|
|
31
|
+
from . import __Tools__ as Tools
|
|
32
|
+
from .__Core__ import Core
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
===============================================================================
|
|
4
|
+
Boundary -- Subclass of GenericGeometry for Boundary Pores
|
|
5
|
+
===============================================================================
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from OpenPNM.Geometry import models as gm
|
|
10
|
+
from OpenPNM.Geometry import GenericGeometry
|
|
11
|
+
|
|
12
|
+
class Boundary(GenericGeometry):
|
|
13
|
+
r"""
|
|
14
|
+
Boundary subclass of GenericGeometry.
|
|
15
|
+
|
|
16
|
+
Parameters
|
|
17
|
+
----------
|
|
18
|
+
network : OpenPNM Network object
|
|
19
|
+
The Network to which the Geometry object should be associated
|
|
20
|
+
pores, throats : array_like
|
|
21
|
+
The pores and/or throats where the Geometry should be applied
|
|
22
|
+
shape: str
|
|
23
|
+
Stick and Ball or Cube and Cuboid? ('spheres','cubes')
|
|
24
|
+
|
|
25
|
+
Examples
|
|
26
|
+
--------
|
|
27
|
+
>>> import OpenPNM
|
|
28
|
+
>>> pn = OpenPNM.Network.TestNet()
|
|
29
|
+
>>> Ps_int = pn.pores(labels=['top','bottom'],mode='not')
|
|
30
|
+
>>> Ps_boun = pn.pores(labels=['top','bottom'],mode='union')
|
|
31
|
+
>>> Ts_int = pn.throats(labels=['top','bottom'],mode='not')
|
|
32
|
+
>>> Ts_boun = pn.throats(labels=['top','bottom'],mode='union')
|
|
33
|
+
>>> geo = OpenPNM.Geometry.Cube_and_Cuboid(network=pn,pores=Ps_int,throats=Ts_int)
|
|
34
|
+
>>> boun = OpenPNM.Geometry.Boundary(network=pn,pores=Ps_boun,throats=Ts_boun)
|
|
35
|
+
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
def __init__(self,shape='spheres',**kwargs):
|
|
39
|
+
r"""
|
|
40
|
+
Initialize
|
|
41
|
+
"""
|
|
42
|
+
super(Boundary,self).__init__(**kwargs)
|
|
43
|
+
self._generate(shape)
|
|
44
|
+
|
|
45
|
+
def _generate(self,shape):
|
|
46
|
+
r'''
|
|
47
|
+
'''
|
|
48
|
+
try:
|
|
49
|
+
self['pore.seed']
|
|
50
|
+
seeds = True
|
|
51
|
+
except:
|
|
52
|
+
seeds = False
|
|
53
|
+
|
|
54
|
+
if seeds: self.models.add(propname='pore.seed',model=gm.pore_misc.constant,value=0.9999)
|
|
55
|
+
self.models.add(propname='pore.diameter',model=gm.pore_misc.constant,value=0)
|
|
56
|
+
if seeds: self.models.add(propname='throat.seed',
|
|
57
|
+
model=gm.throat_misc.neighbor,
|
|
58
|
+
pore_prop='pore.seed',
|
|
59
|
+
mode='max')
|
|
60
|
+
self.models.add(propname='throat.diameter',
|
|
61
|
+
model=gm.throat_misc.neighbor,
|
|
62
|
+
pore_prop='pore.diameter',
|
|
63
|
+
mode='max')
|
|
64
|
+
self['pore.volume'] = 0.0
|
|
65
|
+
self['pore.seed'] = 0.0
|
|
66
|
+
self.models.add(propname='throat.length',model=gm.throat_length.straight)
|
|
67
|
+
self['throat.volume'] = 0.0
|
|
68
|
+
self['throat.seed'] = 0.0
|
|
69
|
+
if shape == 'spheres':
|
|
70
|
+
self.models.add(propname='throat.area',model=gm.throat_area.cylinder)
|
|
71
|
+
self.models.add(propname='throat.surface_area',model=gm.throat_surface_area.cylinder)
|
|
72
|
+
elif shape == 'cubes':
|
|
73
|
+
self.models.add(propname='throat.area',model=gm.throat_area.cuboid)
|
|
74
|
+
self.models.add(propname='throat.surface_area',model=gm.throat_surface_area.cuboid)
|
|
75
|
+
self['pore.area'] = 1.0
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
if __name__ == '__main__':
|
|
79
|
+
import doctest
|
|
80
|
+
doctest.testmod(verbose=True)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
===============================================================================
|
|
4
|
+
Cube_and_Cuboid -- A standard Cubic pore and Cuboic throat model
|
|
5
|
+
===============================================================================
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from OpenPNM.Geometry import models as gm
|
|
10
|
+
from OpenPNM.Geometry import GenericGeometry
|
|
11
|
+
|
|
12
|
+
class Cube_and_Cuboid(GenericGeometry):
|
|
13
|
+
r"""
|
|
14
|
+
Toray090 subclass of GenericGeometry
|
|
15
|
+
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(self, **kwargs):
|
|
19
|
+
r"""
|
|
20
|
+
Initialize
|
|
21
|
+
"""
|
|
22
|
+
super(Cube_and_Cuboid,self).__init__(**kwargs)
|
|
23
|
+
self._generate()
|
|
24
|
+
|
|
25
|
+
def _generate(self):
|
|
26
|
+
r'''
|
|
27
|
+
'''
|
|
28
|
+
self.models.add(propname='pore.seed',
|
|
29
|
+
model=gm.pore_misc.random,
|
|
30
|
+
seed=self._seed)
|
|
31
|
+
self.models.add(propname='throat.seed',
|
|
32
|
+
model=gm.throat_misc.neighbor,
|
|
33
|
+
pore_prop='pore.seed',
|
|
34
|
+
mode='min')
|
|
35
|
+
self.models.add(propname='pore.diameter',
|
|
36
|
+
model=gm.pore_diameter.sphere,
|
|
37
|
+
psd_name='weibull_min',
|
|
38
|
+
psd_shape=1.5,
|
|
39
|
+
psd_loc=14e-6,
|
|
40
|
+
psd_scale=2e-6)
|
|
41
|
+
self.models.add(propname='pore.area',
|
|
42
|
+
model=gm.pore_area.cubic)
|
|
43
|
+
self.models.add(propname='pore.volume',
|
|
44
|
+
model=gm.pore_volume.cube)
|
|
45
|
+
self.models.add(propname='throat.diameter',
|
|
46
|
+
model=gm.throat_diameter.cylinder,
|
|
47
|
+
tsd_name='weibull_min',
|
|
48
|
+
tsd_shape=1.5,
|
|
49
|
+
tsd_loc=14e-6,
|
|
50
|
+
tsd_scale=2e-6)
|
|
51
|
+
self.models.add(propname='throat.length',
|
|
52
|
+
model=gm.throat_length.straight)
|
|
53
|
+
self.models.add(propname='throat.volume',
|
|
54
|
+
model=gm.throat_volume.cuboid)
|
|
55
|
+
self.models.add(propname='throat.area',
|
|
56
|
+
model=gm.throat_area.cuboid)
|
|
57
|
+
self.models.add(propname='throat.surface_area',
|
|
58
|
+
model=gm.throat_surface_area.cuboid)
|
|
59
|
+
|
|
60
|
+
if __name__ == '__main__':
|
|
61
|
+
#Run doc tests
|
|
62
|
+
import doctest
|
|
63
|
+
doctest.testmod(verbose=True)
|
|
64
|
+
|