Statistiques
| Révision :

root / ase / visualize / vtk / grid.py @ 3

Historique | Voir | Annoter | Télécharger (10,83 ko)

1 1 tkerber
2 1 tkerber
import numpy as np
3 1 tkerber
4 1 tkerber
from vtk import vtkPointData, vtkDataArray, vtkUnstructuredGrid, vtkPoints, \
5 1 tkerber
                vtkIdList, vtkStructuredPoints
6 1 tkerber
from ase.visualize.vtk.cell import vtkUnitCellModule
7 1 tkerber
from ase.visualize.vtk.data import vtkDataArrayFromNumPyBuffer, \
8 1 tkerber
                                   vtkDoubleArrayFromNumPyArray, \
9 1 tkerber
                                   vtkDoubleArrayFromNumPyMultiArray
10 1 tkerber
11 1 tkerber
# -------------------------------------------------------------------
12 1 tkerber
13 1 tkerber
class vtkBaseGrid:
14 1 tkerber
    def __init__(self, npoints, cell):
15 1 tkerber
        self.npoints = npoints
16 1 tkerber
17 1 tkerber
        # Make sure cell argument is correct type
18 1 tkerber
        assert isinstance(cell, vtkUnitCellModule)
19 1 tkerber
        self.cell = cell
20 1 tkerber
21 1 tkerber
        self.vtk_pointdata = None
22 1 tkerber
23 1 tkerber
    def set_point_data(self, vtk_pointdata):
24 1 tkerber
        if self.vtk_pointdata is not None:
25 1 tkerber
            raise RuntimeError('VTK point data already present.')
26 1 tkerber
27 1 tkerber
        assert isinstance(vtk_pointdata, vtkPointData)
28 1 tkerber
        self.vtk_pointdata = vtk_pointdata
29 1 tkerber
        #self.vtk_pointdata.SetCopyScalars(False)
30 1 tkerber
        #self.vtk_pointdata.SetCopyVectors(False)
31 1 tkerber
        #self.vtk_pointdata.SetCopyNormals(False)
32 1 tkerber
33 1 tkerber
    def get_point_data(self):
34 1 tkerber
        if self.vtk_pointdata is None:
35 1 tkerber
            raise RuntimeError('VTK point data missing.')
36 1 tkerber
37 1 tkerber
        return self.vtk_pointdata
38 1 tkerber
39 1 tkerber
    def get_number_of_points(self):
40 1 tkerber
        return self.npoints
41 1 tkerber
42 1 tkerber
    def add_scalar_data_array(self, data, name=None, active=True):
43 1 tkerber
44 1 tkerber
        # Are we converting from NumPy buffer to VTK array?
45 1 tkerber
        if isinstance(data, vtkDataArray):
46 1 tkerber
            vtk_sda = data
47 1 tkerber
        elif isinstance(data, vtkDataArrayFromNumPyBuffer):
48 1 tkerber
            vtk_sda = data.get_output()
49 1 tkerber
        else:
50 1 tkerber
            raise ValueError('Data is not a valid scalar data array.')
51 1 tkerber
52 1 tkerber
        del data
53 1 tkerber
54 1 tkerber
        assert vtk_sda.GetNumberOfComponents() == 1
55 1 tkerber
        assert vtk_sda.GetNumberOfTuples() == self.npoints
56 1 tkerber
57 1 tkerber
        if name is not None:
58 1 tkerber
            vtk_sda.SetName(name)
59 1 tkerber
60 1 tkerber
        # Add VTK array to VTK point data
61 1 tkerber
        self.vtk_pointdata.AddArray(vtk_sda)
62 1 tkerber
63 1 tkerber
        if active:
64 1 tkerber
            self.vtk_pointdata.SetActiveScalars(name)
65 1 tkerber
66 1 tkerber
        return vtk_sda
67 1 tkerber
68 1 tkerber
    def add_vector_data_array(self, data, name=None, active=True):
69 1 tkerber
70 1 tkerber
        # Are we converting from NumPy buffer to VTK array?
71 1 tkerber
        if isinstance(data, vtkDataArray):
72 1 tkerber
            vtk_vda = data
73 1 tkerber
        elif isinstance(data, vtkDataArrayFromNumPyBuffer):
74 1 tkerber
            vtk_vda = data.get_output()
75 1 tkerber
        else:
76 1 tkerber
            raise ValueError('Data is not a valid vector data array.')
77 1 tkerber
78 1 tkerber
        del data
79 1 tkerber
80 1 tkerber
        assert vtk_vda.GetNumberOfComponents() == 3
81 1 tkerber
        assert vtk_vda.GetNumberOfTuples() == self.npoints
82 1 tkerber
83 1 tkerber
        if name is not None:
84 1 tkerber
            vtk_vda.SetName(name)
85 1 tkerber
86 1 tkerber
        # Add VTK array to VTK point data
87 1 tkerber
        self.vtk_pointdata.AddArray(vtk_vda)
88 1 tkerber
89 1 tkerber
        if active:
90 1 tkerber
            self.vtk_pointdata.SetActiveVectors(name)
91 1 tkerber
92 1 tkerber
        return vtk_vda
93 1 tkerber
94 1 tkerber
# -------------------------------------------------------------------
95 1 tkerber
96 1 tkerber
class vtkAtomicPositions(vtkBaseGrid):
97 1 tkerber
    """Provides an interface for adding ``Atoms``-centered data to VTK
98 1 tkerber
    modules. Atomic positions, e.g. obtained using atoms.get_positions(),
99 1 tkerber
    constitute an unstructured grid in VTK, to which scalar and vector
100 1 tkerber
    can be added as point data sets.
101 1 tkerber

102 1 tkerber
    Just like ``Atoms``, instances of ``vtkAtomicPositions`` can be divided
103 1 tkerber
    into subsets, which makes it easy to select atoms and add properties.
104 1 tkerber

105 1 tkerber
    Example:
106 1 tkerber

107 1 tkerber
    >>> cell = vtkUnitCellModule(atoms)
108 1 tkerber
    >>> apos = vtkAtomicPositions(atoms.get_positions(), cell)
109 1 tkerber
    >>> apos.add_scalar_property(atoms.get_charges(), 'charges')
110 1 tkerber
    >>> apos.add_vector_property(atoms.get_forces(), 'forces')
111 1 tkerber

112 1 tkerber
    """
113 1 tkerber
    def __init__(self, pos, cell):
114 1 tkerber
        """Construct basic VTK-representation of a set of atomic positions.
115 1 tkerber

116 1 tkerber
        pos: NumPy array of dtype float and shape ``(n,3)``
117 1 tkerber
            Cartesian positions of the atoms.
118 1 tkerber
        cell: Instance of vtkUnitCellModule of subclass thereof
119 1 tkerber
            Holds information equivalent to that of atoms.get_cell().
120 1 tkerber

121 1 tkerber
        """
122 1 tkerber
        # Make sure position argument is a valid array
123 1 tkerber
        if not isinstance(pos, np.ndarray):
124 1 tkerber
            pos = np.array(pos)
125 1 tkerber
126 1 tkerber
        assert pos.dtype == float and pos.shape[1:] == (3,)
127 1 tkerber
128 1 tkerber
        vtkBaseGrid.__init__(self, len(pos), cell)
129 1 tkerber
130 1 tkerber
        # Convert positions to VTK array
131 1 tkerber
        npy2da = vtkDoubleArrayFromNumPyArray(pos)
132 1 tkerber
        vtk_pda = npy2da.get_output()
133 1 tkerber
        del npy2da
134 1 tkerber
135 1 tkerber
        # Transfer atomic positions to VTK points
136 1 tkerber
        self.vtk_pts = vtkPoints()
137 1 tkerber
        self.vtk_pts.SetData(vtk_pda)
138 1 tkerber
139 1 tkerber
        # Create a VTK unstructured grid of these points
140 1 tkerber
        self.vtk_ugd = vtkUnstructuredGrid()
141 1 tkerber
        self.vtk_ugd.SetWholeBoundingBox(self.cell.get_bounding_box())
142 1 tkerber
        self.vtk_ugd.SetPoints(self.vtk_pts)
143 1 tkerber
144 1 tkerber
        # Extract the VTK point data set
145 1 tkerber
        self.set_point_data(self.vtk_ugd.GetPointData())
146 1 tkerber
147 1 tkerber
    def get_points(self, subset=None):
148 1 tkerber
        """Return (subset of) vtkPoints containing atomic positions.
149 1 tkerber

150 1 tkerber
        subset=None: list of int
151 1 tkerber
            A list of indices into the atomic positions; ignored if None.
152 1 tkerber

153 1 tkerber
        """
154 1 tkerber
        if subset is None:
155 1 tkerber
            return self.vtk_pts
156 1 tkerber
157 1 tkerber
        # Create a list of indices from the subset
158 1 tkerber
        vtk_il = vtkIdList()
159 1 tkerber
        for i in subset:
160 1 tkerber
            vtk_il.InsertNextId(i)
161 1 tkerber
162 1 tkerber
        # Allocate VTK points for subset
163 1 tkerber
        vtk_subpts = vtkPoints()
164 1 tkerber
        vtk_subpts.SetDataType(self.vtk_pts.GetDataType())
165 1 tkerber
        vtk_subpts.SetNumberOfPoints(vtk_il.GetNumberOfIds())
166 1 tkerber
167 1 tkerber
        # Transfer subset of VTK points
168 1 tkerber
        self.vtk_pts.GetPoints(vtk_il, vtk_subpts)
169 1 tkerber
170 1 tkerber
        return vtk_subpts
171 1 tkerber
172 1 tkerber
    def get_unstructured_grid(self, subset=None):
173 1 tkerber
        """Return (subset of) an unstructured grid of the atomic positions.
174 1 tkerber

175 1 tkerber
        subset=None: list of int
176 1 tkerber
            A list of indices into the atomic positions; ignored if None.
177 1 tkerber

178 1 tkerber
        """
179 1 tkerber
        if subset is None:
180 1 tkerber
            return self.vtk_ugd
181 1 tkerber
182 1 tkerber
        # Get subset of VTK points
183 1 tkerber
        vtk_subpts = self.get_points(subset)
184 1 tkerber
185 1 tkerber
        # Create a VTK unstructured grid of these points
186 1 tkerber
        vtk_subugd = vtkUnstructuredGrid()
187 1 tkerber
        vtk_subugd.SetWholeBoundingBox(self.cell.get_bounding_box())
188 1 tkerber
        vtk_subugd.SetPoints(vtk_subpts)
189 1 tkerber
190 1 tkerber
        return vtk_subugd
191 1 tkerber
192 1 tkerber
    def add_scalar_property(self, data, name=None, active=True):
193 1 tkerber
        """Add VTK-representation of scalar data at the atomic positions.
194 1 tkerber

195 1 tkerber
        data: NumPy array of dtype float and shape ``(n,)``
196 1 tkerber
            Scalar values corresponding to the atomic positions.
197 1 tkerber
        name=None: str
198 1 tkerber
            Unique identifier for the scalar data.
199 1 tkerber
        active=True: bool
200 1 tkerber
            Flag indicating whether to use as active scalar data.
201 1 tkerber

202 1 tkerber
        """
203 1 tkerber
        # Make sure data argument is a valid array
204 1 tkerber
        if not isinstance(data, np.ndarray):
205 1 tkerber
            data = np.array(data)
206 1 tkerber
207 1 tkerber
        assert data.dtype == float and data.shape == (self.npoints,)
208 1 tkerber
209 1 tkerber
        # Convert scalar properties to VTK array
210 1 tkerber
        npa2da = vtkDoubleArrayFromNumPyArray(data)
211 1 tkerber
        return vtkBaseGrid.add_scalar_data_array(self, npa2da, name, active)
212 1 tkerber
213 1 tkerber
    def add_vector_property(self, data, name=None, active=True):
214 1 tkerber
        """Add VTK-representation of vector data at the atomic positions.
215 1 tkerber

216 1 tkerber
        data: NumPy array of dtype float and shape ``(n,3)``
217 1 tkerber
            Vector components corresponding to the atomic positions.
218 1 tkerber
        name=None: str
219 1 tkerber
            Unique identifier for the vector data.
220 1 tkerber
        active=True: bool
221 1 tkerber
            Flag indicating whether to use as active vector data.
222 1 tkerber

223 1 tkerber
        """
224 1 tkerber
        # Make sure data argument is a valid array
225 1 tkerber
        if not isinstance(data, np.ndarray):
226 1 tkerber
            data = np.array(data)
227 1 tkerber
228 1 tkerber
        assert data.dtype == float and data.shape == (self.npoints,3,)
229 1 tkerber
230 1 tkerber
        # Convert vector properties to VTK array
231 1 tkerber
        npa2da = vtkDoubleArrayFromNumPyArray(data)
232 1 tkerber
        return vtkBaseGrid.add_vector_data_array(self, npa2da, name, active)
233 1 tkerber
234 1 tkerber
# -------------------------------------------------------------------
235 1 tkerber
236 1 tkerber
class vtkVolumeGrid(vtkBaseGrid):
237 1 tkerber
    def __init__(self, elements, cell, origin=None):
238 1 tkerber
239 1 tkerber
        # Make sure element argument is a valid array
240 1 tkerber
        if not isinstance(elements, np.ndarray):
241 1 tkerber
            elements = np.array(elements)
242 1 tkerber
243 1 tkerber
        assert elements.dtype == int and elements.shape == (3,)
244 1 tkerber
        self.elements = elements
245 1 tkerber
246 1 tkerber
        vtkBaseGrid.__init__(self, np.prod(self.elements), cell)
247 1 tkerber
248 1 tkerber
        # Create a VTK grid of structured points
249 1 tkerber
        self.vtk_spts = vtkStructuredPoints()
250 1 tkerber
        self.vtk_spts.SetWholeBoundingBox(self.cell.get_bounding_box())
251 1 tkerber
        self.vtk_spts.SetDimensions(self.elements)
252 1 tkerber
        self.vtk_spts.SetSpacing(self.get_grid_spacing())
253 1 tkerber
254 1 tkerber
        if origin is not None:
255 1 tkerber
            self.vtk_spts.SetOrigin(origin)
256 1 tkerber
257 1 tkerber
        # Extract the VTK point data set
258 1 tkerber
        self.set_point_data(self.vtk_spts.GetPointData())
259 1 tkerber
260 1 tkerber
    def get_grid_spacing(self):
261 1 tkerber
        # Periodic boundary conditions leave out one boundary along an axis
262 1 tkerber
        # Zero/fixed boundary conditions leave out both boundaries of an axis
263 1 tkerber
        return self.cell.get_size()/(self.elements+1.0-self.cell.get_pbc())
264 1 tkerber
265 1 tkerber
    def get_relaxation_factor(self):
266 1 tkerber
        # The relaxation factor is a floating point value between zero and one.
267 1 tkerber
        # It expresses the need for smoothening (relaxation) e.g. of isosurfaces
268 1 tkerber
        # due to coarse grid spacings. Larger grid spacing -> larger relaxation.
269 1 tkerber
        x = self.get_grid_spacing().mean()/self.cell.get_characteristic_length()
270 1 tkerber
271 1 tkerber
        # The relaxation function f(x) satisfies the following requirements
272 1 tkerber
        # f(x) -> 0 for x -> 0+   and   f(x) -> b for x -> inf
273 1 tkerber
        # f'(x) -> a for x -> 0+  and   f'(x) -> 0 for x -> inf
274 1 tkerber
275 1 tkerber
        # Furthermore, it is a rescaling of arctan, hence we know
276 1 tkerber
        # f(x) = 2 b arctan(a pi x / 2 b) / pi
277 1 tkerber
278 1 tkerber
        # Our reference point is x = r for which medium relaxion is needed
279 1 tkerber
        # f(r) = b/2   <=>   r = 2 b / a pi   <=>   a = 2 b / r pi
280 1 tkerber
        r = 0.025 # corresponding to 0.2 Ang grid spacing in 8 Ang cell
281 1 tkerber
        b = 0.5
282 1 tkerber
        f = 2*b*np.arctan(x/r)/np.pi
283 1 tkerber
284 1 tkerber
        if f > 0.1:
285 1 tkerber
           return f.round(1)
286 1 tkerber
        else:
287 1 tkerber
           return None
288 1 tkerber
289 1 tkerber
    def get_structured_points(self):
290 1 tkerber
        return self.vtk_spts
291 1 tkerber
292 1 tkerber
    def add_scalar_field(self, data, name=None, active=True):
293 1 tkerber
294 1 tkerber
        # Make sure data argument is a valid array
295 1 tkerber
        if not isinstance(data, np.ndarray):
296 1 tkerber
            data = np.array(data)
297 1 tkerber
298 1 tkerber
        assert data.dtype == float and data.shape == tuple(self.elements)
299 1 tkerber
300 1 tkerber
        # Convert scalar field to VTK array
301 1 tkerber
        npa2da = vtkDoubleArrayFromNumPyMultiArray(data[...,np.newaxis])
302 1 tkerber
        return vtkBaseGrid.add_scalar_data_array(self, npa2da, name, active)
303 1 tkerber
304 1 tkerber
    def add_vector_field(self, data, name=None, active=True):
305 1 tkerber
306 1 tkerber
        # Make sure data argument is a valid array
307 1 tkerber
        if not isinstance(data, np.ndarray):
308 1 tkerber
            data = np.array(data)
309 1 tkerber
310 1 tkerber
        assert data.dtype == float and data.shape == tuple(self.elements)+(3,)
311 1 tkerber
312 1 tkerber
        # Convert vector field to VTK array
313 1 tkerber
        npa2da = vtkDoubleArrayFromNumPyMultiArray(data)
314 1 tkerber
        return vtkBaseGrid.add_vector_data_array(self, npa2da, name, active)