/[escript]/trunk/pyvisi/py_src/datacollector.py
ViewVC logotype

Contents of /trunk/pyvisi/py_src/datacollector.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2009 - (show annotations)
Mon Nov 10 10:01:50 2008 UTC (11 years ago) by phornby
File MIME type: text/x-python
File size: 14508 byte(s)
Simplify the _del_ method's file closure and unlinking based upon mkstemp's advertised
behaviour.


1
2 ########################################################
3 #
4 # Copyright (c) 2003-2008 by University of Queensland
5 # Earth Systems Science Computational Center (ESSCC)
6 # http://www.uq.edu.au/esscc
7 #
8 # Primary Business: Queensland, Australia
9 # Licensed under the Open Software License version 3.0
10 # http://www.opensource.org/licenses/osl-3.0.php
11 #
12 ########################################################
13
14 __copyright__="""Copyright (c) 2003-2008 by University of Queensland
15 Earth Systems Science Computational Center (ESSCC)
16 http://www.uq.edu.au/esscc
17 Primary Business: Queensland, Australia"""
18 __license__="""Licensed under the Open Software License version 3.0
19 http://www.opensource.org/licenses/osl-3.0.php"""
20 __url__="http://www.uq.edu.au/esscc/escript-finley"
21
22 """
23 @var __author__: name of author
24 @var __copyright__: copyrights
25 @var __license__: licence agreement
26 @var __url__: url entry point on documentation
27 @var __version__: version
28 @var __date__: date of the version
29 """
30
31 __author__="John Ngui, john.ngui@uq.edu.au"
32
33
34 import vtk
35 import tempfile, os, sys
36 from constant import Source, ColorMode
37 try:
38 import esys.escript
39 except ImportError:
40 print "Warning: importing esys.escript failed."
41
42 class DataCollector:
43 """
44 Class that defines a data collector. A data collector is used to read
45 data from a XML file or from an escript object directly. Writing XML
46 files are expensive, but this approach has the advantage given that the
47 results can be analyzed easily after the simulation has completed.
48
49 @attention: A DataCollector instance can only be used to specify one
50 scalar, vector and tensor attribute from a source at any one time. If a
51 second scalar, vector or tensor attribute needs to be specified from the
52 same source, a second DataCollector instance must be created.
53 """
54
55 def __init__(self, source = Source.XML):
56 """
57 Initialise the data collector.
58
59 @type source: L{Source <constant.Source>} constant
60 @param source: Source type
61 """
62
63 self.__source = source
64 # Keeps track on whether DataCollector have been modified.
65 self.__modified = True
66 # Keeps track of the number of times the 'setFileName' or 'setData'
67 # method have been executed.
68 self.__count = 0
69 # Keeps track on whether any specific scalar, vector or tensor
70 # field have been specified.
71 self.__set_scalar = False
72 self.__set_vector= False
73 self.__set_tensor= False
74 self.__tmp_fd = None
75 self.__tmp_file = None
76
77
78 if(source == Source.XML): # Source is an XML file.
79 self.__vtk_xml_reader = vtk.vtkXMLUnstructuredGridReader()
80 # Source is a escript data object using a temp file in the background.
81 elif (self.__source == Source.ESCRIPT):
82 self.__vtk_xml_reader = vtk.vtkXMLUnstructuredGridReader()
83 # Create a temporary .xml file and retrieve its path.
84 # Should raise IOError on failure, in wich case
85 # __tmp_fd will remain None.
86 fd_and_name = tempfile.mkstemp(suffix=".xml")
87 self.__tmp_fd = fd_and_name[0]
88 self.__tmp_file = fd_and_name[1]
89
90 def __del__(self):
91 """
92 Perform some clean up of ths assumese temporary file.
93 """
94 # remove this test and rely upon the existance of an open
95 # __tmp_file to decide upon closing and unlinking.
96 # if (self.__source == Source.ESCRIPT):
97 if self.__tmp_fd != None :
98 os.close(self.__tmp_fd)
99 os.unlink(self.__tmp_file)
100
101 def setFileName(self, file_name):
102 """
103 Set the XML file name to read.
104
105 @type file_name: String
106 @param file_name: Name of the file to read
107 """
108
109 self.__modified = True
110 self.__count += 1
111
112 if(self.__source == Source.XML):
113 # Check whether the specified file exists, otherwise an error is
114 # raised.
115 if not(os.access(file_name, os.F_OK)):
116 raise IOError("\nERROR: '%s' file does NOT exists.\n" % \
117 file_name)
118
119 self.__vtk_xml_reader.SetFileName(file_name)
120 # Update must be called after SetFileName to make the reader
121 # up-to-date. Otherwise, some output values may be incorrect.
122 self.__vtk_xml_reader.Update()
123 self.__get_attribute_lists()
124 else:
125 raise ValueError("Source type %s does not support \
126 'setFileName'\n" % self.__source)
127
128 def setData(self,**args):
129 """
130 Create data using the <name>=<data> pairing. Assumption is made
131 that the data will be given in the appropriate format.
132 """
133
134 self.__modified = True
135 self.__count += 1
136
137 if self.__source == Source.ESCRIPT:
138 esys.escript.saveVTK(self.__tmp_file,**args)
139 self.__vtk_xml_reader.SetFileName(self.__tmp_file)
140
141 # Modified must be called for setData but NOT for
142 # setFileName. If Modified is not called, only the first file
143 # will always be displayed. The reason Modified is used is
144 # because the same temporary file name is always used
145 # (previous file is overwritten). Modified MUST NOT be used in
146 # setFileName, as it can cause incorrect output such as map.
147 self.__vtk_xml_reader.Modified()
148
149 # Update must be called after Modified. If Update is called before
150 # Modified, then the first/second image(s) may not be updated
151 # correctly.
152 self.__vtk_xml_reader.Update()
153 self.__get_attribute_lists()
154 else:
155 raise ValueError("Source type %s does not support 'setData'\n" \
156 % self.__source)
157
158 # This method is used to delay the execution of setting the active scalar
159 # until 'setFileName' or 'setData' have been executed.
160 def setActiveScalar(self, scalar):
161 """
162 Specify the scalar field to load.
163
164 @type scalar: String
165 @param scalar: Scalar field to load from the file.
166 """
167
168 self.__set_scalar = True
169 self.__active_scalar = scalar
170
171 def _setActiveScalar(self):
172 """
173 Load the specified scalar field.
174 """
175
176 # Check whether the specified scalar is available in either point
177 # or cell data. If not available, an error is raised.
178
179 # NOTE: This check is similar to the check used in _getScalarRange
180 # but this is used only when a scalar attribute has been specified.
181 if self.__active_scalar in self.__point_attribute['scalars']:
182 self._getDataCollectorOutput().GetPointData().SetActiveScalars(
183 self.__active_scalar)
184 elif self.__active_scalar in self.__cell_attribute['scalars']:
185 self._getDataCollectorOutput().GetCellData().SetActiveScalars(
186 self.__active_scalar)
187 else:
188 raise IOError("ERROR: No scalar called '%s' is available." % \
189 self.__active_scalar)
190
191 # This method is used to delay the execution of setting the active vector
192 # until 'setFileName' or 'setData' have been executed.
193 def setActiveVector(self, vector):
194 """
195 Specify the vector field to load.
196
197 @type vector: String
198 @param vector: Vector field to load from the file.
199 """
200
201 self.__set_vector = True
202 self.__active_vector = vector
203
204 def _setActiveVector(self):
205 """
206 Load the specified vector field.
207 """
208
209 # Check whether the specified vector is available in either point
210 # or cell data. If not available, error is raised.
211
212 # NOTE: This check is similar to the check used in _getVectorRange
213 # but this is used only when a vector attribute has been specified.
214 if self.__active_vector in self.__point_attribute['vectors']:
215 self._getDataCollectorOutput().GetPointData().SetActiveVectors(
216 self.__active_vector)
217 elif self.__active_vector in self.__cell_attribute['vectors']:
218 self._getDataCollectorOutput().GetCellData().SetActiveVectors(
219 self.__active_vector)
220 else:
221 raise IOError("ERROR: No vector called '%s' is available." % \
222 self.__active_vector)
223
224 # This method is used to delay the execution of setting the active tensor
225 # until 'setFileName' or 'setData' have been executed.
226 def setActiveTensor(self, tensor):
227 """
228 Specify the tensor field to load.
229
230 @type tensor: String
231 @param tensor: Tensor field to load from the file.
232 """
233
234 self.__set_tensor = True
235 self.__active_tensor = tensor
236
237 def _setActiveTensor(self):
238 """
239 Load the the specified tensor field.
240 """
241
242 # Check whether the specified tensor is available in either point
243 # or cell data. If not available, error is raised.
244
245 # NOTE: This check is similar to the check used in _getTensorRange
246 # but this is used only when a tensor attribute has been specified.
247 if self.__active_tensor in self.__point_attribute['tensors']:
248 self._getDataCollectorOutput().GetPointData().SetActiveTensors(
249 self.__active_tensor)
250 elif self.__active_tensor in self.__cell_attribute['tensors']:
251 self._getDataCollectorOutput().GetCellData().SetActiveTensors(
252 self.__active_tensor)
253 else:
254 raise IOError("ERROR: No tensor called '%s' is available." % \
255 self.__active_tensor)
256
257 def __get_array_type(self, arr):
258 """
259 Return whether an array type is scalar, vector or tensor by looking
260 at the number of components in the array.
261
262 @type arr: vtkDataArray
263 @param arr: An array from the source.
264 @rtype: String
265 @return: Array type ('scalar', vector' or 'tensor')
266 """
267
268 # Number of components in an array.
269 num_components = arr.GetNumberOfComponents()
270
271 if num_components == 1:
272 return 'scalars'
273 elif num_components == 3:
274 return 'vectors'
275 elif num_components == 9:
276 return 'tensors'
277
278 def __get_attribute_list(self, data):
279 """
280 Return the available scalar, vector and tensor attributes
281 (either point or cell data).
282
283 @type data: vtkPointData or vtkCellData
284 @param data: Available point data or cell data from the source
285 @rtype: Dictionary
286 @return: Dictionary containing the available scalar, vector and \
287 tensor attributes
288 """
289
290 attribute = {'scalars':[], 'vectors':[], 'tensors':[]}
291 if data:
292 num_arrays = data.GetNumberOfArrays() # Number of arrays.
293 for i in range(num_arrays):
294 name = data.GetArrayName(i) # Get an array name.
295 type = self.__get_array_type(data.GetArray(i)) # Get array type.
296 attribute[type].extend([name]) # Add array name to dictionary.
297
298 return attribute
299
300 def __get_attribute_lists(self):
301 """
302 Get all the available point and cell data attributes from the source.
303 """
304
305 # Get all the available point data attributes into a list.
306 self.__point_attribute = \
307 self.__get_attribute_list(
308 self._getDataCollectorOutput().GetPointData())
309
310 # Get all the available cell data attributes into another list.
311 self.__cell_attribute = \
312 self.__get_attribute_list(
313 self._getDataCollectorOutput().GetCellData())
314
315 def _getScalarRange(self):
316 """
317 Return the scalar range.
318
319 @rtype: Two column tuple containing numbers
320 @return: Scalar range
321 """
322
323 # Check whether any scalar is available in either point or cell data.
324 # If not available, an error is raised.
325
326 # NOTE: This check is similar to the check used in _setActiveScalar
327 # but this is used only when no scalar attribute has been specified.
328 if(len(self.__point_attribute['scalars']) != 0):
329 return self._getDataCollectorOutput().GetPointData().\
330 GetScalars().GetRange(-1)
331 elif(len(self.__cell_attribute['scalars']) != 0):
332 return self._getDataCollectorOutput().GetCellData().\
333 GetScalars().GetRange(-1)
334 else:
335 raise IOError("\nERROR: No scalar is available.\n")
336
337 def _getVectorRange(self):
338 """
339 Return the vector range.
340
341 @rtype: Two column tuple containing numbers
342 @return: Vector range
343 """
344
345 # Check whether any vector is available in either point or cell data.
346 # If not available, an error is raised.
347
348 # NOTE: This check is similar to the check used in _setActiveVector
349 # but this is used only when no vector attribute has been specified.
350
351 # NOTE: Generally GetRange(-1) returns the correct vector range.
352 # However, there are certain data sets where GetRange(-1) seems
353 # to return incorrect mimimum vector although the maximum vector is
354 # correct. As a result, the mimimum vector has been hard coded to 0.0
355 # to accommodate for the incorrect cases.
356 if(len(self.__point_attribute['vectors']) != 0):
357 vector_range = \
358 self._getDataCollectorOutput().GetPointData().\
359 GetVectors().GetRange(-1)
360 return (0.0, vector_range[1])
361 elif(len(self.__cell_attribute['vectors']) != 0):
362 vector_range = \
363 self._getDataCollectorOutput().GetCellData().\
364 GetVectors().GetRange(-1)
365 return (0.0, vector_range[1])
366 else:
367 raise IOError("\nERROR: No vector is available.\n")
368
369 def _getTensorRange(self):
370 """
371 Return the tensor range.
372
373 @rtype: Two column tuple containing numbers
374 @return: Tensor range
375 """
376
377 # Check whether any tensor is available in either point or cell data.
378 # If not available, an error is raised.
379
380 # NOTE: This check is similar to the check used in _setActiveTensor
381 # but this is used only when no tensor attribute has been specified.
382 if(len(self.__point_attribute['tensors']) != 0):
383 return self._getDataCollectorOutput().GetPointData().\
384 GetTensors().GetRange(-1)
385 elif(len(self.__cell_attribute['tensors']) != 0):
386 return self._getDataCollectorOutput().GetCellData().\
387 GetTensors().GetRange(-1)
388 else:
389 raise IOError("\nERROR: No tensor is available.\n")
390
391 def _getDataCollectorOutput(self):
392 """
393 Return the output of the data collector.
394
395 @rtype: vtkUnstructuredGrid
396 @return: Unstructured grid
397 """
398 return self.__vtk_xml_reader.GetOutput()
399
400 def _isModified(self):
401 """
402 Return whether the DataCollector has been modified.
403
404 @rtype: Boolean
405 @return: True or False
406 """
407
408 if(self.__modified == True):
409 # 'self.__modified' is set to False only if the 'setFileName' or
410 # 'setData' method have been called once. This is to prevent
411 # the scalar range and active field (i.e. scalar, vector or tensor)
412 # from being updated as no changes has taken place (for performance
413 # reasons). However if the 'setFileName' or 'setData' method is
414 # called more than once, then 'self.__modified' remains True.
415 if(self.__count == 1):
416 self.__modified = False
417 return True
418 else:
419 return False
420
421 def _isScalarSet(self):
422 """
423 Return whether a specific scalar field has been specified.
424
425 @rtype: Boolean
426 @return: True or False
427 """
428
429 return self.__set_scalar
430
431 def _isVectorSet(self):
432 """
433 Return whether a specific vector field has been specified.
434
435 @rtype: Boolean
436 @return: True or False
437 """
438
439 return self.__set_vector
440
441 def _isTensorSet(self):
442 """
443 Return whether a specific tensor field has been specified.
444
445 @rtype: Boolean
446 @return: True or False
447 """
448
449 return self.__set_tensor
450
451 def _getCenter(self):
452 """
453 Return the center of the rendered object.
454
455 @rtype: Three column tuple containing numbers
456 @return: Center of the rendered object
457 """
458
459 return self._getDataCollectorOutput().GetCenter()
460

  ViewVC Help
Powered by ViewVC 1.1.26