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,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
|
+
|