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,133 @@
1
+ r"""
2
+ ===============================================================================
3
+ Submodule -- diffusive_conductance
4
+ ===============================================================================
5
+
6
+ """
7
+
8
+ import scipy as sp
9
+
10
+ def conduit_conductance(physics,
11
+ phase,
12
+ network,
13
+ throat_conductance,
14
+ throat_occupancy='throat.occupancy',
15
+ pore_occupancy='pore.occupancy',
16
+ mode='strict',
17
+ factor=1e-6,
18
+ **kwargs):
19
+ r"""
20
+ Add a new multiphase conductance property to the conduits of network, where a
21
+ conduit is ( 1/2 pore - full throat - 1/2 pore ) based on the areas.
22
+
23
+ This method "closes" conduits that are not sufficiently filled with the
24
+ specified phase by multiplying the original conductance by a very small *factor*.
25
+
26
+ Parameters
27
+ ----------
28
+ network : OpenPNM Network Object
29
+
30
+ phase : OpenPNM Phase Object
31
+ The phase of interest
32
+
33
+ occupied_condition : 'occupancy'
34
+ The name of the pore and throat property that dictates whether conduit is "closed" or not
35
+
36
+ mode : 'strict' or 'medium' or 'loose'
37
+ How agressive the method should be in "closing" conduits.
38
+ 'strict' implies that if any pore or throat in the conduit is unoccupied by the given phase, the conduit is closed.
39
+ 'medium' implies that if either the throat or both pores are unoccupied, the conduit is closed
40
+ 'loose' will only close the conduit if the throat is unoccupied.
41
+
42
+ factor : 1/1e3
43
+ The "closing factor" which becomes multiplied to the original conduit's conductance to severely limit transport.
44
+
45
+ Notes
46
+ -----
47
+ This function requires that all the necessary phase properties already be
48
+ calculated.
49
+
50
+ """
51
+ throats = phase.throats(physics.name)
52
+ if (mode == 'loose'):
53
+ closed_conduits = -sp.array(phase[throat_occupancy],dtype=bool)
54
+ else:
55
+ throats_closed = -sp.array(phase[throat_occupancy],dtype=bool)
56
+ connected_pores = network.find_connected_pores(throats)
57
+ pores_1 = connected_pores[:,0]
58
+ pores_2 = connected_pores[:,1]
59
+ pores_1_closed = -sp.array(phase[pore_occupancy][pores_1],dtype=bool)
60
+ pores_2_closed = -sp.array(phase[pore_occupancy][pores_2],dtype=bool)
61
+ if(mode == 'medium'):
62
+ closed_conduits = throats_closed | (pores_1_closed & pores_2_closed)
63
+
64
+ if(mode == 'strict'):
65
+ closed_conduits = pores_1_closed | throats_closed | pores_2_closed
66
+ open_conduits = -closed_conduits
67
+ throat_value = phase[throat_conductance]
68
+ value = throat_value*open_conduits + throat_value*closed_conduits*factor
69
+ return value
70
+
71
+ def late_throat_filling(network,phase,Pc_star,eta):
72
+ pass
73
+
74
+ def late_pore_filling(physics,
75
+ phase,
76
+ network,
77
+ Pc,
78
+ Swp_star=0.2,
79
+ eta=3,
80
+ wetting_phase=False,
81
+ pore_occupancy='pore.occupancy',
82
+ throat_capillary_pressure='throat.capillary_pressure',
83
+ **kwargs):
84
+ r'''
85
+ Applies a late pore filling model to calculate fractional pore filling as
86
+ a function of applied capillary pressure.
87
+
88
+ Parameters
89
+ ----------
90
+ Pc : float
91
+ The capillary pressure in the non-wetting phase (Pc > 0)
92
+ Swp_star : float
93
+ The residual wetting phase in an invaded pore immediately after
94
+ nonwetting phase invasion
95
+ eta : float
96
+ Exponent to control the rate at which wetting phase is displaced
97
+ wetting_phase : boolean
98
+ Indicates whether supplied phase is the wetting or non-wetting phase
99
+
100
+
101
+ '''
102
+ pores = phase.pores(physics.name)
103
+ prop = phase[throat_capillary_pressure]
104
+ neighborTs = network.find_neighbor_throats(pores,flatten=False)
105
+ Pc_star = sp.array([sp.amin(prop[row]) for row in neighborTs])
106
+ Swp = Swp_star*(Pc_star/Pc)**eta
107
+ if wetting_phase:
108
+ values = Swp*phase[pore_occupancy]*(Pc_star<Pc)
109
+ else:
110
+ values = (1-Swp)*(1-phase[pore_occupancy])*(Pc_star<Pc)
111
+ return values
112
+
113
+
114
+
115
+
116
+
117
+
118
+
119
+
120
+
121
+
122
+
123
+
124
+
125
+
126
+
127
+
128
+
129
+
130
+
131
+
132
+
133
+
@@ -0,0 +1,67 @@
1
+ r"""
2
+ ===============================================================================
3
+ Submodule -- thermal_conductance
4
+ ===============================================================================
5
+
6
+ """
7
+
8
+ import scipy as _sp
9
+
10
+ def series_resistors(physics,
11
+ phase,
12
+ network,
13
+ thermal_conductivity = 'pore.thermal_conductivity',
14
+ pore_diameter = 'pore.diameter',
15
+ pore_area = 'pore.area',
16
+ throat_area = 'throat.area',
17
+ throat_length = 'throat.length',
18
+ **kwargs):
19
+ r"""
20
+ Calculate the thermal conductance of void conduits in network ( 1/2 pore - full throat - 1/2 pore ) based on size (assuming cylindrical geometry)
21
+
22
+ Parameters
23
+ ----------
24
+ network : OpenPNM Network Object
25
+
26
+ phase : OpenPNM Phase Object
27
+ The phase of interest
28
+
29
+ Notes
30
+ -----
31
+ (1) This function requires that all the necessary phase properties already
32
+ be calculated.
33
+
34
+ (2) This function calculates the specified property for the *entire*
35
+ network then extracts the values for the appropriate throats at the end.
36
+
37
+ """
38
+ #Get Nt-by-2 list of pores connected to each throat
39
+ Ps = network['throat.conns']
40
+ #Get properties in every pore in the network
41
+ kp = phase[thermal_conductivity]
42
+ kt = phase.interpolate_data(kp)
43
+ #Find g for half of pore 1
44
+ pdia = network[pore_diameter]
45
+ parea = network[pore_area]
46
+ pdia1 = pdia[Ps[:,0]]
47
+ pdia2 = pdia[Ps[:,1]]
48
+ #remove any non-positive lengths
49
+ pdia1[pdia1<=0] = 1e-12
50
+ pdia2[pdia2<=0] = 1e-12
51
+ gp1 = kt*parea[Ps[:,0]]/(0.5*pdia1)
52
+ gp1[~(gp1>0)] = _sp.inf #Set 0 conductance pores (boundaries) to inf
53
+ #Find g for half of pore 2
54
+ gp2 = kt*parea[Ps[:,1]]/(0.5*pdia2)
55
+ gp2[~(gp2>0)] = _sp.inf #Set 0 conductance pores (boundaries) to inf
56
+ #Find g for full throat
57
+ tarea = network[throat_area]
58
+ tlen = network[throat_length]
59
+ #remove any non-positive lengths
60
+ tlen[tlen<=0] = 1e-12
61
+ gt = kt*tarea/tlen
62
+ value = (1/gt + 1/gp1 + 1/gp2)**(-1)
63
+ value = value[phase.throats(physics.name)]
64
+ return value
65
+
66
+
67
+
@@ -0,0 +1,251 @@
1
+ from tempfile import NamedTemporaryFile
2
+ from subprocess import call
3
+ from itertools import count
4
+ import numpy as np
5
+ from matplotlib import cm
6
+
7
+ try:
8
+ import vtk
9
+ except ImportError:
10
+ vtk = type("", (), {'vtkActor': object})
11
+
12
+ class Actor(vtk.vtkActor):
13
+
14
+ def __init__(self):
15
+ raise NotImplementedError()
16
+
17
+ def pointArray(self, _points):
18
+ points = vtk.vtkPoints()
19
+ for x,y,z in _points:
20
+ points.InsertNextPoint(x, y, z)
21
+ return points
22
+
23
+ def lineArray(self, _lines):
24
+ lines = vtk.vtkCellArray()
25
+ for id_set in _lines:
26
+ l = vtk.vtkIdList()
27
+ for i in id_set:
28
+ l.InsertNextId(i)
29
+ lines.InsertNextCell(l)
30
+ return lines
31
+
32
+ def faceArray(self, faces):
33
+ lines = vtk.vtkCellArray()
34
+ for face in faces:
35
+ l = vtk.vtkIdList()
36
+ for i in face:
37
+ l.InsertNextId(i)
38
+ lines.InsertNextCell(l)
39
+ return lines
40
+
41
+ def floatArray(self, array):
42
+ floats = vtk.vtkFloatArray()
43
+ for n in array:
44
+ floats.InsertNextValue(n)
45
+ return floats
46
+
47
+ def colorArray(self, array, cmap=None):
48
+ colors = vtk.vtkUnsignedCharArray()
49
+ colors.SetNumberOfComponents(3)
50
+ if cmap is None:
51
+ cmap = 'coolwarm'
52
+ colormap = cm.get_cmap(cmap)
53
+ mapped = colormap(array)
54
+ for r,g,b,a in 255*mapped:
55
+ colors.InsertNextTuple3(r,g,b)
56
+ return colors
57
+
58
+ def update(self, t=0):
59
+ pass
60
+
61
+
62
+ class Wires(Actor):
63
+
64
+ def __init__(self, vertex_coords, edge_pairs, vertex_weights=None, alpha=1, cmap=None):
65
+ self.polydata = vtk.vtkPolyData()
66
+ self.polydata.SetPoints(self.pointArray(vertex_coords))
67
+ self.polydata.SetLines(self.lineArray(edge_pairs))
68
+ self.mapper = vtk.vtkPolyDataMapper()
69
+ self.mapper.SetInput(self.polydata)
70
+ self.SetMapper(self.mapper)
71
+
72
+ if vertex_weights is None:
73
+ weights = np.atleast_2d([128 for _ in vertex_coords])
74
+ else:
75
+ weights = np.atleast_2d(vertex_weights)
76
+ weights = np.subtract(weights, weights.min())
77
+ weights = np.true_divide(weights, weights.max())
78
+ self.weights = weights
79
+ self.cmap = cmap
80
+ self.update()
81
+
82
+ self.GetProperty().SetOpacity(alpha)
83
+
84
+ def update(self, t=0):
85
+ i = t % len(self.weights)
86
+ self.polydata.GetPointData().SetScalars(self.colorArray(self.weights[i], self.cmap))
87
+
88
+
89
+ class Surface(Actor):
90
+
91
+ def __init__(self, vertex_coords, edge_pairs, vertex_weights=None, alpha=1,
92
+ cmap=None, offset=0):
93
+ self.offset = offset
94
+ self.polydata = vtk.vtkPolyData()
95
+ self.polydata.SetPoints(self.pointArray(vertex_coords))
96
+ self.polydata.SetLines(self.lineArray(edge_pairs))
97
+ self.mapper = vtk.vtkPolyDataMapper()
98
+ self.mapper.SetInput(self.polydata)
99
+ self.SetMapper(self.mapper)
100
+
101
+ if vertex_weights is None:
102
+ weights = np.atleast_2d([128 for _ in vertex_coords])
103
+ else:
104
+ weights = np.atleast_2d(vertex_weights)
105
+ self.weights = weights
106
+ self.cmap = cmap
107
+ self.update()
108
+
109
+ self.GetProperty().SetOpacity(alpha)
110
+
111
+ def update(self, t=0):
112
+ i = t % len(self.weights)
113
+ values = self.weights[i]
114
+ # update z-positions
115
+ points = self.polydata.GetPoints()
116
+ for i, v in enumerate(values):
117
+ x,y,_ = points.GetPoint(i)
118
+ points.SetPoint(i, x, y, v+self.offset)
119
+ # update colors
120
+ normalized = np.true_divide(values, np.abs(self.weights).max())
121
+ normalized = np.subtract(normalized, self.weights.min())
122
+ colors = self.colorArray(normalized, self.cmap)
123
+ self.polydata.GetPointData().SetScalars(colors)
124
+
125
+
126
+ class Tubes(Actor):
127
+
128
+ def __init__(self, centers, vectors, radii, alpha=1, cmap=None):
129
+ tails = centers - vectors/2.
130
+ heads = centers + vectors/2.
131
+ points = np.vstack(zip(tails, heads))
132
+ pairs = np.arange(len(centers)*2).reshape(-1, 2)
133
+ radii = radii.repeat(2)
134
+
135
+ assert (points.size/3. == pairs.size)
136
+ assert (pairs.size == radii.size)
137
+
138
+ self.polydata = vtk.vtkPolyData()
139
+ self.polydata.SetPoints(self.pointArray(points))
140
+ self.polydata.SetLines(self.lineArray(pairs))
141
+ self.polydata.GetPointData().SetScalars(self.floatArray(radii))
142
+
143
+ self.tubeFilter = vtk.vtkTubeFilter()
144
+ self.tubeFilter.SetInput(self.polydata)
145
+ self.tubeFilter.SetVaryRadiusToVaryRadiusByAbsoluteScalar()
146
+ self.tubeFilter.SetNumberOfSides(10)
147
+ self.tubeFilter.CappingOn()
148
+
149
+ self.mapper = vtk.vtkPolyDataMapper()
150
+ self.mapper.SetInputConnection(self.tubeFilter.GetOutputPort())
151
+ self.mapper.ScalarVisibilityOff()
152
+ self.SetMapper(self.mapper)
153
+
154
+ self.GetProperty().SetOpacity(alpha)
155
+
156
+
157
+ class Spheres(Actor):
158
+
159
+ def __init__(self, centers, radii, alpha=1, color=(1,1,1)):
160
+ self.polydata = vtk.vtkPolyData()
161
+ self.polydata.SetPoints(self.pointArray(centers))
162
+ self.radii = np.atleast_2d(radii)
163
+ self.update()
164
+
165
+ self.sphere_source = vtk.vtkSphereSource()
166
+ self.glypher = vtk.vtkProgrammableGlyphFilter()
167
+ self.glypher.SetInput(self.polydata)
168
+ self.glypher.SetSource(self.sphere_source.GetOutput())
169
+ self.glypher.SetGlyphMethod(self.glyph_method)
170
+
171
+ self.mapper = vtk.vtkPolyDataMapper()
172
+ self.mapper.SetInputConnection(self.glypher.GetOutputPort())
173
+ self.SetMapper(self.mapper)
174
+
175
+ self.GetProperty().SetOpacity(alpha)
176
+ r,g,b = color
177
+ self.mapper.SetScalarVisibility(False)
178
+ self.GetProperty().SetColor(r,g,b)
179
+
180
+ def glyph_method(self):
181
+ pid = self.glypher.GetPointId()
182
+ self.sphere_source.SetCenter(self.glypher.GetPoint())
183
+ radius = self.glypher.GetPointData().GetScalars().GetValue(pid)
184
+ self.sphere_source.SetRadius(radius)
185
+
186
+ def update(self, t=0):
187
+ i = t % len(self.radii)
188
+ self.polydata.GetPointData().SetScalars(self.floatArray(self.radii[i]))
189
+
190
+
191
+ class Scene(object):
192
+ ticks = count(0)
193
+
194
+ def __init__(self, parent=None, fix_camera=True):
195
+ '''
196
+ fix_camera : more sensible default
197
+ '''
198
+ if parent is not None:
199
+ self.renWin = parent.GetRenderWindow()
200
+ self.iren = self.renWin.GetInteractor()
201
+ else:
202
+ self.renWin = vtk.vtkRenderWindow()
203
+ self.iren = vtk.vtkRenderWindowInteractor()
204
+ self.iren.SetRenderWindow(self.renWin)
205
+
206
+ self.ren = vtk.vtkRenderer()
207
+ self.renWin.AddRenderer(self.ren)
208
+
209
+ if fix_camera:
210
+ camera = vtk.vtkInteractorStyleTrackballCamera()
211
+ self.iren.SetInteractorStyle(camera)
212
+
213
+ def update_all(self, object=None, event=None, t=None):
214
+ if t is None: t = next(self.ticks)
215
+ for aid in range(self.ren.VisibleActorCount()):
216
+ actor = self.ren.GetActors().GetItemAsObject(aid)
217
+ actor.update(t)
218
+ self.renWin.Render()
219
+
220
+ def save(self, frames, outfile='animated.gif'):
221
+ '''
222
+ takes a snapshot of the frames at given t, and returns the paths
223
+ '''
224
+ windowToImage = vtk.vtkWindowToImageFilter()
225
+ windowToImage.SetInput(self.renWin)
226
+ writer = vtk.vtkPNGWriter()
227
+ writer.SetInput(windowToImage.GetOutput())
228
+
229
+ slide_paths = []
230
+ for t in frames:
231
+ f = NamedTemporaryFile(suffix='.png', delete=False)
232
+ self.update_all(t=t)
233
+ windowToImage.Modified()
234
+ writer.SetFileName(f.name)
235
+ writer.Write()
236
+ slide_paths.append( f.name )
237
+
238
+ call(["convert"] + slide_paths + [outfile])
239
+ call(["rm"] + slide_paths)
240
+
241
+ def play(self, timeout=1):
242
+ self.iren.Initialize()
243
+ if timeout is not None:
244
+ self.iren.AddObserver('TimerEvent', self.update_all)
245
+ self.timer = self.iren.CreateRepeatingTimer(timeout)
246
+ self.update_all()
247
+ self.iren.Start()
248
+
249
+ def add_actors(self, list_of_actors):
250
+ for actor in list_of_actors:
251
+ self.ren.AddActor(actor)