1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 """
20 VTK XML file.
21
22 For a detailed description of the file format, see:
23 http://www.geophysik.uni-muenchen.de/intranet/it-service/applications/paraview/vtk-file-formats/
24 """
27 """
28 Base class for VTK XML format data writer.
29
30 @cvar cltpn_map: mapper for cell type number.
31 @ctype cltpn_map: numpy.ndarray
32
33 @ivar appended: append data at the end of XML file. Forces binary.
34 @itype appended: bool
35 @ivar binary: flag for BINARY (False for ASCII).
36 @itype binary: bool
37 @ivar encoding: encoding for binary data ('base64' or 'raw'). Default is
38 raw. Must be base64 if inline (not appended).
39 @itype encoding: str
40 @ivar compressor: compressor for binary data. Can only be 'gz' or ''.
41 @itype compressor: str
42 @ivar fpdtype: floating-point data type (single/double).
43 @itype fpdtype: numpy.dtype
44 @ivar blk: corresponding block object.
45 @itype blk: solvcon.block.Block
46 """
47 from numpy import array, float32, float64, int32
48 cltpn_map = array([1, 3, 9, 5, 12, 10, 13, 14], dtype='int32')
49 dtype_map = dict(
50 float32='Float32',
51 float64='Float64',
52 int32='Int32',
53 )
54 del array, float32, float64, int32
55
57 self.appended = kw.pop('appended', True)
58 binary = kw.pop('binary', False)
59 self.binary = True if self.appended else binary
60 encoding = kw.pop('encoding', 'raw')
61 if self.binary and not self.appended:
62 self.encoding = 'base64'
63 else:
64 self.encoding = encoding
65 self.compressor = kw.pop('compressor', 'gz')
66 fpdtype = kw.pop('fpdtype', None)
67 if fpdtype == None:
68 fpdtype = blk.fpdtype
69 self.fpdtype = fpdtype
70 self.blk = blk
71 super(VtkXmlWriter, self).__init__()
72 self.lvl = 0
73
74 - def _tag_open(self, tag, attr=None, newline=True, close=False):
75 """
76 Create an opening XML tag.
77
78 @param tag: the name of tag.
79 @type tag: str
80 @keyword attr: attribute to be assigned to the tag in the format
81 ('name1', value1), ('name2', value2) ...
82 @type attr: list
83 @keyword newline: add newline at the end. Default is True.
84 @type newline: bool
85 @keyword close: close the tag while opening. Default is False.
86 @type close:
87 @return: contructed opening tag.
88 @rtype: str
89 """
90 if self.lvl < 0:
91 raise ValueError('lvl %d < 0 when opening %s' % (lvl, tag))
92 lvl = self.lvl
93 msg = [' '*(lvl*2)]
94 finish = ' />' if close else '>'
95 if attr:
96 msg.append('<%s %s%s' % (
97 tag,
98 ' '.join(['%s="%s"'%(key, str(val)) for key, val in attr]),
99 finish,
100 ))
101 else:
102 msg.append('<%s%s' % (tag, finish))
103 if newline:
104 msg.append('\n')
105 if not close:
106 self.lvl += 1
107 return ''.join(msg)
109 """
110 Create a closing XML tag.
111
112 @param tag: the name of tag.
113 @type tag: str
114 @keyword newline: add newline at the end. Default is True.
115 @type newline: bool
116 @return: contructed closing tag.
117 @rtype: str
118 """
119 self.lvl -= 1
120 if self.lvl < 0:
121 raise ValueError('lvl %d < 0 when closing %s' % (lvl, tag))
122 lvl = self.lvl
123 msg = [' '*(lvl*2)]
124 msg.append('</%s>'%tag)
125 if newline:
126 msg.append('\n')
127 return ''.join(msg)
128
130 """
131 Create data buffer from array.
132
133 @param arr: input array.
134 @type arr: numpy.ndarray
135 @return: the created data buffer.
136 @rtype: buffer
137 """
138 from struct import pack
139 from base64 import standard_b64encode
140 from zlib import compress
141 data = arr.tostring()
142 if self.compressor == 'gz':
143 osize = len(data)
144 data = compress(data)
145 zsize = len(data)
146 if self.encoding == 'base64':
147 data = standard_b64encode(data)
148 if self.compressor == 'gz':
149 size = pack('iiii', 1, osize, osize, zsize)
150 else:
151 size = pack('i', len(data))
152 if self.encoding == 'base64':
153 size = standard_b64encode(size)
154 return ''.join([size, data])
155
157 """
158 Write data array to a stream.
159
160 @param arr: data array to be written.
161 @type arr: numpy.ndarray
162 @param outf: output file stream.
163 @type outf: file
164 @param aplist: appended data list.
165 @type aplist: list
166 @param attr: additional attributes to the DataArray tag.
167 @type attr: list
168 @return: nothing
169 """
170
171 mattr = [
172 ('type', self.dtype_map[str(arr.dtype)]),
173 ]
174 if self.binary:
175 if aplist is None:
176 mattr.append(('format', 'binary'))
177 mattr.append(('encoding', self.encoding))
178 else:
179 mattr.append(('format', 'appended'))
180 mattr.append(('offset', sum([len(dat) for dat in aplist])))
181 else:
182 mattr.append(('format', 'ascii'))
183 mattr.extend(attr)
184 attr = mattr
185
186 if self.binary:
187 outf.write(self._tag_open('DataArray', attr, close=True))
188 data = self._create_data(arr)
189 if aplist is None:
190 outf.write(data)
191 outf.write('\n')
192 else:
193 aplist.append(data)
194 else:
195 outf.write(self._tag_open('DataArray', attr))
196 arr.tofile(outf, sep=' ')
197 outf.write('\n')
198 outf.write(self._tag_close('DataArray'))
199
201 """
202 Write appended data list to a stream.
203
204 @param aplist: the appendedn data list to be outputted.
205 @type aplist: list
206 @param outf: the file stream to be written.
207 @type outf: file
208 @return: nothing
209 """
210 outf.write(self._tag_open('AppendedData', [
211 ('encoding', self.encoding),
212 ]))
213 outf.write('_')
214 for data in aplist:
215 outf.write(data)
216 outf.write('\n')
217 outf.write(self._tag_close('AppendedData'))
218
220 """
221 VTK XML unstructured mesh file format. Capable for ASCII or BINARY.
222
223 @ivar cache_grid: flag to cache the grid data (True) or not (False).
224 Default True.
225 @itype cache_grid: bool
226 @ivar scalars: dictionary holding scalar data.
227 @itype scalars: dict
228 @ivar vectors: dictionary holding vector data.
229 @itype vectors: dict
230 @ivar griddata: cached grid data.
231 @itype griddata: str
232 """
234 self.cache_grid = kw.pop('cache_grid', True)
235 self.scalars = kw.pop('scalars', dict())
236 self.vectors = kw.pop('vectors', dict())
237 super(VtkXmlUstGridWriter, self).__init__(blk, *args, **kw)
238 self.griddata = None
239
241 """
242 Helper to convert vector data array from a block.
243
244 @param arr: array to be converted. It will be copied and remain
245 untouched.
246 @type arr: numpy.ndarray
247 @return: converted array.
248 @rtype: numpy.ndarray
249 """
250 from numpy import empty
251 arr = arr.copy()
252 ndim = self.blk.ndim
253 nit = arr.shape[0]
254 if ndim == 2:
255 arrn = empty((nit, ndim+1), dtype=arr.dtype)
256 arrn[:,2] = 0.0
257 arrn[:,:2] = arr[:,:]
258 arr = arrn
259 return arr
260
261 @staticmethod
263 """
264 Convert nodes in cells into a compressed array format.
265
266 @param clnds: the array to be compressed.
267 @type clnds: numpy.ndarray
268 @return: the compressed array.
269 @rtype: numpy.ndarray
270 """
271 from numpy import empty
272 arr = empty(clnds[:,0].sum(), dtype='int32')
273 ncell = clnds.shape[0]
274 icl = 0
275 it = 0
276 while icl < ncell:
277 ncl = clnds[icl,0]
278 arr[it:it+ncl] = clnds[icl,1:ncl+1]
279 it += ncl
280 icl += 1
281 return arr
282
283 - def write(self, outf, close_on_finish=False):
284 """
285 Write to file.
286
287 @param outf: output file object or file name.
288 @type outf: file str
289 @keyword close_on_finish: flag close on finishing (True). Default
290 False. If outf is file name, the output file will be close no
291 matter what is set in this flag.
292 @type close_on_finish: bool
293 @return: nothing
294 """
295 if isinstance(outf, str):
296 mode = 'wb' if self.binary else 'w'
297 outf = open(outf, mode)
298 close_on_finish = True
299
300 outf.write('<?xml version="1.0"?>\n')
301 attr = [
302 ('type', 'UnstructuredGrid'),
303 ('version', '0.1'),
304 ('byte_order', 'LittleEndian'),
305 ]
306 if self.compressor == 'gz':
307 attr.append(('compressor', 'vtkZLibDataCompressor'))
308 outf.write(self._tag_open('VTKFile', attr))
309 outf.write(self._tag_open('UnstructuredGrid'))
310 outf.write(self._tag_open('Piece', [
311 ('NumberOfPoints', self.blk.nnode),
312 ('NumberOfCells', self.blk.ncell),
313 ]))
314 aplist = list() if self.appended else None
315
316 outf.write(self._tag_open('Points'))
317 self._write_darr(self._convert_varr(self.blk.ndcrd), outf, aplist, [
318 ('NumberOfComponents', 3),
319 ])
320 outf.write(self._tag_close('Points'))
321
322 outf.write(self._tag_open('Cells'))
323 self._write_darr(self._convert_clnds(self.blk.clnds), outf, aplist, [
324 ('Name', 'connectivity'),
325 ])
326 self._write_darr(self.blk.clnds[:,0].cumsum(dtype='int32'), outf,
327 aplist, [
328 ('Name', 'offsets'),
329 ])
330 self._write_darr(self.cltpn_map[self.blk.cltpn], outf, aplist, [
331 ('Name', 'types'),
332 ])
333 outf.write(self._tag_close('Cells'))
334
335 outf.write(self._tag_close('Piece'))
336 outf.write(self._tag_close('UnstructuredGrid'))
337 if aplist:
338 self._write_appended(aplist, outf)
339 outf.write(self._tag_close('VTKFile'))
340 if close_on_finish:
341 outf.close()
342
343 if not self.cache_grid:
344 self.griddata = None
345