Giter VIP home page Giter VIP logo

uvw's Introduction

UVW - Universal VTK Writer

Build Status Coverage Status PyPI Version

UVW is a small utility library to write XML VTK files from data contained in Numpy arrays. It handles fully-fledged ndarrays defined over {1, 2, 3}-d domains, with arbitrary number of components. There are no constraints on the particular order of components, although copy of data can be avoided if the array is Fortran contiguous, as VTK files are written in Fortran order. UVW supports multi-process writing of VTK files, so that it can be used in an MPI environment.

Getting Started

Here is how to install and use uvw.

Prerequisites

  • Python 3. It may work with python 2, but it hasn't been tested.
  • Numpy. This code has been tested with Numpy version 1.14.3.
  • (Optional) mpi4py only if you wish to use the parallel classes of UVW (i.e. the submodule uvw.parallel)

Installing

This library can be installed with pip:

pip install --user uvw

If you want to activate parallel capabilities, run:

pip install --user uvw[mpi]

which will automatically pull mpi4py as a dependency.

Writing Numpy arrays

As a first example, let us write a multi-component numpy array into a rectilinear grid:

import numpy as np
from uvw import RectilinearGrid, DataArray

# Creating coordinates
x = np.linspace(-0.5, 0.5, 10)
y = np.linspace(-0.5, 0.5, 20)
z = np.linspace(-0.9, 0.9, 30)

# Creating the file (with possible data compression)
grid = RectilinearGrid('grid.vtr', (x, y, z), compression=True)

# A centered ball
x, y, z = np.meshgrid(x, y, z, indexing='ij')
r = np.sqrt(x**2 + y**2 + z**2)
ball = r < 0.3

# Some multi-component multi-dimensional data
data = np.zeros([10, 20, 30, 3, 3])
data[ball, ...] = np.array([[0, 1, 0],
                            [1, 0, 0],
                            [0, 1, 1]])

# Some cell data
cell_data = np.zeros([9, 19, 29])
cell_data[0::2, 0::2, 0::2] = 1

# Adding the point data (see help(DataArray) for more info)
grid.addPointData(DataArray(data, range(3), 'ball'))
# Adding the cell data
grid.addCellData(DataArray(cell_data, range(3), 'checkers'))
grid.write()

UVW also supports writing data on 2D and 1D physical domains, for example:

import sys
import numpy as np
from uvw import RectilinearGrid, DataArray

# Creating coordinates
x = np.linspace(-0.5, 0.5, 10)
y = np.linspace(-0.5, 0.5, 20)

# A centered disk
xx, yy = np.meshgrid(x, y, indexing='ij')
r = np.sqrt(xx**2 + yy**2)
R = 0.3
disk = r < R

data = np.zeros([10, 20])
data[disk] = np.sqrt(1-(r[disk]/R)**2)

# File object can be used as a context manager
# and you can write to stdout!
with RectilinearGrid(sys.stdout, (x, y)) as grid:
  grid.addPointData(DataArray(data, range(2), 'data'))

Writing in parallel with mpi4py

The classes contained in the uvw.parallel submodule support multi-process writing using mpi4py. Here is a code example:

import numpy as np

from mpi4py import MPI

from uvw.parallel import PRectilinearGrid
from uvw import DataArray

comm = MPI.COMM_WORLD
rank = comm.Get_rank()

N = 20

# Domain bounds per rank
bounds = [
    {'x': (-2, 0), 'y': (-2, 0)},
    {'x': (-2, 0), 'y': (0,  2)},
    {'x': (0,  2), 'y': (-2, 2)},
]

# Domain sizes per rank
sizes = [
    {'x': N, 'y': N},
    {'x': N, 'y': N},
    {'x': N, 'y': 2*N-1},  # account for overlap
]

# Size offsets per rank
offsets = [
    [0, 0],
    [0, N],
    [N, 0],
]

x = np.linspace(*bounds[rank]['x'], sizes[rank]['x'])
y = np.linspace(*bounds[rank]['y'], sizes[rank]['y'])

xx, yy = np.meshgrid(x, y, indexing='ij', sparse=True)
r = np.sqrt(xx**2 + yy**2)
data = np.exp(-r**2)

# Indicating rank info with a cell array
proc = np.ones((x.size-1, y.size-1)) * rank

with PRectilinearGrid('pgrid.pvtr', (x, y), offsets[rank]) as rect:
    rect.addPointData(DataArray(data, range(2), 'gaussian'))
    rect.addCellData(DataArray(proc, range(2), 'proc'))

As you can see, using PRectilinearGrid feels just like using RectilinearGrid, except that you need to supply the position of the local grid in the global grid numbering (the offsets[rank] in the above example). Note that RecilinearGrid VTK files need an overlap in point data, hence why the global grid size ends up being (2*N-1, 2*N-1). If you forget that overlap, Paraview (or another VTK-based software) may complain that some parts in the global grid (aka "extents" in VTK) are missing data.

Writing unstructured data

UVW supports VTK's UnstructuredGrid, where the geometry is given with a list of nodes and a connectivity. The UnstructuredGrid class expects connectivity to be a dictionnary enumerating the different connectivity types and the cells associated to each type. For example:

import numpy as np

from uvw import UnstructuredGrid
from uvw.unstructured import CellType

nodes = np.array([
    [0, 0, 0],
    [1, 0, 0],
    [1, 1, 0],
    [0, 1, 0],
    [2, 0, 0],
    [0, 2, 0],
    [1, 2, 0],
])

connectivity = {
    CellType.QUAD: np.array([
        [0, 1, 2, 3], [2, 6, 5, 3],
    ]),
    5: np.array([[4, 2, 1]]),
}

f = UnstructuredGrid('ugrid.vtu', nodes, connectivity)
f.write()

As you can see, cell types can be specified with the unstructured.CellType enumeration or with the underlying integer value (see VTKFileFormats for more info). UnstructuredGrid performs a sanity check of the connectivity to see if the number of nodes matches the cell type.

If you work with large amounts of unstructured data, consider checking out meshio which provides many different read/write capabilities for various unstructured formats, some of which are supported by VTK and are better than VTK's simple XML format.

List of features

Here is a list of what is available in UVW:

VTK file formats

  • Image data (.vti)
  • Rectilinear grid (.vtr)
  • Structured grid (.vts)
  • Unstructured grid (.vtu)
  • Parallel Rectilinear grid (.pvtr)
  • Parallel Image data (.pvti)
  • ParaView Data (.pvd)

Data representation

  • ASCII
  • Base64 (raw and compressed: the compression argument of file constructors can be True, False, or an integer in [-1, 9] for compression levels)

Note that raw binary data, while more space efficient and supported by VTK, is not valid XML, and therefore not supported by UVW, which uses minidom for XML writing.

PyEVTK high-level API implementation

To facilitate transition from PyEVTK, UVW implements a part of its API, without imposing restrictions on data (such as the number of components per array) and allowing data compression. Simply replace import pyevtk.hl by import uvw.dropin.hl. To enable compression, provide compression=True to any of the functions in uvw.dropin.hl. Note: the drop-in is not automatically tested, do not hesitate to report problems.

Planned developments

Here is a list of future developments:

  • Image data
  • Unstructured grid
  • Structured grid
  • Parallel writing (mpi4py-enabled PRectilinearGrid and PImageData are now available!)
  • Benchmarking + performance comparison with pyevtk

Developing

These instructions will get you a copy of the project up and running on your local machine for development and testing purposes.

Git repository

First clone the git repository:

git clone https://github.com/prs513rosewood/uvw.git

Then you can use pip in development mode (possibly in virtualenv):

pip install --user -e .[mpi,tests]

Installing with the tests extra pulls vtk as a dependency. This is because reading files with VTK in tests is the most reliable way to check file integrity.

Running the tests

The tests can be run using pytest:

pytest
# or for tests with mpi
mpiexec -n 2 pytest --with-mpi

License

This project is licensed under the MIT License - see the LICENSE.md file for details.

Acknowledgments

uvw's People

Contributors

jonasbreuling avatar prs513rosewood avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

uvw's Issues

'>f8' type arrays will not convert to VTK

When trying to create a rectilinear grid from numpy arrays, I got an error if my arrays were formatted with the data type '>f8': TypeError: Array dtype >f8 is not supported by VTK. This seems similar to an issue recently reported for pyvista (#540).

The following code raised the error:

from uvw import RectilinearGrid, DataArray
import numpy as np

data = np.zeros((5,5,5))

#xdim = np.array([0,1,2,3,4]).astype('>f8')
#ydim = np.array([0,1,2,3,4]).astype('>f8')
#zdim = np.array([0,1,2,3,4]).astype('>f8')

grid = RectilinearGrid('data.vtr', (ydim, xdim, zdim), compression = True)
grid.addPointData(DataArray(data, range(3), 'data'))
grid.write()

Changing xdim, ydim, and zdim as follows resolved the error:

xdim = np.array([0,1,2,3,4], dtype=np.float64)
ydim = np.array([0,1,2,3,4], dtype=np.float64)
zdim = np.array([0,1,2,3,4], dtype=np.float64)

While this may not matter much for cases where the arrays are defined within the code, it can cause problems when data is imported from other files that may have strange formatting.

(Sorry if my terminology is bad, or if this isn't a proper issue. I'm very new to github.)

System info:

OS: Windows 10 Home
Architecture: 64bit

Python 3.7.6
uvw 0.3.1
numpy 1.18.1

Update cell/point data

If I need to write a file multiple times, is there a way to update the cell or point data appended in a Data object? SO I can write the same VTK but with updated values (and possibly change the filename as well)

Number of Nodes in HEXAHEDRON elements

Hello,

I think I found a small error in the "unstructured.py"-part. The Hexahedron type should only have 8 nodes instead of 9 in the NODES_PER_CELL list.

CellType.HEXAHEDRON: 8, instead of CellType.HEXAHEDRON: 9, in line 65. This corrects a few errors I had using the .vtu files with paraview such as clipping elements.

Best greetings and thanks - very helpful stuff

Write Vector Data to VTK File

Hi,

I'm using uvw successfully to write structured scalar data to vtr-file, and I'm able to open and visualize the data with e.g. Paraview. Now I have vector valued data, e.g. the velocity, which I have stored in three diffrerent numpy arrays for the x,y,z components of the velocity, here U, V, W respectively. I can successfully write the three different ndarrays of shape (nx, ny, nz) as scalar data, and I build vector data from that inside Paraview. I have tried different reshape/ravel/dstack variants (e.g. "velocity=numpy.dstack((U.ravel(), V.ravel(), W.ravel()))"), but I didn't succeed and I have no idea of "how to write the velocity vector, which can easily be build from the components, to the VTK file, such that I can access the vector data in Paraview!?

Please, any help is highly appreciated!

Kind Regards
Jörg

addCellData produces mangled volumetric output, where addPointData is well-behaved

Description of problem:

Hi,

Thank you for writing this module, it's far superior to alternatives I have tried with respect to the compression of output.

However, please consult the following example, adapted from the example given in the uvw README:

import numpy as np
from uvw import ImageData, DataArray

x = np.linspace(-0.5, 0.5, 128)
y = np.linspace(-0.5, 0.5, 128)
z = np.linspace(-0.5, 0.5, 128)


cell_data = np.zeros([128, 128, 128])
cell_data[54:74, 54:74, 10:118] = 1.0
cell_data[10:118, 54:74, 54:74] = 1.0
cell_data[54:74, 10:118, 54:74] = 1.0

grid = ImageData(
    "test-good.vti",
    ranges=[(-0.5, 0.5), (-0.5, 0.5), (-0.5, 0.5)],
    points=[128, 128, 128],
    compression=False,
)
grid.addPointData(DataArray(cell_data, range(3), "value"))
grid.write()

grid = ImageData(
    "test-mangled.vti",
    ranges=[(-0.5, 0.5), (-0.5, 0.5), (-0.5, 0.5)],
    points=[128, 128, 128],
    compression=False,
)
grid.addCellData(DataArray(cell_data, range(3), "value"))
grid.write()

This example outputs two VTI files representing two identical ndarrays, distinguished by whether the data are added as a point data array or a cell data array. ParaView renderings of these data are shown:

test-good.vti:

Screenshot from 2023-05-31 19-39-56

test-mangled.vti:

Screenshot from 2023-05-31 19-40-00

Note that the data in test-mangled.vti is skewed.

Expected behaviour:

Broadly comparable data representations, distinguished by whether the data is of a cell or point type.

Attempted mitigations:

  • Enabling or disabling compression didn't do anything.
  • Using a RectilinearGrid produced analogous results, however performance was somewhat impaired in ParaView, likely because the RectilinearGrid structure can be anisotropic.
  • Played around with the offset argument of ImageData, no improvement.

Commentary

  • This behaviour appears to manifest in the README example, however because the array in the example is populated with a stride-2 grid, the effect is masked.
  • This may be a bug, or may be me misunderstanding CellData. If the latter, please accept my apologies and a request for the correct means of populating CellData.
  • For the sort of data I am working with, CellData is very much preferred to PointData.

Platform:

uvw 0.5.1
Python 3.10
ParaView 5.11.1
Linux 6.1

Number of tuples

Hi, I'm creating an ImageData file, and when writing the file, the NumberOfTuples property produces the size of the flattened data rather than the number of n-component elements in the data array. For instance

grid = uvw.ImageData('test_vtk.vti', [(-10., 10.), (-5, 5), (-5, 5)], [3, 3, 2], compression=True)
grid.addCellData(uvw.DataArray(np.arange(1., 9.).reshape(-1, 2), spatial_axes=[0], name='x0d'))

Produces a vti file with NumberOfTuples=8 rather than 4 which is is the number of pair data values I set.
Is the NumberOfTuples property necessary? I think the VTK file works as well without this property but it might be needed to allocate memory properly. There is very little documentation of this value in the VTK docs.

I found that the array is flattened here:

"NumberOfTuples": str(self.flat_data.size),

Subcommunicators in PVTKFile class

Hello,

In the PVTKFile class you set the comm attribute to be self.comm = MPI.COMM_WORLD. Can the user use a communicator other than MPI_COMM_WORLD to write files in parallel ?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.