├── .gitattributes ├── .github └── workflows │ ├── black.yml │ ├── deploy.yml │ ├── test.yml │ └── test_deploy.yml ├── .gitignore ├── .hgignore ├── .pre-commit-config.yaml ├── CHANGES.txt ├── LICENSE.txt ├── MANIFEST.in ├── README.md ├── evtk └── __init__.py ├── examples ├── group.py ├── image.py ├── lines.py ├── lowlevel.py ├── points.py ├── poly_lines.py ├── rectilinear.py ├── structured.py └── unstructured.py ├── pyevtk ├── __init__.py ├── _version.py ├── evtk.py ├── hl.py ├── vtk.py └── xml.py ├── requirements.txt ├── setup.cfg ├── setup.py ├── tests └── dummy.py └── versioneer.py /.gitattributes: -------------------------------------------------------------------------------- 1 | pyevtk/_version.py export-subst 2 | -------------------------------------------------------------------------------- /.github/workflows/black.yml: -------------------------------------------------------------------------------- 1 | 2 | # GitHub Action that uses Black to reformat the Python code in an incoming pull request. 3 | # If all Python code in the pull request is compliant with Black then this Action does nothing. 4 | # Othewrwise, Black is run and its changes are committed back to the incoming pull request. 5 | # https://github.com/cclauss/autoblack 6 | 7 | name: autoblack 8 | on: [pull_request] 9 | jobs: 10 | black: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v3 14 | - uses: psf/black@stable 15 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | # This workflow will upload a Python Package using Twine when a release is created 2 | # For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries 3 | 4 | name: Upload Python Package 5 | 6 | on: 7 | push: 8 | tags: 9 | - "v*" 10 | 11 | jobs: 12 | pypi: 13 | 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v2 18 | - name: Set up Python 19 | uses: actions/setup-python@v2 20 | with: 21 | python-version: '3.x' 22 | - name: Build dist artefacts 23 | run: | 24 | python -m pip install --upgrade pip 25 | pip install build setuptools wheel 26 | python -m build --sdist --wheel --outdir dist/ 27 | - name: Publish distribution 📦 to PyPI 28 | uses: pypa/gh-action-pypi-publish@master 29 | with: 30 | user: __token__ 31 | password: ${{ secrets.PYPI_TOKEN }} 32 | github: 33 | name: Create Release 34 | runs-on: ubuntu-latest 35 | steps: 36 | - name: Checkout code 37 | uses: actions/checkout@v2 38 | - name: Create Release 39 | id: create_release 40 | uses: actions/create-release@v1 41 | env: 42 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 43 | with: 44 | tag_name: ${{ github.ref }} 45 | release_name: ${{ github.ref }} 46 | body: | 47 | Changes in this Release 48 | - First Change 49 | - Second Change 50 | draft: true 51 | prerelease: false 52 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run tests and lint with a variety of Python versions 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions 3 | 4 | name: Test Python 5 | 6 | on: 7 | pull_request: 8 | push: 9 | 10 | jobs: 11 | test: 12 | 13 | runs-on: ubuntu-latest 14 | strategy: 15 | matrix: 16 | python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] 17 | 18 | env: 19 | SDIST_DIR: /tmp/sdist 20 | steps: 21 | - uses: actions/checkout@v2 22 | - name: Set up Python ${{ matrix.python-version }} 23 | uses: actions/setup-python@v2 24 | with: 25 | python-version: ${{ matrix.python-version }} 26 | - name: Install dependencies 27 | run: | 28 | python -m pip install --upgrade pip 29 | pip install -r requirements.txt 30 | - name: Test with pytest 31 | run: | 32 | python setup.py test 33 | codecov 34 | - name: Test with pytest 35 | run: | 36 | python setup.py bdist_wheel 37 | python setup.py sdist -d ${SDIST_DIR}/ --format=gztar 38 | twine check ${SDIST_DIR}/* 39 | check-manifest -p python ${PWD} 40 | cd ${SDIST_DIR} 41 | pip install $(ls ${SDIST_DIR}) 42 | -------------------------------------------------------------------------------- /.github/workflows/test_deploy.yml: -------------------------------------------------------------------------------- 1 | # This workflow will upload a Python Package using Twine when a release is created 2 | # For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries 3 | 4 | name: Upload Python Package 5 | 6 | on: 7 | push: 8 | branches: 9 | 10 | jobs: 11 | deploy: 12 | 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v2 17 | with: 18 | # to guarantee proper git tag pickup for versioneer 19 | fetch-depth: 0 20 | - name: Set up Python 21 | uses: actions/setup-python@v2 22 | with: 23 | python-version: '3.x' 24 | - name: Build dist artefacts 25 | run: | 26 | python -m pip install --upgrade pip 27 | pip install build setuptools wheel 28 | python -m build --sdist --wheel --outdir dist/ 29 | - name: Publish distribution 📦 to Test PyPI 30 | uses: pypa/gh-action-pypi-publish@master 31 | with: 32 | user: __token__ 33 | password: ${{ secrets.TEST_PYPI_TOKEN }} 34 | repository_url: https://test.pypi.org/legacy/ 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *.cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # Jupyter Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # SageMath parsed files 79 | *.sage.py 80 | 81 | # Environments 82 | .env 83 | .venv 84 | env/ 85 | venv/ 86 | ENV/ 87 | 88 | # Spyder project settings 89 | .spyderproject 90 | .spyproject 91 | 92 | # Rope project settings 93 | .ropeproject 94 | 95 | # mkdocs documentation 96 | /site 97 | 98 | # mypy 99 | .mypy_cache/ 100 | 101 | # pycharm 102 | .idea 103 | 104 | # test artefacts 105 | *.vtu 106 | *.vts 107 | *.vtr 108 | *.pvd 109 | *.vti 110 | -------------------------------------------------------------------------------- /.hgignore: -------------------------------------------------------------------------------- 1 | syntax: glob 2 | build 3 | dist 4 | pyevtk.egg-info 5 | .eggs 6 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # See https://pre-commit.com for more information 2 | # See https://pre-commit.com/hooks.html for more hooks 3 | repos: 4 | - repo: https://github.com/pre-commit/pre-commit-hooks 5 | rev: v4.1.0 6 | hooks: 7 | - id: trailing-whitespace 8 | - id: check-yaml 9 | - id: check-added-large-files 10 | - repo: https://github.com/psf/black 11 | rev: 22.1.0 12 | hooks: 13 | - id: black 14 | -------------------------------------------------------------------------------- /CHANGES.txt: -------------------------------------------------------------------------------- 1 | ======= 2 | History 3 | ======= 4 | 5 | 1.1.2 (2019-03-17) 6 | ------------------ 7 | * Brings this repo in sync with Paulo Herrera's old BitBucket and new GitHub 8 | * Adds some new examples and fixes some compatibility issues with != None 9 | * Vector image support for imagetoVTK 10 | * Adds more tests to CI 11 | * Adds "evtk" package (identical to "pyevtk") for backward compatibility with 12 | depricated warning 13 | 14 | 1.1.1 (2019-02-01) 15 | ------------------ 16 | 17 | * Makes sdist installable update CI infrastructure 18 | 19 | 1.1.0 (2017-08-03) 20 | ------------------ 21 | 22 | * Added unit-tests and Travis-CI integration. 23 | 24 | 1.0.2 (2017-07-25) 25 | ------------------ 26 | 27 | * Added Python3-compatible relative imports (PR by Rene Milk). 28 | 29 | 1.0.1 (2017-06-02) 30 | ------------------ 31 | 32 | * Ported over latest changes made in the original repo by Paulo Herrera. 33 | 34 | 0.1.0 (2014-09-05) 35 | ------------------ 36 | 37 | * First port of the original PyEVTK by Paulo Herrera. 38 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | *********************************************************************************** 2 | * Copyright 2010 - 2016 Paulo A. Herrera. All rights reserved. * 3 | * * 4 | * Redistribution and use in source and binary forms, with or without * 5 | * modification, are permitted provided that the following conditions are met: * 6 | * * 7 | * 1. Redistributions of source code must retain the above copyright notice, * 8 | * this list of conditions and the following disclaimer. * 9 | * * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, * 11 | * this list of conditions and the following disclaimer in the documentation * 12 | * and/or other materials provided with the distribution. * 13 | * * 14 | * THIS SOFTWARE IS PROVIDED BY PAULO A. HERRERA ``AS IS'' AND ANY EXPRESS OR * 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * 16 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * 17 | * EVENT SHALL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * 18 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * 19 | * BUT NOT LIMITED TO, PROCUREMEN OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * 20 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * 21 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * 22 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 24 | *********************************************************************************** 25 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include *.txt 2 | include *.md 3 | include MANIFEST.in 4 | recursive-include examples *.py 5 | recursive-include tests *.py 6 | include versioneer.py 7 | include pyevtk/_version.py 8 | exclude .pre-commit-config.yaml 9 | prune .github 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Coverage Status](https://codecov.io/gh/pyscience-projects/pyevtk/branch/master/graph/badge.svg)](https://codecov.io/gh/pyscience-projects/pyevtk) 2 | [![Build Status](https://github.com/pyscience-projects/pyevtk/workflows/Test%20Python/badge.svg)](https://github.com/pyscience-projects/pyevtk/actions?query=workflow%3A%22Test+Python%22) 3 | 4 | PREAMBLE: 5 | ========= 6 | 7 | This package in its entirety belongs to Paulo Herrera and its currently hosted under: 8 | 9 | https://github.com/paulo-herrera/PyEVTK 10 | 11 | I've misappropriated, well forked and repackaged really, this package in order to host it on PyPI and allow for its easy distribution and installation as I use it a lot. I take no credit whatsoever for it. 12 | 13 | My fork is hosted under: 14 | 15 | https://github.com/pyscience-projects/pyevtk 16 | 17 | This package is nowadays primarily maintained by [René Fritze](https://github.com/renefritze) and [Xylar Asay-Davis](https://github.com/xylar). 18 | 19 | INTRODUCTION: 20 | ============= 21 | 22 | EVTK (Export VTK) package allows exporting data to binary VTK files for 23 | visualization and data analysis with any of the visualization packages that 24 | support VTK files, e.g. Paraview, VisIt and Mayavi. EVTK does not depend on any 25 | external library (e.g. VTK), so it is easy to install in different systems. 26 | 27 | Since version 0.9 the package is composed only of a set of pure Python files, hence 28 | it is straightforwrd to install and run in any system where Python is installed. 29 | EVTK provides low and high level interfaces. While the low level interface 30 | can be used to export data that is stored in any type of container, the high 31 | level functions make easy to export data stored in Numpy arrays. 32 | 33 | INSTALLATION: 34 | ============= 35 | 36 | This package is being hosted on PyPI under: 37 | 38 | https://pypi.python.org/pypi/PyEVTK 39 | 40 | and can be installed with pip using `pip install pyevtk` 41 | 42 | DOCUMENTATION: 43 | ============== 44 | 45 | This file together with the included examples in the examples directory in the 46 | source tree provide enough information to start using the package. 47 | 48 | DESIGN GUIDELINES: 49 | ================== 50 | 51 | The design of the package considered the following objectives: 52 | 53 | 1. Self-contained. The package does not require any external library with 54 | the exception of Numpy, which is becoming a standard package in many Python 55 | installations. 56 | 57 | 2. Flexibility. It is possible to use EVTK to export data stored in any 58 | container and in any of the grid formats supported by VTK by using the low level 59 | interface. 60 | 61 | 3. Easy of use. The high level interface makes very easy to export data stored 62 | in Numpy arrays. The high level interface provides functions to export most of 63 | the grids supported by VTK: image data, rectilinear and structured grids. It 64 | also includes a function to export point sets and associated data that can be 65 | used to export results from particle and meshless numerical simulations. 66 | 67 | 4. Performance. The aim of the package is to be used as a part of 68 | post-processing tools. Thus, good performance is important to handle the results 69 | of large simulations. However, latest versions give priority to ease of installation 70 | and use over performance. 71 | 72 | REQUIREMENTS: 73 | ============= 74 | 75 | - Numpy. Tested with Numpy 1.11.3. 76 | 77 | The package has been tested on: 78 | - MacOSX 10.6 x86-64. 79 | - Ubuntu 10.04 x86-64 guest running on VMWare Fusion. 80 | - Ubuntu 12.04 x86-64 running Python Anaconda (3.4.3) 81 | - Windows 7 x86-64 running Python Anaconda (3.4.3) 82 | 83 | It is compatible with both Python 2.7 and Python 3.3. Since version 0.9 it is only compatible 84 | with VTK 6.0 and newer versions. 85 | 86 | DEVELOPER NOTES: 87 | ================ 88 | 89 | It is useful to build and install the package to a temporary location without 90 | touching the global python site-packages directory while developing. To do 91 | this, while in the root directory, one can type: 92 | 93 | 1. python setup.py build --debug install --prefix=./tmp 94 | 2. export PYTHONPATH=./tmp/lib/python2.6/site-packages/:$PYTHONPATH 95 | 96 | NOTE: you may have to change the Python version depending of the installed 97 | version on your system. 98 | 99 | To test the package one can run some of the examples, e.g.: 100 | ./tmp/lib/python2.6/site-packages/examples/points.py 101 | 102 | That should create a points.vtu file in the current directory. 103 | 104 | SUPPORT: 105 | ======= 106 | 107 | I will continue releasing this package as open source, so it is free to be used in any kind of project. 108 | I will also continue providing support for simple questions and making incremental improvements as time 109 | allows. However, I also provide contract based support for commercial or research projects interested 110 | in this package or in topics related to data analysis and scientific programming with Python, Java, MATLAB/Octave, C/C++ or Fortran. 111 | For further details, please contact me to: paulo.herrera.eirl@gmail.com. 112 | 113 | **NOTE: PyEVTK moved to GitHub. The new official page is this one (https://github.com/paulo-herrera/PyEVTK)** 114 | -------------------------------------------------------------------------------- /evtk/__init__.py: -------------------------------------------------------------------------------- 1 | from pyevtk import * 2 | 3 | import warnings 4 | 5 | warnings.warn( 6 | 'the "evtk" package is deprecated, use "pyevtk" instead', 7 | DeprecationWarning, 8 | ) 9 | -------------------------------------------------------------------------------- /examples/group.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | # *********************************************************************************** 4 | # * Copyright 2010 - 2016 Paulo A. Herrera. All rights reserved. * 5 | # * * 6 | # * Redistribution and use in source and binary forms, with or without * 7 | # * modification, are permitted provided that the following conditions are met: * 8 | # * * 9 | # * 1. Redistributions of source code must retain the above copyright notice, * 10 | # * this list of conditions and the following disclaimer. * 11 | # * * 12 | # * 2. Redistributions in binary form must reproduce the above copyright notice, * 13 | # * this list of conditions and the following disclaimer in the documentation * 14 | # * and/or other materials provided with the distribution. * 15 | # * * 16 | # * THIS SOFTWARE IS PROVIDED BY PAULO A. HERRERA ``AS IS'' AND ANY EXPRESS OR * 17 | # * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * 18 | # * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * 19 | # * EVENT SHALL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * 20 | # * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * 21 | # * BUT NOT LIMITED TO, PROCUREMEN OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * 22 | # * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * 23 | # * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * 24 | # * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * 25 | # * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 26 | # *********************************************************************************** 27 | 28 | # ************************************************************** 29 | # * Example of how to create a VTK group to visualize time * 30 | # * dependent data. * 31 | # ************************************************************** 32 | 33 | from pyevtk.vtk import VtkGroup 34 | 35 | g = VtkGroup("./group") 36 | g.addFile(filepath="sim0000.vtu", sim_time=0.0) 37 | g.addFile(filepath="sim0001.vtu", sim_time=1.0) 38 | g.addFile(filepath="sim0002.vtu", sim_time=2.0) 39 | g.addFile(filepath="sim0003.vtu", sim_time=3.0) 40 | g.save() 41 | -------------------------------------------------------------------------------- /examples/image.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | # *********************************************************************************** 4 | # * Copyright 2010 - 2016 Paulo A. Herrera. All rights reserved. * 5 | # * * 6 | # * Redistribution and use in source and binary forms, with or without * 7 | # * modification, are permitted provided that the following conditions are met: * 8 | # * * 9 | # * 1. Redistributions of source code must retain the above copyright notice, * 10 | # * this list of conditions and the following disclaimer. * 11 | # * * 12 | # * 2. Redistributions in binary form must reproduce the above copyright notice, * 13 | # * this list of conditions and the following disclaimer in the documentation * 14 | # * and/or other materials provided with the distribution. * 15 | # * * 16 | # * THIS SOFTWARE IS PROVIDED BY PAULO A. HERRERA ``AS IS'' AND ANY EXPRESS OR * 17 | # * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * 18 | # * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * 19 | # * EVENT SHALL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * 20 | # * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * 21 | # * BUT NOT LIMITED TO, PROCUREMEN OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * 22 | # * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * 23 | # * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * 24 | # * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * 25 | # * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 26 | # *********************************************************************************** 27 | 28 | # ************************************************************** 29 | # * Example of how to use the high level imageToVTK function. * 30 | # ************************************************************** 31 | 32 | from pyevtk.hl import imageToVTK 33 | import numpy as np 34 | 35 | # Dimensions 36 | nx, ny, nz = 6, 6, 2 37 | ncells = nx * ny * nz 38 | npoints = (nx + 1) * (ny + 1) * (nz + 1) 39 | 40 | # Variables 41 | pressure = np.random.rand(ncells).reshape((nx, ny, nz), order="C") 42 | temp = np.random.rand(npoints).reshape((nx + 1, ny + 1, nz + 1)) 43 | 44 | imageToVTK("./image", cellData={"pressure": pressure}, pointData={"temp": temp}) 45 | 46 | fluxx = np.random.rand(ncells).reshape((nx, ny, nz), order="F") 47 | fluxy = np.random.rand(ncells).reshape((nx, ny, nz), order="F") 48 | fluxz = np.random.rand(ncells).reshape((nx, ny, nz), order="F") 49 | flux = (fluxx, fluxy, fluxz) 50 | 51 | Efieldx = np.random.rand(npoints).reshape((nx + 1, ny + 1, nz + 1), order="F") 52 | Efieldy = np.random.rand(npoints).reshape((nx + 1, ny + 1, nz + 1), order="F") 53 | Efieldz = np.random.rand(npoints).reshape((nx + 1, ny + 1, nz + 1), order="F") 54 | Efield = (Efieldx, Efieldy, Efieldz) 55 | 56 | imageToVTK("./image", cellData={"flux": flux}, pointData={"Efield": Efieldx}) 57 | -------------------------------------------------------------------------------- /examples/lines.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | # *********************************************************************************** 4 | # * Copyright 2010 - 2016 Paulo A. Herrera. All rights reserved. * 5 | # * * 6 | # * Redistribution and use in source and binary forms, with or without * 7 | # * modification, are permitted provided that the following conditions are met: * 8 | # * * 9 | # * 1. Redistributions of source code must retain the above copyright notice, * 10 | # * this list of conditions and the following disclaimer. * 11 | # * * 12 | # * 2. Redistributions in binary form must reproduce the above copyright notice, * 13 | # * this list of conditions and the following disclaimer in the documentation * 14 | # * and/or other materials provided with the distribution. * 15 | # * * 16 | # * THIS SOFTWARE IS PROVIDED BY PAULO A. HERRERA ``AS IS'' AND ANY EXPRESS OR * 17 | # * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * 18 | # * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * 19 | # * EVENT SHALL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * 20 | # * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * 21 | # * BUT NOT LIMITED TO, PROCUREMEN OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * 22 | # * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * 23 | # * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * 24 | # * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * 25 | # * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 26 | # *********************************************************************************** 27 | 28 | # ************************************************************** 29 | # * Example of how to use the high level pointsToVTK function. * 30 | # ************************************************************** 31 | 32 | from pyevtk.hl import linesToVTK 33 | import numpy as np 34 | 35 | # Example 1 36 | npoints = 4 37 | x = np.zeros(npoints) 38 | y = np.zeros(npoints) 39 | z = np.zeros(npoints) 40 | pressure = np.random.rand(npoints) 41 | temp = np.random.rand(npoints) 42 | vel = np.zeros(2) 43 | vel[0] = 1.0 44 | vel[1] = 5.0 45 | 46 | x[0], y[0], z[0] = 0.0, 0.0, 0.0 47 | x[1], y[1], z[1] = 1.0, 1.0, 1.0 48 | x[2], y[2], z[2] = 0.0, 0.0, 0.0 49 | x[3], y[3], z[3] = -1.0, 1.0, 1.0 50 | 51 | linesToVTK( 52 | "./lines", 53 | x, 54 | y, 55 | z, 56 | cellData={"vel": vel}, 57 | pointData={"temp": temp, "pressure": pressure}, 58 | ) 59 | -------------------------------------------------------------------------------- /examples/lowlevel.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | # *********************************************************************************** 4 | # * Copyright 2010 - 2016 Paulo A. Herrera. All rights reserved * 5 | # * * 6 | # * Redistribution and use in source and binary forms, with or without * 7 | # * modification, are permitted provided that the following conditions are met: * 8 | # * * 9 | # * 1. Redistributions of source code must retain the above copyright notice, * 10 | # * this list of conditions and the following disclaimer. * 11 | # * * 12 | # * 2. Redistributions in binary form must reproduce the above copyright notice, * 13 | # * this list of conditions and the following disclaimer in the documentation * 14 | # * and/or other materials provided with the distribution. * 15 | # * * 16 | # * THIS SOFTWARE IS PROVIDED BY PAULO A. HERRERA ``AS IS'' AND ANY EXPRESS OR * 17 | # * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * 18 | # * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * 19 | # * EVENT SHALL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * 20 | # * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * 21 | # * BUT NOT LIMITED TO, PROCUREMEN OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * 22 | # * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * 23 | # * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * 24 | # * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * 25 | # * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 26 | # *********************************************************************************** 27 | 28 | # ************************************************************** 29 | # * Example of how to use the low level VtkFile class. * 30 | # ************************************************************** 31 | 32 | from pyevtk.vtk import VtkFile, VtkRectilinearGrid 33 | import numpy as np 34 | 35 | nx, ny, nz = 6, 6, 2 36 | lx, ly, lz = 1.0, 1.0, 1.0 37 | dx, dy, dz = lx / nx, ly / ny, lz / nz 38 | ncells = nx * ny * nz 39 | npoints = (nx + 1) * (ny + 1) * (nz + 1) 40 | x = np.arange(0, lx + 0.1 * dx, dx, dtype="float64") 41 | y = np.arange(0, ly + 0.1 * dy, dy, dtype="float64") 42 | z = np.arange(0, lz + 0.1 * dz, dz, dtype="float64") 43 | start, end = (0, 0, 0), (nx, ny, nz) 44 | 45 | w = VtkFile("./evtk_test", VtkRectilinearGrid) 46 | w.openGrid(start=start, end=end) 47 | w.openPiece(start=start, end=end) 48 | 49 | # Point data 50 | temp = np.random.rand(npoints) 51 | vx = vy = vz = np.zeros([nx + 1, ny + 1, nz + 1], dtype="float64", order="F") 52 | w.openData("Point", scalars="Temperature", vectors="Velocity") 53 | w.addData("Temperature", temp) 54 | w.addData("Velocity", (vx, vy, vz)) 55 | w.closeData("Point") 56 | 57 | # Cell data 58 | pressure = np.zeros([nx, ny, nz], dtype="float64", order="F") 59 | w.openData("Cell", scalars="Pressure") 60 | w.addData("Pressure", pressure) 61 | w.closeData("Cell") 62 | 63 | # Coordinates of cell vertices 64 | w.openElement("Coordinates") 65 | w.addData("x_coordinates", x) 66 | w.addData("y_coordinates", y) 67 | w.addData("z_coordinates", z) 68 | w.closeElement("Coordinates") 69 | 70 | w.closePiece() 71 | w.closeGrid() 72 | 73 | w.appendData(data=temp) 74 | w.appendData(data=(vx, vy, vz)) 75 | w.appendData(data=pressure) 76 | w.appendData(x).appendData(y).appendData(z) 77 | w.save() 78 | -------------------------------------------------------------------------------- /examples/points.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | # *********************************************************************************** 4 | # * Copyright 2010 - 2016 Paulo A. Herrera. All rights reserved. * 5 | # * * 6 | # * Redistribution and use in source and binary forms, with or without * 7 | # * modification, are permitted provided that the following conditions are met: * 8 | # * * 9 | # * 1. Redistributions of source code must retain the above copyright notice, * 10 | # * this list of conditions and the following disclaimer. * 11 | # * * 12 | # * 2. Redistributions in binary form must reproduce the above copyright notice, * 13 | # * this list of conditions and the following disclaimer in the documentation * 14 | # * and/or other materials provided with the distribution. * 15 | # * * 16 | # * THIS SOFTWARE IS PROVIDED BY PAULO A. HERRERA ``AS IS'' AND ANY EXPRESS OR * 17 | # * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * 18 | # * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * 19 | # * EVENT SHALL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * 20 | # * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * 21 | # * BUT NOT LIMITED TO, PROCUREMEN OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * 22 | # * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * 23 | # * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * 24 | # * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * 25 | # * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 26 | # *********************************************************************************** 27 | 28 | # ************************************************************** 29 | # * Example of how to use the high level pointsToVTK function. * 30 | # ************************************************************** 31 | 32 | from pyevtk.hl import pointsToVTK 33 | import numpy as np 34 | 35 | # Example 1 36 | npoints = 100 37 | x = np.random.rand(npoints) 38 | y = np.random.rand(npoints) 39 | z = np.random.rand(npoints) 40 | pressure = np.random.rand(npoints) 41 | temp = np.random.rand(npoints) 42 | pointsToVTK("./rnd_points", x, y, z, data={"temp": temp, "pressure": pressure}) 43 | 44 | # Example 2 45 | x = np.arange(1.0, 10.0, 0.1) 46 | y = np.arange(1.0, 10.0, 0.1) 47 | z = np.arange(1.0, 10.0, 0.1) 48 | pointsToVTK("./line_points", x, y, z, data={"elev": z}) 49 | -------------------------------------------------------------------------------- /examples/poly_lines.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | # *********************************************************************************** 4 | # * Copyright 2010 - 2016 Paulo A. Herrera. All rights reserved. * 5 | # * * 6 | # * Redistribution and use in source and binary forms, with or without * 7 | # * modification, are permitted provided that the following conditions are met: * 8 | # * * 9 | # * 1. Redistributions of source code must retain the above copyright notice, * 10 | # * this list of conditions and the following disclaimer. * 11 | # * * 12 | # * 2. Redistributions in binary form must reproduce the above copyright notice, * 13 | # * this list of conditions and the following disclaimer in the documentation * 14 | # * and/or other materials provided with the distribution. * 15 | # * * 16 | # * THIS SOFTWARE IS PROVIDED BY PAULO A. HERRERA ``AS IS'' AND ANY EXPRESS OR * 17 | # * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * 18 | # * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * 19 | # * EVENT SHALL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * 20 | # * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * 21 | # * BUT NOT LIMITED TO, PROCUREMEN OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * 22 | # * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * 23 | # * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * 24 | # * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * 25 | # * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 26 | # *********************************************************************************** 27 | 28 | # ************************************************************** 29 | # * Example of how to use the high level pointsToVTK function. * 30 | # ************************************************************** 31 | 32 | from pyevtk.hl import polyLinesToVTK 33 | import numpy as np 34 | 35 | # Positions of points that define lines 36 | npoints = 7 37 | x = np.zeros(npoints) 38 | y = np.zeros(npoints) 39 | z = np.zeros(npoints) 40 | 41 | # First line 42 | x[0], y[0], z[0] = 0.0, 0.0, 0.0 43 | x[1], y[1], z[1] = 1.0, 1.0, 0.0 44 | x[2], y[2], z[2] = 2.0, 0.0, 0.0 45 | x[3], y[3], z[3] = 3.0, -1.0, 0.0 46 | 47 | # Second line 48 | x[4], y[4], z[4] = 0.0, 0.0, 3.0 49 | x[5], y[5], z[5] = 1.0, 1.0, 3.0 50 | x[6], y[6], z[6] = 2.0, 0.0, 3.0 51 | 52 | # Connectivity of the lines 53 | pointsPerLine = np.zeros(2) 54 | pointsPerLine[0] = 4 55 | pointsPerLine[1] = 3 56 | 57 | # Some variables 58 | pressure = np.random.rand(npoints) 59 | temp = np.random.rand(npoints) 60 | vel = np.zeros(6) 61 | vel[0:3] = 1.0 62 | vel[4:6] = 5.0 63 | 64 | polyLinesToVTK( 65 | "./poly_lines", 66 | x, 67 | y, 68 | z, 69 | pointsPerLine=pointsPerLine, 70 | cellData={"vel": vel}, 71 | pointData={"temp": temp, "pressure": pressure}, 72 | ) 73 | -------------------------------------------------------------------------------- /examples/rectilinear.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | # *********************************************************************************** 4 | # * Copyright 2010 - 2016 Paulo A. Herrera. All rights reserved. * 5 | # * * 6 | # * Redistribution and use in source and binary forms, with or without * 7 | # * modification, are permitted provided that the following conditions are met: * 8 | # * * 9 | # * 1. Redistributions of source code must retain the above copyright notice, * 10 | # * this list of conditions and the following disclaimer. * 11 | # * * 12 | # * 2. Redistributions in binary form must reproduce the above copyright notice, * 13 | # * this list of conditions and the following disclaimer in the documentation * 14 | # * and/or other materials provided with the distribution. * 15 | # * * 16 | # * THIS SOFTWARE IS PROVIDED BY PAULO A. HERRERA ``AS IS'' AND ANY EXPRESS OR * 17 | # * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * 18 | # * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * 19 | # * EVENT SHALL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * 20 | # * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * 21 | # * BUT NOT LIMITED TO, PROCUREMEN OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * 22 | # * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * 23 | # * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * 24 | # * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * 25 | # * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 26 | # *********************************************************************************** 27 | 28 | # ************************************************************** 29 | # * Example of how to use the high level gridToVTK function. * 30 | # * This example shows how to export a rectilinear grid. * 31 | # ************************************************************** 32 | 33 | from pyevtk.hl import gridToVTK, writeParallelVTKGrid 34 | import numpy as np 35 | 36 | # ================== 37 | # Serial example 38 | # ================== 39 | 40 | # Dimensions 41 | nx, ny, nz = 6, 6, 2 42 | lx, ly, lz = 1.0, 1.0, 1.0 43 | dx, dy, dz = lx / nx, ly / ny, lz / nz 44 | 45 | ncells = nx * ny * nz 46 | npoints = (nx + 1) * (ny + 1) * (nz + 1) 47 | 48 | # Coordinates 49 | x = np.arange(0, lx + 0.1 * dx, dx, dtype="float64") 50 | y = np.arange(0, ly + 0.1 * dy, dy, dtype="float64") 51 | z = np.arange(0, lz + 0.1 * dz, dz, dtype="float64") 52 | 53 | # Variables 54 | pressure = np.random.rand(ncells).reshape((nx, ny, nz)) 55 | temp = np.random.rand(npoints).reshape((nx + 1, ny + 1, nz + 1)) 56 | 57 | gridToVTK( 58 | "./rectilinear", 59 | x, 60 | y, 61 | z, 62 | cellData={"pressure": pressure}, 63 | pointData={"temp": temp}, 64 | ) 65 | 66 | 67 | # ================== 68 | # Parallel example 69 | # ================== 70 | 71 | # Dimensions 72 | x1 = np.linspace(0, 1, 10) 73 | x2 = np.linspace(1, 2, 20) 74 | 75 | y = np.linspace(0, 1, 10) 76 | z = np.linspace(0, 1, 10) 77 | 78 | gridToVTK("test.0", x1, y, z, start=(0, 0, 0)) 79 | gridToVTK("test.1", x2, y, z, start=(9, 0, 0)) 80 | 81 | writeParallelVTKGrid( 82 | "test_full", 83 | coordsData=((29, 10, 10), x.dtype), 84 | starts=[(0, 0, 0), (9, 0, 0)], 85 | ends=[(9, 9, 9), (28, 9, 9)], 86 | sources=["test.0.vtr", "test.1.vtr"], 87 | ) 88 | -------------------------------------------------------------------------------- /examples/structured.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | # *********************************************************************************** 4 | # * Copyright 2010 - 2016 Paulo A. Herrera. All rights reserved. * 5 | # * * 6 | # * Redistribution and use in source and binary forms, with or without * 7 | # * modification, are permitted provided that the following conditions are met: * 8 | # * * 9 | # * 1. Redistributions of source code must retain the above copyright notice, * 10 | # * this list of conditions and the following disclaimer. * 11 | # * * 12 | # * 2. Redistributions in binary form must reproduce the above copyright notice, * 13 | # * this list of conditions and the following disclaimer in the documentation * 14 | # * and/or other materials provided with the distribution. * 15 | # * * 16 | # * THIS SOFTWARE IS PROVIDED BY PAULO A. HERRERA ``AS IS'' AND ANY EXPRESS OR * 17 | # * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * 18 | # * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * 19 | # * EVENT SHALL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * 20 | # * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * 21 | # * BUT NOT LIMITED TO, PROCUREMEN OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * 22 | # * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * 23 | # * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * 24 | # * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * 25 | # * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 26 | # *********************************************************************************** 27 | 28 | # ************************************************************** 29 | # * Example of how to use the high level gridToVTK function. * 30 | # * This example shows how to export a structured grid. * 31 | # ************************************************************** 32 | 33 | from pyevtk.hl import gridToVTK, writeParallelVTKGrid 34 | import numpy as np 35 | import random as rnd 36 | 37 | # =================== 38 | # Serial Example 39 | # =================== 40 | 41 | # Dimensions 42 | nx, ny, nz = 6, 6, 2 43 | lx, ly, lz = 1.0, 1.0, 1.0 44 | dx, dy, dz = lx / nx, ly / ny, lz / nz 45 | 46 | ncells = nx * ny * nz 47 | npoints = (nx + 1) * (ny + 1) * (nz + 1) 48 | 49 | # Coordinates 50 | X = np.arange(0, lx + 0.1 * dx, dx, dtype="float64") 51 | Y = np.arange(0, ly + 0.1 * dy, dy, dtype="float64") 52 | Z = np.arange(0, lz + 0.1 * dz, dz, dtype="float64") 53 | 54 | x = np.zeros((nx + 1, ny + 1, nz + 1)) 55 | y = np.zeros((nx + 1, ny + 1, nz + 1)) 56 | z = np.zeros((nx + 1, ny + 1, nz + 1)) 57 | 58 | # We add some random fluctuation to make the grid 59 | # more interesting 60 | for k in range(nz + 1): 61 | for j in range(ny + 1): 62 | for i in range(nx + 1): 63 | x[i, j, k] = X[i] + (0.5 - rnd.random()) * 0.1 * dx 64 | y[i, j, k] = Y[j] + (0.5 - rnd.random()) * 0.1 * dy 65 | z[i, j, k] = Z[k] + (0.5 - rnd.random()) * 0.1 * dz 66 | 67 | # Variables 68 | pressure = np.random.rand(ncells).reshape((nx, ny, nz)) 69 | temp = np.random.rand(npoints).reshape((nx + 1, ny + 1, nz + 1)) 70 | 71 | gridToVTK( 72 | "./structured", 73 | x, 74 | y, 75 | z, 76 | cellData={"pressure": pressure}, 77 | pointData={"temp": temp}, 78 | ) 79 | 80 | 81 | # =================== 82 | # Parallel example 83 | # =================== 84 | 85 | # Dimensions 86 | x1 = np.linspace(0, 1, 20) 87 | 88 | x2_1 = np.linspace(0, 0.5, 10) 89 | x2_2 = np.linspace(0.5, 1, 10) 90 | 91 | x3 = np.linspace(0, 2, 30) 92 | 93 | XX1_1, XX2_1, XX3_1 = np.meshgrid(x1, x2_1, x3, indexing="ij") 94 | XX1_2, XX2_2, XX3_2 = np.meshgrid(x1, x2_2, x3, indexing="ij") 95 | 96 | pi = np.pi 97 | sphere = lambda R, Th, Ph: ( 98 | R * np.cos(pi * Ph) * np.sin(pi * Th), 99 | R * np.sin(pi * Ph) * np.sin(pi * Th), 100 | R * np.cos(pi * Th), 101 | ) 102 | 103 | # First Half sphere 104 | gridToVTK( 105 | "sphere.0", 106 | *sphere(XX1_1, XX2_1, XX3_1), 107 | start=(0, 0, 0), 108 | pointData={"R": XX1_1, "Theta": XX2_1, "Phi": XX3_1} 109 | ) 110 | # Second Half sphere 111 | gridToVTK( 112 | "sphere.1", 113 | *sphere(XX1_2, XX2_2, XX3_2), 114 | start=(0, 9, 0), 115 | pointData={"R": XX1_2, "Theta": XX2_2, "Phi": XX3_2} 116 | ) 117 | 118 | # Write parallel file 119 | writeParallelVTKGrid( 120 | "sphere_full", 121 | coordsData=((20, 19, 30), XX1_1.dtype), 122 | starts=[(0, 0, 0), (0, 9, 0)], 123 | ends=[(19, 9, 29), (19, 18, 29)], 124 | sources=["sphere.0.vts", "sphere.1.vts"], 125 | pointData={ 126 | "R": (XX1_1.dtype, 1), 127 | "Theta": (XX2_1.dtype, 1), 128 | "Phi": (XX3_1.dtype, 1), 129 | }, 130 | ) 131 | -------------------------------------------------------------------------------- /examples/unstructured.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | # *********************************************************************************** 4 | # * Copyright 2010 - 2017 Paulo A. Herrera. All rights reserved. * 5 | # * * 6 | # * Redistribution and use in source and binary forms, with or without * 7 | # * modification, are permitted provided that the following conditions are met: * 8 | # * * 9 | # * 1. Redistributions of source code must retain the above copyright notice, * 10 | # * this list of conditions and the following disclaimer. * 11 | # * * 12 | # * 2. Redistributions in binary form must reproduce the above copyright notice, * 13 | # * this list of conditions and the following disclaimer in the documentation * 14 | # * and/or other materials provided with the distribution. * 15 | # * * 16 | # * THIS SOFTWARE IS PROVIDED BY PAULO A. HERRERA ``AS IS'' AND ANY EXPRESS OR * 17 | # * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * 18 | # * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * 19 | # * EVENT SHALL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * 20 | # * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * 21 | # * BUT NOT LIMITED TO, PROCUREMEN OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * 22 | # * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * 23 | # * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * 24 | # * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * 25 | # * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 26 | # *********************************************************************************** 27 | 28 | # ************************************************************************ 29 | # * Example of how to use the high level unstructuredGridToVTK function. * 30 | # * This example shows how to export a unstructured grid give its * 31 | # * nodes and topology through a connectivity and offset lists. * 32 | # * Check the VTK file format for details of the unstructured grid. * 33 | # ************************************************************************ 34 | 35 | from pyevtk.hl import unstructuredGridToVTK 36 | from pyevtk.vtk import VtkTriangle, VtkQuad 37 | import numpy as np 38 | 39 | # Define vertices 40 | x = np.zeros(6) 41 | y = np.zeros(6) 42 | z = np.zeros(6) 43 | 44 | x[0], y[0], z[0] = 0.0, 0.0, 0.0 45 | x[1], y[1], z[1] = 1.0, 0.0, 0.0 46 | x[2], y[2], z[2] = 2.0, 0.0, 0.0 47 | x[3], y[3], z[3] = 0.0, 1.0, 0.0 48 | x[4], y[4], z[4] = 1.0, 1.0, 0.0 49 | x[5], y[5], z[5] = 2.0, 1.0, 0.0 50 | 51 | point_data = {"test_pd": np.array([1, 2, 3, 4, 5, 6])} 52 | cell_data = {"test_cd": np.array([1, 2, 3])} 53 | field_data = {"test_fd": np.array([1.0, 2.0])} 54 | # Define connectivity or vertices that belongs to each element 55 | conn = np.zeros(10) 56 | 57 | conn[0], conn[1], conn[2] = 0, 1, 3 # first triangle 58 | conn[3], conn[4], conn[5] = 1, 4, 3 # second triangle 59 | conn[6], conn[7], conn[8], conn[9] = 1, 2, 5, 4 # rectangle 60 | 61 | # Define offset of last vertex of each element 62 | offset = np.zeros(3) 63 | offset[0] = 3 64 | offset[1] = 6 65 | offset[2] = 10 66 | 67 | # Define cell types 68 | 69 | ctype = np.zeros(3) 70 | ctype[0], ctype[1] = VtkTriangle.tid, VtkTriangle.tid 71 | ctype[2] = VtkQuad.tid 72 | 73 | unstructuredGridToVTK( 74 | "unstructured", 75 | x, 76 | y, 77 | z, 78 | connectivity=conn, 79 | offsets=offset, 80 | cell_types=ctype, 81 | cellData=cell_data, 82 | pointData=point_data, 83 | fieldData=field_data, 84 | ) 85 | -------------------------------------------------------------------------------- /pyevtk/__init__.py: -------------------------------------------------------------------------------- 1 | # ************************************************************************* 2 | # * Copyright 2010 - 2016 Paulo Herrera * 3 | # * * 4 | # * This file is part of EVTK. * 5 | # * * 6 | # * EVTK is free software: you can redistribute it and/or modify * 7 | # * it under the terms of the GNU General Public License as published by * 8 | # * the Free Software Foundation, either version 3 of the License, or * 9 | # * (at your option) any later version. * 10 | # * * 11 | # * EVTK is distributed in the hope that it will be useful, * 12 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of * 13 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 14 | # * GNU General Public License for more details. * 15 | # * * 16 | # * You should have received a copy of the GNU General Public License * 17 | # * along with EVTK. If not, see . * 18 | # ************************************************************************* 19 | 20 | from . import evtk 21 | from . import hl 22 | from . import vtk 23 | from . import xml 24 | 25 | from ._version import get_versions 26 | 27 | __version__ = get_versions()["version"] 28 | del get_versions 29 | -------------------------------------------------------------------------------- /pyevtk/_version.py: -------------------------------------------------------------------------------- 1 | # This file helps to compute a version number in source trees obtained from 2 | # git-archive tarball (such as those provided by githubs download-from-tag 3 | # feature). Distribution tarballs (built by setup.py sdist) and build 4 | # directories (produced by setup.py build) will contain a much shorter file 5 | # that just contains the computed version number. 6 | 7 | # This file is released into the public domain. Generated by 8 | # versioneer-0.19 (https://github.com/python-versioneer/python-versioneer) 9 | 10 | """Git implementation of _version.py.""" 11 | 12 | import errno 13 | import os 14 | import re 15 | import subprocess 16 | import sys 17 | 18 | 19 | def get_keywords(): 20 | """Get the keywords needed to look up the version information.""" 21 | # these strings will be replaced by git during git-archive. 22 | # setup.py/versioneer.py will grep for the variable names, so they must 23 | # each be defined on a line of their own. _version.py will just call 24 | # get_keywords(). 25 | git_refnames = " (HEAD -> master, tag: v1.6.0)" 26 | git_full = "4894780e69c4f7125da679589bf85548d90f58b6" 27 | git_date = "2023-06-05 17:09:42 +0200" 28 | keywords = {"refnames": git_refnames, "full": git_full, "date": git_date} 29 | return keywords 30 | 31 | 32 | class VersioneerConfig: 33 | """Container for Versioneer configuration parameters.""" 34 | 35 | 36 | def get_config(): 37 | """Create, populate and return the VersioneerConfig() object.""" 38 | # these strings are filled in when 'setup.py versioneer' creates 39 | # _version.py 40 | cfg = VersioneerConfig() 41 | cfg.VCS = "git" 42 | cfg.style = "pep440-pre" 43 | cfg.tag_prefix = "" 44 | cfg.parentdir_prefix = "" 45 | cfg.versionfile_source = "pyevtk/_version.py" 46 | cfg.verbose = False 47 | return cfg 48 | 49 | 50 | class NotThisMethod(Exception): 51 | """Exception raised if a method is not valid for the current scenario.""" 52 | 53 | 54 | LONG_VERSION_PY = {} 55 | HANDLERS = {} 56 | 57 | 58 | def register_vcs_handler(vcs, method): # decorator 59 | """Create decorator to mark a method as the handler of a VCS.""" 60 | 61 | def decorate(f): 62 | """Store f in HANDLERS[vcs][method].""" 63 | if vcs not in HANDLERS: 64 | HANDLERS[vcs] = {} 65 | HANDLERS[vcs][method] = f 66 | return f 67 | 68 | return decorate 69 | 70 | 71 | def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, env=None): 72 | """Call the given command(s).""" 73 | assert isinstance(commands, list) 74 | p = None 75 | for c in commands: 76 | try: 77 | dispcmd = str([c] + args) 78 | # remember shell=False, so use git.cmd on windows, not just git 79 | p = subprocess.Popen( 80 | [c] + args, 81 | cwd=cwd, 82 | env=env, 83 | stdout=subprocess.PIPE, 84 | stderr=(subprocess.PIPE if hide_stderr else None), 85 | ) 86 | break 87 | except EnvironmentError: 88 | e = sys.exc_info()[1] 89 | if e.errno == errno.ENOENT: 90 | continue 91 | if verbose: 92 | print("unable to run %s" % dispcmd) 93 | print(e) 94 | return None, None 95 | else: 96 | if verbose: 97 | print("unable to find command, tried %s" % (commands,)) 98 | return None, None 99 | stdout = p.communicate()[0].strip().decode() 100 | if p.returncode != 0: 101 | if verbose: 102 | print("unable to run %s (error)" % dispcmd) 103 | print("stdout was %s" % stdout) 104 | return None, p.returncode 105 | return stdout, p.returncode 106 | 107 | 108 | def versions_from_parentdir(parentdir_prefix, root, verbose): 109 | """Try to determine the version from the parent directory name. 110 | 111 | Source tarballs conventionally unpack into a directory that includes both 112 | the project name and a version string. We will also support searching up 113 | two directory levels for an appropriately named parent directory 114 | """ 115 | rootdirs = [] 116 | 117 | for i in range(3): 118 | dirname = os.path.basename(root) 119 | if dirname.startswith(parentdir_prefix): 120 | return { 121 | "version": dirname[len(parentdir_prefix) :], 122 | "full-revisionid": None, 123 | "dirty": False, 124 | "error": None, 125 | "date": None, 126 | } 127 | else: 128 | rootdirs.append(root) 129 | root = os.path.dirname(root) # up a level 130 | 131 | if verbose: 132 | print( 133 | "Tried directories %s but none started with prefix %s" 134 | % (str(rootdirs), parentdir_prefix) 135 | ) 136 | raise NotThisMethod("rootdir doesn't start with parentdir_prefix") 137 | 138 | 139 | @register_vcs_handler("git", "get_keywords") 140 | def git_get_keywords(versionfile_abs): 141 | """Extract version information from the given file.""" 142 | # the code embedded in _version.py can just fetch the value of these 143 | # keywords. When used from setup.py, we don't want to import _version.py, 144 | # so we do it with a regexp instead. This function is not used from 145 | # _version.py. 146 | keywords = {} 147 | try: 148 | f = open(versionfile_abs, "r") 149 | for line in f.readlines(): 150 | if line.strip().startswith("git_refnames ="): 151 | mo = re.search(r'=\s*"(.*)"', line) 152 | if mo: 153 | keywords["refnames"] = mo.group(1) 154 | if line.strip().startswith("git_full ="): 155 | mo = re.search(r'=\s*"(.*)"', line) 156 | if mo: 157 | keywords["full"] = mo.group(1) 158 | if line.strip().startswith("git_date ="): 159 | mo = re.search(r'=\s*"(.*)"', line) 160 | if mo: 161 | keywords["date"] = mo.group(1) 162 | f.close() 163 | except EnvironmentError: 164 | pass 165 | return keywords 166 | 167 | 168 | @register_vcs_handler("git", "keywords") 169 | def git_versions_from_keywords(keywords, tag_prefix, verbose): 170 | """Get version information from git keywords.""" 171 | if not keywords: 172 | raise NotThisMethod("no keywords at all, weird") 173 | date = keywords.get("date") 174 | if date is not None: 175 | # Use only the last line. Previous lines may contain GPG signature 176 | # information. 177 | date = date.splitlines()[-1] 178 | 179 | # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant 180 | # datestamp. However we prefer "%ci" (which expands to an "ISO-8601 181 | # -like" string, which we must then edit to make compliant), because 182 | # it's been around since git-1.5.3, and it's too difficult to 183 | # discover which version we're using, or to work around using an 184 | # older one. 185 | date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) 186 | refnames = keywords["refnames"].strip() 187 | if refnames.startswith("$Format"): 188 | if verbose: 189 | print("keywords are unexpanded, not using") 190 | raise NotThisMethod("unexpanded keywords, not a git-archive tarball") 191 | refs = set([r.strip() for r in refnames.strip("()").split(",")]) 192 | # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of 193 | # just "foo-1.0". If we see a "tag: " prefix, prefer those. 194 | TAG = "tag: " 195 | tags = set([r[len(TAG) :] for r in refs if r.startswith(TAG)]) 196 | if not tags: 197 | # Either we're using git < 1.8.3, or there really are no tags. We use 198 | # a heuristic: assume all version tags have a digit. The old git %d 199 | # expansion behaves like git log --decorate=short and strips out the 200 | # refs/heads/ and refs/tags/ prefixes that would let us distinguish 201 | # between branches and tags. By ignoring refnames without digits, we 202 | # filter out many common branch names like "release" and 203 | # "stabilization", as well as "HEAD" and "master". 204 | tags = set([r for r in refs if re.search(r"\d", r)]) 205 | if verbose: 206 | print("discarding '%s', no digits" % ",".join(refs - tags)) 207 | if verbose: 208 | print("likely tags: %s" % ",".join(sorted(tags))) 209 | for ref in sorted(tags): 210 | # sorting will prefer e.g. "2.0" over "2.0rc1" 211 | if ref.startswith(tag_prefix): 212 | r = ref[len(tag_prefix) :] 213 | if verbose: 214 | print("picking %s" % r) 215 | return { 216 | "version": r, 217 | "full-revisionid": keywords["full"].strip(), 218 | "dirty": False, 219 | "error": None, 220 | "date": date, 221 | } 222 | # no suitable tags, so version is "0+unknown", but full hex is still there 223 | if verbose: 224 | print("no suitable tags, using unknown + full revision id") 225 | return { 226 | "version": "0+unknown", 227 | "full-revisionid": keywords["full"].strip(), 228 | "dirty": False, 229 | "error": "no suitable tags", 230 | "date": None, 231 | } 232 | 233 | 234 | @register_vcs_handler("git", "pieces_from_vcs") 235 | def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): 236 | """Get version from 'git describe' in the root of the source tree. 237 | 238 | This only gets called if the git-archive 'subst' keywords were *not* 239 | expanded, and _version.py hasn't already been rewritten with a short 240 | version string, meaning we're inside a checked out source tree. 241 | """ 242 | GITS = ["git"] 243 | if sys.platform == "win32": 244 | GITS = ["git.cmd", "git.exe"] 245 | 246 | out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True) 247 | if rc != 0: 248 | if verbose: 249 | print("Directory %s not under git control" % root) 250 | raise NotThisMethod("'git rev-parse --git-dir' returned error") 251 | 252 | # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] 253 | # if there isn't one, this yields HEX[-dirty] (no NUM) 254 | describe_out, rc = run_command( 255 | GITS, 256 | [ 257 | "describe", 258 | "--tags", 259 | "--dirty", 260 | "--always", 261 | "--long", 262 | "--match", 263 | "%s*" % tag_prefix, 264 | ], 265 | cwd=root, 266 | ) 267 | # --long was added in git-1.5.5 268 | if describe_out is None: 269 | raise NotThisMethod("'git describe' failed") 270 | describe_out = describe_out.strip() 271 | full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) 272 | if full_out is None: 273 | raise NotThisMethod("'git rev-parse' failed") 274 | full_out = full_out.strip() 275 | 276 | pieces = {} 277 | pieces["long"] = full_out 278 | pieces["short"] = full_out[:7] # maybe improved later 279 | pieces["error"] = None 280 | 281 | # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] 282 | # TAG might have hyphens. 283 | git_describe = describe_out 284 | 285 | # look for -dirty suffix 286 | dirty = git_describe.endswith("-dirty") 287 | pieces["dirty"] = dirty 288 | if dirty: 289 | git_describe = git_describe[: git_describe.rindex("-dirty")] 290 | 291 | # now we have TAG-NUM-gHEX or HEX 292 | 293 | if "-" in git_describe: 294 | # TAG-NUM-gHEX 295 | mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe) 296 | if not mo: 297 | # unparseable. Maybe git-describe is misbehaving? 298 | pieces["error"] = "unable to parse git-describe output: '%s'" % describe_out 299 | return pieces 300 | 301 | # tag 302 | full_tag = mo.group(1) 303 | if not full_tag.startswith(tag_prefix): 304 | if verbose: 305 | fmt = "tag '%s' doesn't start with prefix '%s'" 306 | print(fmt % (full_tag, tag_prefix)) 307 | pieces["error"] = "tag '%s' doesn't start with prefix '%s'" % ( 308 | full_tag, 309 | tag_prefix, 310 | ) 311 | return pieces 312 | pieces["closest-tag"] = full_tag[len(tag_prefix) :] 313 | 314 | # distance: number of commits since tag 315 | pieces["distance"] = int(mo.group(2)) 316 | 317 | # commit: short hex revision ID 318 | pieces["short"] = mo.group(3) 319 | 320 | else: 321 | # HEX: no tags 322 | pieces["closest-tag"] = None 323 | count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], cwd=root) 324 | pieces["distance"] = int(count_out) # total number of commits 325 | 326 | # commit date: see ISO-8601 comment in git_versions_from_keywords() 327 | date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[ 328 | 0 329 | ].strip() 330 | # Use only the last line. Previous lines may contain GPG signature 331 | # information. 332 | date = date.splitlines()[-1] 333 | pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) 334 | 335 | return pieces 336 | 337 | 338 | def plus_or_dot(pieces): 339 | """Return a + if we don't already have one, else return a .""" 340 | if "+" in pieces.get("closest-tag", ""): 341 | return "." 342 | return "+" 343 | 344 | 345 | def render_pep440(pieces): 346 | """Build up version string, with post-release "local version identifier". 347 | 348 | Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you 349 | get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty 350 | 351 | Exceptions: 352 | 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] 353 | """ 354 | if pieces["closest-tag"]: 355 | rendered = pieces["closest-tag"] 356 | if pieces["distance"] or pieces["dirty"]: 357 | rendered += plus_or_dot(pieces) 358 | rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) 359 | if pieces["dirty"]: 360 | rendered += ".dirty" 361 | else: 362 | # exception #1 363 | rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) 364 | if pieces["dirty"]: 365 | rendered += ".dirty" 366 | return rendered 367 | 368 | 369 | def render_pep440_pre(pieces): 370 | """TAG[.post0.devDISTANCE] -- No -dirty. 371 | 372 | Exceptions: 373 | 1: no tags. 0.post0.devDISTANCE 374 | """ 375 | if pieces["closest-tag"]: 376 | rendered = pieces["closest-tag"] 377 | if pieces["distance"]: 378 | rendered += ".post0.dev%d" % pieces["distance"] 379 | else: 380 | # exception #1 381 | rendered = "0.post0.dev%d" % pieces["distance"] 382 | return rendered 383 | 384 | 385 | def render_pep440_post(pieces): 386 | """TAG[.postDISTANCE[.dev0]+gHEX] . 387 | 388 | The ".dev0" means dirty. Note that .dev0 sorts backwards 389 | (a dirty tree will appear "older" than the corresponding clean one), 390 | but you shouldn't be releasing software with -dirty anyways. 391 | 392 | Exceptions: 393 | 1: no tags. 0.postDISTANCE[.dev0] 394 | """ 395 | if pieces["closest-tag"]: 396 | rendered = pieces["closest-tag"] 397 | if pieces["distance"] or pieces["dirty"]: 398 | rendered += ".post%d" % pieces["distance"] 399 | if pieces["dirty"]: 400 | rendered += ".dev0" 401 | rendered += plus_or_dot(pieces) 402 | rendered += "g%s" % pieces["short"] 403 | else: 404 | # exception #1 405 | rendered = "0.post%d" % pieces["distance"] 406 | if pieces["dirty"]: 407 | rendered += ".dev0" 408 | rendered += "+g%s" % pieces["short"] 409 | return rendered 410 | 411 | 412 | def render_pep440_old(pieces): 413 | """TAG[.postDISTANCE[.dev0]] . 414 | 415 | The ".dev0" means dirty. 416 | 417 | Exceptions: 418 | 1: no tags. 0.postDISTANCE[.dev0] 419 | """ 420 | if pieces["closest-tag"]: 421 | rendered = pieces["closest-tag"] 422 | if pieces["distance"] or pieces["dirty"]: 423 | rendered += ".post%d" % pieces["distance"] 424 | if pieces["dirty"]: 425 | rendered += ".dev0" 426 | else: 427 | # exception #1 428 | rendered = "0.post%d" % pieces["distance"] 429 | if pieces["dirty"]: 430 | rendered += ".dev0" 431 | return rendered 432 | 433 | 434 | def render_git_describe(pieces): 435 | """TAG[-DISTANCE-gHEX][-dirty]. 436 | 437 | Like 'git describe --tags --dirty --always'. 438 | 439 | Exceptions: 440 | 1: no tags. HEX[-dirty] (note: no 'g' prefix) 441 | """ 442 | if pieces["closest-tag"]: 443 | rendered = pieces["closest-tag"] 444 | if pieces["distance"]: 445 | rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) 446 | else: 447 | # exception #1 448 | rendered = pieces["short"] 449 | if pieces["dirty"]: 450 | rendered += "-dirty" 451 | return rendered 452 | 453 | 454 | def render_git_describe_long(pieces): 455 | """TAG-DISTANCE-gHEX[-dirty]. 456 | 457 | Like 'git describe --tags --dirty --always -long'. 458 | The distance/hash is unconditional. 459 | 460 | Exceptions: 461 | 1: no tags. HEX[-dirty] (note: no 'g' prefix) 462 | """ 463 | if pieces["closest-tag"]: 464 | rendered = pieces["closest-tag"] 465 | rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) 466 | else: 467 | # exception #1 468 | rendered = pieces["short"] 469 | if pieces["dirty"]: 470 | rendered += "-dirty" 471 | return rendered 472 | 473 | 474 | def render(pieces, style): 475 | """Render the given version pieces into the requested style.""" 476 | if pieces["error"]: 477 | return { 478 | "version": "unknown", 479 | "full-revisionid": pieces.get("long"), 480 | "dirty": None, 481 | "error": pieces["error"], 482 | "date": None, 483 | } 484 | 485 | if not style or style == "default": 486 | style = "pep440" # the default 487 | 488 | if style == "pep440": 489 | rendered = render_pep440(pieces) 490 | elif style == "pep440-pre": 491 | rendered = render_pep440_pre(pieces) 492 | elif style == "pep440-post": 493 | rendered = render_pep440_post(pieces) 494 | elif style == "pep440-old": 495 | rendered = render_pep440_old(pieces) 496 | elif style == "git-describe": 497 | rendered = render_git_describe(pieces) 498 | elif style == "git-describe-long": 499 | rendered = render_git_describe_long(pieces) 500 | else: 501 | raise ValueError("unknown style '%s'" % style) 502 | 503 | return { 504 | "version": rendered, 505 | "full-revisionid": pieces["long"], 506 | "dirty": pieces["dirty"], 507 | "error": None, 508 | "date": pieces.get("date"), 509 | } 510 | 511 | 512 | def get_versions(): 513 | """Get version information or return default if unable to do so.""" 514 | # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have 515 | # __file__, we can work backwards from there to the root. Some 516 | # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which 517 | # case we can only use expanded keywords. 518 | 519 | cfg = get_config() 520 | verbose = cfg.verbose 521 | 522 | try: 523 | return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, verbose) 524 | except NotThisMethod: 525 | pass 526 | 527 | try: 528 | root = os.path.realpath(__file__) 529 | # versionfile_source is the relative path from the top of the source 530 | # tree (where the .git directory might live) to this file. Invert 531 | # this to find the root from __file__. 532 | for i in cfg.versionfile_source.split("/"): 533 | root = os.path.dirname(root) 534 | except NameError: 535 | return { 536 | "version": "0+unknown", 537 | "full-revisionid": None, 538 | "dirty": None, 539 | "error": "unable to find root of source tree", 540 | "date": None, 541 | } 542 | 543 | try: 544 | pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) 545 | return render(pieces, cfg.style) 546 | except NotThisMethod: 547 | pass 548 | 549 | try: 550 | if cfg.parentdir_prefix: 551 | return versions_from_parentdir(cfg.parentdir_prefix, root, verbose) 552 | except NotThisMethod: 553 | pass 554 | 555 | return { 556 | "version": "0+unknown", 557 | "full-revisionid": None, 558 | "dirty": None, 559 | "error": "unable to compute version", 560 | "date": None, 561 | } 562 | -------------------------------------------------------------------------------- /pyevtk/evtk.py: -------------------------------------------------------------------------------- 1 | # *********************************************************************************** 2 | # * Copyright 2010 - 2016 Paulo A. Herrera. All rights reserved. * 3 | # * * 4 | # * Redistribution and use in source and binary forms, with or without * 5 | # * modification, are permitted provided that the following conditions are met: * 6 | # * * 7 | # * 1. Redistributions of source code must retain the above copyright notice, * 8 | # * this list of conditions and the following disclaimer. * 9 | # * * 10 | # * 2. Redistributions in binary form must reproduce the above copyright notice, * 11 | # * this list of conditions and the following disclaimer in the documentation * 12 | # * and/or other materials provided with the distribution. * 13 | # * * 14 | # * THIS SOFTWARE IS PROVIDED BY PAULO A. HERRERA ``AS IS'' AND ANY EXPRESS OR * 15 | # * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * 16 | # * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * 17 | # * EVENT SHALL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * 18 | # * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * 19 | # * BUT NOT LIMITED TO, PROCUREMEN OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * 20 | # * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * 21 | # * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * 22 | # * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * 23 | # * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 24 | # *********************************************************************************** 25 | """Export routines.""" 26 | 27 | import sys 28 | import struct 29 | 30 | # import base64 31 | import numpy as np 32 | 33 | # Map numpy dtype to struct format 34 | np_to_struct = { 35 | "int8": "b", 36 | "uint8": "B", 37 | "int16": "h", 38 | "uint16": "H", 39 | "int32": "i", 40 | "uint32": "I", 41 | "int64": "q", 42 | "uint64": "Q", 43 | "float32": "f", 44 | "float64": "d", 45 | } 46 | 47 | 48 | def _get_byte_order_char(): 49 | # Check format in https://docs.python.org/3.5/library/struct.html 50 | if sys.byteorder == "little": 51 | return "<" 52 | return ">" 53 | 54 | 55 | # ================================ 56 | # Python interface 57 | # ================================ 58 | def writeBlockSize(stream, block_size): 59 | """ 60 | Write block size to a given stream. 61 | 62 | Parameters 63 | ---------- 64 | stream : stream 65 | open stream. 66 | block_size : int 67 | block size. 68 | """ 69 | fmt = ( 70 | _get_byte_order_char() + "Q" 71 | ) # Write size as unsigned long long == 64 bits unsigned integer 72 | stream.write(struct.pack(fmt, block_size)) 73 | 74 | 75 | def writeArrayToFile(stream, data): 76 | """ 77 | Write array to a given stream. 78 | 79 | Parameters 80 | ---------- 81 | stream : stream 82 | open stream. 83 | data : array-like 84 | data array to be saved. 85 | """ 86 | # stream.flush() # this should not be necessary 87 | assert data.ndim == 1 or data.ndim == 3 88 | fmt = ( 89 | _get_byte_order_char() + str(data.size) + np_to_struct[data.dtype.name] 90 | ) # > for big endian 91 | 92 | # Check if array is contiguous 93 | assert data.flags["C_CONTIGUOUS"] or data.flags["F_CONTIGUOUS"] 94 | 95 | # NOTE: VTK expects data in FORTRAN order 96 | # This is only needed when a multidimensional array has C-layout 97 | dd = np.ravel(data, order="F") 98 | 99 | bin_pack = struct.pack(fmt, *dd) 100 | stream.write(bin_pack) 101 | 102 | 103 | # ============================================================================== 104 | def writeArraysToFile(stream, x, y, z): 105 | """ 106 | Write multiple array to a given stream. 107 | 108 | Parameters 109 | ---------- 110 | stream : stream 111 | open stream. 112 | x : array-like 113 | x array to be saved. 114 | y : array-like 115 | y array to be saved. 116 | z : array-like 117 | z array to be saved. 118 | """ 119 | # Check if arrays have same shape and data type 120 | assert x.size == y.size == z.size, "Different array sizes." 121 | assert ( 122 | x.dtype.itemsize == y.dtype.itemsize == z.dtype.itemsize 123 | ), "Different item sizes." 124 | 125 | nitems = x.size 126 | # itemsize = x.dtype.itemsize 127 | 128 | fmt = ( 129 | _get_byte_order_char() + str(1) + np_to_struct[x.dtype.name] 130 | ) # > for big endian 131 | 132 | # Check if arrays are contiguous 133 | assert x.flags["C_CONTIGUOUS"] or x.flags["F_CONTIGUOUS"] 134 | assert y.flags["C_CONTIGUOUS"] or y.flags["F_CONTIGUOUS"] 135 | assert z.flags["C_CONTIGUOUS"] or z.flags["F_CONTIGUOUS"] 136 | 137 | # NOTE: VTK expects data in FORTRAN order 138 | # This is only needed when a multidimensional array has C-layout 139 | xx = np.ravel(x, order="F") 140 | yy = np.ravel(y, order="F") 141 | zz = np.ravel(z, order="F") 142 | 143 | # eliminate this loop by creating a composed array. 144 | for i in range(nitems): 145 | bx = struct.pack(fmt, xx[i]) 146 | by = struct.pack(fmt, yy[i]) 147 | bz = struct.pack(fmt, zz[i]) 148 | stream.write(bx) 149 | stream.write(by) 150 | stream.write(bz) 151 | -------------------------------------------------------------------------------- /pyevtk/hl.py: -------------------------------------------------------------------------------- 1 | # *********************************************************************************** 2 | # * Copyright 2010 - 2016 Paulo A. Herrera. All rights reserved. * 3 | # * * 4 | # * Redistribution and use in source and binary forms, with or without * 5 | # * modification, are permitted provided that the following conditions are met: * 6 | # * * 7 | # * 1. Redistributions of source code must retain the above copyright notice, * 8 | # * this list of conditions and the following disclaimer. * 9 | # * * 10 | # * 2. Redistributions in binary form must reproduce the above copyright notice, * 11 | # * this list of conditions and the following disclaimer in the documentation * 12 | # * and/or other materials provided with the distribution. * 13 | # * * 14 | # * THIS SOFTWARE IS PROVIDED BY PAULO A. HERRERA ``AS IS'' AND ANY EXPRESS OR * 15 | # * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * 16 | # * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * 17 | # * EVENT SHALL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * 18 | # * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * 19 | # * BUT NOT LIMITED TO, PROCUREMEN OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * 20 | # * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * 21 | # * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * 22 | # * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * 23 | # * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 24 | # *********************************************************************************** 25 | """High level Python library to export data to binary VTK file.""" 26 | 27 | import numpy as np 28 | from .vtk import ( 29 | VtkFile, 30 | VtkParallelFile, 31 | VtkUnstructuredGrid, 32 | VtkImageData, 33 | VtkRectilinearGrid, 34 | VtkStructuredGrid, 35 | VtkPImageData, 36 | VtkPRectilinearGrid, 37 | VtkPStructuredGrid, 38 | VtkUnstructuredGrid, 39 | VtkVertex, 40 | VtkLine, 41 | VtkPolyLine, 42 | VtkPixel, 43 | ) 44 | 45 | 46 | # ================================= 47 | # Helper functions 48 | # ================================= 49 | def _addDataToFile(vtkFile, cellData, pointData, fieldData=None): 50 | # Point data 51 | if pointData: 52 | keys = list(pointData.keys()) 53 | # find first scalar and vector data key to set it as attribute 54 | scalars = next( 55 | (key for key in keys if isinstance(pointData[key], np.ndarray)), None 56 | ) 57 | vectors = next((key for key in keys if isinstance(pointData[key], tuple)), None) 58 | vtkFile.openData("Point", scalars=scalars, vectors=vectors) 59 | for key in keys: 60 | data = pointData[key] 61 | vtkFile.addData(key, data) 62 | vtkFile.closeData("Point") 63 | 64 | # Cell data 65 | if cellData: 66 | keys = list(cellData.keys()) 67 | # find first scalar and vector data key to set it as attribute 68 | scalars = next( 69 | (key for key in keys if isinstance(cellData[key], np.ndarray)), None 70 | ) 71 | vectors = next((key for key in keys if isinstance(cellData[key], tuple)), None) 72 | vtkFile.openData("Cell", scalars=scalars, vectors=vectors) 73 | for key in keys: 74 | data = cellData[key] 75 | vtkFile.addData(key, data) 76 | vtkFile.closeData("Cell") 77 | 78 | # Field data 79 | # https://www.visitusers.org/index.php?title=Time_and_Cycle_in_VTK_files#XML_VTK_files 80 | if fieldData: 81 | keys = list(fieldData.keys()) 82 | vtkFile.openData("Field") # no attributes in FieldData 83 | for key in keys: 84 | data = fieldData[key] 85 | vtkFile.addData(key, data) 86 | vtkFile.closeData("Field") 87 | 88 | 89 | def _addDataToParallelFile(vtkParallelFile, cellData, pointData): 90 | assert isinstance(vtkParallelFile, VtkParallelFile) 91 | # Point data 92 | if pointData: 93 | keys = list(pointData.keys()) 94 | # find first scalar and vector data key to set it as attribute 95 | scalars = next((key for key in keys if pointData[key][1] == 1), None) 96 | vectors = next((key for key in keys if pointData[key][1] == 3), None) 97 | vtkParallelFile.openData("PPoint", scalars=scalars, vectors=vectors) 98 | for key in keys: 99 | dtype, ncomp = pointData[key] 100 | vtkParallelFile.addHeader(key, dtype=dtype, ncomp=ncomp) 101 | vtkParallelFile.closeData("PPoint") 102 | 103 | # Cell data 104 | if cellData: 105 | keys = list(cellData.keys()) 106 | # find first scalar and vector data key to set it as attribute 107 | scalars = next((key for key in keys if cellData[key][1] == 1), None) 108 | vectors = next((key for key in keys if cellData[key][1] == 3), None) 109 | vtkParallelFile.openData("PCell", scalars=scalars, vectors=vectors) 110 | for key in keys: 111 | dtype, ncomp = cellData[key] 112 | vtkParallelFile.addHeader(key, dtype=dtype, ncomp=ncomp) 113 | vtkParallelFile.closeData("PCell") 114 | 115 | 116 | def _appendDataToFile(vtkFile, cellData, pointData, fieldData=None): 117 | # Append data to binary section 118 | if pointData is not None: 119 | keys = list(pointData.keys()) 120 | for key in keys: 121 | data = pointData[key] 122 | vtkFile.appendData(data) 123 | 124 | if cellData is not None: 125 | keys = list(cellData.keys()) 126 | for key in keys: 127 | data = cellData[key] 128 | vtkFile.appendData(data) 129 | 130 | if fieldData is not None: 131 | keys = list(fieldData.keys()) 132 | for key in keys: 133 | data = fieldData[key] 134 | vtkFile.appendData(data) 135 | 136 | 137 | # ================================= 138 | # High level functions 139 | # ================================= 140 | def imageToVTK( 141 | path, 142 | origin=(0.0, 0.0, 0.0), 143 | spacing=(1.0, 1.0, 1.0), 144 | cellData=None, 145 | pointData=None, 146 | fieldData=None, 147 | start=(0, 0, 0), 148 | ): 149 | """ 150 | Export data values as a rectangular image. 151 | 152 | Parameters 153 | ---------- 154 | path : str 155 | name of the file without extension where data should be saved. 156 | start : tuple, optional 157 | start of the coordinates. 158 | Used in the distributed context where each process 159 | writes its own vtk file. Default is (0, 0, 0). 160 | origin : tuple, optional 161 | grid origin. 162 | The default is (0.0, 0.0, 0.0). 163 | spacing : tuple, optional 164 | grid spacing. 165 | The default is (1.0, 1.0, 1.0). 166 | cellData : dict, optional 167 | dictionary containing arrays with cell centered data. 168 | Keys should be the names of the data arrays. 169 | Arrays must have the same dimensions in all directions and can contain 170 | scalar data ([n,n,n]) or vector data ([n,n,n],[n,n,n],[n,n,n]). 171 | The default is None. 172 | pointData : dict, optional 173 | dictionary containing arrays with node centered data. 174 | Keys should be the names of the data arrays. 175 | Arrays must have same dimension in each direction and 176 | they should be equal to the dimensions of the cell data plus one and 177 | can contain scalar data ([n+1,n+1,n+1]) or 178 | ([n+1,n+1,n+1],[n+1,n+1,n+1],[n+1,n+1,n+1]). 179 | The default is None. 180 | fieldData : dict, optional 181 | dictionary with variables associated with the field. 182 | Keys should be the names of the variable stored in each array. 183 | 184 | Returns 185 | ------- 186 | str 187 | Full path to saved file. 188 | 189 | Notes 190 | ----- 191 | At least, cellData or pointData must be present 192 | to infer the dimensions of the image. 193 | """ 194 | assert cellData is not None or pointData is not None 195 | 196 | # Extract dimensions 197 | end = None 198 | if cellData is not None: 199 | keys = list(cellData.keys()) 200 | data = cellData[keys[0]] 201 | if hasattr(data, "shape"): 202 | end = data.shape 203 | elif data[0].ndim == 3 and data[1].ndim == 3 and data[2].ndim == 3: 204 | end = data[0].shape 205 | for i, s in enumerate(spacing): 206 | if np.isclose(s, 0.0): 207 | if end[i] == 1: 208 | end = end[:i] + (0,) + end[i + 1 :] 209 | else: 210 | raise ValueError("imageToVTK: grid has lower dimension than data") 211 | elif pointData is not None: 212 | keys = list(pointData.keys()) 213 | data = pointData[keys[0]] 214 | if hasattr(data, "shape"): 215 | end = data.shape 216 | elif data[0].ndim == 3 and data[1].ndim == 3 and data[2].ndim == 3: 217 | end = data[0].shape 218 | end = (end[0] - 1, end[1] - 1, end[2] - 1) 219 | for i, s in enumerate(spacing): 220 | if np.isclose(s, 0.0) and end[i] > 0: 221 | raise ValueError("imageToVTK: grid has lower dimension than data") 222 | 223 | # Write data to file 224 | w = VtkFile(path, VtkImageData) 225 | w.openGrid(start=start, end=end, origin=origin, spacing=spacing) 226 | w.openPiece(start=start, end=end) 227 | _addDataToFile(w, cellData, pointData, fieldData) 228 | w.closePiece() 229 | w.closeGrid() 230 | _appendDataToFile(w, cellData, pointData, fieldData) 231 | w.save() 232 | return w.getFileName() 233 | 234 | 235 | # ============================================================================== 236 | def gridToVTK( 237 | path, x, y, z, cellData=None, pointData=None, fieldData=None, start=(0, 0, 0) 238 | ): 239 | """ 240 | Write data values as a rectilinear or structured grid. 241 | 242 | Parameters 243 | ---------- 244 | path : str 245 | name of the file without extension where data should be saved. 246 | x : array-like 247 | x coordinate axis. 248 | y : array-like 249 | y coordinate axis. 250 | z : array-like 251 | z coordinate axis. 252 | start : tuple, optional 253 | start of the coordinates. 254 | Used in the distributed context where each process 255 | writes its own vtk file. Default is (0, 0, 0). 256 | cellData : dict, optional 257 | dictionary containing arrays with cell centered data. 258 | Keys should be the names of the data arrays. 259 | Arrays must have the same dimensions in all directions and must contain 260 | only scalar data. 261 | pointData : dict, optional 262 | dictionary containing arrays with node centered data. 263 | Keys should be the names of the data arrays. 264 | Arrays must have same dimension in each direction and 265 | they should be equal to the dimensions of the cell data plus one and 266 | must contain only scalar data. 267 | fieldData : dict, optional 268 | dictionary with variables associated with the field. 269 | Keys should be the names of the variable stored in each array. 270 | Returns 271 | ------- 272 | str 273 | Full path to saved file. 274 | Notes 275 | ----- 276 | coordinates of the nodes of the grid. They can be 1D or 3D depending if 277 | the grid should be saved as a rectilinear or logically structured grid, 278 | respectively. 279 | Arrays should contain coordinates of the nodes of the grid. 280 | If arrays are 1D, then the grid should be Cartesian, 281 | i.e. faces in all cells are orthogonal. 282 | If arrays are 3D, then the grid should be logically structured 283 | with hexahedral cells. 284 | In both cases the arrays dimensions should be 285 | equal to the number of nodes of the grid. 286 | """ 287 | nx = ny = nz = 0 288 | 289 | if x.ndim == 1 and y.ndim == 1 and z.ndim == 1: 290 | nx, ny, nz = x.size - 1, y.size - 1, z.size - 1 291 | isRect = True 292 | ftype = VtkRectilinearGrid 293 | elif x.ndim == 3 and y.ndim == 3 and z.ndim == 3: 294 | s = x.shape 295 | nx, ny, nz = s[0] - 1, s[1] - 1, s[2] - 1 296 | isRect = False 297 | ftype = VtkStructuredGrid 298 | else: 299 | raise ValueError( 300 | f"x, y and z should have ndim == 3 but they have ndim of {x.ndim}, {y.ndim}" 301 | f" and {z.ndim} respectively" 302 | ) 303 | 304 | # Write extent 305 | end = (start[0] + nx, start[1] + ny, start[2] + nz) 306 | 307 | # Open File 308 | w = VtkFile(path, ftype) 309 | 310 | # Open Grid part 311 | w.openGrid(start=start, end=end) 312 | w.openPiece(start=start, end=end) 313 | 314 | # Add coordinates description 315 | if isRect: 316 | w.openElement("Coordinates") 317 | w.addData("x_coordinates", x) 318 | w.addData("y_coordinates", y) 319 | w.addData("z_coordinates", z) 320 | w.closeElement("Coordinates") 321 | else: 322 | w.openElement("Points") 323 | w.addData("points", (x, y, z)) 324 | w.closeElement("Points") 325 | 326 | # Add data description 327 | _addDataToFile(w, cellData, pointData, fieldData) 328 | 329 | # Close Grid part 330 | w.closePiece() 331 | w.closeGrid() 332 | 333 | # Write coordinates 334 | if isRect: 335 | w.appendData(x).appendData(y).appendData(z) 336 | else: 337 | w.appendData((x, y, z)) 338 | # Write data 339 | _appendDataToFile(w, cellData, pointData, fieldData) 340 | 341 | # Close file 342 | w.save() 343 | 344 | return w.getFileName() 345 | 346 | 347 | def writeParallelVTKGrid( 348 | path, coordsData, starts, ends, sources, ghostlevel=0, cellData=None, pointData=None 349 | ): 350 | """ 351 | Writes a parallel vtk file from grid-like data: 352 | VTKStructuredGrid or VTKRectilinearGrid 353 | 354 | Parameters 355 | ---------- 356 | path : str 357 | name of the file without extension. 358 | coordsData : tuple 359 | 2-tuple (shape, dtype) where shape is the 360 | shape of the coordinates of the full mesh 361 | and dtype is the dtype of the coordinates. 362 | starts : list 363 | list of 3-tuple representing where each source file starts 364 | in each dimension 365 | source : list 366 | list of the relative paths of the source files where the actual data is found 367 | ghostlevel : int, optional 368 | Number of ghost-levels by which 369 | the extents in the individual source files overlap. 370 | pointData : dict 371 | dictionnary containing the information about the arrays 372 | containing node centered data. 373 | Keys shoud be the names of the arrays. 374 | Values are (dtype, number of components) 375 | cellData : 376 | dictionnary containing the information about the arrays 377 | containing cell centered data. 378 | Keys shoud be the names of the arrays. 379 | Values are (dtype, number of components) 380 | """ 381 | # Check that every source as a start and an end 382 | assert len(starts) == len(ends) == len(sources) 383 | 384 | # Get the extension + check that it's consistent accros all source files 385 | common_ext = sources[0].split(".")[-1] 386 | assert all(s.split(".")[-1] == common_ext for s in sources) 387 | 388 | if common_ext == "vts": 389 | ftype = VtkPStructuredGrid 390 | is_Rect = False 391 | elif common_ext == "vtr": 392 | ftype = VtkPRectilinearGrid 393 | is_Rect = True 394 | else: 395 | raise ValueError("This functions is meant to work only with ") 396 | 397 | w = VtkParallelFile(path, ftype) 398 | start = (0, 0, 0) 399 | (s_x, s_y, s_z), dtype = coordsData 400 | end = s_x - 1, s_y - 1, s_z - 1 401 | 402 | w.openGrid(start=start, end=end, ghostlevel=ghostlevel) 403 | 404 | _addDataToParallelFile(w, cellData=cellData, pointData=pointData) 405 | 406 | if is_Rect: 407 | w.openElement("PCoordinates") 408 | w.addHeader("x_coordinates", dtype=dtype, ncomp=1) 409 | w.addHeader("y_coordinates", dtype=dtype, ncomp=1) 410 | w.addHeader("z_coordinates", dtype=dtype, ncomp=1) 411 | w.closeElement("PCoordinates") 412 | else: 413 | w.openElement("PPoints") 414 | w.addHeader("points", dtype=dtype, ncomp=3) 415 | w.closeElement("PPoints") 416 | 417 | for start_source, end_source, source in zip(starts, ends, sources): 418 | w.addPiece(start_source, end_source, source) 419 | 420 | w.closeGrid() 421 | w.save() 422 | return w.getFileName() 423 | 424 | 425 | # ============================================================================== 426 | def pointsToVTK(path, x, y, z, data=None, fieldData=None): 427 | """ 428 | Export points and associated data as an unstructured grid. 429 | 430 | Parameters 431 | ---------- 432 | path : str 433 | name of the file without extension where data should be saved. 434 | x : array-like 435 | x coordinates of the points. 436 | y : array-like 437 | y coordinates of the points. 438 | z : array-like 439 | z coordinates of the points. 440 | data : dict, optional 441 | dictionary with variables associated to each point. 442 | Keys should be the names of the variable stored in each array. 443 | All arrays must have the same number of elements. 444 | fieldData : dict, optional 445 | dictionary with variables associated with the field. 446 | Keys should be the names of the variable stored in each array. 447 | 448 | Returns 449 | ------- 450 | str 451 | Full path to saved file. 452 | """ 453 | assert x.size == y.size == z.size 454 | npoints = x.size 455 | 456 | # create some temporary arrays to write grid topology 457 | offsets = np.arange( 458 | start=1, stop=npoints + 1, dtype="int32" 459 | ) # index of last node in each cell 460 | connectivity = np.arange( 461 | npoints, dtype="int32" 462 | ) # each point is only connected to itself 463 | cell_types = np.empty(npoints, dtype="uint8") 464 | 465 | cell_types[:] = VtkVertex.tid 466 | 467 | w = VtkFile(path, VtkUnstructuredGrid) 468 | w.openGrid() 469 | w.openPiece(ncells=npoints, npoints=npoints) 470 | 471 | w.openElement("Points") 472 | w.addData("points", (x, y, z)) 473 | w.closeElement("Points") 474 | w.openElement("Cells") 475 | w.addData("connectivity", connectivity) 476 | w.addData("offsets", offsets) 477 | w.addData("types", cell_types) 478 | w.closeElement("Cells") 479 | 480 | _addDataToFile(w, cellData=None, pointData=data, fieldData=fieldData) 481 | 482 | w.closePiece() 483 | w.closeGrid() 484 | w.appendData((x, y, z)) 485 | w.appendData(connectivity).appendData(offsets).appendData(cell_types) 486 | 487 | _appendDataToFile(w, cellData=None, pointData=data, fieldData=fieldData) 488 | 489 | w.save() 490 | return w.getFileName() 491 | 492 | 493 | # ============================================================================== 494 | def linesToVTK(path, x, y, z, cellData=None, pointData=None, fieldData=None): 495 | """ 496 | Export line segments that joint 2 points and associated data. 497 | 498 | Parameters 499 | ---------- 500 | path : str 501 | name of the file without extension where data should be saved. 502 | x : array-like 503 | x coordinates of the points in lines. 504 | y : array-like 505 | y coordinates of the points in lines. 506 | z : array-like 507 | z coordinates of the points in lines. 508 | cellData : dict, optional 509 | dictionary with variables associated to each line. 510 | Keys should be the names of the variable stored in each array. 511 | All arrays must have the same number of elements. 512 | pointData : dict, optional 513 | dictionary with variables associated to each vertex. 514 | Keys should be the names of the variable stored in each array. 515 | All arrays must have the same number of elements. 516 | fieldData : dict, optional 517 | dictionary with variables associated with the field. 518 | Keys should be the names of the variable stored in each array. 519 | 520 | Returns 521 | ------- 522 | str 523 | Full path to saved file. 524 | 525 | Notes 526 | ----- 527 | x, y, z are 1D arrays with coordinates of the vertex of the lines. 528 | It is assumed that each line. 529 | is defined by two points, 530 | then the lenght of the arrays should be equal to 2 * number of lines. 531 | """ 532 | assert x.size == y.size == z.size 533 | assert x.size % 2 == 0 534 | npoints = x.size 535 | ncells = x.size / 2 536 | 537 | # Check cellData has the same size that the number of cells 538 | 539 | # create some temporary arrays to write grid topology 540 | offsets = np.arange( 541 | start=2, step=2, stop=npoints + 1, dtype="int32" 542 | ) # index of last node in each cell 543 | connectivity = np.arange( 544 | npoints, dtype="int32" 545 | ) # each point is only connected to itself 546 | cell_types = np.empty(npoints, dtype="uint8") 547 | 548 | cell_types[:] = VtkLine.tid 549 | 550 | w = VtkFile(path, VtkUnstructuredGrid) 551 | w.openGrid() 552 | w.openPiece(ncells=ncells, npoints=npoints) 553 | 554 | w.openElement("Points") 555 | w.addData("points", (x, y, z)) 556 | w.closeElement("Points") 557 | w.openElement("Cells") 558 | w.addData("connectivity", connectivity) 559 | w.addData("offsets", offsets) 560 | w.addData("types", cell_types) 561 | w.closeElement("Cells") 562 | 563 | _addDataToFile(w, cellData=cellData, pointData=pointData, fieldData=fieldData) 564 | 565 | w.closePiece() 566 | w.closeGrid() 567 | w.appendData((x, y, z)) 568 | w.appendData(connectivity).appendData(offsets).appendData(cell_types) 569 | 570 | _appendDataToFile(w, cellData=cellData, pointData=pointData, fieldData=fieldData) 571 | 572 | w.save() 573 | return w.getFileName() 574 | 575 | 576 | # ============================================================================== 577 | def polyLinesToVTK( 578 | path, x, y, z, pointsPerLine, cellData=None, pointData=None, fieldData=None 579 | ): 580 | """ 581 | Export line segments that joint n points and associated data. 582 | 583 | Parameters 584 | ---------- 585 | path : str 586 | name of the file without extension where data should be saved. 587 | x : array-like 588 | x coordinates of the points in lines. 589 | y : array-like 590 | y coordinates of the points in lines. 591 | z : array-like 592 | z coordinates of the points in lines. 593 | pointsPerLine : array-like 594 | Points in each poly-line. 595 | cellData : dict, optional 596 | dictionary with variables associated to each line. 597 | Keys should be the names of the variable stored in each array. 598 | All arrays must have the same number of elements. 599 | pointData : dict, optional 600 | dictionary with variables associated to each vertex. 601 | Keys should be the names of the variable stored in each array. 602 | All arrays must have the same number of elements. 603 | fieldData : dict, optional 604 | dictionary with variables associated with the field. 605 | Keys should be the names of the variable stored in each array. 606 | 607 | Returns 608 | ------- 609 | str 610 | Full path to saved file. 611 | """ 612 | assert x.size == y.size == z.size 613 | npoints = x.size 614 | ncells = pointsPerLine.size 615 | 616 | # create some temporary arrays to write grid topology 617 | offsets = np.zeros(ncells, dtype="int32") # index of last node in each cell 618 | ii = 0 619 | for i in range(ncells): 620 | ii += pointsPerLine[i] 621 | offsets[i] = ii 622 | 623 | connectivity = np.arange( 624 | npoints, dtype="int32" 625 | ) # each line connects points that are consecutive 626 | 627 | cell_types = np.empty(npoints, dtype="uint8") 628 | cell_types[:] = VtkPolyLine.tid 629 | 630 | w = VtkFile(path, VtkUnstructuredGrid) 631 | w.openGrid() 632 | w.openPiece(ncells=ncells, npoints=npoints) 633 | 634 | w.openElement("Points") 635 | w.addData("points", (x, y, z)) 636 | w.closeElement("Points") 637 | w.openElement("Cells") 638 | w.addData("connectivity", connectivity) 639 | w.addData("offsets", offsets) 640 | w.addData("types", cell_types) 641 | w.closeElement("Cells") 642 | 643 | _addDataToFile(w, cellData=cellData, pointData=pointData, fieldData=fieldData) 644 | 645 | w.closePiece() 646 | w.closeGrid() 647 | w.appendData((x, y, z)) 648 | w.appendData(connectivity).appendData(offsets).appendData(cell_types) 649 | 650 | _appendDataToFile(w, cellData=cellData, pointData=pointData, fieldData=fieldData) 651 | 652 | w.save() 653 | return w.getFileName() 654 | 655 | 656 | # ============================================================================== 657 | def unstructuredGridToVTK( 658 | path, 659 | x, 660 | y, 661 | z, 662 | connectivity, 663 | offsets, 664 | cell_types, 665 | cellData=None, 666 | pointData=None, 667 | fieldData=None, 668 | ): 669 | """ 670 | Export unstructured grid and associated data. 671 | 672 | Parameters 673 | ---------- 674 | path : str 675 | name of the file without extension where data should be saved. 676 | x : array-like 677 | x coordinates of the vertices. 678 | y : array-like 679 | y coordinates of the vertices. 680 | z : array-like 681 | z coordinates of the vertices. 682 | connectivity : array-like 683 | 1D array that defines the vertices associated to each element. 684 | Together with offset define the connectivity or topology of the grid. 685 | It is assumed that vertices in an element are listed consecutively. 686 | offsets : array-like 687 | 1D array with the index of the last vertex of each element 688 | in the connectivity array. 689 | It should have length nelem, 690 | where nelem is the number of cells or elements in the grid.. 691 | cell_types : TYPE 692 | 1D array with an integer that defines the cell type of 693 | each element in the grid. 694 | It should have size nelem. 695 | This should be assigned from evtk.vtk.VtkXXXX.tid, where XXXX represent 696 | the type of cell. 697 | Please check the VTK file format specification for allowed cell types. 698 | cellData : dict, optional 699 | dictionary with variables associated to each cell. 700 | Keys should be the names of the variable stored in each array. 701 | All arrays must have the same number of elements. 702 | pointData : dict, optional 703 | dictionary with variables associated to each vertex. 704 | Keys should be the names of the variable stored in each array. 705 | All arrays must have the same number of elements. 706 | fieldData : dict, optional 707 | dictionary with variables associated with the field. 708 | Keys should be the names of the variable stored in each array. 709 | 710 | Returns 711 | ------- 712 | str 713 | Full path to saved file. 714 | """ 715 | assert x.size == y.size == z.size 716 | npoints = x.size 717 | ncells = cell_types.size 718 | assert offsets.size == ncells 719 | 720 | w = VtkFile(path, VtkUnstructuredGrid) 721 | w.openGrid() 722 | w.openPiece(ncells=ncells, npoints=npoints) 723 | 724 | w.openElement("Points") 725 | w.addData("points", (x, y, z)) 726 | w.closeElement("Points") 727 | w.openElement("Cells") 728 | w.addData("connectivity", connectivity) 729 | w.addData("offsets", offsets) 730 | w.addData("types", cell_types) 731 | w.closeElement("Cells") 732 | 733 | _addDataToFile(w, cellData=cellData, pointData=pointData, fieldData=fieldData) 734 | 735 | w.closePiece() 736 | w.closeGrid() 737 | w.appendData((x, y, z)) 738 | w.appendData(connectivity).appendData(offsets).appendData(cell_types) 739 | 740 | _appendDataToFile(w, cellData=cellData, pointData=pointData, fieldData=fieldData) 741 | 742 | w.save() 743 | return w.getFileName() 744 | 745 | 746 | # ============================================================================== 747 | def cylinderToVTK( 748 | path, 749 | x0, 750 | y0, 751 | z0, 752 | z1, 753 | radius, 754 | nlayers, 755 | npilars=16, 756 | cellData=None, 757 | pointData=None, 758 | fieldData=None, 759 | ): 760 | """ 761 | Export cylinder as VTK unstructured grid. 762 | 763 | Parameters 764 | ---------- 765 | path : str 766 | name of the file without extension where data should be saved. 767 | x0 : float 768 | x-center of the cylinder. 769 | y0 : float 770 | y-center of the cylinder. 771 | z0 : float 772 | lower end of the cylinder. 773 | z1 : float 774 | upper end of the cylinder. 775 | radius : float 776 | radius of the cylinder. 777 | nlayers : int 778 | Number of layers in z direction to divide the cylinder.. 779 | npilars : int, optional 780 | Number of points around the diameter of the cylinder. 781 | Higher value gives higher resolution to represent the curved shape. 782 | The default is 16. 783 | cellData : dict, optional 784 | dictionary with variables associated to each cell. 785 | Keys should be the names of the variable stored in each array. 786 | Arrays should have number of elements equal to 787 | ncells = npilars * nlayers. 788 | pointData : dict, optional 789 | dictionary with variables associated to each vertex. 790 | Keys should be the names of the variable stored in each array. 791 | Arrays should have number of elements equal to 792 | npoints = npilars * (nlayers + 1). 793 | fieldData : dict, optional 794 | dictionary with variables associated with the field. 795 | Keys should be the names of the variable stored in each array. 796 | 797 | Returns 798 | ------- 799 | str 800 | Full path to saved file. 801 | 802 | Notes 803 | ----- 804 | This function only export vertical shapes for now. 805 | However, it should be easy to 806 | rotate the cylinder to represent other orientations. 807 | """ 808 | import math as m 809 | 810 | # Define x, y coordinates from polar coordinates. 811 | dpi = 2.0 * m.pi / npilars 812 | angles = np.arange(0.0, 2.0 * m.pi, dpi) 813 | 814 | x = radius * np.cos(angles) + x0 815 | y = radius * np.sin(angles) + y0 816 | 817 | dz = (z1 - z0) / nlayers 818 | z = np.arange(z0, z1 + dz, step=dz) 819 | 820 | npoints = npilars * (nlayers + 1) 821 | ncells = npilars * nlayers 822 | 823 | xx = np.zeros(npoints) 824 | yy = np.zeros(npoints) 825 | zz = np.zeros(npoints) 826 | 827 | ii = 0 828 | for k in range(nlayers + 1): 829 | for p in range(npilars): 830 | xx[ii] = x[p] 831 | yy[ii] = y[p] 832 | zz[ii] = z[k] 833 | ii = ii + 1 834 | 835 | # Define connectivity 836 | conn = np.zeros(4 * ncells, dtype=np.int64) 837 | ii = 0 838 | for l in range(nlayers): 839 | for p in range(npilars): 840 | p0 = p 841 | if p + 1 == npilars: 842 | p1 = 0 843 | else: 844 | p1 = p + 1 # circular loop 845 | 846 | n0 = p0 + l * npilars 847 | n1 = p1 + l * npilars 848 | n2 = n0 + npilars 849 | n3 = n1 + npilars 850 | 851 | conn[ii + 0] = n0 852 | conn[ii + 1] = n1 853 | conn[ii + 2] = n3 854 | conn[ii + 3] = n2 855 | ii = ii + 4 856 | 857 | # Define offsets 858 | offsets = np.zeros(ncells, dtype=np.int64) 859 | for i in range(ncells): 860 | offsets[i] = (i + 1) * 4 861 | 862 | # Define cell types 863 | ctype = np.ones(ncells) + VtkPixel.tid 864 | 865 | return unstructuredGridToVTK( 866 | path, 867 | xx, 868 | yy, 869 | zz, 870 | connectivity=conn, 871 | offsets=offsets, 872 | cell_types=ctype, 873 | cellData=cellData, 874 | pointData=pointData, 875 | fieldData=fieldData, 876 | ) 877 | -------------------------------------------------------------------------------- /pyevtk/vtk.py: -------------------------------------------------------------------------------- 1 | # *********************************************************************************** 2 | # * Copyright 2010 - 2016 Paulo A. Herrera. All rights reserved. * 3 | # * * 4 | # * Redistribution and use in source and binary forms, with or without * 5 | # * modification, are permitted provided that the following conditions are met: * 6 | # * * 7 | # * 1. Redistributions of source code must retain the above copyright notice, * 8 | # * this list of conditions and the following disclaimer. * 9 | # * * 10 | # * 2. Redistributions in binary form must reproduce the above copyright notice, * 11 | # * this list of conditions and the following disclaimer in the documentation * 12 | # * and/or other materials provided with the distribution. * 13 | # * * 14 | # * THIS SOFTWARE IS PROVIDED BY PAULO A. HERRERA ``AS IS'' AND ANY EXPRESS OR * 15 | # * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * 16 | # * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * 17 | # * EVENT SHALL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * 18 | # * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * 19 | # * BUT NOT LIMITED TO, PROCUREMEN OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * 20 | # * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * 21 | # * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * 22 | # * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * 23 | # * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 24 | # *********************************************************************************** 25 | """Low level Python library to export data to binary VTK file.""" 26 | 27 | import sys 28 | import os 29 | import numpy as np 30 | 31 | from .evtk import writeBlockSize, writeArrayToFile, writeArraysToFile 32 | from .xml import XmlWriter 33 | 34 | 35 | # ================================ 36 | # VTK Types 37 | # ================================ 38 | 39 | 40 | # FILE TYPES 41 | class VtkFileType: 42 | """ 43 | Wrapper class for VTK file types. 44 | 45 | Parameters 46 | ---------- 47 | name : str 48 | Data name. 49 | ext : str 50 | File extension. 51 | """ 52 | 53 | def __init__(self, name, ext): 54 | self.name = name 55 | self.ext = ext 56 | 57 | def __str__(self): 58 | return "Name: %s Ext: %s \n" % (self.name, self.ext) 59 | 60 | 61 | VtkImageData = VtkFileType("ImageData", ".vti") 62 | VtkPolyData = VtkFileType("PolyData", ".vtp") 63 | VtkRectilinearGrid = VtkFileType("RectilinearGrid", ".vtr") 64 | VtkStructuredGrid = VtkFileType("StructuredGrid", ".vts") 65 | VtkUnstructuredGrid = VtkFileType("UnstructuredGrid", ".vtu") 66 | 67 | 68 | class VtkParallelFileType: 69 | """ 70 | A wrapper class for parallel vtk file types. 71 | 72 | Parameters 73 | ---------- 74 | vtkftype : VtkFileType 75 | Vtk file type 76 | """ 77 | 78 | def __init__(self, vtkftype): 79 | self.name = "P" + vtkftype.name 80 | ext = vtkftype.ext 81 | self.ext = ext[0] + "p" + ext[1:] 82 | 83 | 84 | VtkPImageData = VtkParallelFileType(VtkImageData) 85 | VtkPPolyData = VtkParallelFileType(VtkPolyData) 86 | VtkPRectilinearGrid = VtkParallelFileType(VtkRectilinearGrid) 87 | VtkPStructuredGrid = VtkParallelFileType(VtkStructuredGrid) 88 | VtkPUnstructuredGrid = VtkParallelFileType(VtkUnstructuredGrid) 89 | 90 | 91 | # DATA TYPES 92 | class VtkDataType: 93 | """ 94 | Wrapper class for VTK data types. 95 | 96 | Parameters 97 | ---------- 98 | size : int 99 | Size in byte. 100 | name : str 101 | Type name. 102 | """ 103 | 104 | def __init__(self, size, name): 105 | self.size = size 106 | self.name = name 107 | 108 | def __str__(self): 109 | return "Type: %s Size: %d \n" % (self.name, self.size) 110 | 111 | 112 | VtkInt8 = VtkDataType(1, "Int8") 113 | VtkUInt8 = VtkDataType(1, "UInt8") 114 | VtkInt16 = VtkDataType(2, "Int16") 115 | VtkUInt16 = VtkDataType(2, "UInt16") 116 | VtkInt32 = VtkDataType(4, "Int32") 117 | VtkUInt32 = VtkDataType(4, "UInt32") 118 | VtkInt64 = VtkDataType(8, "Int64") 119 | VtkUInt64 = VtkDataType(8, "UInt64") 120 | VtkFloat32 = VtkDataType(4, "Float32") 121 | VtkFloat64 = VtkDataType(8, "Float64") 122 | 123 | # Map numpy to VTK data types 124 | np_to_vtk = { 125 | "int8": VtkInt8, 126 | "uint8": VtkUInt8, 127 | "int16": VtkInt16, 128 | "uint16": VtkUInt16, 129 | "int32": VtkInt32, 130 | "uint32": VtkUInt32, 131 | "int64": VtkInt64, 132 | "uint64": VtkUInt64, 133 | "float32": VtkFloat32, 134 | "float64": VtkFloat64, 135 | } 136 | 137 | 138 | # CELL TYPES 139 | class VtkCellType: 140 | """ 141 | Wrapper class for VTK cell types. 142 | 143 | Parameters 144 | ---------- 145 | tid : int 146 | Type ID. 147 | name : str 148 | Cell type name. 149 | """ 150 | 151 | def __init__(self, tid, name): 152 | self.tid = tid 153 | self.name = name 154 | 155 | def __str__(self): 156 | return "VtkCellType( %s ) \n" % (self.name) 157 | 158 | 159 | VtkVertex = VtkCellType(1, "Vertex") 160 | VtkPolyVertex = VtkCellType(2, "PolyVertex") 161 | VtkLine = VtkCellType(3, "Line") 162 | VtkPolyLine = VtkCellType(4, "PolyLine") 163 | VtkTriangle = VtkCellType(5, "Triangle") 164 | VtkTriangleStrip = VtkCellType(6, "TriangleStrip") 165 | VtkPolygon = VtkCellType(7, "Polygon") 166 | VtkPixel = VtkCellType(8, "Pixel") 167 | VtkQuad = VtkCellType(9, "Quad") 168 | VtkTetra = VtkCellType(10, "Tetra") 169 | VtkVoxel = VtkCellType(11, "Voxel") 170 | VtkHexahedron = VtkCellType(12, "Hexahedron") 171 | VtkWedge = VtkCellType(13, "Wedge") 172 | VtkPyramid = VtkCellType(14, "Pyramid") 173 | VtkQuadraticEdge = VtkCellType(21, "Quadratic_Edge") 174 | VtkQuadraticTriangle = VtkCellType(22, "Quadratic_Triangle") 175 | VtkQuadraticQuad = VtkCellType(23, "Quadratic_Quad") 176 | VtkQuadraticTetra = VtkCellType(24, "Quadratic_Tetra") 177 | VtkQuadraticHexahedron = VtkCellType(25, "Quadratic_Hexahedron") 178 | 179 | 180 | # ============================== 181 | # Helper functions 182 | # ============================== 183 | def _mix_extents(start, end): 184 | assert len(start) == len(end) == 3 185 | string = "%d %d %d %d %d %d" % ( 186 | start[0], 187 | end[0], 188 | start[1], 189 | end[1], 190 | start[2], 191 | end[2], 192 | ) 193 | return string 194 | 195 | 196 | def _array_to_string(a): 197 | s = "".join([repr(num) + " " for num in a]) 198 | return s 199 | 200 | 201 | def _get_byte_order(): 202 | if sys.byteorder == "little": 203 | return "LittleEndian" 204 | return "BigEndian" 205 | 206 | 207 | # ================================ 208 | # VtkGroup class 209 | # ================================ 210 | class VtkGroup: 211 | """ 212 | Creates a VtkGroup file that is stored in filepath. 213 | 214 | Parameters 215 | ---------- 216 | filepath : str 217 | filename without extension. 218 | """ 219 | 220 | def __init__(self, filepath): 221 | self.xml = XmlWriter(filepath + ".pvd") 222 | self.xml.openElement("VTKFile") 223 | self.xml.addAttributes( 224 | type="Collection", version="0.1", byte_order=_get_byte_order() 225 | ) 226 | self.xml.openElement("Collection") 227 | self.root = os.path.dirname(filepath) 228 | 229 | def save(self): 230 | """Close this VtkGroup.""" 231 | self.xml.closeElement("Collection") 232 | self.xml.closeElement("VTKFile") 233 | self.xml.close() 234 | 235 | def addFile(self, filepath, sim_time, group="", part="0", name=""): 236 | """ 237 | Add a file to this VTK group. 238 | 239 | Parameters 240 | ---------- 241 | filepath : str 242 | full path to VTK file. 243 | sim_time : float 244 | simulated time. 245 | group : str, optional 246 | This attribute is not required; 247 | it is only for informational purposes. 248 | The default is "". 249 | part : int, optional 250 | It is an integer value greater than or equal to 0. 251 | The default is "0". 252 | 253 | Notes 254 | ----- 255 | See: http://www.paraview.org/Wiki/ParaView/Data_formats#PVD_File_Format for details. 256 | """ 257 | # TODO: Check what the other attributes are for. 258 | filename = os.path.relpath(filepath, start=self.root) 259 | self.xml.openElement("DataSet") 260 | self.xml.addAttributes( 261 | timestep=sim_time, group=group, part=part, file=filename, name=name 262 | ) 263 | self.xml.closeElement() 264 | 265 | 266 | # ================================ 267 | # VtkFile class 268 | # ================================ 269 | class VtkFile: 270 | """ 271 | Class for a VTK file. 272 | 273 | Parameters 274 | ---------- 275 | filepath : str 276 | filename without extension. 277 | ftype : str 278 | file type, e.g. VtkImageData, etc. 279 | largeFile : bool, optional 280 | If size of the stored data cannot be represented by a UInt32. 281 | The default is False. 282 | """ 283 | 284 | def __init__(self, filepath, ftype): 285 | self.ftype = ftype 286 | self.filename = filepath + ftype.ext 287 | self.xml = XmlWriter(self.filename) 288 | self.offset = 0 # offset in bytes after beginning of binary section 289 | self.appendedDataIsOpen = False 290 | self.xml.openElement("VTKFile").addAttributes( 291 | type=ftype.name, 292 | version="1.0", 293 | byte_order=_get_byte_order(), 294 | header_type="UInt64", 295 | ) 296 | 297 | def getFileName(self): 298 | """Return absolute path to this file.""" 299 | return os.path.abspath(self.filename) 300 | 301 | def openPiece( 302 | self, 303 | start=None, 304 | end=None, 305 | npoints=None, 306 | ncells=None, 307 | nverts=None, 308 | nlines=None, 309 | nstrips=None, 310 | npolys=None, 311 | ): 312 | """ 313 | Open piece section. 314 | 315 | Parameters 316 | ---------- 317 | start : array-like, optional 318 | array or list with start indexes in each direction. 319 | Must be given with end. 320 | end : array-like, optional 321 | array or list with end indexes in each direction. 322 | Must be given with start. 323 | npoints : int, optional 324 | number of points in piece 325 | ncells : int, optional 326 | number of cells in piece. 327 | If present, npoints must also be given. 328 | nverts : int, optional 329 | number of vertices. 330 | nlines : int, optional 331 | number of lines. 332 | nstrips : int, optional 333 | number of stripes. 334 | npolys : int, optional 335 | number of poly. 336 | 337 | Returns 338 | ------- 339 | VtkFile 340 | This VtkFile to allow chained calls. 341 | """ 342 | # TODO: Check what are the requirements for each type of grid. 343 | 344 | self.xml.openElement("Piece") 345 | if start and end: 346 | ext = _mix_extents(start, end) 347 | self.xml.addAttributes(Extent=ext) 348 | 349 | elif ncells and npoints: 350 | self.xml.addAttributes(NumberOfPoints=npoints, NumberOfCells=ncells) 351 | 352 | elif npoints or nverts or nlines or nstrips or npolys: 353 | if npoints is None: 354 | npoints = str(0) 355 | if nverts is None: 356 | nverts = str(0) 357 | if nlines is None: 358 | nlines = str(0) 359 | if nstrips is None: 360 | nstrips = str(0) 361 | if npolys is None: 362 | npolys = str(0) 363 | self.xml.addAttributes( 364 | NumberOfPoints=npoints, 365 | NumberOfVerts=nverts, 366 | NumberOfLines=nlines, 367 | NumberOfStrips=nstrips, 368 | NumberOfPolys=npolys, 369 | ) 370 | else: 371 | assert False 372 | 373 | return self 374 | 375 | def closePiece(self): 376 | """Close Piece.""" 377 | self.xml.closeElement("Piece") 378 | 379 | def openData( 380 | self, 381 | nodeType, 382 | scalars=None, 383 | vectors=None, 384 | normals=None, 385 | tensors=None, 386 | tcoords=None, 387 | ): 388 | """ 389 | Open data section. 390 | 391 | Parameters 392 | ---------- 393 | nodeType : str 394 | Either "Point", "Cell" or "Field". 395 | scalars : str, optional 396 | default data array name for scalar data. 397 | vectors : str, optional 398 | default data array name for vector data. 399 | normals : str, optional 400 | default data array name for normals data. 401 | tensors : str, optional 402 | default data array name for tensors data. 403 | tcoords : str, optional 404 | default data array name for tcoords data. 405 | 406 | Returns 407 | ------- 408 | VtkFile 409 | This VtkFile to allow chained calls. 410 | """ 411 | self.xml.openElement(nodeType + "Data") 412 | if scalars: 413 | self.xml.addAttributes(Scalars=scalars) 414 | if vectors: 415 | self.xml.addAttributes(Vectors=vectors) 416 | if normals: 417 | self.xml.addAttributes(Normals=normals) 418 | if tensors: 419 | self.xml.addAttributes(Tensors=tensors) 420 | if tcoords: 421 | self.xml.addAttributes(TCoords=tcoords) 422 | 423 | return self 424 | 425 | def closeData(self, nodeType): 426 | """ 427 | Close data section. 428 | 429 | Parameters 430 | ---------- 431 | nodeType : str 432 | "Point", "Cell" or "Field". 433 | 434 | Returns 435 | ------- 436 | VtkFile 437 | This VtkFile to allow chained calls. 438 | """ 439 | self.xml.closeElement(nodeType + "Data") 440 | 441 | def openGrid(self, start=None, end=None, origin=None, spacing=None): 442 | """ 443 | Open grid section. 444 | 445 | Parameters 446 | ---------- 447 | start : array-like, optional 448 | array or list of start indexes. 449 | Required for Structured, Rectilinear and ImageData grids. 450 | The default is None. 451 | end : array-like, optional 452 | array or list of end indexes. 453 | Required for Structured, Rectilinear and ImageData grids. 454 | The default is None. 455 | origin : array-like, optional 456 | 3D array or list with grid origin. 457 | Only required for ImageData grids. 458 | The default is None. 459 | spacing : array-like, optional 460 | 3D array or list with grid spacing. 461 | Only required for ImageData grids. 462 | The default is None. 463 | 464 | Returns 465 | ------- 466 | VtkFile 467 | This VtkFile to allow chained calls. 468 | """ 469 | gType = self.ftype.name 470 | self.xml.openElement(gType) 471 | if gType == VtkImageData.name: 472 | if not start or not end or not origin or not spacing: 473 | assert False 474 | ext = _mix_extents(start, end) 475 | self.xml.addAttributes( 476 | WholeExtent=ext, 477 | Origin=_array_to_string(origin), 478 | Spacing=_array_to_string(spacing), 479 | ) 480 | 481 | elif gType in [VtkStructuredGrid.name, VtkRectilinearGrid.name]: 482 | if not start or not end: 483 | assert False 484 | ext = _mix_extents(start, end) 485 | self.xml.addAttributes(WholeExtent=ext) 486 | 487 | return self 488 | 489 | def closeGrid(self): 490 | """ 491 | Close grid element. 492 | 493 | Returns 494 | ------- 495 | VtkFile 496 | This VtkFile to allow chained calls. 497 | """ 498 | self.xml.closeElement(self.ftype.name) 499 | 500 | def addHeader(self, name, dtype, nelem, ncomp): 501 | """ 502 | Add data array description to xml header section. 503 | 504 | Parameters 505 | ---------- 506 | name : str 507 | data array name. 508 | dtype : str 509 | data type. 510 | nelem : int 511 | number of elements in array. 512 | ncomp : int 513 | number of components, 1 (=scalar) and 3 (=vector). 514 | 515 | Returns 516 | ------- 517 | VtkFile 518 | This VtkFile to allow chained calls. 519 | 520 | Notes 521 | ----- 522 | This is a low level function. 523 | Use addData if you want to add a numpy array. 524 | """ 525 | dtype = np_to_vtk[dtype] 526 | 527 | self.xml.openElement("DataArray") 528 | self.xml.addAttributes( 529 | Name=name, 530 | NumberOfComponents=ncomp, 531 | type=dtype.name, 532 | format="appended", 533 | offset=self.offset, 534 | ) 535 | self.xml.closeElement() 536 | 537 | self.offset += nelem * ncomp * dtype.size + 8 # add 8 to indicate array size 538 | return self 539 | 540 | def addData(self, name, data): 541 | """ 542 | Add array description to xml header section. 543 | 544 | Parameters 545 | ---------- 546 | name : str 547 | data array name. 548 | data : array-like 549 | one numpy array or a tuple with 3 numpy arrays. 550 | If a tuple, the individual arrays must represent the components 551 | of a vector field. 552 | All arrays must be one dimensional or three-dimensional. 553 | """ 554 | if isinstance(data, tuple): # vector data 555 | assert len(data) == 3 556 | x = data[0] 557 | self.addHeader(name, x.dtype.name, x.size, 3) 558 | elif isinstance(data, np.ndarray): 559 | if data.ndim == 1 or data.ndim == 3: 560 | self.addHeader(name, data.dtype.name, data.size, 1) 561 | else: 562 | assert False, "Bad array shape: " + str(data.shape) 563 | else: 564 | assert False, "Argument must be a Numpy array" 565 | 566 | def appendHeader(self, dtype, nelem, ncomp): 567 | """ 568 | Append size of data block to header. 569 | 570 | This function only writes the size of the data block 571 | that will be appended. 572 | The data itself must be written immediately after 573 | calling this function. 574 | 575 | Parameters 576 | ---------- 577 | dtype : str 578 | string with data type representation (same as numpy). 579 | For example, 'float64'. 580 | nelem : int 581 | number of elements. 582 | ncomp : int 583 | number of components, 1 (=scalar) or 3 (=vector).. 584 | """ 585 | self.openAppendedData() 586 | dsize = np_to_vtk[dtype].size 587 | block_size = dsize * ncomp * nelem 588 | writeBlockSize(self.xml.stream, block_size) 589 | # else: # this routine does not exist! 590 | # writeBlockSize64Bit(self.xml.stream, block_size) 591 | 592 | def appendData(self, data): 593 | """ 594 | Append data to binary section. 595 | 596 | This function writes the header section 597 | and the data to the binary file. 598 | 599 | Parameters 600 | ---------- 601 | data : array-like 602 | one numpy array or a tuple with 3 numpy arrays. 603 | If a tuple, the individual 604 | arrays must represent the components of a vector field. 605 | All arrays must be one dimensional or three-dimensional. 606 | The order of the arrays must coincide with 607 | the numbering scheme of the grid. 608 | 609 | Returns 610 | ------- 611 | VtkFile 612 | This VtkFile to allow chained calls. 613 | """ 614 | # TODO: Extend this function to accept contiguous C order arrays. 615 | self.openAppendedData() 616 | 617 | if isinstance(data, tuple): # 3 numpy arrays 618 | ncomp = len(data) 619 | assert ncomp == 3 620 | dsize = data[0].dtype.itemsize 621 | nelem = data[0].size 622 | block_size = ncomp * nelem * dsize 623 | # if self.largeFile == False: 624 | writeBlockSize(self.xml.stream, block_size) 625 | # else: 626 | # writeBlockSize64Bit(self.xml.stream, block_size) 627 | x, y, z = data[0], data[1], data[2] 628 | writeArraysToFile(self.xml.stream, x, y, z) 629 | 630 | elif isinstance(data, np.ndarray) and ( 631 | data.ndim == 1 or data.ndim == 3 632 | ): # single numpy array 633 | ncomp = 1 634 | dsize = data.dtype.itemsize 635 | nelem = data.size 636 | block_size = ncomp * nelem * dsize 637 | # if self.largeFile == False: 638 | writeBlockSize(self.xml.stream, block_size) 639 | # else: 640 | # writeBlockSize64Bit(self.xml.stream, block_size) 641 | writeArrayToFile(self.xml.stream, data) 642 | 643 | else: 644 | assert False 645 | 646 | return self 647 | 648 | def openAppendedData(self): 649 | """ 650 | Open binary section. 651 | 652 | It is not necessary to explicitly call this function 653 | from an external library. 654 | """ 655 | if not self.appendedDataIsOpen: 656 | self.xml.openElement("AppendedData").addAttributes(encoding="raw").addText( 657 | "_" 658 | ) 659 | self.appendedDataIsOpen = True 660 | 661 | def closeAppendedData(self): 662 | """ 663 | Close binary section. 664 | 665 | It is not necessary to explicitly call this function 666 | from an external library. 667 | """ 668 | self.xml.closeElement("AppendedData") 669 | 670 | def openElement(self, tagName): 671 | """ 672 | Open an element. 673 | 674 | Useful to add elements such as: Coordinates, Points, Verts, etc. 675 | """ 676 | self.xml.openElement(tagName) 677 | 678 | def closeElement(self, tagName): 679 | """Close an element.""" 680 | self.xml.closeElement(tagName) 681 | 682 | def save(self): 683 | """Close file.""" 684 | if self.appendedDataIsOpen: 685 | self.xml.closeElement("AppendedData") 686 | self.xml.closeElement("VTKFile") 687 | self.xml.close() 688 | 689 | 690 | # ================================ 691 | # VtkParallelFile class 692 | # ================================ 693 | class VtkParallelFile: 694 | """ 695 | Class for a VTK parallel file. 696 | 697 | Parameters 698 | ---------- 699 | filepath : str 700 | filename without extension 701 | ftype : VtkParallelFileType 702 | """ 703 | 704 | def __init__(self, filepath, ftype): 705 | assert isinstance(ftype, VtkParallelFileType) 706 | self.ftype = ftype 707 | self.filename = filepath + ftype.ext 708 | self.xml = XmlWriter(self.filename) 709 | self.xml.openElement("VTKFile").addAttributes( 710 | type=ftype.name, 711 | version="1.0", 712 | byte_order=_get_byte_order(), 713 | header_type="UInt64", 714 | ) 715 | 716 | def getFileName(self): 717 | """Return absolute path to this file.""" 718 | return os.path.abspath(self.filename) 719 | 720 | def addPiece( 721 | self, 722 | start=None, 723 | end=None, 724 | source=None, 725 | ): 726 | """ 727 | Add piece section with extent and source. 728 | Parameters 729 | ---------- 730 | start : array-like, optional 731 | array or list with start indexes in each direction. 732 | Must be given with end. 733 | end : array-like, optional 734 | array or list with end indexes in each direction. 735 | Must be given with start. 736 | source : str 737 | Source of this piece 738 | Returns 739 | ------- 740 | VtkParallelFile 741 | This VtkFile to allow chained calls. 742 | """ 743 | # Check Source 744 | assert source is not None 745 | assert source.split(".")[-1] == self.ftype.ext[2:] 746 | 747 | self.xml.openElement("Piece") 748 | if start and end: 749 | ext = _mix_extents(start, end) 750 | self.xml.addAttributes(Extent=ext) 751 | self.xml.addAttributes(Source=source) 752 | self.xml.closeElement() 753 | return self 754 | 755 | def openData( 756 | self, 757 | nodeType, 758 | scalars=None, 759 | vectors=None, 760 | normals=None, 761 | tensors=None, 762 | tcoords=None, 763 | ): 764 | """ 765 | Open data section. 766 | Parameters 767 | ---------- 768 | nodeType : str 769 | Either "Point", "Cell" or "Field". 770 | scalars : str, optional 771 | default data array name for scalar data. 772 | vectors : str, optional 773 | default data array name for vector data. 774 | normals : str, optional 775 | default data array name for normals data. 776 | tensors : str, optional 777 | default data array name for tensors data. 778 | tcoords : str, optional 779 | default data array name for tcoords data. 780 | Returns 781 | ------- 782 | VtkFile 783 | This VtkFile to allow chained calls. 784 | """ 785 | self.xml.openElement(nodeType + "Data") 786 | if scalars: 787 | self.xml.addAttributes(Scalars=scalars) 788 | if vectors: 789 | self.xml.addAttributes(Vectors=vectors) 790 | if normals: 791 | self.xml.addAttributes(Normals=normals) 792 | if tensors: 793 | self.xml.addAttributes(Tensors=tensors) 794 | if tcoords: 795 | self.xml.addAttributes(TCoords=tcoords) 796 | 797 | return self 798 | 799 | def closeData(self, nodeType): 800 | """ 801 | Close data section. 802 | Parameters 803 | ---------- 804 | nodeType : str 805 | "Point", "Cell" or "Field". 806 | Returns 807 | ------- 808 | VtkFile 809 | This VtkFile to allow chained calls. 810 | """ 811 | self.xml.closeElement(nodeType + "Data") 812 | 813 | def openGrid(self, start=None, end=None, origin=None, spacing=None, ghostlevel=0): 814 | """ 815 | Open grid section. 816 | 817 | Parameters 818 | ---------- 819 | start : array-like, optional 820 | array or list of start indexes. 821 | Required for Structured, Rectilinear and ImageData grids. 822 | The default is None. 823 | end : array-like, optional 824 | array or list of end indexes. 825 | Required for Structured, Rectilinear and ImageData grids. 826 | The default is None. 827 | origin : array-like, optional 828 | 3D array or list with grid origin. 829 | Only required for ImageData grids. 830 | The default is None. 831 | spacing : array-like, optional 832 | 3D array or list with grid spacing. 833 | Only required for ImageData grids. 834 | The default is None. 835 | ghostlevel : int 836 | Number of ghost-levels by which 837 | the extents in the individual pieces overlap. 838 | Returns 839 | ------- 840 | VtkFile 841 | This VtkFile to allow chained calls. 842 | """ 843 | gType = self.ftype.name 844 | self.xml.openElement(gType) 845 | 846 | if gType == VtkPImageData.name: 847 | if not start or not end or not origin or not spacing: 848 | raise ValueError(f"start, end, origin and spacing required for {gType}") 849 | ext = _mix_extents(start, end) 850 | self.xml.addAttributes( 851 | WholeExtent=ext, 852 | Origin=_array_to_string(origin), 853 | Spacing=_array_to_string(spacing), 854 | ) 855 | 856 | elif gType in [VtkPStructuredGrid.name, VtkPRectilinearGrid.name]: 857 | if not start or not end: 858 | raise ValueError(f"start and end required for {gType}.") 859 | ext = _mix_extents(start, end) 860 | self.xml.addAttributes(WholeExtent=ext) 861 | 862 | # Ghostlevel 863 | self.xml.addAttributes(Ghostlevel=ghostlevel) 864 | return self 865 | 866 | def closeGrid(self): 867 | """ 868 | Close grid element. 869 | Returns 870 | ------- 871 | VtkFile 872 | This VtkFile to allow chained calls. 873 | """ 874 | self.xml.closeElement(self.ftype.name) 875 | 876 | def addHeader(self, name, dtype, ncomp): 877 | """ 878 | Add data array description to xml header section. 879 | Parameters 880 | ---------- 881 | name : str 882 | data array name. 883 | dtype : str 884 | data type. 885 | ncomp : int 886 | number of components, 1 (=scalar) and 3 (=vector). 887 | Returns 888 | ------- 889 | 890 | VtkFile 891 | This VtkFile to allow chained calls. 892 | Notes 893 | ----- 894 | 895 | This is a low level function. 896 | Use addData if you want to add a numpy array. 897 | """ 898 | dtype = np_to_vtk[dtype.name] 899 | 900 | self.xml.openElement("DataArray") 901 | self.xml.addAttributes( 902 | Name=name, 903 | NumberOfComponents=ncomp, 904 | type=dtype.name, 905 | ) 906 | self.xml.closeElement() 907 | 908 | def openElement(self, tagName): 909 | """ 910 | Open an element. 911 | Useful to add elements such as: Coordinates, Points, Verts, etc. 912 | """ 913 | self.xml.openElement(tagName) 914 | 915 | def closeElement(self, tagName): 916 | self.xml.closeElement(tagName) 917 | 918 | def save(self): 919 | """Close file.""" 920 | self.xml.closeElement("VTKFile") 921 | self.xml.close() 922 | -------------------------------------------------------------------------------- /pyevtk/xml.py: -------------------------------------------------------------------------------- 1 | # *********************************************************************************** 2 | # * Copyright 2010 - 2016 Paulo A. Herrera. All rights reserved * 3 | # * * 4 | # * Redistribution and use in source and binary forms, with or without * 5 | # * modification, are permitted provided that the following conditions are met: * 6 | # * * 7 | # * 1. Redistributions of source code must retain the above copyright notice, * 8 | # * this list of conditions and the following disclaimer. * 9 | # * * 10 | # * 2. Redistributions in binary form must reproduce the above copyright notice, * 11 | # * this list of conditions and the following disclaimer in the documentation * 12 | # * and/or other materials provided with the distribution. * 13 | # * * 14 | # * THIS SOFTWARE IS PROVIDED BY PAULO A. HERRERA ``AS IS'' AND ANY EXPRESS OR * 15 | # * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * 16 | # * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * 17 | # * EVENT SHALL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * 18 | # * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * 19 | # * BUT NOT LIMITED TO, PROCUREMEN OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * 20 | # * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * 21 | # * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * 22 | # * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * 23 | # * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 24 | # *********************************************************************************** 25 | """Simple class to generate a well-formed XML file.""" 26 | 27 | 28 | class XmlWriter: 29 | """ 30 | xml writer class. 31 | 32 | Parameters 33 | ---------- 34 | filepath : str 35 | Path to the xml file. 36 | addDeclaration : bool, optional 37 | Whether to add the declaration. 38 | The default is True. 39 | """ 40 | 41 | def __init__(self, filepath, addDeclaration=True): 42 | self.stream = open(filepath, "wb") 43 | self.openTag = False 44 | self.current = [] 45 | if addDeclaration: 46 | self.addDeclaration() 47 | 48 | def close(self): 49 | """Close the file.""" 50 | assert not self.openTag 51 | self.stream.close() 52 | 53 | def addDeclaration(self): 54 | """Add xml declaration.""" 55 | self.stream.write(b'') 56 | 57 | def openElement(self, tag): 58 | """Open a new xml element.""" 59 | if self.openTag: 60 | self.stream.write(b">") 61 | st = "\n<%s" % tag 62 | self.stream.write(str.encode(st)) 63 | self.openTag = True 64 | self.current.append(tag) 65 | return self 66 | 67 | def closeElement(self, tag=None): 68 | """ 69 | Close the current element. 70 | 71 | Parameters 72 | ---------- 73 | tag : str, optional 74 | Tag of the element. 75 | The default is None. 76 | 77 | Returns 78 | ------- 79 | XmlWriter 80 | The XmlWriter itself for chained calles. 81 | """ 82 | if tag: 83 | assert self.current.pop() == tag 84 | if self.openTag: 85 | self.stream.write(b">") 86 | self.openTag = False 87 | st = "\n" % tag 88 | self.stream.write(str.encode(st)) 89 | else: 90 | self.stream.write(b"/>") 91 | self.openTag = False 92 | self.current.pop() 93 | return self 94 | 95 | def addText(self, text): 96 | """ 97 | Add text. 98 | 99 | Parameters 100 | ---------- 101 | text : str 102 | Text to add. 103 | 104 | Returns 105 | ------- 106 | XmlWriter 107 | The XmlWriter itself for chained calles. 108 | """ 109 | if self.openTag: 110 | self.stream.write(b">\n") 111 | self.openTag = False 112 | self.stream.write(str.encode(text)) 113 | return self 114 | 115 | def addAttributes(self, **kwargs): 116 | """ 117 | Add attributes. 118 | 119 | Parameters 120 | ---------- 121 | **kwargs 122 | keys as attribute names. 123 | 124 | Returns 125 | ------- 126 | XmlWriter 127 | The XmlWriter itself for chained calles. 128 | """ 129 | assert self.openTag 130 | for key in kwargs: 131 | st = ' %s="%s"' % (key, kwargs[key]) 132 | self.stream.write(str.encode(st)) 133 | return self 134 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pytest >= 3.1 2 | pytest-cov 3 | numpy 4 | wheel 5 | codecov 6 | twine 7 | check-manifest 8 | readme_renderer[md] 9 | black~=22.1.0 10 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [aliases] 2 | # this allows calling 'python setup.py test' 3 | test=pytest 4 | 5 | [pep8] 6 | max-line-length = 120 7 | ignore = E221,E226,E241,E242, W0105, N803, N806 8 | # E221 multiple spaces before operator 9 | # E226 missing whitespace around arithmetic operator [ignored by default] 10 | # E241 multiple spaces after ':' [ignored by default] 11 | # E242 tab after `,' [ignored by default] 12 | # W0105 String statement has no effect (we use triple qoted strings as documentation in some files) 13 | # N803 argument name should be lowercase (we use single capital letters everywhere for vectorarrays) 14 | # N806 same for variables in function 15 | 16 | [flake8] 17 | max-line-length = 120 18 | ignore = E221,E226,E241,E242, W0105, N803, N806 19 | # The following exclude avoids wrong warnings for unused imports 20 | exclude = __init__.py 21 | 22 | [tool:pytest] 23 | testpaths = tests/ 24 | python_files = tests/*.py 25 | python_class = Test 26 | pep8maxlinelength = 120 27 | pep8ignore = E221,E226,E241,E242 28 | addopts= --cov pyevtk 29 | 30 | # See the docstring in versioneer.py for instructions. Note that you must 31 | # re-run 'versioneer.py setup' after changing this section, and commit the 32 | # resulting files. 33 | 34 | [versioneer] 35 | VCS = git 36 | style = pep440-pre 37 | versionfile_source = pyevtk/_version.py 38 | versionfile_build = pyevtk/_version.py 39 | tag_prefix = 40 | parentdir_prefix = 41 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # *********************************************************************************** 2 | # * Copyright 2010-2017 Paulo A. Herrera. All rights reserved. * 3 | # * * 4 | # * Redistribution and use in source and binary forms, with or without * 5 | # * modification, are permitted provided that the following conditions are met: * 6 | # * * 7 | # * 1. Redistributions of source code must retain the above copyright notice, * 8 | # * this list of conditions and the following disclaimer. * 9 | # * * 10 | # * 2. Redistributions in binary form must reproduce the above copyright notice, * 11 | # * this list of conditions and the following disclaimer in the documentation * 12 | # * and/or other materials provided with the distribution. * 13 | # * * 14 | # * THIS SOFTWARE IS PROVIDED BY PAULO A. HERRERA ``AS IS'' AND ANY EXPRESS OR * 15 | # * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * 16 | # * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * 17 | # * EVENT SHALL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * 18 | # * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * 19 | # * BUT NOT LIMITED TO, PROCUREMEN OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * 20 | # * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * 21 | # * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * 22 | # * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * 23 | # * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 24 | # *********************************************************************************** 25 | 26 | try: 27 | from setuptools import setup 28 | except ImportError: 29 | from distutils.core import setup 30 | 31 | import versioneer 32 | 33 | 34 | def readme(fname): 35 | """Open the readme file.""" 36 | with open(fname, "r") as f: 37 | return f.read() 38 | 39 | 40 | setup( 41 | name="pyevtk", 42 | version=versioneer.get_version(), 43 | cmdclass=versioneer.get_cmdclass(), 44 | description="Export data as binary VTK files", 45 | long_description=readme("README.md"), 46 | long_description_content_type="text/markdown", 47 | author="Paulo Herrera", 48 | author_email="pauloa.herrera@gmail.com", 49 | maintainer="Adamos Kyriakou", 50 | maintainer_email="somada141@gmail.com", 51 | url="https://github.com/pyscience-projects/pyevtk", 52 | packages=["pyevtk", "evtk"], 53 | package_dir={"pyevtk": "pyevtk"}, 54 | package_data={"pyevtk": ["LICENSE.txt", "examples/*.py"]}, 55 | install_requires=["numpy >= 1.8.0"], 56 | # necessary for 'python setup.py test' 57 | setup_requires=["pytest-runner"], 58 | tests_require=["pytest>=3.1", "pytest-cov", "twine", "check-manifest"], 59 | classifiers=[ 60 | "Programming Language :: Python :: 3.7", 61 | "Programming Language :: Python :: 3.8", 62 | "Programming Language :: Python :: 3.9", 63 | "Programming Language :: Python :: 3.10", 64 | "Programming Language :: Python :: 3.11", 65 | ], 66 | ) 67 | -------------------------------------------------------------------------------- /tests/dummy.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import os 3 | import runpy 4 | 5 | import numpy as np 6 | 7 | 8 | def test_imports(): 9 | import pyevtk 10 | 11 | print(pyevtk.evtk) 12 | 13 | 14 | def test_examples(): 15 | this_dir = os.path.dirname(os.path.abspath(__file__)) 16 | example_dir = os.path.join(this_dir, "..", "examples") 17 | for root, _, files in os.walk(example_dir): 18 | examples = [os.path.join(root, f) for f in files if f.endswith(".py")] 19 | for ex in examples: 20 | runpy.run_path(ex) 21 | 22 | 23 | def test_compat_lib(): 24 | with pytest.warns(DeprecationWarning): 25 | import evtk 26 | import pyevtk 27 | 28 | assert pyevtk.evtk is evtk.evtk 29 | assert pyevtk.hl is evtk.hl 30 | assert pyevtk.vtk is evtk.vtk 31 | assert pyevtk.xml is evtk.xml 32 | 33 | 34 | def test_positional_args_only_image(): 35 | from pyevtk.hl import imageToVTK 36 | 37 | nx, ny, nz = 6, 6, 2 38 | ncells = nx * ny * nz 39 | npoints = (nx + 1) * (ny + 1) * (nz + 1) 40 | 41 | # Variables 42 | pressure = np.random.rand(ncells).reshape((nx, ny, nz), order="C") 43 | temp = np.random.rand(npoints).reshape((nx + 1, ny + 1, nz + 1)) 44 | 45 | imageToVTK( 46 | "./image", 47 | (0.0, 0.0, 0.0), 48 | (1.0, 1.0, 1.0), 49 | {"pressure": pressure}, 50 | {"temp": temp}, 51 | ) 52 | 53 | 54 | def test_positional_args_only_grid(): 55 | from pyevtk.hl import gridToVTK 56 | 57 | nx, ny, nz = 6, 6, 2 58 | 59 | ncells = nx * ny * nz 60 | npoints = (nx + 1) * (ny + 1) * (nz + 1) 61 | 62 | x = np.zeros((nx + 1, ny + 1, nz + 1)) 63 | y = np.zeros((nx + 1, ny + 1, nz + 1)) 64 | z = np.zeros((nx + 1, ny + 1, nz + 1)) 65 | 66 | # Variables 67 | pressure = np.random.rand(ncells).reshape((nx, ny, nz)) 68 | temp = np.random.rand(npoints).reshape((nx + 1, ny + 1, nz + 1)) 69 | 70 | gridToVTK( 71 | "./structured", 72 | x, 73 | y, 74 | z, 75 | {"pressure": pressure}, 76 | {"temp": temp}, 77 | ) 78 | --------------------------------------------------------------------------------