PYTHON: Rewrite vtkio.
Signed-off-by: Grzegorz Kowal <grzegorz@amuncode.org>
This commit is contained in:
parent
e153cd417e
commit
1c4fa6035d
@ -22,120 +22,67 @@
|
|||||||
|
|
||||||
================================================================================
|
================================================================================
|
||||||
|
|
||||||
submodule: vtkio.py
|
module: VTKIO
|
||||||
|
|
||||||
This submodule provides a function to store a dataset as VTK image file.
|
Module provides a function to store given dataset in the VTK image file.
|
||||||
|
|
||||||
The only requirements for this package are:
|
|
||||||
|
|
||||||
- numpy
|
|
||||||
- lz4 (for LZ4 compression)
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
"""
|
"""
|
||||||
import base64, numpy, struct, zlib, lz4.block, lzma
|
|
||||||
|
|
||||||
def WriteVTK(vtkfile, vname, data, origin = (0.0, 0.0, 0.0), \
|
def WriteVTK(vtkfile, vname, data, \
|
||||||
spacing = (1.0, 1.0, 1.0), points = False, encode = True, \
|
origin=(0, 0, 0), spacing=(1, 1, 1), \
|
||||||
compression=None, block_size = 32768, lz4mode = 'fast', \
|
compression=None, compression_level=19, encode=True, \
|
||||||
compression_level = 6, verbose = False):
|
lz4mode='default', lz4acceleration=1, block_size=32768, \
|
||||||
|
points=False, verbose=False):
|
||||||
|
|
||||||
|
import base64, numpy, struct, zlib, lz4.block, lzma
|
||||||
|
|
||||||
# Separate cases when the input is a vector field and scalar field.
|
|
||||||
#
|
|
||||||
if isinstance(data, (list, tuple)):
|
if isinstance(data, (list, tuple)):
|
||||||
|
|
||||||
# Check if all list or tuple components are arrays.
|
if not all(isinstance(d, (numpy.ndarray)) for d in data):
|
||||||
#
|
raise Exception('All input data components in WriteVTK must be arrays!')
|
||||||
allarrays = True
|
|
||||||
for d in data:
|
|
||||||
allarrays = allarrays & isinstance(d, (numpy.ndarray))
|
|
||||||
|
|
||||||
# Quit if not all elements are arrays.
|
if not all(data[0].shape == d.shape for d in data):
|
||||||
#
|
raise Exception('All input data components in WriteVTK must have the same dimensions!')
|
||||||
if not allarrays:
|
|
||||||
|
|
||||||
print('All input data components must be arrays!')
|
|
||||||
return
|
|
||||||
|
|
||||||
# Check if the components have the same dimensions
|
|
||||||
#
|
|
||||||
sameshapes = True
|
|
||||||
for d in data:
|
|
||||||
sameshapes = sameshapes & (data[0].shape == d.shape)
|
|
||||||
|
|
||||||
# Quit if elements have different dimensions.
|
|
||||||
#
|
|
||||||
if not sameshapes:
|
|
||||||
print('All input data component must have the same dimensions!')
|
|
||||||
return
|
|
||||||
|
|
||||||
# Define the type of input data.
|
|
||||||
#
|
|
||||||
dtype = 'vector'
|
dtype = 'vector'
|
||||||
|
ncomp = len(data)
|
||||||
# Get the number of vector components.
|
ndims = data[0].ndim
|
||||||
#
|
dims = data[0].shape
|
||||||
nc = len(data)
|
|
||||||
|
|
||||||
# Get the number of dimansions
|
|
||||||
#
|
|
||||||
nd = data[0].ndim
|
|
||||||
|
|
||||||
# Get the variable dimensions.
|
|
||||||
#
|
|
||||||
dm = data[0].shape
|
|
||||||
|
|
||||||
elif isinstance(data, (numpy.ndarray)):
|
elif isinstance(data, (numpy.ndarray)):
|
||||||
|
|
||||||
# Define the type of input data.
|
|
||||||
#
|
|
||||||
dtype = 'scalar'
|
dtype = 'scalar'
|
||||||
|
ncomp = 1
|
||||||
# Get the number of vector components.
|
ndims = data.ndim
|
||||||
#
|
dims = data.shape
|
||||||
nc = 1
|
|
||||||
|
|
||||||
# Get the number of dimansions
|
|
||||||
#
|
|
||||||
nd = data.ndim
|
|
||||||
|
|
||||||
# Get the variable dimensions.
|
|
||||||
#
|
|
||||||
dm = data.shape
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print('Unknown type of the input data!')
|
raise Exception('Unknown type of the input data in WriteVTK!')
|
||||||
return
|
|
||||||
|
|
||||||
# Create the VTK output file and open it in the binary mode.
|
|
||||||
#
|
|
||||||
with open(vtkfile, 'wb') as vt:
|
with open(vtkfile, 'wb') as vt:
|
||||||
|
|
||||||
# Initiate offset and array size.
|
|
||||||
#
|
|
||||||
offset = 0
|
offset = 0
|
||||||
|
|
||||||
# Prepare strong for dimensions.
|
|
||||||
#
|
|
||||||
sdims = '"'
|
sdims = '"'
|
||||||
if points:
|
if points:
|
||||||
for i in range(nd - 1, 0, -1):
|
for i in range(ndims - 1, 0, -1):
|
||||||
sdims +='%d %d ' % (0, dm[i] - 1)
|
sdims +='%d %d ' % (0, dims[i] - 1)
|
||||||
sdims += '%d %d" ' % (0, dm[0] - 1)
|
sdims += '%d %d" ' % (0, dims[0] - 1)
|
||||||
else:
|
else:
|
||||||
for i in range(nd - 1, 0, -1):
|
for i in range(ndims - 1, 0, -1):
|
||||||
sdims +='%d %d ' % (0, dm[i])
|
sdims +='%d %d ' % (0, dims[i])
|
||||||
sdims += '%d %d" ' % (0, dm[0])
|
sdims += '%d %d" ' % (0, dims[0])
|
||||||
|
|
||||||
# Write the VTK header and data description.
|
|
||||||
#
|
|
||||||
string = '<?xml version="1.0"?>\n<VTKFile type="ImageData" version="1.0" byte_order="LittleEndian" header_type="UInt64"'
|
string = '<?xml version="1.0"?>\n<VTKFile type="ImageData" version="1.0" byte_order="LittleEndian" header_type="UInt64"'
|
||||||
if compression == 'zlib':
|
if compression == 'zlib':
|
||||||
string += ' compressor="vtkZLibDataCompressor"'
|
string += ' compressor="vtkZLibDataCompressor"'
|
||||||
|
compression_level = min(max(compression_level, 0), 9)
|
||||||
elif compression == 'lzma':
|
elif compression == 'lzma':
|
||||||
string += ' compressor="vtkLZMADataCompressor"'
|
string += ' compressor="vtkLZMADataCompressor"'
|
||||||
|
compression_level = min(max(compression_level, 0), 9)
|
||||||
elif compression == 'lz4':
|
elif compression == 'lz4':
|
||||||
string += ' compressor="vtkLZ4DataCompressor"'
|
string += ' compressor="vtkLZ4DataCompressor"'
|
||||||
|
compression_level = min(max(compression_level, 0), 12)
|
||||||
|
lz4acceleration = max(lz4acceleration, 1)
|
||||||
string += '>\n <ImageData WholeExtent=%s' % sdims
|
string += '>\n <ImageData WholeExtent=%s' % sdims
|
||||||
string += 'Origin="%e %e %e" ' % origin
|
string += 'Origin="%e %e %e" ' % origin
|
||||||
string += 'Spacing="%e %e %e">\n' % spacing
|
string += 'Spacing="%e %e %e">\n' % spacing
|
||||||
@ -144,7 +91,7 @@ def WriteVTK(vtkfile, vname, data, origin = (0.0, 0.0, 0.0), \
|
|||||||
string += ' <PointData %ss="%s">\n' % (dtype, vname)
|
string += ' <PointData %ss="%s">\n' % (dtype, vname)
|
||||||
else:
|
else:
|
||||||
string += ' <CellData %ss="%s">\n' % (dtype, vname)
|
string += ' <CellData %ss="%s">\n' % (dtype, vname)
|
||||||
if nc == 1:
|
if ncomp == 1:
|
||||||
dmin = data.min()
|
dmin = data.min()
|
||||||
dmax = data.max()
|
dmax = data.max()
|
||||||
else:
|
else:
|
||||||
@ -154,8 +101,8 @@ def WriteVTK(vtkfile, vname, data, origin = (0.0, 0.0, 0.0), \
|
|||||||
dmin = numpy.sqrt(dd.min())
|
dmin = numpy.sqrt(dd.min())
|
||||||
dmax = numpy.sqrt(dd.max())
|
dmax = numpy.sqrt(dd.max())
|
||||||
string += ' <DataArray '
|
string += ' <DataArray '
|
||||||
if nc > 1:
|
if ncomp > 1:
|
||||||
string += 'NumberOfComponents="{:d}" '.format(nc)
|
string += 'NumberOfComponents="{:d}" '.format(ncomp)
|
||||||
string += 'type="Float32" Name="{}" RangeMin="{:e}" RangeMax="{:e}" format="appended" offset="{}">\n'.format(vname, dmin, dmax, offset)
|
string += 'type="Float32" Name="{}" RangeMin="{:e}" RangeMax="{:e}" format="appended" offset="{}">\n'.format(vname, dmin, dmax, offset)
|
||||||
string += " </DataArray>\n"
|
string += " </DataArray>\n"
|
||||||
if points:
|
if points:
|
||||||
@ -166,8 +113,6 @@ def WriteVTK(vtkfile, vname, data, origin = (0.0, 0.0, 0.0), \
|
|||||||
string += ' </ImageData>\n'
|
string += ' </ImageData>\n'
|
||||||
vt.write(string.encode())
|
vt.write(string.encode())
|
||||||
|
|
||||||
# Append variable data.
|
|
||||||
#
|
|
||||||
if encode:
|
if encode:
|
||||||
string = ' <AppendedData encoding="base64">\n'
|
string = ' <AppendedData encoding="base64">\n'
|
||||||
else:
|
else:
|
||||||
@ -175,40 +120,27 @@ def WriteVTK(vtkfile, vname, data, origin = (0.0, 0.0, 0.0), \
|
|||||||
string += ' _'
|
string += ' _'
|
||||||
vt.write(string.encode())
|
vt.write(string.encode())
|
||||||
|
|
||||||
# Convert the input data to Float32. In the case of vector data concatenate the components first.
|
if dtype == 'vector':
|
||||||
#
|
qt = numpy.zeros([ dims[0], dims[1], dims[2], ncomp ], dtype=numpy.float32)
|
||||||
if (dtype == 'vector'):
|
|
||||||
qt = numpy.zeros([ dm[0], dm[1], dm[2], nc ], dtype = numpy.float32)
|
|
||||||
for n, d in enumerate(data[:]):
|
for n, d in enumerate(data[:]):
|
||||||
qt[:,:,:,n] = numpy.float32(d)
|
qt[:,:,:,n] = numpy.float32(d)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
qt = numpy.float32(data)
|
qt = numpy.float32(data)
|
||||||
|
|
||||||
barr = qt.tobytes()
|
barr = qt.tobytes()
|
||||||
|
|
||||||
# Compress if desired.
|
|
||||||
#
|
|
||||||
if compression != None:
|
if compression != None:
|
||||||
|
|
||||||
lz4compression = 10 - compression_level
|
|
||||||
|
|
||||||
if len(barr) < block_size:
|
if len(barr) < block_size:
|
||||||
|
|
||||||
if compression == 'zlib':
|
if compression == 'zlib':
|
||||||
carr = zlib.compress(barr, compression_level)
|
carr = zlib.compress(barr, compression_level)
|
||||||
elif compression == 'lz4':
|
elif compression == 'lz4':
|
||||||
carr = lz4.block.compress(barr, mode = lz4mode, acceleration = lz4compression, compression = compression_level, store_size = False)
|
carr = lz4.block.compress(barr, mode=lz4mode, acceleration=lz4acceleration, compression=compression_level, store_size=False)
|
||||||
elif compression == 'lzma':
|
elif compression == 'lzma':
|
||||||
carr = lzma.compress(barr)
|
carr = lzma.compress(barr)
|
||||||
|
|
||||||
# Prepare the number of blocks, the size of the last partial block,
|
|
||||||
# and the size of the compressed data.
|
|
||||||
#
|
|
||||||
head = struct.pack("QQQQ", 1, len(barr), 0, len(carr))
|
head = struct.pack("QQQQ", 1, len(barr), 0, len(carr))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
||||||
nblocks = len(barr) // block_size
|
nblocks = len(barr) // block_size
|
||||||
rsize = len(barr) % block_size
|
rsize = len(barr) % block_size
|
||||||
if verbose:
|
if verbose:
|
||||||
@ -231,7 +163,7 @@ def WriteVTK(vtkfile, vname, data, origin = (0.0, 0.0, 0.0), \
|
|||||||
cctx = lzma
|
cctx = lzma
|
||||||
for i in range(nblocks):
|
for i in range(nblocks):
|
||||||
ie = min(len(barr), ib + block_size)
|
ie = min(len(barr), ib + block_size)
|
||||||
cblk = cctx.compress(barr[ib:ie], preset = compression_level)
|
cblk = cctx.compress(barr[ib:ie], preset=compression_level)
|
||||||
head += struct.pack("Q", len(cblk))
|
head += struct.pack("Q", len(cblk))
|
||||||
carr += cblk
|
carr += cblk
|
||||||
ib = ie
|
ib = ie
|
||||||
@ -240,7 +172,7 @@ def WriteVTK(vtkfile, vname, data, origin = (0.0, 0.0, 0.0), \
|
|||||||
cctx = lz4.block
|
cctx = lz4.block
|
||||||
for i in range(nblocks):
|
for i in range(nblocks):
|
||||||
ie = min(len(barr), ib + block_size)
|
ie = min(len(barr), ib + block_size)
|
||||||
cblk = cctx.compress(barr[ib:ie], mode = lz4mode, acceleration = lz4compression, compression = compression_level, store_size = False)
|
cblk = cctx.compress(barr[ib:ie], mode=lz4mode, acceleration=lz4acceleration, compression=compression_level, store_size=False)
|
||||||
head += struct.pack("Q", len(cblk))
|
head += struct.pack("Q", len(cblk))
|
||||||
carr += cblk
|
carr += cblk
|
||||||
ib = ie
|
ib = ie
|
||||||
@ -251,16 +183,12 @@ def WriteVTK(vtkfile, vname, data, origin = (0.0, 0.0, 0.0), \
|
|||||||
vt.write(head+carr)
|
vt.write(head+carr)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
||||||
head = struct.pack("Q", len(barr))
|
head = struct.pack("Q", len(barr))
|
||||||
|
|
||||||
if encode:
|
if encode:
|
||||||
vt.write(base64.b64encode(head+barr))
|
vt.write(base64.b64encode(head+barr))
|
||||||
else:
|
else:
|
||||||
vt.write(head+barr)
|
vt.write(head+barr)
|
||||||
|
|
||||||
# Close the appended data section.
|
|
||||||
#
|
|
||||||
string = '\n </AppendedData>\n'
|
string = '\n </AppendedData>\n'
|
||||||
string += '</VTKFile>\n'
|
string += '</VTKFile>\n'
|
||||||
vt.write(string.encode())
|
vt.write(string.encode())
|
||||||
|
Loading…
x
Reference in New Issue
Block a user