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,91 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ ========================================================================
4
+ Tortuosity: Network Tortuosity Algorithm
5
+ ========================================================================
6
+ This algorithm uses Djkstra's algorithm to get the shortest path between
7
+ two points folliwng the network, and the the direct distance between the same
8
+ points. The ratio of these is returned as the 'tortuosity'
9
+
10
+ TODO: It currently uses the 'throat.length' to weight the network connections
11
+ but this should probably use diffusive conductance.
12
+ """
13
+
14
+ import scipy as sp
15
+ import scipy.sparse.csgraph as spgr
16
+ from OpenPNM.Algorithms import GenericAlgorithm
17
+ import OpenPNM.Network
18
+ from OpenPNM.Base import logging
19
+ logger = logging.getLogger(__name__)
20
+
21
+ class Tortuosity(GenericAlgorithm):
22
+ r"""
23
+ Determines the tortuosity of the network using a shortest path search algorithm.
24
+
25
+ """
26
+
27
+ def __init__(self, **kwargs):
28
+ r"""
29
+
30
+ """
31
+ super(Tortuosity,self).__init__(**kwargs)
32
+ logger.debug("Create Tortuosity Object")
33
+
34
+ def estimate_time(self):
35
+ r'''
36
+ '''
37
+ pn_temp = OpenPNM.Network.TestNet()
38
+ graph = pn_temp.create_adjacency_matrix(sprsfmt='csr')
39
+ self._net.tic()
40
+ path = spgr.shortest_path(csgraph = graph, method='D', directed = False)
41
+ t = self._net.toc(quiet=True)
42
+ N = 125
43
+ k = 6
44
+ O = t/(N*(N*k + N*sp.log(N)))
45
+ N = self._net.num_pores()
46
+ k = sp.median(self._net.num_neighbors(pores=self._net.pores()))
47
+ t_est = O*(N*(N*k + N*sp.log(N)))
48
+ print("Based on the network size and PC performance, this algorithm will require: ",t_est,' seconds')
49
+ return
50
+
51
+ def run(self,phase=None):
52
+ r'''
53
+ '''
54
+ logger.warning('This algorithm can take some time...')
55
+ graph = self._net.create_adjacency_matrix(data=self._net['throat.length'],sprsfmt='csr')
56
+
57
+ if phase is not None:
58
+ self._phase = phase
59
+ if 'throat.occupancy' in self._phase.props():
60
+ temp = self._net['throat.length']*(self._phase['throat.occupancy']==1)
61
+ graph = self._net.create_adjacency_matrix(data=temp,sprsfmt='csr',prop='temp')
62
+
63
+ #self._net.tic()
64
+ path = spgr.shortest_path(csgraph = graph, method='D', directed = False)
65
+ #self._net.toc()
66
+
67
+ Px = sp.array(self._net['pore.coords'][:,0],ndmin=2)
68
+ Py = sp.array(self._net['pore.coords'][:,1],ndmin=2)
69
+ Pz = sp.array(self._net['pore.coords'][:,2],ndmin=2)
70
+
71
+ Cx = sp.square(Px.T - Px)
72
+ Cy = sp.square(Py.T - Py)
73
+ Cz = sp.square(Pz.T - Pz)
74
+ Ds = sp.sqrt(Cx + Cy + Cz)
75
+
76
+ temp = path/Ds
77
+ #temp = path
78
+
79
+ temp[sp.isnan(temp)] = 0
80
+ temp[sp.isinf(temp)] = 0
81
+
82
+ return temp
83
+
84
+
85
+
86
+
87
+
88
+
89
+
90
+ if __name__ == '__main__':
91
+ print('no tests yet')
@@ -0,0 +1,48 @@
1
+ r"""
2
+ ###############################################################################
3
+ :mod:`OpenPNM.Algorithms` -- Algorithms on Networks
4
+ ###############################################################################
5
+
6
+ Contents
7
+ --------
8
+ This submodule contains algorithms for performing simulations on pore networks
9
+
10
+ Classes
11
+ -------
12
+
13
+ .. autoclass:: GenericAlgorithm
14
+ :members:
15
+
16
+ .. autoclass:: OrdinaryPercolation
17
+ :members:
18
+
19
+ .. autoclass:: InvasionPercolation
20
+ :members:
21
+
22
+ .. autoclass:: FickianDiffusion
23
+ :members:
24
+
25
+ .. autoclass:: StokesFlow
26
+ :members:
27
+
28
+ .. autoclass:: OhmicConduction
29
+ :members:
30
+
31
+ .. autoclass:: FourierConduction
32
+ :members:
33
+
34
+ .. autoclass:: Tortuosity
35
+ :members:
36
+
37
+ """
38
+
39
+ from .__GenericAlgorithm__ import GenericAlgorithm
40
+ from .__GenericLinearTransport__ import GenericLinearTransport
41
+ from .__FickianDiffusion__ import FickianDiffusion
42
+ from .__FourierConduction__ import FourierConduction
43
+ from .__OhmicConduction__ import OhmicConduction
44
+ from .__StokesFlow__ import StokesFlow
45
+ from .__InvasionPercolation__ import InvasionPercolation
46
+ from .__InvasionPercolationTimed__ import InvasionPercolationTimed
47
+ from .__OrdinaryPercolation__ import OrdinaryPercolation
48
+ from . __Tortuosity__ import Tortuosity
@@ -0,0 +1,480 @@
1
+ '''
2
+ ###############################################################################
3
+ Controller: Overall controller class
4
+ ###############################################################################
5
+ '''
6
+ import pickle as _pickle
7
+ import copy as _copy
8
+ import time, random, string
9
+ import OpenPNM
10
+ from OpenPNM.Base import logging
11
+ logger = logging.getLogger()
12
+
13
+ class Controller(dict):
14
+ r"""
15
+
16
+ """
17
+ # The following __instance__ class variable and subclassed __new__ method
18
+ # makes the Controller class a 'Singleton'. This way, the _ctrl attribute
19
+ # of every OpenPNM object is the same, AND if you create a ctrl on the
20
+ # command line (ctrl = OpenPNM.Base.Controller()) it will be the same ctrl!
21
+ __instance__ = None
22
+ def __new__(cls, *args,**kwargs):
23
+ if Controller.__instance__ is None:
24
+ Controller.__instance__ = dict.__new__(cls)
25
+ return Controller.__instance__
26
+
27
+ def __init__(self):
28
+ r'''
29
+ '''
30
+ self.comments = 'Using OpenPNM ' + OpenPNM.__version__
31
+
32
+ def __str__(self):
33
+ for net in self.networks():
34
+ header = ('-'*60)
35
+ print(header)
36
+ print('{a:<15} {b:<20} ({c})'.format(a='Object: ',b='Name',c='Class'))
37
+ print(header)
38
+ print('{a:<15} {b:<20} ({c})'.format(a='Network: ',b=net.name,c=net.__class__.__name__))
39
+ for geom in net._geometries:
40
+ print('++ {a:<12} {b:<20} ({c})'.format(a='Geometry: ',b=geom.name,c=geom.__class__.__name__))
41
+ for phase in net._phases:
42
+ if len(phase._phases)==0:
43
+ print('+ {a:<13} {b:<20} ({c})'.format(a='Pure Phase: ',b=phase.name,c=phase.__class__.__name__))
44
+ if len(phase._phases)>1:
45
+ print('+ {a:<13} {b:<20} ({c})'.format(a='Mixture Phase: ',b=phase.name,c=phase.__class__.__name__))
46
+ comps = phase.phases()
47
+ for compname in comps:
48
+ print('++ {a:<12} {b:<20} ({c})}'.format(a='Component Phase: ',b=phase.name,c=phase.__class__.__name__))
49
+ for phys in phase._physics:
50
+ print('++ {a:<12} {b:<20} ({c})'.format(a='Physics: ',b=phys.name,c=phys.__class__.__name__))
51
+ return ''
52
+
53
+ def _setloglevel(self,level):
54
+ logger.setLevel(level)
55
+
56
+ def _getloglevel(self):
57
+ print('Log level is currently set to -->',logger.level)
58
+
59
+ loglevel = property(fget=_getloglevel,fset=_setloglevel)
60
+
61
+ def networks(self):
62
+ r'''
63
+ Returns a list of all Network objects
64
+ '''
65
+ return self._get_objects(obj_type='GenericNetwork')
66
+
67
+ def geometries(self):
68
+ r'''
69
+ Returns a list of all Geometry objects
70
+ '''
71
+ return self._get_objects(obj_type='GenericGeometry')
72
+
73
+ def phases(self):
74
+ r'''
75
+ Returns a list of all Phase objects
76
+ '''
77
+ return self._get_objects(obj_type='GenericPhase')
78
+
79
+ def physics(self):
80
+ r'''
81
+ Returns a list of all Physics objects
82
+ '''
83
+ return self._get_objects(obj_type='GenericPhysics')
84
+
85
+ def algorithms(self):
86
+ r'''
87
+ Returns a list of all Algorithm objects
88
+ '''
89
+ return self._get_objects(obj_type='GenericAlgorithm')
90
+
91
+ def _get_objects(self,obj_type):
92
+ temp = []
93
+ for obj in self.keys():
94
+ mro = [item.__name__ for item in self[obj].__class__.__mro__]
95
+ if obj_type in mro:
96
+ temp.append(self[obj])
97
+ return temp
98
+
99
+ def clear(self):
100
+ r'''
101
+ This is an overloaded version of the standard dict's ``clear`` method.
102
+ This completely clears the Controller object's dict as expected, but
103
+ also removes links to the Controller object in all objects.
104
+
105
+ '''
106
+ for item in self.keys():
107
+ self[item]._ctrl = {}
108
+ self.__dict__ = {}
109
+ super(Controller,self).clear()
110
+
111
+ def update(self,arg):
112
+ r'''
113
+ This is a subclassed version of the standard dict's ``update`` method.
114
+ It can accept a dictionary of OpenPNM Core objects in which case it
115
+ adds the objects to the Controller. It can also accept an OpenPNM
116
+ Network object in which case it extracts all associated objects and
117
+ adds them to the Controller. In both cases it adds the Controller to
118
+ all object's ``controller`` attribute.
119
+
120
+ Notes
121
+ -----
122
+ The Network (and other Core objects) do not store Algorithms, so this
123
+ update will not add any Algorithm objects to the Controller. This may
124
+ change.
125
+ '''
126
+ if arg.__class__ == dict:
127
+ for item in arg.keys():
128
+ self[item] = arg[item]
129
+ arg[item]._ctrl = self
130
+ else:
131
+ mro = [item.__name__ for item in arg.__class__.__mro__]
132
+ if 'GenericNetwork' in mro:
133
+ net = arg
134
+ self[net.name] = net
135
+ net._ctrl = self
136
+ for item in net._geometries + net._physics + net._phases:
137
+ self[item.name] = item
138
+ item._ctrl = self
139
+
140
+ def purge_object(self,obj,mode='single'):
141
+ r'''
142
+ Remove an object, including all traces of it in its associated objects
143
+
144
+ Parameters
145
+ ----------
146
+ obj : OpenPNM Object
147
+ The object to be removed. This method removes all traces of the
148
+ object from everywhere, including all the object tracking lists and
149
+ label dictionaries of every object.
150
+ mode : string
151
+ Dicates the type of purge to be performed. Options are:
152
+
153
+ - 'single': Only purges the specified object
154
+ - 'complete': Purges the specified object AND all of its associated objects
155
+
156
+ Notes
157
+ -----
158
+ To only remove an object from the Contoller object use the dictionary's
159
+ native ``pop`` method.
160
+
161
+ Examples
162
+ --------
163
+ >>> import OpenPNM
164
+ >>> ctrl = OpenPNM.Base.Controller()
165
+ >>> pn = OpenPNM.Network.TestNet()
166
+ >>> geom = OpenPNM.Geometry.GenericGeometry(network=pn,pores=pn.Ps,throats=pn.Ts)
167
+ >>> 'pore.'+geom.name in pn.keys() # Label entries are added to the Network where geom is defined
168
+ True
169
+ >>> ctrl.purge_object(geom)
170
+ >>> geom.name in ctrl.keys() # geom is removed from Controller object
171
+ False
172
+ >>> 'pore.'+geom.name in pn.keys() # geom's labels are removed from the Network too
173
+ False
174
+ '''
175
+ if mode == 'complete':
176
+ if obj._net is None:
177
+ net = obj
178
+ else:
179
+ net = obj._net
180
+ for item in net.geometries() + net.phases() + net.physics():
181
+ blank = self.pop(item,None)
182
+ del self[net.name]
183
+ elif mode == 'single':
184
+ name = obj.name
185
+ for item in list(self.keys()):
186
+ # Remove label arrays from all other objects
187
+ self[item].pop('pore.'+name,None)
188
+ self[item].pop('throat.'+name,None)
189
+ # Remove associations on other objects
190
+ self[item]._geometries[:] = [x for x in self[item]._geometries if x is not obj]
191
+ self[item]._phases[:] = [x for x in self[item]._phases if x is not obj]
192
+ self[item]._physics[:] = [x for x in self[item]._physics if x is not obj]
193
+ # Set object's controller attribute to an empty dict
194
+ self[name]._ctrl = {}
195
+ # Remove object from Controller dict
196
+ del self[name]
197
+
198
+ def ghost_object(self,obj):
199
+ r'''
200
+ Create a ghost OpenPNM Object containing all the data, methods and
201
+ associations of the original object, but without registering the ghost
202
+ anywhere. This ghost is intended as a disposable object, for
203
+ instance, to receive data without overwriting existing data.
204
+
205
+ Parameters
206
+ ----------
207
+ obj : OpenPNM Object
208
+ The object to be cloned can be any OpenPNM Object
209
+
210
+ Returns
211
+ -------
212
+ A clone of the specified object is returned, but it retains all its links
213
+ to the objects associated with the original object. The cloned object is
214
+ not associated with the Network.
215
+
216
+ Examples
217
+ --------
218
+ >>> import OpenPNM
219
+ >>> ctrl = OpenPNM.Base.Controller()
220
+ >>> pn = OpenPNM.Network.TestNet()
221
+ >>> pn2 = ctrl.ghost_object(pn)
222
+ >>> pn is pn2 # A copy of pn is created
223
+ False
224
+ >>> pn2.keys() == pn.keys() # They have otherwise identical data
225
+ True
226
+ >>> pn2.controller is ctrl # pn2 is not associated with existing Controller
227
+ False
228
+
229
+ It can also be used to create ghosts of other object types:
230
+
231
+ >>> geom = OpenPNM.Geometry.TestGeometry(network=pn,pores=pn.Ps,throats=pn.Ts)
232
+ >>> geo2 = ctrl.ghost_object(geom)
233
+ >>> geom is geo2
234
+ False
235
+ >>> geom.name == geo2.name # Ghost has same name as ancestor
236
+ True
237
+ >>> geo2 is ctrl[geo2.name] # But they are not the same object
238
+ False
239
+ >>> geo2.controller # The ghost is not registered with the Controller
240
+ {}
241
+ >>> # The following comparisons look at some 'behind the scenes' information
242
+ >>> geo2._net == geom._net # The ghost and ancestor are assoicated with the same Network
243
+ True
244
+ >>> geo2 in pn._geometries # But the Network remains aware of the ancestor only
245
+ False
246
+
247
+ '''
248
+ obj_new = _copy.copy(obj)
249
+ obj_new.__dict__ = obj.__dict__
250
+ obj_new._ctrl = {}
251
+ del self[obj.name]
252
+ self[obj.name] = obj
253
+ return obj_new
254
+
255
+ def save_simulation(self,network,filename=''):
256
+ r'''
257
+ Save a single Network simulation to a 'net' file, including all of its
258
+ associated objects, but not Algorithms
259
+
260
+ Parameters
261
+ ----------
262
+ network : OpenPNM Network object
263
+ The Network to save
264
+ filename : string, optional
265
+ If no filename is given the name of the Network is used
266
+ '''
267
+ if filename == '':
268
+ filename = network.name
269
+ else:
270
+ filename = filename.rstrip('.net')
271
+
272
+ network._ctrl = {}
273
+ #Save nested dictionary pickle
274
+ _pickle.dump(network,open(filename+'.net','wb'))
275
+ network._ctrl = self
276
+
277
+ def load_simulation(self,filename):
278
+ r'''
279
+ Loads a Network simulation fromt the specified 'net' file and adds it
280
+ to the Controller
281
+
282
+ Parameters
283
+ ----------
284
+ filename : string
285
+ The name of the file containing the Network simulation to load
286
+ '''
287
+ filename = filename.rstrip('.net')
288
+ net = _pickle.load(open(filename+'.net','rb'))
289
+ net.controller = self
290
+
291
+ def save(self,filename=''):
292
+ r'''
293
+ Save the entire state of the Controller to a 'pnm' file.
294
+
295
+ Parameters
296
+ ----------
297
+ filename : string, optional
298
+ The file name to save as. If no filename is provided the current
299
+ date and time is used.
300
+
301
+ Examples
302
+ --------
303
+ >>> import OpenPNM
304
+ >>> ctrl = OpenPNM.Base.Controller()
305
+ >>> pn = OpenPNM.Network.TestNet()
306
+ >>> ctrl.save('test.pnm')
307
+ >>> pn.name in ctrl.keys()
308
+ True
309
+ >>> ctrl.clear()
310
+ >>> ctrl.keys()
311
+ dict_keys([])
312
+ >>> ctrl.load('test.pnm')
313
+ >>> pn.name in ctrl.keys()
314
+ True
315
+ '''
316
+ if filename == '':
317
+ from datetime import datetime
318
+ i = datetime.now()
319
+ filename = i.strftime('%Y-%m-%d_%H-%M-%S')
320
+ else:
321
+ filename = filename.rstrip('.pnm')
322
+
323
+ #Save nested dictionary pickle
324
+ _pickle.dump(self,open(filename+'.pnm','wb'))
325
+
326
+ def load(self,filename):
327
+ r'''
328
+ Load an entire Controller from a 'pnm' file.
329
+
330
+ Parameters
331
+ ----------
332
+ filename : string
333
+ The file name of the Controller to load.
334
+
335
+ Notes
336
+ -----
337
+ This calls the ``clear`` method of the Controller object, so it will
338
+ over write the calling objects information AND remove any references
339
+ to the calling object from existing objects.
340
+ '''
341
+ filename = filename.strip('.pnm')
342
+ if self != {}:
343
+ print('Warning: Loading data onto non-empty controller object, existing data will be lost')
344
+ self.clear()
345
+ self = _pickle.load(open(filename+'.pnm','rb'))
346
+
347
+ def export(self,network=None,filename='',fileformat='VTK'):
348
+ r'''
349
+ Export data to the specified file format.
350
+
351
+ Parameters
352
+ ----------
353
+ network : OpenPNM Network Object
354
+ This Network and all of its phases will be written to the specified
355
+ file. If no Netowrk is given it will check to ensure that only one
356
+ Network exists on the Controller and use that. If there is more
357
+ than one Network an error is thrown.
358
+ filename : string, optional
359
+ The file name to save as. If no name is given then the name of
360
+ suppiled object is used. If no object is given, the name of the
361
+ Network is used.
362
+ fileformat : string
363
+ The type of file to create. Options are:
364
+
365
+ 1. VTK: Suitable for visualizing in VTK capable software such as Paraview
366
+ 2. MAT: Suitable for loading data into Matlab for post-processing
367
+
368
+ '''
369
+ if network is None:
370
+ if len(self.networks()) == 1:
371
+ network = self.networks()[0]
372
+ else:
373
+ raise Exception('Multiple Networks found, please specify which to Export')
374
+ import OpenPNM.Utilities.IO as io
375
+ if fileformat == 'VTK':
376
+ phases = network._phases
377
+ io.VTK.save(filename=filename,network=network,phases=phases)
378
+ return
379
+ if fileformat == 'MAT':
380
+ phases = network._phases
381
+ io.MAT.save(filename=filename,network=network,phases=phases)
382
+ return
383
+
384
+ def _script(self,filename,mode='read'):
385
+ r'''
386
+ Save or reload the script files used for the modeling
387
+
388
+ Parameters
389
+ ----------
390
+ filename : string
391
+ The name of the file to read or write
392
+ mode : string
393
+ Whether to 'archive' the given script file on the object or to
394
+ 'retrieve' it from the object and create a new file with it. The
395
+ default is 'archive'.
396
+ '''
397
+ filename = filename.split('.')[0]+'.py'
398
+ if mode == 'archive':
399
+ with open(filename, "rb") as read_file:
400
+ contents = read_file.read()
401
+ self._script = contents
402
+ if mode == 'retrieve':
403
+ with open(filename, "wb") as write_file:
404
+ write_file.write(self._script)
405
+
406
+ def _set_comments(self,string):
407
+ if hasattr(self,'_comments') is False:
408
+ self._comments = {}
409
+ self._comments[time.strftime("%c")] = string
410
+
411
+ def _get_comments(self):
412
+ if hasattr(self,'_comments') is False:
413
+ print('No comments found')
414
+ else:
415
+ for key in self._comments.keys():
416
+ print(key, ': ', self._comments[key])
417
+
418
+ comments = property(fget=_get_comments,fset=_set_comments)
419
+
420
+ def clone_simulation(self,network,name=None):
421
+ r'''
422
+ Accepts a Network object and creates a complete clone including all
423
+ associated objects. All objects in the cloned simulation are
424
+ registered with the Controller object and are fully functional.
425
+
426
+ Returns
427
+ -------
428
+ A handle to the new Network object, which will include handles to
429
+ clones of all associated objects.
430
+
431
+ See Also
432
+ --------
433
+ ghost_object
434
+
435
+ Notes
436
+ -----
437
+ One useful application of this method is to create a cloned simulation
438
+ that can be trimmed to a smaller size. This small simulation will
439
+ result in much faster Algorithms calculations.
440
+
441
+ Examples
442
+ --------
443
+ None yet
444
+ '''
445
+ if network._parent != None:
446
+ logger.error('Cannot clone a network that is already a clone')
447
+ return
448
+ bak = {}
449
+ bak.update(self)
450
+ self.clear()
451
+ net = _copy.deepcopy(network)
452
+ self.update(net)
453
+ if name == None:
454
+ name = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(5))
455
+ for item in list(self.keys()):
456
+ temp = self.pop(item)
457
+ temp._parent = network
458
+ new_name = temp.name + '_' + name
459
+ temp.name = new_name
460
+ self[temp.name] = temp
461
+ # Add parent Network numbering to clone
462
+ net['pore.'+network.name] = network.Ps
463
+ net['throat.'+network.name] = network.Ts
464
+ self.update(bak)
465
+ return net
466
+
467
+ if __name__ == '__main__':
468
+ ctrl = Controller()
469
+
470
+
471
+
472
+
473
+
474
+
475
+
476
+
477
+
478
+
479
+
480
+